简体   繁体   中英

LUIS / Bot Framework multiple dialog, move intent handling to another dialog

my goal is to implement both dialogs and LUIS into a Microsoft Bot Framework application using their C# SDK. I tried to follow this thread https://github.com/Microsoft/BotBuilder/issues/127 and their related posts (referenced at the end) but couldn't get my code working in practice. This is my RootDialog class. Note that I created a method which handles the "GetProduct" intent, when it gets this intent, it should forward the LuisResult to ProductsDialog using context.Forward() method, but instead what I see is just that it goes straight to the ResumeAfter method, ProductsDialogCompleted. Now, here is probably where I fail but I couldn't find an example showing multiple LUIS dialogs.

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);
    }
}

The expected behavior is the following

  1. The user triggers the GetProduct intent
  2. The bot creates a new dialog and goes to the StartAsync method, where it waits for another user input
  3. The user triggers the None intent
  4. The dialog closes, returns true and triggers the ProductsDialogCompleted.

It seems like I'm not correctly binding the dialogs. How can I solve this?

EDIT: Added MessageController, version is 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;
    }
}

Try removing the Chain.From(() from the context.Forward call. Not sure why you are adding it, but it shouldn't be there at all.

Try with:

await context.Forward(new ProductsDialog(), ProductsDialogCompleted, context.Activity, CancellationToken.None);

And btw, if the message you forward hits the None intent the ProductsDialogCompleted method will be hit because you are doing context.Done , which basically ends the ProductsDialog .

Also, have in mind the StartAsync method is present in the LuisDialog<T> base class, so you need to add the override keyword.

I had this same question, but I am using a newer version of Bot Framework, more specifically, V4.

Here is what I found:

  • BeginDialogAsync 's options parameter takes an array of objects that will then be accessible in your dialog.
// Get skill LUIS model from configuration.
localizedServices.LuisServices.TryGetValue("MySkill", out var luisService);

if (luisService != null)
{
    // Get the Luis result. 
    var result = innerDc.Context.TurnState.Get<MySkillLuis>(StateProperties.SkillLuisResult);
    var intent = result?.TopIntent().intent;

    // Behavior switched on intent. 
    switch (intent)
    {
        case MySkillLuis.Intent.MyIntent:
            {
                // result is passed on to my dialog through the Options parameter. 
                await innerDc.BeginDialogAsync(_myDialog.Id, result);
                break;
            }

        case MySkillLuis.Intent.None:
        default:
            {
                // intent was identified but not yet implemented
                await innerDc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("UnsupportedMessage"));
                break;
            }
    }
}

From our second dialog, we can access the object through the context and perform any casting, etc. as necessary. In my case, it was a waterfall dialog, so I used stepContext.options .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM