【问题标题】:How to forward from RootDialog to LuisDialog in Bot Framework如何在 Bot Framework 中从 RootDialog 转发到 LuisDialog
【发布时间】:2018-05-20 07:27:17
【问题描述】:

我正在为 FAQ 创建一个机器人。当机器人开始对话时,会发送一个带有 2 个选项的 PromptDialog:英语、法语。

我想在用户选择英语按钮时将对话框转发给 EnglishLuis,在选择法语时转发给 FrenchLuis。

这是我的代码:

Rootdialog.cs

public class RootDialog : IDialog<object>
{
    private const string EnglishMenu = "English";
    private const string FrenchMenu = "French";
    private const string QAMenu = "Q&A";

    private List<string> mainMenuList = new List<string>() { EnglishMenu, FrenchMenu, QAMenu };
    private string location;

    public async Task StartAsync(IDialogContext context)
    {
        await context.PostAsync("Welcome to Root Dialog");
        context.Wait(MessageReceiveAsync);
    }

    private async Task MessageReceiveAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
    {
        var reply = await result;
        if (reply.Text.ToLower().Contains("help"))
        {
            await context.PostAsync("You can implement help menu here");
        }
        else
        {
            await ShowMainmenu(context);
        }
    }

    private async Task ShowMainmenu(IDialogContext context)
    {
        //Show menues
        PromptDialog.Choice(context, this.CallDialog, this.mainMenuList, "What do you want to do?");
    }

    private async Task CallDialog(IDialogContext context, IAwaitable<string> result)
    {
        //This method is resume after user choise menu
       // this.luisResult = result;
       // var message = await result;
        var selectedMenu = await result;
        var message = await result;
        switch (selectedMenu)
        {
            case EnglishMenu:
                //Call child dialog without data
               //  context.Call(new EnglishLuis(),ResumeAfterDialog);
                //  context.Call(new EnglishLuis(), ResumeAfterDialog);

               await Conversation.SendAsync(context.MakeMessage(), () => new EnglishLuis());
                break;
            case FrenchMenu:
                //Call child dialog with data
                context.Call(new HotelDialog(location), ResumeAfterDialog);
                break;
            case QAMenu:
                context.Call(new LuisCallDialog(),ResumeAfterDialog);
                break;
        }

    }



    private async Task ResumeAfterDialog(IDialogContext context, IAwaitable<object> result)
    {
        //Resume this method after child Dialog is done.
        var test = await result;
        if (test != null)
        {
            location = test.ToString();
        }
        else
        {
            location = null;
        }
        await this.ShowMainmenu(context);
    }
}

}

英文Luis.cs:

 public class EnglishLuis : LuisDialog<object>
{
    private string location;



    //   string message = $"welcome to english dialog";

    public async Task None(IDialogContext context, LuisResult result)
    {
        string message = $"Sorry, I did not understand '{result.Query}'. Please try again";

        await context.PostAsync(message);

        context.Wait(this.MessageReceived);
        context.Done(true);
    }


    [LuisIntent("gretting")]
    [LuisIntent("intentfr")]
    public async Task Greeting(IDialogContext context, IAwaitable<IMessageActivity> activity, LuisResult result)
    {


        await context.PostAsync("Welcome :) ");


        context.Wait(MessageReceived);
        context.Done(true);
    }



    [LuisIntent("test")]
    public async Task test(IDialogContext context, IAwaitable<IMessageActivity> activity, LuisResult result)
    {
        await context.PostAsync("Do you want to test our bot ? We suggest to type : hi or who are you, help etc..");
        // context.Done(true);
        context.Wait(MessageReceived);
        context.Done(true);
    }

我的问题是,当我选择英语(甚至法语)时,我收到了这个错误:向你的机器人发送此消息时出错:HTTP 状态代码 InternalServerError

你能帮我如何启动 luis dialog 吗? P.S 如果我直接从 MessagesController.cs 开始效果很好......但我的意图是让人们在两种语言之间进行选择。

我尝试使用以下方法调用 luis:await context.Forward(new EnglishLuis(), ResumeAfterDialog, message, CancellationToken.None);但没有结果。

新文件 RootDialog.cs(更新):

   using System;
   using System.Collections.Generic;
   using System.Threading.Tasks;
    using Microsoft.Bot.Builder.Dialogs;
   using Microsoft.Bot.Connector;
    using System.Threading;

   namespace TeamsBot.Dialogs
    {
[Serializable]
public class RootDialog : IDialog<object>
{
    private const string EnglishMenu = "English";
    private const string FrenchMenu = "French";
    private const string QAMenu = "Q&A";

    private List<string> mainMenuList = new List<string>() { EnglishMenu, 
        FrenchMenu, QAMenu };
    private string location;

    private string originalMessage;

    public async Task StartAsync(IDialogContext context)
    {
        await context.PostAsync("Welcome to Root Dialog");
        context.Wait(MessageReceiveAsync);
    }

    private async Task MessageReceiveAsync(IDialogContext context, 
     IAwaitable<IMessageActivity> result)
    {
        var reply = await result;

        this.originalMessage = reply.Text;




        if (reply.Text.ToLower().Contains("help"))
        {
            await context.PostAsync("You can implement help menu here");
        }
        else
        {
            await ShowMainmenu(context);
        }
    }

    private async Task ShowMainmenu(IDialogContext context)
    {
        //Show menues
        PromptDialog.Choice(context, this.CallDialog, this.mainMenuList, 
   "What do you want to do?");
    }

    private async Task CallDialog(IDialogContext context, IAwaitable<string> 
    result)
    {

        var selectedMenu = await result;
        switch (selectedMenu)
        {
            case EnglishMenu:
                //Call child dialog without data
                var newMessage = context.MakeMessage();
                newMessage.Text = reply.Text; 
                 await context.Forward(new EnglishLuis(), ResumeAfterDialog, newMessage, CancellationToken.None);
                break;
            case FrenchMenu:
                //Call child dialog with data
                //   context.Call(new HotelDialog(location), ResumeAfterDialog);

                var frenchLuis = new FrenchLuis();
                var messageToForward = await result;
             //   await context.Forward(new FrenchLuis(), ResumeAfterDialog, messageToForward, CancellationToken.None);
                break;
            case QAMenu:
                context.Call(new LuisCallDialog(),ResumeAfterDialog);
                break;
        }

    }



    private async Task ResumeAfterDialog(IDialogContext context, IAwaitable<object> result)
    {
        //Resume this method after child Dialog is done.
        var test = await result;
        if (test != null)
        {
            location = test.ToString();
        }
        else
        {
            location = null;
        }
        await this.ShowMainmenu(context);
    }
}

}

【问题讨论】:

    标签: c# bots botframework azure-language-understanding


    【解决方案1】:

    首先,做

    context.Wait(this.MessageReceived);
    context.Done(true);
    

    这是错误的。您需要选择:或者您在EnglishDialog 中等待新消息,或者您结束EnglishDialog(使用Done

    然后,您尝试在context.Forward 中发送一个字符串,并且您需要转发一个IMessageActivity。而且我怀疑您想发送原始消息,因此您需要将其保存在全局变量中,然后再继续提示。尝试:

    var newMessage = context.MakeMessage();
    newMessage.Text = this.originalMessageText //the variable that contains the text of the original message that you will have to save at MessageReceiveAsync
    await context.Forward(new EnglishLuis(), ResumeAfterDialog, newMessage, CancellationToken.None);
    
    
    MessageReceivedAsync in RootDialog should looks like:
    
     private async Task MessageReceiveAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
        {
            var reply = await result;
            if (reply.Text.ToLower().Contains("help"))
            {
                await context.PostAsync("You can implement help menu here");
            }
            else
            {
                this.originalMessage = reply.Text;
                await ShowMainmenu(context);
            }
        }
    

    【讨论】:

    • 我不知道该放什么:this.originalMessageText
    • 传入的消息文本。在根对话框中查看您的代码,它应该是reply.Text。
    • 我不知道会发生什么但没有结果。我尝试输入: newMessage.Text = selectedMenu.ToString();或 newMessage.Text = 等待结果;或 newMessage.Text = reply.Text :( 我真的需要让它工作
    • 不行,在 Root 对话框的 MessageReceivedAsync 中你需要做this.originalMessage = reply.Text(你需要声明全局变量)
    • 我已经按照你说的更新了 RootDialog ,但是我得到了一个错误(名称'reply'在当前上下文中不存在),回复在这部分代码中:case EnglishMenu: var newMessage = context.MakeMessage(); newMessage.Text =回复.文本; //包含必须保存在 MessageReceiveAsync 的原始消息文本的变量 await context.Forward(new EnglishLuis(), ResumeAfterDialog, newMessage, CancellationToken.None);休息;
    【解决方案2】:

    这就是我将如何实现您调用不同对话框的方法。我倾向于使用对话框的依赖注入,所以我不必不断地更新它们。

    private async Task CallDialog(IDialogContext context, IAwaitable<string> result)
    {
        //These two variables will be exactly the same, you only need one     
        //var selectedMenu = await result;
        var message = await result;
        switch (selectedMenu)
        {
            case EnglishMenu:
                // Forward the context to the new LuisDialog to bring it to the top of the stack.  
                // This will also send your message to it so it gets processed there.
                await context.Forward<object>(new EnglishLuis(), ResumeAfterDialog, message , CancellationToken.None);
                break;
            case FrenchMenu:
                 await context.Forward<object>(new HotelDialog(location), ResumeAfterDialog, message , CancellationToken.None);
                break;
            case QAMenu:
                 await context.Forward<object>(new LuisCallDialog(), ResumeAfterDialog, message , CancellationToken.None);
                context.Call(new LuisCallDialog(),ResumeAfterDialog);
                break;
        }
    
    }
    

    在您使用的 EnglishLuis 对话框中存在问题:

    context.Wait(this.MessageReceived);
    context.Done(true);
    

    问题是这两行在通过对话框时都会执行。 context.Done 将导致此对话框离开堆栈,因此您最终将转到上一个对话框,这与您尝试等待响应的事实相冲突。

    实际上不应该有上下文。除非您想返回上一个对话框,否则在您的 luis 对话框中完成。因此,如果您选择使用 context.Done ,则可以将其放在 resumeAfter 方法中并具有适当的条件,或者在退出程序这一部分的单一意图下。

    您没有包含堆栈跟踪,但在使用 Luis 时可能会导致问题的是,如果您使用的是来自美国以外地区的堆栈跟踪。在这种情况下,您需要相应地设置域指向正确 Luis 服务的属性。

    public EnglishLuis(ConstructorParameters parameters) 
        : base(new LuisService(new LuisModelAttribute(
            "<AppId>",
            "<SubscriptionKey>",
            domain: "westeurope.api.cognitive.microsoft.com")))
        {
            // Constructor Stuff...
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-30
      • 1970-01-01
      • 1970-01-01
      • 2021-10-14
      • 1970-01-01
      • 2019-07-27
      • 1970-01-01
      相关资源
      最近更新 更多