C# LUIS/Bot框架多对话框,将意图处理移动到另一个对话框

C# LUIS/Bot框架多对话框,将意图处理移动到另一个对话框,c#,botframework,azure-language-understanding,C#,Botframework,Azure Language Understanding,我的目标是使用dialogs和LUIS的C#SDK将其实现到Microsoft Bot框架应用程序中。 我试图遵循这条线索和他们的相关文章(在最后引用),但无法让我的代码在实践中发挥作用。这是我的RootDialog类。请注意,我创建了一个处理“GetProduct”意图的方法,当它获得此意图时,它应该使用context.forward()方法将LuisResult转发给ProductsDialog,但我看到的是它直接转到ResumeAfter方法ProductsDialogCompleted。

我的目标是使用dialogs和LUIS的C#SDK将其实现到Microsoft Bot框架应用程序中。 我试图遵循这条线索和他们的相关文章(在最后引用),但无法让我的代码在实践中发挥作用。这是我的RootDialog类。请注意,我创建了一个处理“GetProduct”意图的方法,当它获得此意图时,它应该使用context.forward()方法将LuisResult转发给ProductsDialog,但我看到的是它直接转到ResumeAfter方法ProductsDialogCompleted。现在,这里可能是我失败的地方,但我找不到显示多个LUIS对话框的示例

public class RootDialog : LuisDialog<object>
{
    [LuisIntent("GetProduct")]
    private async Task GetProduct(IDialogContext context, LuisResult result)
    {
        await context.PostAsync("Calling ProductsDialog...");
        await context.Forward(Chain.From(() => new ProductsDialog()), ProductsDialogCompleted, context.Activity, CancellationToken.None);
    }

    private async Task ProductsDialogCompleted(IDialogContext context, IAwaitable<object> result)
    {
        var res = await result;
        context.PostAsync("ProductsDialogCompleted" + result);
        context.Wait(this.MessageReceived);
    }
}
public class ProductsDialog : LuisDialog<object>
{
    public async Task StartAsync(IDialogContext context)
    {
        await context.PostAsync("Entered ProductsDialog");

        context.Wait(this.MessageReceived);
    }
    [LuisIntent("None")]
    private async Task None(IDialogContext context, LuisResult result)
    {
        context.Done(true);
    }
}
public类RootDialog:LuisDialog
{
[LuisIntent(“GetProduct”)]
私有异步任务GetProduct(IDialogContext上下文,LuisResult结果)
{
wait context.PostAsync(“调用ProductsDialog…”);
wait context.Forward(Chain.From(()=>newproductsdialog()),ProductsDialogCompleted,context.Activity,CancellationToken.None);
}
专用异步任务ProductsDialogCompleted(IDialogContext上下文,IAwaitable结果)
{
var res=等待结果;
PostAsync(“ProductsDialogCompleted”+结果);
context.Wait(this.MessageReceived);
}
}
公共类产品对话框:LuisDialog
{
公共异步任务StartAsync(IDialogContext上下文)
{
wait context.PostAsync(“已输入产品对话框”);
context.Wait(this.MessageReceived);
}
[路易辛顿(“无”)]
专用异步任务无(IDialogContext上下文,LuisResult结果)
{
上下文。完成(true);
}
}
预期的行为如下

  • 用户触发GetProduct intent
  • bot创建一个新对话框并转到StartAsync方法,在那里等待另一个用户输入
  • 用户触发无意图
  • 对话框关闭,返回true并触发ProductsDialogCompleted
  • 似乎我没有正确绑定对话框。我怎样才能解决这个问题

    编辑:添加MessageController,版本为3.8.1

    [BotAuthentication]
    public class MessagesController : ApiController
    {
        /// <summary>
        /// POST: api/Messages
        /// Receive a message from a user and reply to it
        /// </summary>
        public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
        {
            if (activity.Type == ActivityTypes.Message)
            {
                await Conversation.SendAsync(activity, () => new RootDialog());
            }
            else
            {
                HandleSystemMessage(activity);
            }
            var response = Request.CreateResponse(HttpStatusCode.OK);
            return response;
        }
    
        private Activity HandleSystemMessage(Activity message)
        {
            if (message.Type == ActivityTypes.DeleteUserData)
            {
                // Implement user deletion here
                // If we handle user deletion, return a real message
            }
            else if (message.Type == ActivityTypes.ConversationUpdate)
            {
                // Handle conversation state changes, like members being added and removed
                // Use Activity.MembersAdded and Activity.MembersRemoved and Activity.Action for info
                // Not available in all channels
            }
            else if (message.Type == ActivityTypes.ContactRelationUpdate)
            {
                // Handle add/remove from contact lists
                // Activity.From + Activity.Action represent what happened
            }
            else if (message.Type == ActivityTypes.Typing)
            {
                // Handle knowing tha the user is typing
            }
            else if (message.Type == ActivityTypes.Ping)
            {
            }
    
            return null;
        }
    }
    
    [BotAuthentication]
    公共类消息控制器:ApiController
    {
    /// 
    ///帖子:api/Messages
    ///接收来自用户的消息并回复
    /// 
    公共异步任务发布([FromBody]活动)
    {
    if(activity.Type==ActivityTypes.Message)
    {
    wait Conversation.sendaync(活动,()=>newrootdialog());
    }
    其他的
    {
    HandleSystemMessage(活动);
    }
    var response=Request.CreateResponse(HttpStatusCode.OK);
    返回响应;
    }
    私有活动HandleSystemMessage(活动消息)
    {
    if(message.Type==ActivityTypes.DeleteUserData)
    {
    //在此处执行用户删除
    //如果我们处理用户删除,返回一条真实的消息
    }
    else if(message.Type==ActivityTypes.ConversationUpdate)
    {
    //处理会话状态更改,如添加和删除成员
    //使用Activity.MembersAdded和Activity.MembersRemoved以及Activity.Action获取信息
    //并非所有频道都可用
    }
    else if(message.Type==ActivityTypes.ContactRelationUpdate)
    {
    //处理联系人列表中的添加/删除
    //Activity.From+Activity.Action表示发生了什么
    }
    else if(message.Type==ActivityTypes.Typing)
    {
    //处理知道用户正在键入的内容
    }
    else if(message.Type==ActivityTypes.Ping)
    {
    }
    返回null;
    }
    }
    
    尝试从
    上下文.Forward
    调用中删除
    链From(()
    )。不确定添加它的原因,但它不应该在那里

    尝试:

    await context.Forward(new ProductsDialog(), ProductsDialogCompleted, context.Activity, CancellationToken.None);
    
    顺便说一句,如果转发的消息点击了
    None
    意图,则会点击
    ProductsDialogCompleted
    方法,因为您正在执行
    context.Done
    ,这基本上结束了
    ProductsDialog


    另外,请记住
    StartAsync
    方法存在于
    LuisDialog
    基类中,因此您需要添加
    override
    关键字。

    我有同样的问题,但我使用的是较新版本的Bot框架,更具体地说,是V4

    以下是我的发现:

    • BeginDialogAsync
      选项
      参数接受一组对象,这些对象将在对话框中访问
    //从配置中获取技能LUIS模型。
    localizedServices.LuisServices.TryGetValue(“MySkill”,out var luisService);
    if(luisService!=null)
    {
    //得到路易斯的结果。
    var result=innerDc.Context.TurnState.Get(StateProperties.SkillLuisResult);
    var intent=结果?.TopIntent().intent;
    //行为取决于意图。
    开关(意图)
    {
    案例MySkillLuis.Intent.MyIntent:
    {
    //结果通过Options参数传递给我的对话框。
    等待innerDc.BeginDialogAsync(_myDialog.Id,result);
    打破
    }
    案例MySkillLuis.Intent.None:
    违约:
    {
    //已确定意图,但尚未实施
    等待innerDc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale(“UnsupportedMessage”);
    打破
    }
    }
    }
    

    在第二个对话框中,我们可以通过上下文访问对象,并根据需要执行任何强制转换等操作。在我的例子中,这是一个瀑布式对话框,所以我使用了
    stepContext.options

    它不起作用。我希望ProductsDialog成为活动对话框,以便它可以捕获传入的消息,就像在程序启动,所以它应该在返回t之前接受另一条触发none的消息