public async Task ShouldSendPromptWithoutAddingAList()
        {
            var convoState  = new ConversationState(new MemoryStorage());
            var dialogState = convoState.CreateProperty <DialogState>("dialogState");

            var adapter = new TestAdapter()
                          .Use(convoState);

            var dialogs = new DialogSet(dialogState);

            var listPrompt = new ChoicePrompt("ChoicePrompt", defaultLocale: Culture.English);

            listPrompt.Style = ListStyle.None;
            dialogs.Add(listPrompt);

            await new TestFlow(adapter, async(turnContext, cancellationToken) =>
            {
                var dc = await dialogs.CreateContextAsync(turnContext);

                var results = await dc.ContinueAsync();
                if (!turnContext.Responded && !results.HasActive && !results.HasResult)
                {
                    await dc.PromptAsync("ChoicePrompt",
                                         new PromptOptions
                    {
                        Prompt = new Activity {
                            Type = ActivityTypes.Message, Text = "favorite color?"
                        },
                        Choices = colorChoices
                    });
                }
            })
            .Send("hello")
            .AssertReply("favorite color?")
            .StartTestAsync();
        }
Beispiel #2
0
        public async Task ShouldSendPrompt()
        {
            var convoState  = new ConversationState(new MemoryStorage());
            var dialogState = convoState.CreateProperty <DialogState>("dialogState");

            var adapter = new TestAdapter()
                          .Use(new AutoSaveStateMiddleware(convoState));

            // Create new DialogSet.
            var dialogs = new DialogSet(dialogState);

            dialogs.Add(new ChoicePrompt("ChoicePrompt", defaultLocale: Culture.English));

            await new TestFlow(adapter, async(turnContext, cancellationToken) =>
            {
                var dc = await dialogs.CreateContextAsync(turnContext, cancellationToken);

                var results = await dc.ContinueDialogAsync(cancellationToken);
                if (results.Status == DialogTurnStatus.Empty)
                {
                    await dc.PromptAsync(
                        "ChoicePrompt",
                        new PromptOptions
                    {
                        Prompt = new Activity {
                            Type = ActivityTypes.Message, Text = "favorite color?"
                        },
                        Choices = _colorChoices,
                    },
                        cancellationToken);
                }
            })
            .Send("hello")
            .AssertReply(StartsWithValidator("favorite color?"))
            .StartTestAsync();
        }
        private static TestFlow CreateTestFlow(WaterfallDialog waterfallDialog)
        {
            var convoState  = new ConversationState(new MemoryStorage());
            var dialogState = convoState.CreateProperty <DialogState>("dialogState");

            var adapter = new TestAdapter()
                          .Use(new AutoSaveStateMiddleware(convoState));

            var testFlow = new TestFlow(adapter, async(turnContext, cancellationToken) =>
            {
                var state   = await dialogState.GetAsync(turnContext, () => new DialogState(), cancellationToken);
                var dialogs = new DialogSet(dialogState);

                dialogs.Add(new CancelledComponentDialog(waterfallDialog));

                var dc = await dialogs.CreateContextAsync(turnContext, cancellationToken);

                var results = await dc.ContinueDialogAsync(cancellationToken);
                if (results.Status == DialogTurnStatus.Empty)
                {
                    results = await dc.BeginDialogAsync("TestComponentDialog", null, cancellationToken);
                }

                if (results.Status == DialogTurnStatus.Cancelled)
                {
                    await turnContext.SendActivityAsync(MessageFactory.Text($"Component dialog cancelled (result value is {results.Result?.ToString()})."), cancellationToken);
                }
                else if (results.Status == DialogTurnStatus.Complete)
                {
                    var value = (int)results.Result;
                    await turnContext.SendActivityAsync(MessageFactory.Text($"Bot received the number '{value}'."), cancellationToken);
                }
            });

            return(testFlow);
        }
        public async Task WaterfallNested()
        {
            var convoState = new ConversationState(new MemoryStorage());

            var adapter = new TestAdapter()
                          .Use(convoState);

            await new TestFlow(adapter, async(turnContext, cancellationToken) =>
            {
                var dialogState = convoState.CreateProperty <DialogState>("dialogState");
                var dialogs     = new DialogSet(dialogState);
                dialogs.Add(Create_Waterfall3());
                dialogs.Add(Create_Waterfall4());
                dialogs.Add(Create_Waterfall5());

                var dc = await dialogs.CreateContextAsync(turnContext);

                await dc.ContinueAsync();

                if (!turnContext.Responded)
                {
                    await dc.BeginAsync("test-waterfall-a");
                }
            })
            .Send("hello")
            .AssertReply("step1")
            .AssertReply("step1.1")
            .Send("hello")
            .AssertReply("step1.2")
            .Send("hello")
            .AssertReply("step2")
            .AssertReply("step2.1")
            .Send("hello")
            .AssertReply("step2.2")
            .StartTestAsync();
        }
        public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
        {
            if (turnContext.Activity.Type == ActivityTypes.Message)
            {
                // Run the DialogSet - let the framework identify the current state of the dialog from
                // the dialog stack and figure out what (if any) is the active dialog.
                var dialogContext = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

                var results = await dialogContext.ContinueDialogAsync(cancellationToken);

                // If the DialogTurnStatus is Empty we should start a new dialog.
                if (results.Status == DialogTurnStatus.Empty)
                {
                    await dialogContext.BeginDialogAsync("details", null, cancellationToken);
                }
            }
            // Processes ConversationUpdate Activities to welcome the user.
            else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate)
            {
                if (turnContext.Activity.MembersAdded != null)
                {
                    await SendWelcomeMessageAsync(turnContext, cancellationToken);
                }
            }
            else
            {
                await turnContext.SendActivityAsync($"{turnContext.Activity.Type} event detected", cancellationToken : cancellationToken);
            }


            // Save the dialog state into the conversation state.
            await _accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);

            // Save the user profile updates into the user state.
            //await _accessors.UserState.SaveChangesAsync(turnContext, false, cancellationToken);
        }
Beispiel #6
0
        public static async Task Run(this Dialog dialog, ITurnContext turnContext, IStatePropertyAccessor <DialogState> accessor, CancellationToken cancellationToken = default(CancellationToken))
        {
            var dialogSet = new DialogSet(accessor);

            dialogSet.Add(dialog);

            var dialogContext = await dialogSet.CreateContextAsync(turnContext, cancellationToken);

            // TODO: Remove this if clause entirely when microsoft releases the AdaptiveCardPrompt
            // https://github.com/microsoft/botframework-sdk/issues/5396
            // this is a workaround for using AdaptiveCardsPrompt
            // https://stackoverflow.com/questions/56180596/i-am-using-bot-framework-v4-3-i-want-to-retrieve-adaptive-card-submit-values
            if (string.IsNullOrWhiteSpace(dialogContext.Context.Activity.Text))
            {
                dialogContext.Context.Activity.Text = dialogContext.Context.Activity.Value.ToString();
            }

            var results = await dialogContext.ContinueDialogAsync(cancellationToken);

            if (results.Status == DialogTurnStatus.Empty)
            {
                await dialogContext.BeginDialogAsync(dialog.Id, null, cancellationToken);
            }
        }
Beispiel #7
0
        public static async Task Run(this Dialog dialog, ITurnContext turnContext, IStatePropertyAccessor <DialogState> accessor, CancellationToken cancellationToken)
        {
            var dialogSet = new DialogSet(accessor);

            dialogSet.Add(dialog);

            var dialogContext = await dialogSet.CreateContextAsync(turnContext, cancellationToken);

            // Handle 'cancel' interruption
            if (turnContext.Activity.Text.Equals("cancel", StringComparison.InvariantCultureIgnoreCase))
            {
                Activity reply = turnContext.Activity.CreateReply($"Ok restarting conversation.");
                await turnContext.SendActivityAsync(reply);

                await dialogContext.CancelAllDialogsAsync();
            }

            var results = await dialogContext.ContinueDialogAsync(cancellationToken);

            if (results.Status == DialogTurnStatus.Empty)
            {
                await dialogContext.BeginDialogAsync(dialog.Id, null, cancellationToken);
            }
        }
Beispiel #8
0
    public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
    {
        if (turnContext.Activity.Type == ActivityTypes.Message)
        {
            var dialogContext = await dialogs.CreateContextAsync(turnContext, cancellationToken);

            var results = await dialogContext.ContinueDialogAsync(cancellationToken);

            if (results.Status == DialogTurnStatus.Empty)
            {
                await dialogContext.BeginDialogAsync(nameof(ProfileDialog), null, cancellationToken);
            }
            else if (results.Status == DialogTurnStatus.Complete)
            {
                var userProfile = await accessors.UserProfile.GetAsync(turnContext);

                await turnContext.SendActivityAsync(MessageFactory.Text($"ようこそ '{userProfile.Name}' さん!"));
            }

            await accessors.UserState.SaveChangesAsync(turnContext, false, cancellationToken);

            await accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
        }
    }
Beispiel #9
0
        /// <summary>
        /// Every conversation turn for our NLP Dispatch Bot will call this method.
        /// There are no dialogs used, since it's "single turn" processing, meaning a single
        /// request and response, with no stateful conversation.
        /// </summary>
        /// <param name="turnContext">A <see cref="ITurnContext"/> containing all the data needed
        /// for processing this conversation turn. </param>
        /// <param name="cancellationToken">(Optional) A <see cref="CancellationToken"/> that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A <see cref="Task"/> that represents the work queued to execute.</returns>
        public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            const string facebookPageNameOption = "Facebook Page Name";
            const string quickRepliesOption     = "Quick Replies";
            const string postBackOption         = "PostBack";

            if (turnContext == null)
            {
                throw new ArgumentNullException(nameof(turnContext));
            }

            // Check if we are on the Facebook channel.
            if (turnContext.Activity.ChannelId == Channel.Channels.Facebook)
            {
                // Analyze Facebook payload from channel data.
                ProcessFacebookPayload(turnContext.Activity.ChannelData);

                // Initially the bot offers to showcase 3 Facebook features: Quick replies, PostBack and getting the Facebook Page Name.
                // Below we also show how to get the messaging_optin payload separately as well.
                switch (turnContext.Activity.Text)
                {
                // Here we showcase how to obtain the Facebook page name.
                // This can be useful for the Facebook multi-page support provided by the Bot Framework.
                // The Facebook page name from which the message comes from is in turnContext.Activity.Recipient.Name.
                case facebookPageNameOption:
                {
                    var reply = turnContext.Activity.CreateReply($"This message comes from the following Facebook Page: {turnContext.Activity.Recipient.Name}");
                    await turnContext.SendActivityAsync(reply);

                    break;
                }

                // Here we send a HeroCard with 2 options that will trigger a Facebook PostBack.
                case postBackOption:
                {
                    var dialogContext = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

                    var results = await dialogContext.ContinueDialogAsync(cancellationToken);

                    var card = new HeroCard
                    {
                        Text    = "Is 42 the answer to the ultimate question of Life, the Universe, and Everything?",
                        Buttons = new List <CardAction>
                        {
                            new CardAction()
                            {
                                Title = "Yes", Type = ActionTypes.PostBack, Value = "Yes"
                            },
                            new CardAction()
                            {
                                Title = "No", Type = ActionTypes.PostBack, Value = "No"
                            },
                        },
                    };

                    var reply = turnContext.Activity.CreateReply();
                    reply.Attachments = new List <Attachment> {
                        card.ToAttachment()
                    };
                    await turnContext.SendActivityAsync(reply);

                    break;
                }

                // By default we offer the users different actions that the bot supports, through quick replies.
                case quickRepliesOption:
                default:
                {
                    var reply = turnContext.Activity.CreateReply("What Facebook feature would you like to try? Here are some quick replies to choose from!");
                    reply.SuggestedActions = new SuggestedActions()
                    {
                        Actions = new List <CardAction>()
                        {
                            new CardAction()
                            {
                                Title = quickRepliesOption, Type = ActionTypes.PostBack, Value = quickRepliesOption
                            },
                            new CardAction()
                            {
                                Title = facebookPageNameOption, Type = ActionTypes.PostBack, Value = facebookPageNameOption
                            },
                            new CardAction()
                            {
                                Title = postBackOption, Type = ActionTypes.PostBack, Value = postBackOption
                            },
                        },
                    };
                    await turnContext.SendActivityAsync(reply);

                    break;
                }
                }
            }
            else
            {
                // Check if we are on the Facebook channel.
                if (turnContext.Activity.ChannelId == Channel.Channels.Facebook)
                {
                    // Here we can check for messaging_optin webhook event.
                    // Facebook Documentation for Message optin:
                    // https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/messaging_optins/
                }

                await turnContext.SendActivityAsync($"Received activity of type {turnContext.Activity.Type}.");
            }
        }
        public async Task ShouldAcceptAndRecognizeCustomLocaleDict()
        {
            var convoState  = new ConversationState(new MemoryStorage());
            var dialogState = convoState.CreateProperty <DialogState>("dialogState");

            var adapter = new TestAdapter()
                          .Use(new AutoSaveStateMiddleware(convoState));

            // Create new DialogSet.
            var dialogs = new DialogSet(dialogState);

            var culture = new PromptCultureModel()
            {
                InlineOr      = " customOr ",
                InlineOrMore  = " customOrMore ",
                Locale        = "custom-custom",
                Separator     = "customSeparator",
                NoInLanguage  = "customNo",
                YesInLanguage = "customYes",
            };

            var customDict = new Dictionary <string, ChoiceFactoryOptions>()
            {
                { culture.Locale, new ChoiceFactoryOptions(culture.Separator, culture.InlineOr, culture.InlineOrMore, true) },
            };

            dialogs.Add(new ChoicePrompt("ChoicePrompt", customDict, null, culture.Locale));

            var helloLocale = MessageFactory.Text("hello");

            helloLocale.Locale = culture.Locale;

            await new TestFlow(adapter, async(turnContext, cancellationToken) =>
            {
                var dc = await dialogs.CreateContextAsync(turnContext, cancellationToken);

                var results = await dc.ContinueDialogAsync(cancellationToken);
                if (results.Status == DialogTurnStatus.Empty)
                {
                    await dc.PromptAsync(
                        "ChoicePrompt",
                        new PromptOptions
                    {
                        Prompt = new Activity {
                            Type = ActivityTypes.Message, Text = "favorite color?", Locale = culture.Locale
                        },
                        Choices = _colorChoices,
                    },
                        cancellationToken);
                }
            })
            .Send(helloLocale)
            .AssertReply((activity) =>
            {
                // Use ChoiceFactory to build the expected answer, manually
                var expectedChoices = ChoiceFactory.Inline(_colorChoices, null, null, new ChoiceFactoryOptions()
                {
                    InlineOr        = culture.InlineOr,
                    InlineOrMore    = culture.InlineOrMore,
                    InlineSeparator = culture.Separator,
                }).Text;
                Assert.AreEqual($"favorite color?{expectedChoices}", activity.AsMessageActivity().Text);
            })
            .StartTestAsync();
        }
        public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (turnContext == null)
            {
                throw new ArgumentNullException(nameof(turnContext));
            }

            var didBotWelcomeUser = await _dialogBotConversationStateAndUserStateAccessor.WelcomeUserState.GetAsync(turnContext, () => new WelcomeUserState());

            if (turnContext.Activity.Type == ActivityTypes.Message)
            {
                // Run the DialogSet - let the framework identify the current state of the dialog from
                // the dialog stack and figure out what (if any) is the active dialog.
                var dialogContext = await _dialogSet.CreateContextAsync(turnContext, cancellationToken);

                var dialogTurnResult = await dialogContext.ContinueDialogAsync(cancellationToken);

                // Your bot should proactively send a welcome message to a personal chat the first time
                // (and only the first time) a user initiates a personal chat with your bot.
                if (didBotWelcomeUser.DidBotWelcomeUser == false)
                {
                    didBotWelcomeUser.DidBotWelcomeUser = true;
                    // Update user state flag to reflect bot handled first user interaction.
                    await _dialogBotConversationStateAndUserStateAccessor.WelcomeUserState.SetAsync(turnContext, didBotWelcomeUser);

                    await _dialogBotConversationStateAndUserStateAccessor.UserState.SaveChangesAsync(turnContext);

                    //    // the channel should sends the user name in the 'From' object
                    var userName = turnContext.Activity.From.Name;

                    await turnContext.SendActivityAsync($"You are seeing this message because this was your first message ever to this bot. Notice you will not see this message again.", cancellationToken : cancellationToken);

                    await turnContext.SendActivityAsync($"This is good place to welcome the user. For example, 'Welcome {userName}.' In your future bots -- this is also a good place to let them know what the bot can do.", cancellationToken : cancellationToken);
                }
                else
                {
                    // These are hardcoded phrases.  In future examples - see how AI (LUIS + Dispatch) can be used to understand user's intent with various phrases.
                    var text = turnContext.Activity.Text.ToLowerInvariant();
                    switch (text)
                    {
                    case "hello":
                        await turnContext.SendActivityAsync($"Special Case 'hello': You said {text}.  You can use hardcoded phrases to trigger specific functions from the bot.", cancellationToken : cancellationToken);

                        break;

                    case "special word":
                        await turnContext.SendActivityAsync($"Special Case 'special word': You said {text}. You can use hardcoded phrases to trigger specific functions from the bot.", cancellationToken : cancellationToken);

                        break;

                    case "help":
                        await turnContext.SendActivityAsync($"Special Case 'help': You said {text}. You can use hardcoded phrases to trigger specific functions from the bot.", cancellationToken : cancellationToken);

                        break;

                    default:
                        await turnContext.SendActivityAsync($"Case 'default': You said {text}.  (Try typing 'hello', 'special word', or 'help'", cancellationToken : cancellationToken);

                        break;
                    }
                }

                // Run the DialogSet - let the framework identify the current state of the dialog from
                // the dialog stack and figure out what (if any) is the active dialog.
                //var dialogContext = await _dialogSet.CreateContextAsync(turnContext, cancellationToken);
                //var dialogTurnResult = await dialogContext.ContinueDialogAsync(cancellationToken);

                // If the DialogTurnStatus is Empty we should start a new dialog.
                if (dialogTurnResult.Status == DialogTurnStatus.Empty)
                {
                    if (dialogTurnResult.Status == DialogTurnStatus.Empty)
                    {
                        await dialogContext.BeginDialogAsync("details", null, cancellationToken);
                    }
                }
                //// We had a dialog run (it was the prompt). Now it is Complete.
                //else if (dialogTurnResult.Status == DialogTurnStatus.Complete)
                //{
                //    // Check for a result.
                //    if (dialogTurnResult.Result != null)
                //    {
                //        // Finish by sending a message to the user. Next time ContinueAsync is called it will return DialogTurnStatus.Empty.
                //        await turnContext.SendActivityAsync(MessageFactory.Text($"Thank you, I have your name as: '{dialogTurnResult.Result}'."));
                //    }
                //}
            }
            //Processes ConversationUpdate Activities to welcome the user.
            else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate)
            {
                if (turnContext.Activity.MembersAdded != null)
                {
                    // Iterate over all new members added to the conversation
                    foreach (var member in turnContext.Activity.MembersAdded)
                    {
                        string ConversationUpdateMessage = @"ActivityTypes.ConversationUpdate was triggered!";

                        string WelcomeMessage = @"This is a simple Welcome Bot sample.This bot will introduce you
                                                to welcoming and greeting users.  You are seeing this message because the bot received at least one
                                            'ConversationUpdate' event, indicating you (and possibly others including the bot) joined the conversation. 
                                            If you are using the emulator, pressing the 'Start Over' button to trigger this event again.";

                        //UNCOMMENT THIS SECTION AND THE ACTIVITY WILL NOT BE SENT WHEN THE BOT JOINS THE CHANNEL
                        // Greet anyone that was not the target (recipient) of this message
                        // the 'bot' is the recipient for events from the channel,
                        // turnContext.Activity.MembersAdded == turnContext.Activity.Recipient.Id indicates the
                        // bot was added to the conversation.
                        //if (member.Id != turnContext.Activity.Recipient.Id) //IE. DON'T SEND THIS TO THE BOT
                        //{
                        await turnContext.SendActivityAsync($"Hi there - {member.Name}. \n {ConversationUpdateMessage}", cancellationToken : cancellationToken);

                        await turnContext.SendActivityAsync($"{WelcomeMessage} \n *** Type anything to continue.", cancellationToken : cancellationToken);

                        //}
                    }
                }
            }
            else
            {
                await turnContext.SendActivityAsync($"{turnContext.Activity.Type} event detected", cancellationToken : cancellationToken);
            }
            // Save the new turn count into the conversation state.
            await _dialogBotConversationStateAndUserStateAccessor.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);

            //Save changes to the UserState
            await _dialogBotConversationStateAndUserStateAccessor.UserState.SaveChangesAsync(turnContext, false, cancellationToken);
        }
        public async Task TextPromptWithNaughtyStrings()
        {
            var convoState  = new ConversationState(new MemoryStorage());
            var dialogState = convoState.CreateProperty <DialogState>("dialogState");

            var adapter = new TestAdapter(TestAdapter.CreateConversation(TestContext.TestName))
                          .Use(new AutoSaveStateMiddleware(convoState))
                          .Use(new TranscriptLoggerMiddleware(new TraceTranscriptLogger(traceActivity: false)));

            var dialogs = new DialogSet(dialogState);

            var textPrompt = new TextPrompt("TextPrompt");

            dialogs.Add(textPrompt);

            var filePath = Path.Combine(new string[] { "..", "..", "..", "Resources", "naughtyStrings.txt" });

            using var sr = new StreamReader(filePath);
            var naughtyString = string.Empty;

            do
            {
                naughtyString = GetNextNaughtyString(sr);
                try
                {
                    await new TestFlow(adapter, async(turnContext, cancellationToken) =>
                    {
                        var dc = await dialogs.CreateContextAsync(turnContext, cancellationToken);

                        var results = await dc.ContinueDialogAsync(cancellationToken);
                        if (results.Status == DialogTurnStatus.Empty)
                        {
                            var options = new PromptOptions {
                                Prompt = new Activity {
                                    Type = ActivityTypes.Message, Text = "Enter some text."
                                }
                            };
                            await dc.PromptAsync("TextPrompt", options, cancellationToken);
                        }
                        else if (results.Status == DialogTurnStatus.Complete)
                        {
                            var textResult = (string)results.Result;
                            await turnContext.SendActivityAsync(MessageFactory.Text(textResult), cancellationToken);
                        }
                    })
                    .Send("hello")
                    .AssertReply("Enter some text.")
                    .Send(naughtyString)
                    .AssertReply(naughtyString)
                    .StartTestAsync();
                }
                catch (Exception e)
                {
                    // If the input message is empty after a .Trim() operation, character the comparison will fail because the reply message will be a
                    // Message Activity with null as Text, this is expected behavior
                    var messageIsBlank = e.Message.Equals(" :\nExpected: \nReceived:", StringComparison.CurrentCultureIgnoreCase) && naughtyString.Equals(" ", StringComparison.CurrentCultureIgnoreCase);
                    var messageIsEmpty = e.Message.Equals(":\nExpected:\nReceived:", StringComparison.CurrentCultureIgnoreCase) && naughtyString.IsNullOrEmpty();
                    if (!(messageIsBlank || messageIsEmpty))
                    {
                        throw;
                    }
                }
            }while (!string.IsNullOrEmpty(naughtyString));
        }
Beispiel #13
0
        public async Task ActivityPromptShouldSendRetryPromptIfValidationFailed()
        {
            var convoState  = new ConversationState(new MemoryStorage());
            var dialogState = convoState.CreateProperty <DialogState>("dialogState");

            var adapter = new TestAdapter()
                          .Use(new AutoSaveStateMiddleware(convoState));

            var dialogs = new DialogSet(dialogState);

            PromptValidator <Activity> validator = (prompt, cancellationToken) =>
            {
                return(Task.FromResult(false));
            };

            var eventPrompt = new EventActivityPrompt("EventActivityPrompt", validator);

            dialogs.Add(eventPrompt);

            var eventActivity = new Activity {
                Type = ActivityTypes.Event, Value = 2
            };

            await new TestFlow(adapter, async(turnContext, cancellationToken) =>
            {
                var dc      = await dialogs.CreateContextAsync(turnContext, cancellationToken);
                var results = await dc.ContinueDialogAsync(cancellationToken);
                if (results.Status == DialogTurnStatus.Empty)
                {
                    var options = new PromptOptions
                    {
                        Prompt = new Activity
                        {
                            Type = ActivityTypes.Message,
                            Text = "please send an event.",
                        },
                        RetryPrompt = new Activity
                        {
                            Type = ActivityTypes.Message,
                            Text = "Retrying - please send an event.",
                        },
                    };

                    await dc.PromptAsync("EventActivityPrompt", options);
                }
                else if (results.Status == DialogTurnStatus.Complete)
                {
                    var content = (Activity)results.Result;
                    await turnContext.SendActivityAsync(content, cancellationToken);
                }
                else if (results.Status == DialogTurnStatus.Waiting)
                {
                    await turnContext.SendActivityAsync("Test complete.");
                }
            })
            .Send("hello")
            .AssertReply("please send an event.")
            .Send("test")
            .AssertReply("Retrying - please send an event.")
            .StartTestAsync();
        }
Beispiel #14
0
        // Every conversation turn for our Echo Bot will call this method.
        public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (turnContext == null)
            {
                throw new ArgumentNullException(nameof(turnContext));
            }

            // Handle Message activity type, which is the main activity type for shown within a conversational interface
            if (turnContext.Activity.Type == ActivityTypes.Message)
            {
                // Establish dialog state from the conversation state.
                DialogContext dc = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

                // Get the user's info.
                UserProfile userInfo = await _accessors.UserProfile.GetAsync(turnContext, () => new UserProfile(), cancellationToken);

                // ONGOING DIALOG CASE: Continue any current dialog.
                DialogTurnResult dialogTurnResult = await dc.ContinueDialogAsync();

                // COMPLETED DIALOG CASE: last result was EndDialogAsync, process the result of any complete dialog
                if (dialogTurnResult.Status is DialogTurnStatus.Complete)
                {
                    switch (dialogTurnResult.Result)
                    {
                    case UserProfile upResult:
                        // Store the results of FFHelloDialog
                        await _accessors.UserProfile.SetAsync(turnContext, upResult, cancellationToken);

                        //await _accessors.UserProfile.SetAsync(turnContext, upResult);

                        // now start our bot's main dialog.
                        await dc.BeginDialogAsync(MainDialogId, null, cancellationToken);

                        break;

                    default:
                        // We shouldn't get here, since the main dialog is designed to loop.
                        break;
                    }
                }

                // INACTIVE DIALOG CASE: Every dialog step sends a response, so if no response was sent,
                //      then no dialog is currently active.
                else if (!turnContext.Responded)
                {
                    if (string.IsNullOrEmpty(userInfo.UserName)) //string.IsNullOrEmpty(userInfo.Guest?.Name))
                    {
                        // If we don't yet have the guest's info, start the check-in dialog.
                        await dc.BeginDialogAsync(FFHelloDialogId, null, cancellationToken);
                    }
                    else
                    {
                        // Otherwise, start our bot's main dialog.
                        await dc.BeginDialogAsync(MainDialogId, null, cancellationToken);
                    }
                }

                // Save the new turn count into the conversation state.
                await _accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);

                await _accessors.UserState.SaveChangesAsync(turnContext, false, cancellationToken);
            }
            else
            {
                await turnContext.SendActivityAsync($"{turnContext.Activity.Type} event detected");
            }
        }
        public async void AskForATopicSampleTest()
        {
            var storage = new MemoryStorage();

            var userState         = new UserState(storage);
            var conversationState = new ConversationState(storage);

            var adapter = new TestAdapter()
                          .Use(new AutoSaveStateMiddleware(conversationState));

            // Adding LUIS Router accessor
            LuisRouterAccessor luisRouterAccessor = null;

            using (LuisRouterHelper luisRouterHelper = new LuisRouterHelper(Startup.EnvironmentName, Startup.ContentRootPath))
            {
                luisRouterAccessor = luisRouterHelper.BuildAccessor(userState, null);
            }

            // Adding QnAMaker Router accessor
            QnAMakerAccessor qnaMakerAccessor = null;

            using (QnAMakerHelper qnaMakerHelper = new QnAMakerHelper(Startup.EnvironmentName, Startup.ContentRootPath))
            {
                qnaMakerAccessor = qnaMakerHelper.BuildAccessor();
            }

            var accessors = new BotAccessors(new LoggerFactory(), conversationState, userState)
            {
                ConversationDialogState   = conversationState.CreateProperty <DialogState>("DialogState"),
                AskForExamplePreference   = conversationState.CreateProperty <bool>("AskForExamplePreference"),
                IsAuthenticatedPreference = userState.CreateProperty <bool>("IsAuthenticatedPreference")
            };

            List <MediaUrl> mediaList = new List <MediaUrl>();

            mediaList.Add(new MediaUrl("https://www.youtube.com/watch?v=CmTSY9oO3dw"));

            VideoCard videoCard = new VideoCard
            {
                Title     = "Interview Sample",
                Text      = "Each interview takes on a life of its own, but there are certain standard questions that arise. By reviewing them in advance, you can arrive confident and ready to articulate your skills and qualifications. Take a look at the sample questions here, and then bolster them with those specific to your goals and the organization. Both your answers to the interviewer's questions and those you post to them can provide a mechanism by which to communicate your qualifications.",
                Autostart = false,
                Media     = mediaList
            };

            Activity activity = new Activity
            {
                Type        = ActivityTypes.Message,
                Attachments = new List <Attachment> {
                    videoCard.ToAttachment()
                }
            };

            await new TestFlow(adapter, async(turnContext, cancellationToken) =>
            {
                var state   = await accessors.ConversationDialogState.GetAsync(turnContext, () => new DialogState());
                var dialogs = new DialogSet(accessors.ConversationDialogState);
                dialogs.Add(new LuisQnADialog(accessors, luisRouterAccessor, qnaMakerAccessor));

                var dc = await dialogs.CreateContextAsync(turnContext, cancellationToken);

                var results = await dc.ContinueDialogAsync(cancellationToken);
                if (results.Status == DialogTurnStatus.Empty)
                {
                    await dc.BeginDialogAsync(LuisQnADialog.dialogId, null, cancellationToken);
                }
                else if (results.Status == DialogTurnStatus.Complete)
                {
                    //no additional send activities.
                }
            })
            .Send("")
            .AssertReply("What topic would you like to know more about?")
            .Send("i would like to see a sample about the considerations for a human resources interview")
            .AssertReply((ac) =>
            {
                if (ac.AsMessageActivity().Attachments != null)
                {
                    var contentType = ac.AsMessageActivity().Attachments[0].ContentType;
                    Assert.Equal("application/vnd.microsoft.card.video", contentType);
                }
                else
                {
                    Assert.NotNull(ac.AsMessageActivity().Attachments);
                }
            })
            .StartTestAsync();
        }
Beispiel #16
0
        /// <summary>
        /// Every conversation turn for our EchoBot will call this method.
        /// </summary>
        /// <param name="turnContext">A <see cref="ITurnContext"/> containing all the data needed
        /// for processing this conversation turn. </param>
        /// <param name="cancellationToken">(Optional) A <see cref="CancellationToken"/> that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A <see cref="Task"/> that represents the work queued to execute.</returns>
        /// <seealso cref="BotStateSet"/>
        /// <seealso cref="ConversationState"/>
        /// <seealso cref="IMiddleware"/>
        public async Task OnTurnAsync(
            ITurnContext turnContext,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (turnContext == null)
            {
                throw new ArgumentNullException(nameof(turnContext));
            }

            // Handle Message activity type, which is the main activity type for shown within a conversational interface
            // Message activities may contain text, speech, interactive cards, and binary or unknown attachments.
            // see https://aka.ms/about-bot-activity-message to learn more about the message and other activity types
            if (turnContext.Activity.Type == ActivityTypes.Message)
            {
                string input = turnContext.Activity.Text?.Trim();

                // Handle any "global" interruptions before continuing.

                // On a request for help, display global help.
                if (string.Equals(input, Interruptions.Help, StringComparison.InvariantCultureIgnoreCase))
                {
                    await turnContext.SendActivityAsync(GlobalHelpText, cancellationToken : cancellationToken);

                    return;
                }

                DialogContext dialogContext = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

                // If we're not currently on hold, check whether the user wants to go on hold.
                if (dialogContext.ActiveDialog?.Id != OnHoldDialog)
                {
                    if (string.Equals(input, Interruptions.Wait, StringComparison.InvariantCultureIgnoreCase))
                    {
                        // Transition onto hold.
                        await dialogContext.BeginDialogAsync(OnHoldDialog, null, cancellationToken);

                        await _accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);

                        return;
                    }
                }

                // On a request to cancel, clear the dialog stack completely.
                if (string.Equals(input, Interruptions.Cancel, StringComparison.InvariantCultureIgnoreCase))
                {
                    await dialogContext.CancelAllDialogsAsync(cancellationToken);

                    await turnContext.SendActivityAsync(CancellationText, cancellationToken : cancellationToken);

                    await _accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);

                    return;
                }

                // Run the DialogSet - let the framework identify the current state of the dialog from
                // the dialog stack and figure out what (if any) is the active dialog.
                DialogTurnResult results = await dialogContext.ContinueDialogAsync(cancellationToken);

                switch (results.Status)
                {
                case DialogTurnStatus.Cancelled:
                case DialogTurnStatus.Empty:
                    // If there is no active dialog, we should clear the user info and start a new dialog.
                    await _accessors.UserProfileAccessor.SetAsync(turnContext, new UserProfile(), cancellationToken);

                    await _accessors.UserState.SaveChangesAsync(turnContext, false, cancellationToken);

                    await dialogContext.BeginDialogAsync(TopLevelDialog, null, cancellationToken);

                    break;

                case DialogTurnStatus.Complete:
                    // If we just finished the dialog, capture and display the results.
                    UserProfile userInfo = results.Result as UserProfile;
                    string      status   = "You are signed up to review "
                                           + (userInfo.CompaniesToReview.Count is 0 ? "no companies" : string.Join(" and ", userInfo.CompaniesToReview))
                                           + ".";
                    await turnContext.SendActivityAsync(status);

                    await _accessors.UserProfileAccessor.SetAsync(turnContext, userInfo, cancellationToken);

                    await _accessors.UserState.SaveChangesAsync(turnContext, false, cancellationToken);

                    break;

                case DialogTurnStatus.Waiting:
                    // If there is an active dialog, we don't need to do anything here.
                    break;
                }

                await _accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
            }

            // Processes ConversationUpdate Activities to welcome the user.
            else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate)
            {
                if (turnContext.Activity.MembersAdded != null)
                {
                    await SendWelcomeMessageAsync(turnContext, cancellationToken);
                }
            }
            else
            {
                // Otherwise, note what type of unexpected activity we just received.
                await turnContext.SendActivityAsync(
                    $"{turnContext.Activity.Type} event detected",
                    cancellationToken : cancellationToken);
            }
        }
Beispiel #17
0
        /// <summary>
        /// Every conversation turn for our Echo Bot will call this method.
        /// There are no dialogs used, since it's "single turn" processing, meaning a single
        /// request and response.
        /// </summary>
        /// <param name="turnContext">A <see cref="ITurnContext"/> containing all the data needed
        /// for processing this conversation turn. </param>
        /// <param name="cancellationToken">(Optional) A <see cref="CancellationToken"/> that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A <see cref="Task"/> that represents the work queued to execute.</returns>
        /// <seealso cref="BotStateSet"/>
        /// <seealso cref="ConversationState"/>
        /// <seealso cref="IMiddleware"/>
        public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            DialogContext dc           = null;
            ITeamsContext teamsContext = turnContext.TurnState.Get <ITeamsContext>();

            var asdd = turnContext.Activity.ChannelData;

            if (teamsContext != null)
            {
                // Now fetch the Team ID, Channel ID, and Tenant ID off of the incoming activity
                var incomingTeamId    = teamsContext.Team.Id;
                var incomingChannelid = teamsContext.Channel.Id;
                var incomingTenantId  = teamsContext.Tenant.Id;

                SigninStateVerificationQuery asd = teamsContext.GetSigninStateVerificationQueryData();

                // Make an operation call to fetch the list of channels in the team, and print count of channels.
                var channels = await teamsContext.Operations.FetchChannelListAsync(incomingTeamId, cancellationToken : cancellationToken);

                await turnContext.SendActivityAsync($"You have {channels.Conversations.Count} channels in this team");

                // Make an operation call to fetch details of the team where the activity was posted, and print it.
                var teamInfo = await teamsContext.Operations.FetchTeamDetailsAsync(incomingTeamId);

                await turnContext.SendActivityAsync($"Name of this team is {teamInfo.Name} and group-id is {teamInfo.AadGroupId}");
            }



            if (turnContext.Activity.Type == ActivityTypes.Message)
            {
                dc = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

                // Get the state properties from the turn context.
                Usuario userProfile =
                    await _accessors.UserProfile.GetAsync(turnContext, () => new Usuario());

                if (userProfile.EsperaRespuestaQNA || turnContext.Activity.Text.ToLower() == "ayuda")
                {
                    var recognizerResult = await botServices.LuisServices["DispatchPepe"].RecognizeAsync(turnContext, cancellationToken);
                    var topIntent        = recognizerResult?.GetTopScoringIntent();
                    await DispatchToTopIntentAsync(turnContext, dc, topIntent, cancellationToken);
                }
                // Continue any current dialog.
                DialogTurnResult dialogTurnResult = await dc.ContinueDialogAsync();



                if (dialogTurnResult.Status == DialogTurnStatus.Empty)
                //if (dialogTurnResult.Result is null)
                {
                    // Get the intent recognition result
                    var recognizerResult = await botServices.LuisServices["DispatchPepe"].RecognizeAsync(turnContext, cancellationToken);
                    var topIntent        = recognizerResult?.GetTopScoringIntent();

                    if (topIntent == null)
                    {
                        await turnContext.SendActivityAsync("Unable to get the top intent.");
                    }
                    else
                    {
                        await DispatchToTopIntentAsync(turnContext, dc, topIntent, cancellationToken);
                    }
                }
                else if (dialogTurnResult.Status == DialogTurnStatus.Complete)
                {
                    await dc.BeginDialogAsync("SendWelcomeMessage", cancellationToken);
                }
                //COMBINAR CON ESTO
                //
                //await ProcessInputAsync(turnContext, cancellationToken);
            }
            else if (turnContext.Activity.Type == ActivityTypes.Invoke || turnContext.Activity.Type == ActivityTypes.Event)
            {
                // This handles the Microsoft Teams Invoke Activity sent when magic code is not used.
                // See: https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/authentication/auth-oauth-card#getting-started-with-oauthcard-in-teams
                // Manifest Schema Here: https://docs.microsoft.com/en-us/microsoftteams/platform/resources/schema/manifest-schema
                // It also handles the Event Activity sent from The Emulator when the magic code is not used.
                // See: https://blog.botframework.com/2018/08/28/testing-authentication-to-your-bot-using-the-bot-framework-emulator/

                // Sanity check the activity type and channel Id.
                if (turnContext.Activity.Type == ActivityTypes.Invoke && turnContext.Activity.ChannelId != "msteams")
                {
                    throw new InvalidOperationException("The Invoke type is only valid onthe MSTeams channel.");
                }

                dc = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

                await dc.ContinueDialogAsync(cancellationToken);

                if (!turnContext.Responded)
                {
                    await dc.BeginDialogAsync(OutlookDialogID);
                }
            }
            else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate)
            {
                // Send a welcome message to the user and tell them what actions they may perform to use this bot
                if (turnContext.Activity.MembersAdded != null)
                {
                    dc = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

                    //await dc.BeginDialogAsync("SendWelcomeMessageAsync");
                    var reply = turnContext.Activity.CreateReply();
                    reply.Type = ActivityTypes.Typing;
                    await dc.Context.SendActivityAsync(reply);

                    if (turnContext.Activity.MembersAdded != null)
                    {
                        foreach (var member in turnContext.Activity.MembersAdded)
                        {
                            if (member.Id != turnContext.Activity.Recipient.Id)
                            {
                                this.nuevaConversacion = true;
                                //await SendWelcomeMessageAsync(turnContext, cancellationToken, true);
                                await dc.BeginDialogAsync("SendWelcomeMessage");
                            }
                        }
                    }
                }
            }
            else if (turnContext.Activity.Type == ActivityTypes.DeleteUserData)
            {
                string idChannel   = turnContext.Activity.ChannelId;
                string idChannelx  = turnContext.Activity.Conversation.AadObjectId;
                string idChannelxd = turnContext.Activity.MembersAdded.First().Id;
                await _accessors.UserState.DeleteAsync(turnContext, cancellationToken);

                await _accessors.ConversationState.DeleteAsync(turnContext, cancellationToken);

                //context.Reset();
                //context.ConversationData.Clear();
                //context.UserData.Clear();
                //context.PrivateConversationData.Clear();
                //await context.FlushAsync(CancellationToken.None);
            }
            else if (turnContext.Activity.Type == ActivityTypes.Typing)
            {
            }
            else if (turnContext.Activity.Type == ActivityTypes.Handoff)
            {
            }
            else if (turnContext.Activity.Type == ActivityTypes.Trace)
            {
            }
            else if (turnContext.Activity.Type == ActivityTypes.Suggestion)
            {
            }

            //else if (turnContext.Activity.Type == ActivityTypes.)
            //{

            //}
            // Save the new turn count into the conversation state.
            await _accessors.UserState.SaveChangesAsync(turnContext, false, cancellationToken);

            await _accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
        }
Beispiel #18
0
        // Add QnAMaker

        /// <summary>
        /// Every conversation turn for our Echo Bot will call this method.
        /// There are no dialogs used, since it's "single turn" processing, meaning a single
        /// request and response.
        /// </summary>
        /// <param name="turnContext">A <see cref="ITurnContext"/> containing all the data needed
        /// for processing this conversation turn. </param>
        /// <param name="cancellationToken">(Optional) A <see cref="CancellationToken"/> that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A <see cref="Task"/> that represents the work queued to execute.</returns>
        /// <seealso cref="BotStateSet"/>
        /// <seealso cref="ConversationState"/>
        /// <seealso cref="IMiddleware"/>
        public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            //string uid = turnContext.Activity.From.Id;
            //string uname = turnContext.Activity.From.Name;
            //state.UserID = "Cand_1";
            //state.UserName = "******";
            //state.UserType = "azure";
            //state.UserType = dal.FetchType(state.UserID);
            var state = await _accessors.UserDataState.GetAsync(turnContext, () => new UserData());

            string usertext = string.Empty;
            string reply    = string.Empty;

            if (turnContext.Activity.Type == ActivityTypes.Message)
            {
                try
                {
                    JToken commandToken = JToken.Parse(turnContext.Activity.Value.ToString());
                    usertext = commandToken["x"].Value <string>();
                    turnContext.Activity.Text = usertext;
                }
                catch (Exception ex)
                {
                    try
                    {
                        usertext = turnContext.Activity.Text.ToString();
                    }
                    catch
                    {
                        usertext = turnContext.Activity.Value.ToString();
                        turnContext.Activity.Text = usertext;
                    }
                }
                try
                {
                    //dal.InsertChat(usertext, state.UserID, turnContext.Activity.Conversation.Id);
                    var dialogContext = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

                    var dialogResult = await dialogContext.ContinueDialogAsync(cancellationToken);

                    if (!turnContext.Responded)
                    {
                        switch (dialogResult.Status)
                        {
                        case DialogTurnStatus.Empty:
                            if (usertext == "proceed")
                            {
                                await dialogContext.BeginDialogAsync("start", cancellationToken);
                            }
                            break;

                        case DialogTurnStatus.Waiting:
                            // The active dialog is waiting for a response from the user, so do nothing.
                            break;

                        case DialogTurnStatus.Complete:
                            await dialogContext.EndDialogAsync();

                            break;

                        default:
                            await dialogContext.CancelAllDialogsAsync();

                            break;
                        }
                    }
                    // Save states in the accessor
                    // Get the conversation state from the turn context.

                    // Set the property using the accessor.
                    await _accessors.UserDataState.SetAsync(turnContext, state);

                    // Save the new state into the conversation state.
                    await _accessors.ConversationState.SaveChangesAsync(turnContext);

                    await _accessors.UserState.SaveChangesAsync(turnContext);
                }
                catch (Exception ex)
                {
                    //dal.InsertErrorLog(state.UserID, "OnTurnAsync", ex.Message.ToString(), "Tech");
                }
            }
            else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate && turnContext.Activity.MembersAdded.FirstOrDefault()?.Id == turnContext.Activity.Recipient.Id)
            {
                var response1 = dh.welcomedefault(turnContext);
                await turnContext.SendActivityAsync(response1, cancellationToken);
            }
        }
Beispiel #19
0
        public async Task ActivityPromptResumeDialogShouldPromptNotRetry()
        {
            var convoState  = new ConversationState(new MemoryStorage());
            var dialogState = convoState.CreateProperty <DialogState>("dialogState");

            var adapter = new TestAdapter()
                          .Use(new AutoSaveStateMiddleware(convoState));

            var dialogs     = new DialogSet(dialogState);
            var eventPrompt = new EventActivityPrompt("EventActivityPrompt", (prompt, cancellationToken) => Task.FromResult(false));

            dialogs.Add(eventPrompt);

            await new TestFlow(adapter, async(turnContext, cancellationToken) =>
            {
                var dc = await dialogs.CreateContextAsync(turnContext, cancellationToken);

                switch (turnContext.Activity.Text)
                {
                case "begin":

                    var options = new PromptOptions
                    {
                        Prompt = new Activity
                        {
                            Type = ActivityTypes.Message,
                            Text = "please send an event.",
                        },
                        RetryPrompt = new Activity
                        {
                            Type = ActivityTypes.Message,
                            Text = "Retrying - please send an event.",
                        },
                    };

                    await dc.PromptAsync("EventActivityPrompt", options);

                    break;

                case "continue":

                    await eventPrompt.ContinueDialogAsync(dc);

                    break;

                case "resume":

                    await eventPrompt.ResumeDialogAsync(dc, DialogReason.NextCalled);

                    break;
                }
            })
            .Send("begin")
            .AssertReply("please send an event.")
            .Send("continue")
            .AssertReply("Retrying - please send an event.")
            .Send("resume")

            // 'ResumeDialogAsync' of ActivityPrompt does NOT cause a Retry
            .AssertReply("please send an event.")
            .StartTestAsync();
        }
Beispiel #20
0
        public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (turnContext.Activity.Type == ActivityTypes.Message)
            {
                var luisResult = turnContext.Activity.Text == null
                    ? null
                    : await _luis.RecognizeAsync(turnContext, cancellationToken);

                var(luisIntent, _) = luisResult?.GetTopScoringIntent() ?? (null, 0.0);

                var dialogContext = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

                var dialogStatus = DialogTurnStatus.Empty;
                if (dialogContext.Dialogs != null)
                {
                    var results = await dialogContext.ContinueDialogAsync(cancellationToken);

                    dialogStatus = results.Status;
                }

                // We are not in a dialog, so resume turns as normal
                if (dialogStatus == DialogTurnStatus.Empty)
                {
                    var activityText = turnContext.Activity.Text?.Trim()?.ToLowerInvariant();

                    if (activityText == null)
                    {
                        var jsonData       = turnContext.Activity.Value as JObject;
                        var postBackAction = jsonData?.GetValue("ActionType")?.Value <string>();
                        if (postBackAction == null)
                        {
                            return;
                        }

                        switch (postBackAction)
                        {
                        case PostBackActions.StartBackPainSurvey:
                            await dialogContext.BeginDialogAsync(
                                BackPainDialogFactory.DialogId,
                                cancellationToken : cancellationToken);

                            break;

                        case PostBackActions.SubmitBackPainData:
                            var backPainDemographics = jsonData["Data"].ToObject <BackPainDemographics>();
                            await PredictBackPainTreatmentAsync(turnContext, backPainDemographics, cancellationToken);

                            break;

                        case PostBackActions.Default:
                            break;

                        default:
                            throw new InvalidOperationException($"The PostBack action type {postBackAction} was not recognized.");
                        }
                    }
                    else if (luisIntent == "Root_Command")
                    {
                        await ProcessCommandAsync(turnContext, luisResult, dialogContext, cancellationToken);
                    }
                    else
                    {
                        var responseMessage = MessageFactory.Text($"I'm sorry. I don't know how to do that.");
                        await turnContext.SendActivityAsync(responseMessage, cancellationToken);
                    }
                }

                await _accessors.ConversationState.SaveChangesAsync(turnContext, cancellationToken : cancellationToken);
            }
            else
            {
                await turnContext.SendActivityAsync($"{turnContext.Activity.Type} event detected", cancellationToken : cancellationToken);
            }
        }
        public async Task TextPromptValidatorWithMessageShouldNotSendRetryPrompt()
        {
            var convoState  = new ConversationState(new MemoryStorage());
            var dialogState = convoState.CreateProperty <DialogState>("dialogState");

            var adapter = new TestAdapter(TestAdapter.CreateConversation(TestContext.TestName))
                          .Use(new AutoSaveStateMiddleware(convoState))
                          .Use(new TranscriptLoggerMiddleware(new TraceTranscriptLogger(traceActivity: false)));

            var dialogs = new DialogSet(dialogState);

            PromptValidator <string> validator = async(promptContext, cancellationToken) =>
            {
                var value = promptContext.Recognized.Value;
                if (value.Length <= 3)
                {
                    await promptContext.Context.SendActivityAsync(MessageFactory.Text("The text should be greater than 3 chars."), cancellationToken);

                    return(false);
                }
                else
                {
                    return(true);
                }
            };
            var textPrompt = new TextPrompt("TextPrompt", validator);

            dialogs.Add(textPrompt);

            await new TestFlow(adapter, async(turnContext, cancellationToken) =>
            {
                var dc = await dialogs.CreateContextAsync(turnContext, cancellationToken);

                var results = await dc.ContinueDialogAsync(cancellationToken);
                if (results.Status == DialogTurnStatus.Empty)
                {
                    var options = new PromptOptions
                    {
                        Prompt = new Activity {
                            Type = ActivityTypes.Message, Text = "Enter some text."
                        },
                        RetryPrompt = new Activity {
                            Type = ActivityTypes.Message, Text = "Make sure the text is greater than three characters."
                        },
                    };
                    await dc.PromptAsync("TextPrompt", options);
                }
                else if (results.Status == DialogTurnStatus.Complete)
                {
                    var textResult = (string)results.Result;
                    await turnContext.SendActivityAsync(MessageFactory.Text($"Bot received the text '{textResult}'."), cancellationToken);
                }
            })
            .Send("hello")
            .AssertReply("Enter some text.")
            .Send("hi")
            .AssertReply("The text should be greater than 3 chars.")
            .Send("hello")
            .AssertReply("Bot received the text 'hello'.")
            .StartTestAsync();
        }
        public async Task WaterfallCosmos()
        {
            if (CheckEmulator())
            {
                var convoState = new ConversationState(_storage);

                var adapter = new TestAdapter()
                              .Use(new AutoSaveStateMiddleware(convoState));

                var dialogState = convoState.CreateProperty <DialogState>("dialogState");
                var dialogs     = new DialogSet(dialogState);

                dialogs.Add(new TextPrompt(nameof(TextPrompt), async(promptContext, cancellationToken) =>
                {
                    var result = promptContext.Recognized.Value;
                    if (result.Length > 3)
                    {
                        var succeededMessage = MessageFactory.Text($"You got it at the {promptContext.AttemptCount}th try!");
                        await promptContext.Context.SendActivityAsync(succeededMessage, cancellationToken);
                        return(true);
                    }

                    var reply = MessageFactory.Text($"Please send a name that is longer than 3 characters. {promptContext.AttemptCount}");
                    await promptContext.Context.SendActivityAsync(reply, cancellationToken);

                    return(false);
                }));

                var steps = new WaterfallStep[]
                {
                    async(stepContext, ct) =>
                    {
                        Assert.AreEqual(stepContext.ActiveDialog.State["stepIndex"].GetType(), typeof(int));
                        await stepContext.Context.SendActivityAsync("step1");

                        return(Dialog.EndOfTurn);
                    },
                    async(stepContext, ct) =>
                    {
                        Assert.AreEqual(stepContext.ActiveDialog.State["stepIndex"].GetType(), typeof(int));
                        return(await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text("Please type your name.") }, ct));
                    },
                    async(stepContext, ct) =>
                    {
                        Assert.AreEqual(stepContext.ActiveDialog.State["stepIndex"].GetType(), typeof(int));
                        await stepContext.Context.SendActivityAsync("step3");

                        return(Dialog.EndOfTurn);
                    },
                };

                dialogs.Add(new WaterfallDialog(nameof(WaterfallDialog), steps));

                await new TestFlow(adapter, async(turnContext, cancellationToken) =>
                {
                    var dc = await dialogs.CreateContextAsync(turnContext);

                    await dc.ContinueDialogAsync();
                    if (!turnContext.Responded)
                    {
                        await dc.BeginDialogAsync(nameof(WaterfallDialog));
                    }
                })
                .Send("hello")
                .AssertReply("step1")
                .Send("hello")
                .AssertReply("Please type your name.")
                .Send("hi")
                .AssertReply("Please send a name that is longer than 3 characters. 1")
                .Send("hi")
                .AssertReply("Please send a name that is longer than 3 characters. 2")
                .Send("hi")
                .AssertReply("Please send a name that is longer than 3 characters. 3")
                .Send("Kyle")
                .AssertReply("You got it at the 4th try!")
                .AssertReply("step3")
                .StartTestAsync();
            }
        }
        /// <summary>
        /// Creates a dialog stack and starts a dialog, pushing it onto the stack.
        /// </summary>
        /// <param name="dialog">The dialog to start.</param>
        /// <param name="otherDialogs">Other dialogs to add to the stack other than starting dialog.</param>
        /// <param name="turnContext">The context for the current turn of the conversation.</param>
        /// <param name="accessor">The <see cref="IStatePropertyAccessor{DialogState}"/> accessor
        /// with which to manage the state of the dialog stack.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public static async Task RunAsync(this Dialog dialog, IEnumerable <Dialog> otherDialogs, ITurnContext turnContext, IStatePropertyAccessor <DialogState> accessor, CancellationToken cancellationToken)
        {
            var dialogSet = new DialogSet(accessor)
            {
                TelemetryClient = dialog.TelemetryClient
            };

            dialogSet.Add(dialog);
            if (otherDialogs != null)
            {
                foreach (var d in otherDialogs)
                {
                    dialogSet.Add(d);
                }
            }
            var dialogContext = await dialogSet.CreateContextAsync(turnContext, cancellationToken).ConfigureAwait(false);

            // Handle EoC and Reprompt event from a parent bot (can be root bot to skill or skill to skill)
            if (IsFromParentToSkill(turnContext))
            {
                // Handle remote cancellation request from parent.
                if (turnContext.Activity.Type == ActivityTypes.EndOfConversation)
                {
                    if (!dialogContext.Stack.Any())
                    {
                        // No dialogs to cancel, just return.
                        return;
                    }

                    var activeDialogContext = GetActiveDialogContext(dialogContext);

                    var remoteCancelText = "Skill was canceled through an EndOfConversation activity from the parent.";
                    await turnContext.TraceActivityAsync($"{typeof(Dialog).Name}.RunAsync()", label : $"{remoteCancelText}", cancellationToken : cancellationToken).ConfigureAwait(false);

                    // Send cancellation message to the top dialog in the stack to ensure all the parents are canceled in the right order.
                    await activeDialogContext.CancelAllDialogsAsync(true, cancellationToken : cancellationToken).ConfigureAwait(false);

                    return;
                }

                // Handle a reprompt event sent from the parent.
                if (turnContext.Activity.Type == ActivityTypes.Event && turnContext.Activity.Name == DialogEvents.RepromptDialog)
                {
                    if (!dialogContext.Stack.Any())
                    {
                        // No dialogs to reprompt, just return.
                        return;
                    }

                    await dialogContext.RepromptDialogAsync(cancellationToken).ConfigureAwait(false);

                    return;
                }
            }

            // Continue or start the dialog.
            var result = await dialogContext.ContinueDialogAsync(cancellationToken).ConfigureAwait(false);

            if (result.Status == DialogTurnStatus.Empty)
            {
                result = await dialogContext.BeginDialogAsync(dialog.Id, null, cancellationToken).ConfigureAwait(false);
            }

            // Skills should send EoC when the dialog completes.
            if (result.Status == DialogTurnStatus.Complete || result.Status == DialogTurnStatus.Cancelled)
            {
                if (SendEoCToParent(turnContext))
                {
                    var endMessageText = $"Dialog {dialog.Id} has **completed**. Sending EndOfConversation.";
                    await turnContext.TraceActivityAsync($"{typeof(Dialog).Name}.RunAsync()", label : $"{endMessageText}", value : result.Result, cancellationToken : cancellationToken).ConfigureAwait(false);

                    // Send End of conversation at the end.
                    var code     = result.Status == DialogTurnStatus.Complete ? EndOfConversationCodes.CompletedSuccessfully : EndOfConversationCodes.UserCancelled;
                    var activity = new Activity(ActivityTypes.EndOfConversation)
                    {
                        Value = result.Result, Locale = turnContext.Activity.Locale, Code = code
                    };
                    await turnContext.SendActivityAsync(activity, cancellationToken).ConfigureAwait(false);
                }
            }
        }
        /// <summary>
        /// Every conversation turn for our Echo Bot will call this method.
        /// </summary>
        /// <param name="turnContext">A <see cref="ITurnContext"/> containing all the data needed
        /// for processing this conversation turn. </param>
        /// <param name="cancellationToken">(Optional) A <see cref="CancellationToken"/> that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A <see cref="Task"/> that represents the work queued to execute.</returns>
        /// <seealso cref="BotStateSet"/>
        /// <seealso cref="ConversationState"/>
        /// <seealso cref="IMiddleware"/>
        public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            var dc = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

            if (turnContext == null)
            {
                throw new ArgumentNullException(nameof(turnContext));
            }

            switch (turnContext.Activity.Type)
            {
            case ActivityTypes.Message:

                // This bot is not case sensitive.
                var text = turnContext.Activity.Text.ToLowerInvariant();
                if (text == "help")
                {
                    await turnContext.SendActivityAsync(WelcomeText, cancellationToken : cancellationToken);

                    break;
                }

                if (text == "logout")
                {
                    // The bot adapter encapsulates the authentication processes.
                    var botAdapter = (BotFrameworkAdapter)turnContext.Adapter;
                    await botAdapter.SignOutUserAsync(turnContext, ConnectionName, cancellationToken : cancellationToken);

                    await turnContext.SendActivityAsync("You have been signed out.", cancellationToken : cancellationToken);

                    await turnContext.SendActivityAsync(WelcomeText, cancellationToken : cancellationToken);

                    break;
                }

                await dc.ContinueDialogAsync(cancellationToken);

                if (!turnContext.Responded)
                {
                    // Start the Login process.
                    await dc.BeginDialogAsync("authDialog", cancellationToken : cancellationToken);
                }

                break;

            case ActivityTypes.Event:
            case ActivityTypes.Invoke:
                // This handles the MS Teams Invoke Activity sent when magic code is not used.
                // See: https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/authentication/auth-oauth-card#getting-started-with-oauthcard-in-teams
                // The Teams manifest schema is found here: https://docs.microsoft.com/en-us/microsoftteams/platform/resources/schema/manifest-schema
                // It also handles the Event Activity sent from the emulator when the magic code is not used.
                // See: https://blog.botframework.com/2018/08/28/testing-authentication-to-your-bot-using-the-bot-framework-emulator/
                dc = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

                await dc.ContinueDialogAsync(cancellationToken);

                if (!turnContext.Responded)
                {
                    await dc.BeginDialogAsync("authDialog", cancellationToken : cancellationToken);
                }

                break;

            case ActivityTypes.ConversationUpdate:
                // Send a welcome & help message to the user.
                    << << << < HEAD
                    if (turnContext.Activity.MembersAdded.Any())
                        {
                        == == == =
                            if (turnContext.Activity.MembersAdded != null)
                        {
        public async Task EnsureCancelDialogCalled()
        {
            var convoState = new ConversationState(new MemoryStorage());

            var adapter = new TestAdapter()
                          .Use(new AutoSaveStateMiddleware(convoState));

            var dialogState      = convoState.CreateProperty <DialogState>("dialogState");
            var dialogs          = new DialogSet(dialogState);
            var telemetryClient  = new Mock <IBotTelemetryClient>();
            var saved_properties = new Dictionary <string, IDictionary <string, string> >();
            var counter          = 0;

            // Set up the client to save all logged property names and associated properties (in "saved_properties").
            telemetryClient.Setup(c => c.TrackEvent(It.IsAny <string>(), It.IsAny <IDictionary <string, string> >(), It.IsAny <IDictionary <string, double> >()))
            .Callback <string, IDictionary <string, string>, IDictionary <string, double> >((name, properties, metrics) => saved_properties.Add($"{name}_{counter++}", properties))
            .Verifiable();

            var steps = new WaterfallStep[]
            {
                async(step, cancellationToken) =>
                {
                    await step.Context.SendActivityAsync("step1");

                    return(Dialog.EndOfTurn);
                },
                async(step, cancellationToken) =>
                {
                    await step.Context.SendActivityAsync("step2");

                    return(Dialog.EndOfTurn);
                },
                async(step, cancellationToken) =>
                {
                    await step.CancelAllDialogsAsync();

                    return(Dialog.EndOfTurn);
                },
            };
            var waterfallDialog = new MyWaterfallDialog("test", steps);

            dialogs.Add(waterfallDialog);
            dialogs.TelemetryClient = telemetryClient.Object;

            await new TestFlow(adapter, async(turnContext, cancellationToken) =>
            {
                var dc = await dialogs.CreateContextAsync(turnContext, cancellationToken);
                await dc.ContinueDialogAsync(cancellationToken);
                if (!turnContext.Responded)
                {
                    await dc.BeginDialogAsync("test", null, cancellationToken);
                }
            })
            .Send("hello")
            .AssertReply("step1")
            .Send("hello")
            .AssertReply("step2")
            .Send("hello")
            .AssertReply("step1")
            .StartTestAsync();
            telemetryClient.Verify(m => m.TrackEvent(It.IsAny <string>(), It.IsAny <IDictionary <string, string> >(), It.IsAny <IDictionary <string, double> >()), Times.Exactly(7));

            // Verify:
            // Event name is "WaterfallCancel"
            // Event occurs on the 4th event logged
            // Event contains DialogId
            // Event DialogId is set correctly.
            Assert.IsTrue(saved_properties["WaterfallStart_0"].ContainsKey("DialogId"));
            Assert.IsTrue(saved_properties["WaterfallStart_0"].ContainsKey("InstanceId"));
            Assert.IsTrue(saved_properties["WaterfallCancel_4"].ContainsKey("DialogId"));
            Assert.IsTrue(saved_properties["WaterfallCancel_4"]["DialogId"] == "test");
            Assert.IsTrue(saved_properties["WaterfallCancel_4"].ContainsKey("StepName"));
            Assert.IsTrue(saved_properties["WaterfallCancel_4"].ContainsKey("InstanceId"));

            // Event contains "StepName"
            // Event naming on lambda's is "StepXofY"
            Assert.IsTrue(saved_properties["WaterfallCancel_4"]["StepName"] == "Step3of3");
            Assert.IsTrue(waterfallDialog.CancelDialogCalled);
            Assert.IsFalse(waterfallDialog.EndDialogCalled);
        }
        public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            var botState = await DialogBotConversationStateAndUserStateAccessor.TheUserProfile.GetAsync(turnContext, () => new UserProfile(), cancellationToken);

            //qna
            var myWelcomeUserState = await DialogBotConversationStateAndUserStateAccessor.WelcomeUserState.GetAsync(turnContext, () => new WelcomeUserState(), cancellationToken);

            //qna

            turnContext.TurnState.Add("DialogBotConversationStateAndUserStateAccessor", DialogBotConversationStateAndUserStateAccessor);

            //var myWelcomeUserState = await DialogBotConversationStateAndUserStateAccessor.WelcomeUserState.GetAsync(turnContext, () => new WelcomeUserState(), cancellationToken);
            //turnContext.TurnState.Add("DialogBotConversationStateAndUserStateAccessorMyWelcomeUserState", DialogBotConversationStateAndUserStateAccessor);
            //turnContext.TurnState.Add("DialogBotConversationStateAndUserStateAccessor", DialogBotConversationStateAndUserStateAccessor);


            if (turnContext == null)
            {
                throw new ArgumentNullException(nameof(turnContext));
            }

            if (turnContext.Activity.Type == ActivityTypes.Message)
            {
                ////QNA
                //// Check QnA Maker model
                //var response = await _services.QnAServices[QnAMakerKey].GetAnswersAsync(turnContext);
                //if (response != null && response.Length > 0)
                //{
                //    await turnContext.SendActivityAsync(response[0].Answer, cancellationToken: cancellationToken);
                //}
                ////QNA


                // Run the DialogSet - let the framework identify the current state of the dialog from
                // the dialog stack and figure out what (if any) is the active dialog.
                var dialogContext = await _dialogSet.CreateContextAsync(turnContext, cancellationToken);

                if (dialogContext != null)
                {
                    if (dialogContext.ActiveDialog != null)
                    {
                        if (dialogContext.ActiveDialog.Id == "thirdWaterName")
                        {
                            if (turnContext.Activity.Type == ActivityTypes.Message && turnContext.Activity.Text == "Back")
                            {
                                await dialogContext.CancelAllDialogsAsync();
                            }
                            else
                            {
                                var response = await _services.QnAServices[QnAMakerKey].GetAnswersAsync(turnContext);
                                if (response != null && response.Length > 0)
                                {
                                    await turnContext.SendActivityAsync(response[0].Answer, cancellationToken : cancellationToken);
                                }
                            }
                        }
                    }
                }



                //POP OFF ANY DIALOG IF THE "FLAG IS SWITCHED"
                string didTypeNamestring = "";
                if (turnContext.TurnState.ContainsKey("didTypeName"))
                {
                    didTypeNamestring = turnContext.TurnState["didTypeName"] as string;
                }

                if (didTypeNamestring == "name")
                {
                    //OPTION 1:
                    await dialogContext.CancelAllDialogsAsync();

                    //OPTION 2: //TRY BELOW OPTIONS - WHY DOES IT MISBEHAVE?
                    //NOTE-CALLING THIS HITS THE CONTINUE IN THE BELOW IF STATEMENT
                    //await dialogContext.ReplaceDialogAsync(NameWaterfallDialog.DialogId, null, cancellationToken);

                    //OPTION 3:
                    //DOES NOT WORK WELL HERE - WHEN HAVE YOU SEEN IT WORK CORRECTLY IN PREVIOUS PROJECTS?
                    //await dialogContext.EndDialogAsync();
                }

                if (dialogContext.ActiveDialog == null)
                {
                    if (turnContext.TurnState.ContainsKey("didTypeName"))
                    {
                        didTypeNamestring = turnContext.TurnState["didTypeName"] as string;
                        if (didTypeNamestring == "name")
                        {
                            await dialogContext.BeginDialogAsync(NameWaterfallDialog.DialogId, null, cancellationToken);
                        }
                    }
                    else
                    {
                        await dialogContext.BeginDialogAsync(RootWaterfallDialog.DialogId, null, cancellationToken);
                    }
                }
                else
                {
                    await dialogContext.ContinueDialogAsync(cancellationToken);
                }

                await _dialogBotConversationStateAndUserStateAccessor.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);

                await _dialogBotConversationStateAndUserStateAccessor.UserState.SaveChangesAsync(turnContext, false, cancellationToken);
            }
        }
        public async Task ShouldSendPromptUsingAppendedHeroCard()
        {
            var convoState  = new ConversationState(new MemoryStorage());
            var dialogState = convoState.CreateProperty <DialogState>("dialogState");

            var adapter = new TestAdapter()
                          .Use(new AutoSaveStateMiddleware(convoState));

            var dialogs    = new DialogSet(dialogState);
            var listPrompt = new ChoicePrompt("ChoicePrompt", defaultLocale: Culture.English)
            {
                Style = ListStyle.HeroCard,
            };

            dialogs.Add(listPrompt);

            await new TestFlow(adapter, async(turnContext, cancellationToken) =>
            {
                var dc = await dialogs.CreateContextAsync(turnContext, cancellationToken);

                var results = await dc.ContinueDialogAsync(cancellationToken);
                if (results.Status == DialogTurnStatus.Empty)
                {
                    // Create mock attachment for testing.
                    var attachment = new Attachment {
                        Content = "some content", ContentType = "text/plain"
                    };

                    await dc.PromptAsync(
                        "ChoicePrompt",
                        new PromptOptions
                    {
                        Prompt = new Activity {
                            Type = ActivityTypes.Message, Text = "favorite color?", Attachments = new List <Attachment> {
                                attachment
                            }
                        },
                        Choices = _colorChoices,
                    },
                        cancellationToken);
                }
            })
            .Send("hello")
            .AssertReply(HeroCardValidator(
                             new HeroCard
            {
                Text    = "favorite color?",
                Buttons = new List <CardAction>
                {
                    new CardAction {
                        Type = "imBack", Value = "red", Title = "red"
                    },
                    new CardAction {
                        Type = "imBack", Value = "green", Title = "green"
                    },
                    new CardAction {
                        Type = "imBack", Value = "blue", Title = "blue"
                    },
                },
            },
                             1))
            .StartTestAsync();
        }
Beispiel #28
0
        /// <summary>
        ///     Every conversation turn for our Bot will call this method.
        ///     There are no dialogs used, since it's "single turn" processing, meaning a single
        ///     request and response.
        /// </summary>
        /// <param name="turnContext">
        ///     A <see cref="ITurnContext" /> containing all the data needed
        ///     for processing this conversation turn.
        /// </param>
        /// <param name="cancellationToken">
        ///     (Optional) A <see cref="CancellationToken" /> that can be used by other objects
        ///     or threads to receive notice of cancellation.
        /// </param>
        /// <returns>A <see cref="Task" /> that represents the work queued to execute.</returns>
        /// <seealso cref="BotStateSet" />
        /// <seealso cref="ConversationState" />
        /// <seealso cref="IMiddleware" />
        /// TODO: WIP
        public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (turnContext == null)
            {
                throw new ArgumentNullException(nameof(turnContext));
            }

            await LoadUserRegistryAsync(turnContext);
            await SaveUserIfNewAsync(turnContext);

            // Handle Message activity type, which is the main activity type for shown within a conversational interface
            // Message activities may contain text, speech, interactive cards, and binary or unknown attachments.
            // see https://aka.ms/about-bot-activity-message to learn more about the message and other activity types
            // TODO: WIP
            if (turnContext.Activity.Type == ActivityTypes.Message)
            {
                await LogActivityMessageAsync(turnContext);

                // Run the DialogSet - let the framework identify the current state of the dialog from
                // the dialog stack and figure out what (if any) is the active dialog.
                var dialogContext = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

                var results = await dialogContext.ContinueDialogAsync(cancellationToken);

                // If the DialogTurnStatus is Empty we should start a new dialog.
                if (results.Status == DialogTurnStatus.Empty)
                {
                    await dialogContext.BeginDialogAsync("processMessages", null, cancellationToken);
                }
                else if (results.Status == DialogTurnStatus.Complete)
                {
                    // Check for a result.
                    if (results.Result != null)
                    {
                        // Finish by sending a message to the user. Next time ContinueAsync is called it will return DialogTurnStatus.Empty.
                        // await turnContext.SendActivityAsync(MessageFactory.Text($"Thank you, your response is '{results.Result}'."));
                        _logger.LogInformation($"Thank you, your response is '{results.Result}'.");
                    }
                }
            }
            else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate)
            {
                if (turnContext.Activity.MembersAdded != null)
                {
                    await SendWelcomeMessageAsync(turnContext, cancellationToken);
                }
            }
            else if (turnContext.Activity.Type == ActivityTypes.ContactRelationUpdate)
            {
                // await turnContext.SendActivityAsync($"{turnContext.Activity.Type} activity detected", cancellationToken: cancellationToken);
            }
            else if (turnContext.Activity.Type == ActivityTypes.Typing)
            {
                // await turnContext.SendActivityAsync($"{turnContext.Activity.Type} activity detected", cancellationToken: cancellationToken);
            }
            else if (turnContext.Activity.Type == ActivityTypes.DeleteUserData)
            {
                // await turnContext.SendActivityAsync($"{turnContext.Activity.Type} activity detected", cancellationToken: cancellationToken);
            }

            // Save the new turn count into the conversation state.
            await _accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
        }
        /// <summary>
        /// Every conversation turn calls this method.
        /// </summary>
        /// <param name="turnContext">A <see cref="ITurnContext"/> containing all the data needed
        /// for processing this conversation turn. </param>
        /// <param name="cancellationToken">(Optional) A <see cref="CancellationToken"/> that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A <see cref="Task"/> that represents the work queued to execute.</returns>
        /// <seealso cref="BotStateSet"/>
        /// <seealso cref="ConversationState"/>
        public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            // Get the state properties from the turn context.

            ConversationData conversationData = await _accessors.ConversationDataAccessor.GetAsync(turnContext, () => new ConversationData());

            // Get the user's info.
            UserInfo userInfo = await _accessors.UserInfoAccessor.GetAsync(turnContext, () => new UserInfo(), cancellationToken);

            _logger.LogInformation(turnContext.Activity.Type);

            // Establish dialog state from the conversation state.
            DialogContext dc = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

            // Handle Message activity type, which is the main activity type for shown within a conversational interface
            // Message activities may contain text, speech, interactive cards, and binary or unknown attachments.
            // see https://aka.ms/about-bot-activity-message to learn more about the message and other activity types
            if (turnContext.Activity.Type == ActivityTypes.Message)
            {
                // Continue any current dialog.
                DialogTurnResult dialogTurnResult = await dc.ContinueDialogAsync();

                // Process the result of any complete dialog.
                if (dialogTurnResult.Status is DialogTurnStatus.Complete)
                {
                    switch (dialogTurnResult.Result)
                    {
                    case GuestInfo guestInfo:
                        // Store the results of the greeting dialog.
                        userInfo.Guest = guestInfo;
                        await _accessors.UserInfoAccessor.SetAsync(turnContext, userInfo, cancellationToken);

                        // Show the main menu dialog
                        await dc.BeginDialogAsync(MainDialogId, null, cancellationToken);

                        break;

                    default:
                        // We shouldn't get here, since the main dialog is designed to loop.
                        break;
                    }
                }

                // Every dialog step sends a response, so if no response was sent,
                // then no dialog is currently active.
                else if (!turnContext.Responded)
                {
                    // Otherwise, start our bot's main dialog.
                    await dc.BeginDialogAsync(MainDialogId, null, cancellationToken);
                }
            }
            // Greet when users are added to the conversation.
            // Note that all channels do not send the conversation update activity.
            // If you find that this bot works in the emulator, but does not in
            // another channel the reason is most likely that the channel does not
            // send this activity.
            else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate)
            {
                _logger.LogInformation("Welcome Message Area");

                if (turnContext.Activity.MembersAdded != null)
                {
                    // Iterate over all new members added to the conversation
                    foreach (var member in turnContext.Activity.MembersAdded)
                    {
                        // Greet anyone that was not the target (recipient) of this message
                        // the 'bot' is the recipient for events from the channel,
                        // turnContext.Activity.MembersAdded == turnContext.Activity.Recipient.Id indicates the
                        // bot was added to the conversation.
                        if (member.Id != turnContext.Activity.Recipient.Id)
                        {
                            await turnContext.SendActivityAsync($"Hi there - {member.Name}. {WelcomeMessage}", cancellationToken : cancellationToken);

                            //await turnContext.SendActivityAsync($"What's your name?", cancellationToken: cancellationToken);

                            await dc.BeginDialogAsync(GreetingDialogId, null, cancellationToken);

                            // Can't start a dialog from ConversationUpdated
                            //await dc.BeginDialogAsync(MainDialogId, null, cancellationToken);
                        }
                    }
                }
            }

            // Save the new turn count into the conversation state.
            await _accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);

            await _accessors.UserState.SaveChangesAsync(turnContext, false, cancellationToken);
        }
Beispiel #30
0
        public async Task OnTurnAsync(ITurnContext turnContext,
                                      CancellationToken cancellationToken = default(CancellationToken))
        {
            var dc = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

            if (turnContext == null)
            {
                throw new ArgumentNullException(nameof(turnContext));
            }

            switch (turnContext.Activity.Type)
            {
            case ActivityTypes.Message:

                var text = turnContext.Activity.Text.ToLowerInvariant();
                if (text == "help")
                {
                    await turnContext.SendActivityAsync(WelcomeText, cancellationToken : cancellationToken);

                    break;
                }

                if (text == "logout")
                {
                    var botAdapter = (BotFrameworkAdapter)turnContext.Adapter;
                    await botAdapter.SignOutUserAsync(turnContext, ConnectionName,
                                                      cancellationToken : cancellationToken);

                    await turnContext.SendActivityAsync("You have been signed out.",
                                                        cancellationToken : cancellationToken);

                    await turnContext.SendActivityAsync(WelcomeText, cancellationToken : cancellationToken);

                    break;
                }

                await dc.ContinueDialogAsync(cancellationToken);

                if (!turnContext.Responded)
                {
                    await dc.BeginDialogAsync(WaterfallDialogName, cancellationToken : cancellationToken);
                }

                break;

            case ActivityTypes.Event:
            case ActivityTypes.Invoke:
                dc = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

                await dc.ContinueDialogAsync(cancellationToken);

                if (!turnContext.Responded)
                {
                    await dc.BeginDialogAsync(WaterfallDialogName, cancellationToken : cancellationToken);
                }

                break;

            case ActivityTypes.ConversationUpdate:
                if (turnContext.Activity.MembersAdded != null)
                {
                    await SendWelcomeMessageAsync(turnContext, cancellationToken);
                }

                break;
            }

            await _conversationState.SaveChangesAsync(turnContext, cancellationToken : cancellationToken);
        }