r3plica r3plica - 24 days ago 14
C# Question

Microsoft Bot Framework, LUIS and waterfalling

I am trying to build a bot.
At first I was using Node.js but it because apparent that c# was better for my client, so I have started creating the Bot in c#. I have also created a LUIS application.

Now, the idea behind this Bot is that it will ask you a series of questions before combining your results at the end and picking out a solution based on your answers. The problem I have is that I have no idea how I can set the bot up to do that. In node, it talked about waterfalling, but I can't see anything like that in the c# version.
Also, I am not sure if it should be in LUIS where I should be focusing my attention.

As an example, let's say I want the user to choose an object, then based on that object ask 3 questions like:



  1. Is it small?

  2. Is it light?

  3. What colour do you prefer?




And at the end say "You want a black, small, light camera." I can't seem to get that to work. I know some of you will say use FormFlow but the questions are dynamic and so is the object, which is why I used LUIS.

Does anyone know where I can find a good article on how to use LUIS to create a flow similar to that?

Answer

If FormFlow is too restrictive, you should consider using Dialogs. They allow for a much more open conversation.

I would do the following:

1) Ask the user to choose a category.

If possible, give the user a list of categories to choose from, using buttons. This means you will not have to ask LUIS for the category selected by the user.

Otherwise, allow the user to type an category and pass it to LUIS. The response from LUIS will contain an Entity. The Entity will hold the name of the category.

2) Forward to Dialog for that Category

Depending on the Entity returned from LUIS, forward to the appropriate Dialog which will be responsible for asking the next question

[LuisIntent("AskQuestionAboutCategory")]
    public async Task AskQuestion(IDialogContext context, LuisResult result)
    {
       //get Entity from LUIS response
        string category = result.Entities.FirstOrDefault(e => e.Type == "Category")?.Entity;

        switch (category)
        {
            case "Category 1":

                //forward to Dialog for Category1

                await
                    context.Forward(new Category1Dialog(), ResumeAfter,
                        new Activity {Text = result.Query}, CancellationToken.None);
                break;

            case "Category 2":

                //forward to Dialog for Category2

                await
                    context.Forward(new Category2Dialog(), ResumeAfter,
                        new Activity {Text = result.Query}, CancellationToken.None);
                break;

        }
    }

    private async Task ResumeAfter(IDialogContext context, IAwaitable<object> result)
    {
        context.Wait(MessageReceived);
    }

3) Ask Questions inside Dialog

Inside the Dialog, use a PromptDialog to ask Question 1. Use a switch on the answer of Question 1, to determine what to ask for Question 2. Continue the conversation like this.

[Serializable]
public class Category1Dialog : IDialog<object>
{
    public async Task StartAsync(IDialogContext context)
    {
        context.Wait(MessageReceivedAsync);
    }

    public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
    {

        var prompt = "what is the answer to question 1 ?";

        //ASK QUESTION 1
        PromptDialog.Text(context, ResumeAfterQuestion1, prompt);
    }

    private async Task ResumeAfterQuestion1(IDialogContext context, IAwaitable<string> result)
    {
        var input = await result;

        switch (input)
        {
            //ASK QUESTION 2, DEPENDING ON WHAT WAS ANSWERED FOR QUESTION 1
            case "Answer A":
                PromptDialog.Text(context, ResumeAfterQuestion2, "what is the answer to question 2 ?");
                break;
            case "Answer B":
                PromptDialog.Text(context, ResumeAfterQuestion2, "what is the answer to question 2 ?");
                break;
        }
    }


    private async Task ResumeAfterQuestion2(IDialogContext context, IAwaitable<string> result)
    {
        var input = await result;

        switch (input)
        {
            ASK QUESTION 3
            case "Answer C":
                PromptDialog.Text(context, ResumeAfterQuestion3, "what is the answer to next question after Answer C ?");
        break;
            case "Answer D":
                PromptDialog.Text(context, ResumeAfterQuestion3, "what is the answer to next question after Answer D ?");
        break;
    }
    }

It looks like you will need to use switch statements to determine what questions to ask next.

click here for more info on Dialogs