Microsoft Bot Framework 从对话中的特定瀑布步骤开始对话
Microsoft Bot Framework start the conversation from specific waterfall step in dialog
Microsoft Bot Framework V4,我在对话框中定义了一个瀑布对话框,如下所示
var waterfallSteps = new WaterfallStep[]
{
CallConfirmAsync,
SimilarProductAsync,
CheckNewVersionAsync,
};
AddDialog(new WaterfallDialog("productenquiry", waterfallSteps));
执行前两个瀑布步骤后,由于用户端没有响应,我的对话停止了。所以我想从第三种方法恢复,即当用户再次回到机器人时使用 CheckNewVersionAsync。
谁能帮帮我。
编辑:Drew 的回答是正确的,但我的回答提供了另一种可能的解决方案。您可以在此处找到更多信息:Managing State。特别是:
User state is available in any turn that the bot is conversing with
that user on that channel, regardless of the conversation Conversation
state is available in any turn in a specific conversation, regardless
of user (i.e. group conversations) Private conversation state is
scoped to both the specific conversation and to that specific user
Tip
Both user and conversation state are scoped by channel. The same
person using different channels to access your bot appears as
different users, one for each channel, and each with a distinct user
state.
其他解决方案
如果您能够指定 from Id
,但无法确保 conversation Id
保持不变,则此解决方案最适合(见下文,陷阱部分)。
您可以在他们的 UserState
.
中保存用户正在进行的步骤
基本机器人
BasicBot 用它的 GreetingState
class 来做到这一点。
来自其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
class:
{
/// <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 ID
和 channel ID
。确保在瀑布中间离开的用户在重新进入时具有相同的 from ID
,并且他们从相同的 channel 重新进入。这不是模拟器的默认设置——在模拟器中,当会话重新启动时,会创建一个新的 from ID
。 (注意:考虑 from ID
与 User ID
同义。它只是来自 Activity.From.Id
)
ConversationState 只持续相同的 conversation ID
和 channel ID
。 conversation ID
在频道内的持久性因频道而异。
有关不同 ID 的更多信息:ID fields in the Bot Framework。
因此,在机器人级别,如果您使用 ConversationState
配置了 IStatePropertyAccessor<DialogState>
,这应该会自动发生。无论用户花费多长时间做出响应,您的 WaterfallDialog
都将保留在堆栈的顶部,并且它会准确记住它在哪一步。假设您的用户回到同一个对话,那么它会从中断的地方继续。
鉴于此,您问这个问题这一事实让我相信,也许您使用的 WebChat 不会在页面加载期间保持相同 conversationId
,除非您自己设置它。如果是这种情况,那么我建议你问另一个问题,如果你不知道如何做到这一点,因为这是正确持久化对话框状态的一个单独问题。
Microsoft Bot Framework V4,我在对话框中定义了一个瀑布对话框,如下所示
var waterfallSteps = new WaterfallStep[]
{
CallConfirmAsync,
SimilarProductAsync,
CheckNewVersionAsync,
};
AddDialog(new WaterfallDialog("productenquiry", waterfallSteps));
执行前两个瀑布步骤后,由于用户端没有响应,我的对话停止了。所以我想从第三种方法恢复,即当用户再次回到机器人时使用 CheckNewVersionAsync。
谁能帮帮我。
编辑:Drew 的回答是正确的,但我的回答提供了另一种可能的解决方案。您可以在此处找到更多信息:Managing State。特别是:
User state is available in any turn that the bot is conversing with that user on that channel, regardless of the conversation Conversation state is available in any turn in a specific conversation, regardless of user (i.e. group conversations) Private conversation state is scoped to both the specific conversation and to that specific user
Tip
Both user and conversation state are scoped by channel. The same person using different channels to access your bot appears as different users, one for each channel, and each with a distinct user state.
其他解决方案
如果您能够指定 from Id
,但无法确保 conversation Id
保持不变,则此解决方案最适合(见下文,陷阱部分)。
您可以在他们的 UserState
.
基本机器人
BasicBot 用它的 GreetingState
class 来做到这一点。
来自其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
class:
{
/// <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 ID
和channel ID
。确保在瀑布中间离开的用户在重新进入时具有相同的from ID
,并且他们从相同的 channel 重新进入。这不是模拟器的默认设置——在模拟器中,当会话重新启动时,会创建一个新的from ID
。 (注意:考虑from ID
与User ID
同义。它只是来自Activity.From.Id
)ConversationState 只持续相同的
conversation ID
和channel ID
。conversation ID
在频道内的持久性因频道而异。
有关不同 ID 的更多信息:ID fields in the Bot Framework。
因此,在机器人级别,如果您使用 ConversationState
配置了 IStatePropertyAccessor<DialogState>
,这应该会自动发生。无论用户花费多长时间做出响应,您的 WaterfallDialog
都将保留在堆栈的顶部,并且它会准确记住它在哪一步。假设您的用户回到同一个对话,那么它会从中断的地方继续。
鉴于此,您问这个问题这一事实让我相信,也许您使用的 WebChat 不会在页面加载期间保持相同 conversationId
,除非您自己设置它。如果是这种情况,那么我建议你问另一个问题,如果你不知道如何做到这一点,因为这是正确持久化对话框状态的一个单独问题。