Microsoft Bot Framework从对话框中的特定瀑布步骤开始对话

时间:2019-02-21 06:57:41

标签: dialog botframework bots state-management

Microsoft Bot Framework V4,我在下面的对话框中定义了一个瀑布对话框

var waterfallSteps = new WaterfallStep[]

        {
            CallConfirmAsync,
            SimilarProductAsync,
            CheckNewVersionAsync,
        };

        AddDialog(new WaterfallDialog("productenquiry", waterfallSteps));

在执行前两个瀑布步骤之后,由于用户端无响应,我的对话停止了。因此,当用户再次回到该漫游器时,我想从第三个方法中恢复,即CheckNewVersionAsync。

任何人都可以在这里帮助我。

2 个答案:

答案 0 :(得分:1)

因此,在漫游器级别,如果您将IStatePropertyAccessor<DialogState>配置为ConversationState,则应该自动发生。无论用户响应花费了多长时间,您的WaterfallDialog都将停留在堆栈的顶部,并且将准确记住它所处的步骤。假设您的用户返回了相同的会话,那么它将从上次中断的地方开始。

鉴于此,您在问这个问题的事实使我相信,也许您正在使用WebChat,除非您自己进行设置,否则WebChat在页面加载期间不会保持相同的conversationId。如果是这样,那么我建议您再问一个问题,如果您不知道如何解决问题,那么该问题与正确保存对话框状态无关。

答案 1 :(得分:0)

编辑:Drew的回答是正确的,但是我的提供了另一个潜在的解决方案。您可以在这里找到更多信息:Managing State。特别是:

  

与机器人进行对话的用户状态随时可用   那个用户在那个频道上,无论对话是什么   状态可以在特定对话中随时使用,无论   的用户(即群组对话)的私有对话状态为   适用于特定的对话和特定的用户

     

提示

     

用户和会话状态均按渠道确定范围。相同   使用其他渠道访问您的漫游器的人显示为   不同的用户,每个频道一个,每个都有一个不同的用户   状态。

其他解决方案

如果您能够指定from Id,但不能确保conversation Id保持不变(请参见下文,在Gotchas下),则此解决方案最适合。

您可以在用户UserState中保存用户的操作步骤。

BasicBot

BasicBot通过其GreetingState类来完成此操作。

从其GreetingDialog

第一步,它初始化GreetingState,它通过查看已经设置了哪些用户变量来跟踪用户在对话框中走了多远:

private async Task<DialogTurnResult> InitializeStateStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var greetingState = await UserProfileAccessor.GetAsync(stepContext.Context, () => null);
    if (greetingState == null)
    {
        var greetingStateOpt = stepContext.Options as GreetingState;
        if (greetingStateOpt != null)
        {
            await UserProfileAccessor.SetAsync(stepContext.Context, greetingStateOpt);
        }
        else
        {
            await UserProfileAccessor.SetAsync(stepContext.Context, new GreetingState());
        }
    }

    return await stepContext.NextAsync();
}

然后在每个步骤中,它加载GreetingState

var greetingState = await UserProfileAccessor.GetAsync(stepContext.Context);

并检查该步骤是否已经完成,例如:

if (greetingState != null && !string.IsNullOrWhiteSpace(greetingState.Name) && !string.IsNullOrWhiteSpace(greetingState.City))

如果不存在greetingState.Name.City,则提示输入,如果已经填写,则继续:

return await stepContext.NextAsync();

在每个步骤中,它使用类似以下内容保存到GreetingState

greetingState.Name = char.ToUpper(lowerCaseName[0]) + lowerCaseName.Substring(1);
await UserProfileAccessor.SetAsync(stepContext.Context, greetingState);

简化您的用例

对于您来说,如果您不需要保存用户信息,则可以创建一个简单的Step类:

{
    /// <summary>
    /// User state properties for Waterfall Step.
    /// </summary>
    public class Step
    {
        public string StepNumber { get; set; }
    }
}

进行WaterfallDialog的第一步:

private async Task<DialogTurnResult> InitializeStateStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var StepState = await UserProfileAccessor.GetAsync(stepContext.Context, () => null);
    if (StepState == null)
    {
        var StepStateOpt = stepContext.Options as StepState;
        if (StepStateOpt != null)
        {
            await UserProfileAccessor.SetAsync(stepContext.Context, StepStateOpt );
        }
        else
        {
            await UserProfileAccessor.SetAsync(stepContext.Context, new StepState());
        }
    }

    return await stepContext.NextAsync();
}

在每个步骤上,加载当前的Step

var stepState = await UserProfileAccessor.GetAsync(stepContext.Context);

检查它们是否已经超过当前步骤:

if (stepState.StepNumber <= 2)
{
    // ...do stuff
    // Save that user has completed step
    stepState.StepNumber++;
    await UserProfileAccessor.SetAsync(stepContext.Context, stepState);
}
else
{
    return await stepContext.NextAsync();
}

陷阱

需要注意的几件事:

  • UserState仅针对相同的from IDchannel ID持续存在。确保离开瀑布中间的用户在重新输入时具有相同的from ID,并从相同的channel重新输入。这不是仿真器的默认设置-在仿真器中,重新启动会话后,会创建一个新的from ID。 (注意:请考虑from IDUser ID的同义词。它仅来自Activity.From.Id

  • ConversationState仅对于相同的conversation IDchannel ID持续存在。渠道中conversation ID的持久性因渠道而异。

有关不同ID的更多信息:ID fields in the Bot Framework