Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bot framework v4.0 how to execute the previous waterfall step in a dialog

I'm trying to create a dialog in which I define multiple waterfall steps. In the context of this dialog, I need sometimes to go back to the previous waterfall step according to the choice of the user. I found this method :

 await stepContext.ReplaceDialogAsync("Name of the dialog");

however, this method re-execute the whole dialog and this is not what I need.

In fact, the waterfall steps that I created are three :

  • ChoiceCallStepAsync: The first step will list the first 10 calls of the user with the options to show older steps
  • ShowCallStepAsync: The second step will show the call that the user choose or go back to the first step if the user clicked on "show older"
  • EndDialog: The third step will terminate the dialog

My code is :

public class ListAllCallsDialog : ComponentDialog
    {

        // Dialog IDs
        private const string ProfileDialog = "ListAllCallsDialog";



        /// <summary>
        /// Initializes a new instance of the <see cref="ListAllCallsDialog"/> class.
        /// </summary>
        /// <param name="loggerFactory">The <see cref="ILoggerFactory"/> that enables logging and tracing.</param>
        public ListAllCallsDialog(ILoggerFactory loggerFactory)
            : base(nameof(ListAllCallsDialog))
        {
            // Add control flow dialogs
            var waterfallSteps = new WaterfallStep[]
            {
                   ListAllCallsDialogSteps.ChoiceCallStepAsync,
                   ListAllCallsDialogSteps.ShowCallStepAsync,
                   ListAllCallsDialogSteps.EndDialog,
            };
            AddDialog(new WaterfallDialog(ProfileDialog, waterfallSteps));
            AddDialog(new ChoicePrompt("cardPrompt"));
        }

        /// <summary>
        /// Contains the waterfall dialog steps for the main dialog.
        /// </summary>
        private static class ListAllCallsDialogSteps
        {
            static int callListDepth = 0;
            static List<string> Calls;
            public static async Task<DialogTurnResult> ChoiceCallStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
            {
                await stepContext.Context.SendActivityAsync(
                   "Right now i'm in list all calls dialog",
                   cancellationToken: cancellationToken);
                GetAllCalls();
                return await stepContext.PromptAsync("cardPrompt", GenerateOptions(stepContext.Context.Activity, callListDepth), cancellationToken);
            }

            public static async Task<DialogTurnResult> ShowCallStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
            {
                // Get the text from the activity to use to show the correct card
                var text = stepContext.Context.Activity.Text.ToLowerInvariant();
                if(text == "Show older")
                    //Go back to the first step
                else if(text == "Show earlier")
                    //Go back to the first step
                else
                    await stepContext.Context.SendActivityAsync(
                   "The call you choose is : " + text.ToString(),
                   cancellationToken: cancellationToken);
                   return await stepContext.ContinueDialogAsync();

            }

            public static async Task<DialogTurnResult> EndDialog(WaterfallStepContext stepContext, CancellationToken cancellationToken)
            {
                await stepContext.Context.SendActivityAsync(
               "Getting back to the parent Dialog",
               cancellationToken: cancellationToken);
                return await stepContext.EndDialogAsync(null, cancellationToken);
            }

            /// <summary>
            /// Creates options for a <see cref="ChoicePrompt"/> so the user may select an option.
            /// </summary>
            /// <param name="activity">The message activity the bot received.</param>
            /// <returns>A <see cref="PromptOptions"/> to be used in a prompt.</returns>
            /// <remarks>Related type <see cref="Choice"/>.</remarks>
            private static PromptOptions GenerateOptions(Activity activity, int callListDepth)
            {
                // Create options for the prompt
                var options = new PromptOptions()
                {
                    Prompt = activity.CreateReply("Please choose a call from the list below"),
                    Choices = new List<Choice>(),
                };


                for(int i=10*callListDepth; i <= 10 * (callListDepth + 1); i++)
                {
                    if (Calls.ElementAtOrDefault(i) != null)
                      options.Choices.Add(new Choice() { Value = Calls[i] });

                }
                options.Choices.Add(new Choice() { Value = "Show older" });
                if(callListDepth!=0)
                    options.Choices.Add(new Choice() { Value = "Show earlier" });
                return options;
            }
            private static void GetAllCalls()
            {

                //List of all calls found
                for (int i = 0; i < 30; i++)
                  Calls.Add("Call" + i.ToString());
            }

        }

}

Can someone show me how to do this, please ?

like image 710
Soufien Hajji Avatar asked Sep 28 '18 11:09

Soufien Hajji


People also ask

What is waterfall dialog in bot framework C#?

A waterfall dialog (or waterfall) defines a sequence of steps, allowing your bot to guide a user through a linear process. These dialogs are designed to work within the context of a component dialog.

How do you end a dialog in bot framework?

endDialogAsync() ends the current dialog on the stack returning control to the parent dialog, if present, or to the turn handler. Additionally, it can be called from anywhere the dialog context is accessible. Best practice is to call it at the end of every dialog.

What is step context in bot framework?

stepContext. Options is your way of receiving that object over the called Dialog. For example, in the first document, the main Dialog is calling each child Dialogs and sending them the userInfo. Guest object: return await stepContext.

What is BOT framework composer?

Bot Framework Composer, built on the Bot Framework SDK, is an open-source IDE for developers to author, test, provision, and manage conversational experiences.


1 Answers

You can use the option parameter in the method "ReplaceDialogAsync" and skip steps with the method "NextAsync".

For example in my waterfall steps (defined in the constructor):

        AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
        {
            IntroStepAsync,
            ActStepAsync,
            FinalStepAsync
        }));

        // The initial child Dialog to run.
        InitialDialogId = nameof(WaterfallDialog);

If you want pass to second step (in my case ActStepAsync) from the final step (FinalStepAsync) , when I going to replace the dialog I use the created a label in the Dialog:

private const string FLAG = "MY_FLAG";

When I invoke the method from final step I do this :

return await stepContext.ReplaceDialogAsync(InitialDialogId, FLAG, cancellationToken);

So I only need check the option in the first step if the context has the flag :

    // Use the text provided in FinalStepAsync or the default if it is the first time.
        var messageText = stepContext.Options?.ToString() ?? "welcome-message";
        if (messageText.Equals(FLAG_REPROMPT))
        {
            return await stepContext.NextAsync(null,cancellationToken);
        }

Later this you are in the second step

like image 156
Victor Muñoz Avatar answered Oct 05 '22 11:10

Victor Muñoz