当用户键入“退出”,“退出”等时,终止所有对话框并退出MS Bot Framework中的对话
我无法弄清楚如何在MS Bot Framework中做一个非常简单的事情:允许用户突破任何对话,离开当前对话框并通过键入“quit”,“exit”或“返回主菜单”重来”。
这是我的主要对话设置方式:
public async Task Post([FromBody]Activity activity) { try { if (activity.Type == ActivityTypes.Message) { UserActivityLogger.LogUserBehaviour(activity); if (activity.Text.ToLower() == "start over") { //Do something here, but I don't have the IDialogContext here! } BotUtils.SendTyping(activity); //send "typing" indicator upon each message received await Conversation.SendAsync(activity, () => new RootDialog()); } else { HandleSystemMessage(activity); } }
我知道如何使用context.Done(this);
终止对话框context.Done(this);
,但在这种方法中,我无法访问IDialogContext对象,因此我无法调用.Done()
。
当用户键入某个消息时,除了在所有对话框的每个步骤中添加一个检查之外,还有其他方法可以终止整个对话框堆栈吗?
发布赏金:
我需要一种终止所有IDialog
的方法,而不使用我在这里发布的令人发指的黑客攻击(删除我需要的所有用户数据,例如用户设置和首选项)。
基本上,当用户键入“退出”或“退出”时,我需要退出当前正在进行的任何IDialog
并返回到新状态,就好像用户刚刚发起了对话一样。
我需要能够从MessageController.cs,
执行此操作MessageController.cs,
我仍然无法访问IDialogContext
。 我似乎唯一有用的数据是Activity
对象。 如果有人指出其他方法,我会很高兴。
另一种方法是找到一些其他方法来检查机器人的其他位置的“退出”和“退出”关键字,而不是在Post方法中。
但它不应该是在IDialog
每一步都完成的检查,因为这是太多的代码甚至不可能(当使用PromptDialog
,我无法访问用户键入的文本)。
我没有探索的两种可能方式:
- 而不是终止所有当前的
IDialog
,与用户开始新的对话(newConversationId
) - 获取
IDialogStack
对象并使用它来管理对话框堆栈。
Microsoft文档对此对象保持沉默,因此我不知道如何获取它。 我没有在机器人的任何地方使用允许.Switch()
的Chain
对象,但是如果你认为它可以被重写以使用它,它也可以是解决这个问题的方法之一。 但是,我还没有找到如何在各种类型的对话框( FormFlow
和普通的IDialog
)之间进行分支,这些对话框又调用自己的子对话框等。
问题突然爆发
根据我对您的问题的理解,您想要实现的是重置对话框而不会完全破坏机器人状态 。
FACTS(从我从github存储库中读取的内容)
- 框架如何保存对话框堆栈如下:
BotDataStore> BotData> DialogStack
- BotFramework使用AutoFac作为DI容器
- DialogModule是用于对话框组件的Autofac模块
怎么做
从上面了解FACTS ,我的解决方案就是
- 注册依赖项,以便我们可以在我们的控制器中使用:
// in Global.asax.cs var builder = new ContainerBuilder(); builder.RegisterModule(new DialogModule()); builder.RegisterModule(new ReflectionSurrogateModule()); builder.RegisterModule(new DialogModule_MakeRoot()); var config = GlobalConfiguration.Configuration; builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); builder.RegisterWebApiFilterProvider(config); var container = builder.Build(); config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
- 获取Autofac容器 (随意放在您熟悉的代码中的任何位置)
private static ILifetimeScope Container { get { var config = GlobalConfiguration.Configuration; var resolver = (AutofacWebApiDependencyResolver)config.DependencyResolver; return resolver.Container; } }
- 在范围中加载BotData
- 加载DialogStack
- 重置DialogStack
- 将新BotData推回BotDataStore
using (var scope = DialogModule.BeginLifetimeScope(Container, activity)) { var botData = scope.Resolve(); await botData.LoadAsync(default(CancellationToken)); var stack = scope.Resolve(); stack.Reset(); await botData.FlushAsync(default(CancellationToken)); }
希望能帮助到你。
更新1(2016年8月27日)
感谢@ejadib指出, Container已经在会话类中公开了。
我们可以删除上面答案中的第2步,最后代码看起来像
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity)) { var botData = scope.Resolve(); await botData.LoadAsync(default(CancellationToken)); var stack = scope.Resolve(); stack.Reset(); await botData.FlushAsync(default(CancellationToken)); }
这是一个非常难看的黑客行为。 它基本上删除了所有用户数据(您可能实际需要),这会导致对话重新启动。
如果有人知道更好的方式,而不删除用户数据,请分享。
public async Task Post([FromBody]Activity activity) { try { if (activity.Type == ActivityTypes.Message) { //if the user types certain messages, quit all dialogs and start over string msg = activity.Text.ToLower().Trim(); if (msg == "start over" || msg == "exit" || msg == "quit" || msg == "done" || msg =="start again" || msg == "restart" || msg == "leave" || msg == "reset") { //This is where the conversation gets reset! activity.GetStateClient().BotState.DeleteStateForUser(activity.ChannelId, activity.From.Id); } //and even if we reset everything, show the welcome message again BotUtils.SendTyping(activity); //send "typing" indicator upon each message received await Conversation.SendAsync(activity, () => new RootDialog()); } else { HandleSystemMessage(activity); } }
我知道这有点旧,但我遇到了同样的问题,而且发布的解决方案不再是最好的方法。
我不确定自哪个版本可用,但在3.8.1上您可以注册可在对话框中的任何位置触发的IScorable
服务。
有一个示例代码显示它是如何工作的,它有一个“取消”全局命令处理程序:
https://github.com/Microsoft/BotBuilder-Samples/tree/master/CSharp/core-GlobalMessageHandlers
代码的一部分将如下所示:
protected override async Task PostAsync(IActivity item, string state, CancellationToken token) { this.task.Reset(); }
为其他人工作的其他代码:
private async Task _reset(Activity activity) { await activity.GetStateClient().BotState .DeleteStateForUserWithHttpMessagesAsync(activity.ChannelId, activity.From.Id); var client = new ConnectorClient(new Uri(activity.ServiceUrl)); var clearMsg = activity.CreateReply(); clearMsg.Text = $"Reseting everything for conversation: {activity.Conversation.Id}"; await client.Conversations.SendToConversationAsync(clearMsg); }
此代码由用户mmulhearn在此发布: https : //github.com/Microsoft/BotBuilder/issues/101#issuecomment-316170517