Beispiel #1
0
        protected override async Task OnEventAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
        {
            switch (dc.Context.Activity.Name)
            {
            case TokenEvents.TokenResponseEventName:
            {
                // Auth dialog completion
                var result = await dc.ContinueDialogAsync();

                // If the dialog completed when we sent the token, end the skill conversation
                if (result.Status != DialogTurnStatus.Waiting)
                {
                    var response = dc.Context.Activity.CreateReply();
                    response.Type = ActivityTypes.EndOfConversation;

                    await dc.Context.SendActivityAsync(response);
                }

                break;
            }
            }
        }
        // Runs when this dialog ends. Handles result of prompt to switch skills or resume waiting dialog.
        protected override async Task <DialogTurnResult> EndComponentAsync(DialogContext outerDc, object result, CancellationToken cancellationToken)
        {
            var skillId = await _skillIdAccessor.GetAsync(outerDc.Context, () => null).ConfigureAwait(false);

            var lastActivity = await _lastActivityAccessor.GetAsync(outerDc.Context, () => null).ConfigureAwait(false);

            outerDc.Context.Activity.Text = lastActivity.Text;

            // Ends this dialog.
            await outerDc.EndDialogAsync().ConfigureAwait(false);

            if ((bool)result)
            {
                // If user decided to switch, replace current skill dialog with new skill dialog.
                return(await outerDc.ReplaceDialogAsync(skillId).ConfigureAwait(false));
            }
            else
            {
                // Otherwise, continue the waiting skill dialog with the user's previous utterance.
                return(await outerDc.ContinueDialogAsync().ConfigureAwait(false));
            }
        }
Beispiel #3
0
        protected override async Task OnEventAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
        {
            switch (dc.Context.Activity.Name)
            {
            case Events.SkillBeginEvent:
            {
                var state = await _stateAccessor.GetAsync(dc.Context, () => new EmailSkillState());

                if (dc.Context.Activity.Value is Dictionary <string, object> userData)
                {
                    if (userData.TryGetValue("IPA.Timezone", out var timezone))
                    {
                        // we have a timezone
                        state.UserInfo.Timezone = (TimeZoneInfo)timezone;
                    }
                }

                break;
            }

            case Events.TokenResponseEvent:
            {
                // Auth dialog completion
                var result = await dc.ContinueDialogAsync();

                // If the dialog completed when we sent the token, end the skill conversation
                if (result.Status != DialogTurnStatus.Waiting)
                {
                    var response = dc.Context.Activity.CreateReply();
                    response.Type = ActivityTypes.EndOfConversation;

                    await dc.Context.SendActivityAsync(response);
                }

                break;
            }
            }
        }
Beispiel #4
0
        protected override async Task OnEventActivityAsync(DialogContext innerDc, CancellationToken cancellationToken = default)
        {
            var ev    = innerDc.Context.Activity.AsEventActivity();
            var value = ev.Value?.ToString();

            switch (ev.Name)
            {
            case TokenEvents.TokenResponseEventName:
            {
                // Forward the token response activity to the dialog waiting on the stack.
                await innerDc.ContinueDialogAsync();

                break;
            }

            default:
            {
                await innerDc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Unknown Event '{ev.Name ?? "undefined"}' was received but not processed."));

                break;
            }
            }
        }
        /// <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))
        {
            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)
            {
                dialogContext = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

                var results = await dialogContext.ContinueDialogAsync(cancellationToken);

                if (results.Status is DialogTurnStatus.Empty)
                {
                    if (results.Result == null)
                    {
                        var userInput = turnContext.Activity.Text;

                        if (userInput.ToString().ToLower().Equals("hi") || userInput.ToString().ToLower().Equals("hello"))
                        {
                            await dialogContext.BeginDialogAsync("GetPersonalDetails", cancellationToken);
                        }
                        else
                        {
                            await turnContext.SendActivityAsync(MessageFactory.Text($"You said'{userInput}'."));
                        }
                    }
                }
            }

            // Save the new turn count into the conversation state.
            await _accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
        }
        /// <summary>
        /// OnContinueDialogAsync is executed on every turn of a dialog after the first turn,
        /// and when a child dialog finishes executing.
        /// </summary>
        /// <param name="innerDc">Current DialogContext</param>
        /// <param name="cancellationToken">Thread CancellationToken</param>
        /// <returns>A DialogTurnResult</returns>
        protected override async Task <DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
        {
            var childResult = await innerDc.ContinueDialogAsync(cancellationToken);

            var result = childResult.Result as DialogTurnResult;

            if (result != null)
            {
                var promptResult = result.Result as PromptDialogOptions;
                if (promptResult != null)
                {
                    switch (promptResult.ReturnMethod)
                    {
                    case PromptReturnMethods.After_DeleteTitlePrompt:
                        return(await this.After_DeleteTitlePrompt(innerDc, promptResult.Result));

                    case PromptReturnMethods.After_TextPrompt:
                        return(await this.After_TextPrompt(innerDc, promptResult.Result));

                    case PromptReturnMethods.After_TitlePrompt:
                        return(await this.After_TitlePrompt(innerDc, promptResult.Result));

                    default:
                        throw new InvalidOperationException("Invalid PromptReturnMethods");
                    }
                }
                else
                {
                    return(await base.OnContinueDialogAsync(innerDc, cancellationToken));
                }
            }
            else
            {
                return(await base.OnContinueDialogAsync(innerDc, cancellationToken));
            }
        }
Beispiel #7
0
        protected override async Task <DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
        {
            var activity = innerDc.Context.Activity;

            if (innerDc.ActiveDialog?.Id == nameof(MultiProviderAuthDialog))
            {
                // Handle magic code auth
                var result = await innerDc.ContinueDialogAsync(cancellationToken);

                // forward the token response to the skill
                if (result.Status == DialogTurnStatus.Complete && result.Result is ProviderTokenResponse)
                {
                    activity.Type  = ActivityTypes.Event;
                    activity.Name  = Events.TokenResponseEventName;
                    activity.Value = result.Result as ProviderTokenResponse;
                }
                else
                {
                    return(result);
                }
            }

            return(await ForwardToSkill(innerDc, activity));
        }
Beispiel #8
0
        protected override async Task OnMessageActivityAsync(ITurnContext <IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            DialogContext dialogContext = await this._dialogs.CreateContextAsync(turnContext, cancellationToken);

            if (dialogContext.ActiveDialog != null)
            {
                var dialogResult = await dialogContext.ContinueDialogAsync();
            }
            else
            {
                // First, we use the dispatch model to determine which cognitive service (LUIS or QnA) to use.
                var recognizerResult = await _services.Dispatch.RecognizeAsync(turnContext, cancellationToken);

                // Top intent tell us which cognitive service to use.
                var topIntent = recognizerResult.GetTopScoringIntent();

                // Next, we call the dispatcher with the top intent.
                await DispatchToTopIntentAsync(turnContext, topIntent.intent, recognizerResult, cancellationToken);
            }

            await _conversationState.SaveChangesAsync(turnContext);

            await _userState.SaveChangesAsync(turnContext);
        }
Beispiel #9
0
        /// <summary>
        /// Called when the dialog is continued, where it is the active dialog and the
        /// user replies with a new activity.
        /// </summary>
        /// <param name="innerDc">The inner <see cref="DialogContext"/> for the current turn of conversation.</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>
        /// <remarks>If the task is successful, the result indicates whether the dialog is still
        /// active after the turn has been processed by the dialog. The result may also contain a
        /// return value.
        ///
        /// By default, this calls <see cref="InterruptableDialog.OnInterruptDialogAsync(DialogContext, CancellationToken)"/>
        /// then routes the activity to the waiting active dialog, or to a handling method based on its activity type.
        /// </remarks>
        protected override async Task <DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default)
        {
            // Check for any interruptions.
            var status = await OnInterruptDialogAsync(innerDc, cancellationToken).ConfigureAwait(false);

            if (status == InterruptionAction.Resume)
            {
                // Interruption message was sent, and the waiting dialog should resume/reprompt.
                await innerDc.RepromptDialogAsync().ConfigureAwait(false);
            }
            else if (status == InterruptionAction.Waiting)
            {
                // Interruption intercepted conversation and is waiting for user to respond.
                return(EndOfTurn);
            }
            else if (status == InterruptionAction.End)
            {
                // Interruption ended conversation, and current dialog should end.
                return(await innerDc.EndDialogAsync().ConfigureAwait(false));
            }
            else if (status == InterruptionAction.NoAction)
            {
                // No interruption was detected. Process activity normally.
                var activity = innerDc.Context.Activity;

                switch (activity.Type)
                {
                case ActivityTypes.Message:
                {
                    // Pass message to waiting child dialog.
                    var result = await innerDc.ContinueDialogAsync().ConfigureAwait(false);

                    if (result.Status == DialogTurnStatus.Empty)
                    {
                        // There was no waiting dialog on the stack, process message normally.
                        await OnMessageActivityAsync(innerDc).ConfigureAwait(false);
                    }

                    break;
                }

                case ActivityTypes.Event:
                {
                    await OnEventActivityAsync(innerDc).ConfigureAwait(false);

                    break;
                }

                case ActivityTypes.Invoke:
                {
                    // Used by Teams for Authentication scenarios.
                    await innerDc.ContinueDialogAsync().ConfigureAwait(false);

                    break;
                }

                case ActivityTypes.ConversationUpdate:
                {
                    await OnMembersAddedAsync(innerDc).ConfigureAwait(false);

                    break;
                }

                default:
                {
                    // All other activity types will be routed here. Custom handling should be added in implementation.
                    await OnUnhandledActivityTypeAsync(innerDc).ConfigureAwait(false);

                    break;
                }
                }
            }

            if (innerDc.ActiveDialog == null)
            {
                // If the inner dialog stack completed during this turn, this component should be ended.
                return(await innerDc.EndDialogAsync().ConfigureAwait(false));
            }

            return(EndOfTurn);
        }
Beispiel #10
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 #11
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");
            }
        }
        /// <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)
            {
                // 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.
                DialogContext dialogContext = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

                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
            {
                await turnContext.SendActivityAsync($"{turnContext.Activity.Type} event detected", cancellationToken : cancellationToken);
            }
        }
Beispiel #13
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 #14
0
        /// <summary>
        /// Main activity methond of the chatbot.
        /// </summary>
        /// <param name="turnContext"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            //Create dialogContext which is used to store all information around state.
            DialogContext dialogContext = await _dialogSet.CreateContextAsync(turnContext);

            //Assing user response to be validated against being interruption.
            string interruption = turnContext.Activity.Text;

            //This block validates user response and if one of the key words is used (more,help,cancel,exit) suitable action is taken.
            if (!string.IsNullOrWhiteSpace(interruption))
            {
                if (interruption.Trim().ToLowerInvariant() == "more flight")
                {
                    await turnContext.SendActivityAsync(
                        "Standard - 2 or 3 seats next to each other, radio output in the seat, no meal, cold beverage (water or juice)\n\n" +
                        "Premium - onboarding priority over Standard class, 2 seats next to each other, 230V AC/DC connector and USB connector in the seat, 20% more space for legs then in the Standard class, no meal, cold beverage (water or juice)\n\n" +
                        "Business - Business lounge with buffet and open bar, onboarding priority over Premium and Standard classes, separate seat which can be converted in to bed, 24 inches flat screen (TV, DVD, USB, HDIM), headset, meal and beverage included",
                        cancellationToken : cancellationToken);

                    await dialogContext.RepromptDialogAsync();
                }
                else if (interruption.Trim().ToLowerInvariant() == "more cars")
                {
                    await turnContext.SendActivityAsync(
                        "Economy - Basic radio, manually opened windows and central aircondition. Costs 15$ per a day.\n\n" +
                        "Standard - Audio with jack and usb connectors, electric windows in first seats row, separate aircondition for every seats row. Costs 40$ per a day.\n\n" +
                        "Business - Hight class audio system with jack and usb connectors, colorful satellite navigation with voice control, all electric windows and tailgate, separate aircondition for every seat. Costs 80$ per a day.",
                        cancellationToken : cancellationToken);

                    await dialogContext.RepromptDialogAsync();
                }
                else if (interruption.Trim().ToLowerInvariant() == "help")
                {
                    Attachment attachment = CreateHelpAttachement();
                    var        reply      = turnContext.Activity.CreateReply();
                    reply.Attachments = new List <Attachment>()
                    {
                        attachment
                    };
                    await turnContext.SendActivityAsync(reply, cancellationToken : cancellationToken);

                    await dialogContext.RepromptDialogAsync(cancellationToken : cancellationToken);
                }
                else if (interruption.Trim().ToLowerInvariant() == "cancel")
                {
                    await dialogContext.CancelAllDialogsAsync();

                    await dialogContext.BeginDialogAsync(MainDialogId);
                }
                else if (interruption.Trim().ToLowerInvariant() == "exit")
                {
                    await turnContext.SendActivityAsync("Goodby Passenger!");

                    await dialogContext.CancelAllDialogsAsync();
                }
            }
            //This block is executed if message is posted, existing dialog is continued.
            if (turnContext.Activity.Type == ActivityTypes.Message && !turnContext.Responded)
            {
                DialogTurnResult turnResult = await dialogContext.ContinueDialogAsync();

                if (turnResult.Status == DialogTurnStatus.Complete || turnResult.Status == DialogTurnStatus.Cancelled)
                {
                    await turnContext.SendActivityAsync("Goodby Passenger!");
                }
                else if (!dialogContext.Context.Responded)
                {
                    await turnContext.SendActivityAsync("I am unable to do anything...");
                }
            }
            //This block is executed on conversation update.
            else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate)
            {
                foreach (ChannelAccount member in turnContext.Activity.MembersAdded)
                {
                    if (turnContext.Activity.Recipient.Id != member.Id)
                    {
                        //Message to be send at the begining of the diatlog when user join the conversation
                        await turnContext.SendActivityAsync("Hello new Passenger!", cancellationToken : cancellationToken);

                        //Invoke of the Main Dialog
                        await dialogContext.BeginDialogAsync(MainDialogId);
                    }
                }
            }
            // Save changes after every turn.
            await _accessor.ConversationState.SaveChangesAsync(turnContext, false);
        }
        protected override async Task OnEventAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
        {
            switch (dc.Context.Activity.Name)
            {
            case Events.DeviceStart:
            {
                var state = await _toDoStateAccessor.GetAsync(dc.Context);

                var taskService     = _serviceManager.InitTaskService(state.MsGraphToken, state.ListTypeIds, state.TaskServiceType);
                var currentAllTasks = await taskService.GetTasksAsync(state.ListType);

                var results = new List <TaskItem>();
                foreach (var task in currentAllTasks)
                {
                    if (task.ReminderDateTime != DateTime.MinValue)
                    {
                        results.Add(task);
                    }
                }

                var response = dc.Context.Activity.CreateReply();
                var entities = new Dictionary <string, Entity>();
                entities.Add("reminders", new Entity {
                        Properties = JObject.FromObject(new { reminder = results[0].Topic })
                    });
                response.SemanticAction = new SemanticAction("entity", entities);
                response.Type           = ActivityTypes.EndOfConversation;

                await dc.Context.SendActivityAsync(response);

                await dc.EndDialogAsync();

                break;
            }

            case SkillEvents.SkillBeginEventName:
            {
                var state = await _toDoStateAccessor.GetAsync(dc.Context, () => new ToDoSkillState());

                if (dc.Context.Activity.Value is Dictionary <string, object> userData)
                {
                    // Capture user data from event if needed
                }

                break;
            }


            case TokenEvents.TokenResponseEventName:
            {
                // Auth dialog completion
                var result = await dc.ContinueDialogAsync();

                // If the dialog completed when we sent the token, end the skill conversation
                if (result.Status != DialogTurnStatus.Waiting)
                {
                    var response = dc.Context.Activity.CreateReply();
                    response.Type = ActivityTypes.EndOfConversation;

                    await dc.Context.SendActivityAsync(response);
                }

                break;
            }
            }
        }
Beispiel #16
0
        protected override async Task OnEventAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
        {
            // Check if there was an action submitted from intro card
            var value = dc.Context.Activity.Value;

            if (value.GetType() == typeof(JObject))
            {
                var submit = JObject.Parse(value.ToString());
                if (value != null && (string)submit["action"] == "startOnboarding")
                {
                    await dc.BeginDialogAsync(nameof(OnboardingDialog));

                    return;
                }
            }

            var forward = true;
            var ev      = dc.Context.Activity.AsEventActivity();

            if (!string.IsNullOrWhiteSpace(ev.Name))
            {
                switch (ev.Name)
                {
                case Events.TimezoneEvent:
                {
                    try
                    {
                        var timezone    = ev.Value.ToString();
                        var tz          = TimeZoneInfo.FindSystemTimeZoneById(timezone);
                        var timeZoneObj = new JObject();
                        timeZoneObj.Add(TimeZone, JToken.FromObject(tz));

                        var skillContext = await _skillContextAccessor.GetAsync(dc.Context, () => new SkillContext());

                        if (skillContext.ContainsKey(TimeZone))
                        {
                            skillContext[TimeZone] = timeZoneObj;
                        }
                        else
                        {
                            skillContext.Add(TimeZone, timeZoneObj);
                        }

                        await _skillContextAccessor.SetAsync(dc.Context, skillContext);
                    }
                    catch
                    {
                        await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Timezone passed could not be mapped to a valid Timezone. Property not set."));
                    }

                    forward = false;
                    break;
                }

                case Events.LocationEvent:
                {
                    var location    = ev.Value.ToString();
                    var locationObj = new JObject();
                    locationObj.Add(Location, JToken.FromObject(location));

                    var skillContext = await _skillContextAccessor.GetAsync(dc.Context, () => new SkillContext());

                    if (skillContext.ContainsKey(Location))
                    {
                        skillContext[Location] = locationObj;
                    }
                    else
                    {
                        skillContext.Add(Location, locationObj);
                    }

                    await _skillContextAccessor.SetAsync(dc.Context, skillContext);

                    forward = false;
                    break;
                }

                case TokenEvents.TokenResponseEventName:
                {
                    forward = true;
                    break;
                }

                default:
                {
                    await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Unknown Event {ev.Name} was received but not processed."));

                    forward = false;
                    break;
                }
                }
            }

            if (forward)
            {
                var result = await dc.ContinueDialogAsync();

                if (result.Status == DialogTurnStatus.Complete)
                {
                    await CompleteAsync(dc);
                }
            }
        }
Beispiel #17
0
        protected override async Task OnEventAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
        {
            // Indicates whether the event activity should be sent to the active dialog on the stack
            var forward    = true;
            var ev         = dc.Context.Activity.AsEventActivity();
            var parameters = await _parametersAccessor.GetAsync(dc.Context, () => new Dictionary <string, object>());

            if (!string.IsNullOrEmpty(ev.Name))
            {
                // Send trace to emulator
                var trace = new Activity(type: ActivityTypes.Trace, text: $"Received event: {ev.Name}");
                await dc.Context.SendActivityAsync(trace);

                // see if there's a skillEvent mapping defined with this event
                var skillEvents = _services.SkillEvents;
                if (skillEvents != null && skillEvents.ContainsKey(ev.Name))
                {
                    var skillEvent = skillEvents[ev.Name];

                    var value = ev.Value != null?JsonConvert.DeserializeObject <Dictionary <string, string> >(ev.Value.ToString()) : null;

                    var skillIds = skillEvent.SkillIds;

                    if (skillIds == null || skillIds.Length == 0)
                    {
                        var errorMessage = "SkillIds is not specified in the skillEventConfig. Without it the assistant doesn't know where to route the message to.";
                        await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : errorMessage));

                        TelemetryClient.TrackException(new ArgumentException(errorMessage));
                    }

                    dc.Context.Activity.Value = value;
                    foreach (var skillId in skillIds)
                    {
                        var matchedSkill = _skillRouter.IdentifyRegisteredSkill(skillId);
                        if (matchedSkill != null)
                        {
                            await RouteToSkillAsync(dc, new SkillDialogOptions()
                            {
                                SkillDefinition = matchedSkill,
                            });

                            forward = false;
                        }
                        else
                        {
                            // skill id defined in skillEventConfig is wrong
                            var skillList = new List <string>();
                            _services.SkillDefinitions.ForEach(a => skillList.Add(a.DispatchIntent));

                            var errorMessage = $"SkillId {skillId} for the event {ev.Name} in the skillEventConfig is not supported. It should be one of these: {string.Join(',', skillList.ToArray())}.";

                            await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : errorMessage));

                            TelemetryClient.TrackException(new ArgumentException(errorMessage));
                        }
                    }
                }
                else
                {
                    switch (ev.Name)
                    {
                    case Events.TimezoneEvent:
                    {
                        try
                        {
                            var timezone = ev.Value.ToString();
                            var tz       = TimeZoneInfo.FindSystemTimeZoneById(timezone);

                            parameters[ev.Name] = tz;
                        }
                        catch
                        {
                            await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Timezone passed could not be mapped to a valid Timezone. Property not set."));
                        }

                        forward = false;
                        break;
                    }

                    case Events.LocationEvent:
                    {
                        parameters[ev.Name] = ev.Value;
                        forward             = false;
                        break;
                    }

                    case Events.TokenResponseEvent:
                    {
                        forward = true;
                        break;
                    }

                    case Events.ActiveLocationUpdate:
                    case Events.ActiveRouteUpdate:
                    {
                        var matchedSkill = _skillRouter.IdentifyRegisteredSkill(Dispatch.Intent.l_PointOfInterest.ToString());

                        await RouteToSkillAsync(dc, new SkillDialogOptions()
                            {
                                SkillDefinition = matchedSkill,
                            });

                        forward = false;
                        break;
                    }

                    case Events.ResetUser:
                    {
                        await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : "Reset User Event received, clearing down State and Tokens."));

                        // Clear State
                        await _onboardingState.DeleteAsync(dc.Context, cancellationToken);

                        // Clear Tokens
                        var adapter = dc.Context.Adapter as BotFrameworkAdapter;
                        if (adapter != null)
                        {
                            await adapter.SignOutUserAsync(dc.Context, null, dc.Context.Activity.From.Id, cancellationToken);
                        }

                        forward = false;

                        break;
                    }

                    case Events.StartConversation:
                    {
                        forward = false;

                        if (!_conversationStarted)
                        {
                            if (string.IsNullOrWhiteSpace(dc.Context.Activity.Locale))
                            {
                                // startConversation activity should have locale in it. if not, log it
                                TelemetryClient.TrackEventEx("NoLocaleInStartConversation", dc.Context.Activity, dc.ActiveDialog?.Id);

                                break;
                            }

                            await StartConversation(dc);

                            _conversationStarted = true;
                        }

                        break;
                    }

                    default:
                    {
                        await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Unknown Event {ev.Name} was received but not processed."));

                        forward = false;
                        break;
                    }
                    }
                }

                if (forward)
                {
                    var result = await dc.ContinueDialogAsync();

                    if (result.Status == DialogTurnStatus.Complete)
                    {
                        await CompleteAsync(dc);
                    }
                }
            }
        }
Beispiel #18
0
        /// <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))
        {
            if (turnContext == null)
            {
                throw new ArgumentException(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)
            {
                DialogContext dialogContext = await _dialogSet.CreateContextAsync(turnContext, cancellationToken);

                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 _botAccessor.UserProfileAccessor.SetAsync(turnContext, new IcMProfile(), cancellationToken);
                    await _botAccessor.UserState.SaveChangesAsync(turnContext, false, cancellationToken);

                    var gm = GreetingMessages(turnContext.Activity.Text);
                    if (!string.IsNullOrWhiteSpace(gm))
                    {
                        await turnContext.SendActivityAsync(Constants.GreetingReplyMsg + "\n" + Constants.ContinueMsg);
                    }
                    else
                    {
                        var responseMessage = _services.GetServiceInfo(turnContext.Activity);
                        if (responseMessage != null)
                        {
                            await turnContext.SendActivityAsync(responseMessage, cancellationToken);
                        }
                        else
                        {
                            await turnContext.SendActivityAsync(Constants.VerifyMsg);
                        }

                        await turnContext.SendActivityAsync(Constants.EndMsg);

                        await turnContext.SendActivityAsync(Constants.ContinueMsg, cancellationToken : cancellationToken);
                    }
                    break;

                case DialogTurnStatus.Complete:
                    await turnContext.SendActivityAsync(Constants.EndMsg);

                    break;

                case DialogTurnStatus.Waiting:
                    await turnContext.SendActivityAsync(Constants.VerifyMsg);

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

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

                // Echo back to the user whatever they typed. Please verify your request services
                //await turnContext.SendActivityAsync("Hello World", cancellationToken: cancellationToken);
            }
            else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate)
            {
                IConversationUpdateActivity update = turnContext.Activity;
                if (update.MembersAdded != null && update.MembersAdded.Any())
                {
                    foreach (var newMember in update.MembersAdded)
                    {
                        if (newMember.Id != update.Recipient.Id)
                        {
                            await turnContext.SendActivityAsync(Constants.GreetingMsg + "\n" + Constants.ContinueMsg, cancellationToken : cancellationToken);
                        }
                    }
                }
            }
            //else //if (turnContext.Activity.Type == ActivityTypes.ContactRelationUpdate)
            //{
            //    //if (turnContext.Activity.Action == "add")
            //    //{
            //        await turnContext.SendActivityAsync(Constants.WelcomeMsg, cancellationToken: cancellationToken);
            //    //}
            //}
        }
Beispiel #19
0
        public static async Task SendAsync(this Dialog dialog, ITurnContext turnContext, IStatePropertyAccessor <DialogState> accessor, CancellationToken cancellationToken = default)
        {
            DialogSet dialogSet = new DialogSet(accessor);

            dialogSet.Add(dialog);

            //Dialogs
            dialogSet.Add(new FoodDialog());
            dialogSet.Add(new FlightDialog());
            dialogSet.Add(new TestDialog());
            dialogSet.Add(new FuckDialog());

            ////Test Dialogs
            dialogSet.Add(new FlightNewDialog());
            dialogSet.Add(new FoodNewDialog());

            //Prompts
            dialogSet.Add(new TextPrompt(nameof(TextPrompt)));
            dialogSet.Add(new ChoicePrompt(nameof(ChoicePrompt)));

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

            try
            {
                #region Cancel And Help
                if (turnContext.Activity.Text != null)
                {
                    string res = turnContext.Activity.Text;

                    if (res.ToLower().Contains("cancel"))
                    {
                        await dialogContext.CancelAllDialogsAsync();

                        await turnContext.SendActivityAsync("Cancel Dialog");

                        return;
                    }
                    else if (res.ToLower().Contains("help"))
                    {
                        await turnContext.SendActivityAsync("Help Dialog");
                    }
                }
                #endregion

                #region Dispatch
                if (turnContext.Activity.Text == null && turnContext.Activity.Value != null)
                {
                    await dialogContext.CancelAllDialogsAsync();

                    var intent = turnContext.Activity.Value.GetIntentFromMessageValue();

                    DialogTurnResult result = await dialogContext.BeginDialogAsync(intent);

                    return;
                }
                #endregion

                DialogTurnResult results = await dialogContext.ContinueDialogAsync(cancellationToken);

                if (results.Status == DialogTurnStatus.Empty)
                {
                    await dialogContext.BeginDialogAsync(dialog.Id, null, cancellationToken);
                }
            }
            catch (Exception ex)
            {
                await turnContext.SendActivityAsync($"Pohubilo SE: {ex.ToString()}");
            }
        }
        protected override async Task OnEventAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
        {
            // Check if there was an action submitted from intro card
            var value = dc.Context.Activity.Value;

            if (value.GetType() == typeof(JObject))
            {
                var submit = JObject.Parse(value.ToString());
                if (value != null && (string)submit["action"] == "startOnboarding")
                {
                    await dc.BeginDialogAsync(nameof(OnboardingDialog));

                    return;
                }
                if (value != null && (string)submit["action"] == "pizzaOrdering")
                {
                    await dc.BeginDialogAsync(nameof(PizzaOrderDialog));

                    return;
                }
                if (value != null && (string)submit["action"] == "orderStatus")
                {
                    await dc.BeginDialogAsync(nameof(PizzaStatusDialog));

                    return;
                }
                if (value != null && (string)submit["action"] == "pizza_base_tops")
                {
                    var pizzaOrderState = await _pizzaOrderingState.GetAsync(dc.Context);

                    pizzaOrderState.Base = (string)submit["BaseChoice"];

                    var vegTops    = (string)submit[$"{pizzaOrderState.Base}VegTops"];
                    var nonVegTops = (string)submit[$"{pizzaOrderState.Base}NonVegTops"];

                    if (!string.IsNullOrEmpty(vegTops))
                    {
                        pizzaOrderState.VegTops = vegTops.Split(",");
                    }
                    if (!string.IsNullOrEmpty(nonVegTops))
                    {
                        pizzaOrderState.NonVegTops = nonVegTops.Split(",");
                    }

                    await dc.ContinueDialogAsync();

                    return;
                }
                if (value != null && (string)submit["action"] == "specialPizza")
                {
                    var pizzaOrderState = await _pizzaOrderingState.GetAsync(dc.Context);

                    pizzaOrderState.IsSpecialPizza = false;
                    if ((string)submit["PizzaChoice"] != "customize")
                    {
                        var fact = 1.0;
                        if (pizzaOrderState.Size == "small")
                        {
                            fact = 0.5;
                        }
                        else if (pizzaOrderState.Size == "medium")
                        {
                            fact = 3.0 / 4.0;
                        }
                        //pizzaOrderState.Toppings = (string)submit["Toppings"];
                        pizzaOrderState.IsSpecialPizza = true;
                        pizzaOrderState.PizzaName      = (string)submit["PizzaChoice"];
                        var connect = new DataBaseOperations("Server=tcp:yoyopizzaserver.database.windows.net,1433;Initial Catalog=PizzaOrderdb;Persist Security Info=False;User ID=shubham;Password=Dota365365;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;");
                        var pizza   = connect.GetByName(pizzaOrderState.PizzaName);
                        pizzaOrderState.Base       = (string)pizza["base"];
                        pizzaOrderState.Cheese     = (string)pizza["cheese"];
                        pizzaOrderState.Sauce      = (string)pizza["sauce"];
                        pizzaOrderState.Rating     = (string)pizza["rating"];
                        pizzaOrderState.ImageURL   = (string)pizza["imageurl"];
                        pizzaOrderState.VegTops    = ((string)pizza["vegtops"]).Split(", ");
                        pizzaOrderState.NonVegTops = ((string)pizza["nonvegtops"]).Split(", ");
                        pizzaOrderState.Price      = (Convert.ToDouble(pizza["price"]) * fact);
                    }
                    else
                    {
                        pizzaOrderState.PizzaName = "Your Pizza";
                    }

                    await dc.ContinueDialogAsync();

                    return;
                }
                if (value != null && (string)submit["action"] == "confirmOrder")
                {
                    var pizzaOrderState = await _pizzaOrderingState.GetAsync(dc.Context);

                    var onboardingState = await _onboardingState.GetAsync(dc.Context);

                    pizzaOrderState.Ordered = false;
                    var connect = new DataBaseOperations("Server=tcp:yoyopizzaserver.database.windows.net,1433;Initial Catalog=PizzaOrderdb;Persist Security Info=False;User ID=shubham;Password=Dota365365;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;");
                    pizzaOrderState.OrderId = connect.Add(pizzaOrderState, onboardingState.Number);
                    pizzaOrderState.Ordered = true;
                    await dc.ContinueDialogAsync();

                    return;
                }
            }

            var forward = true;
            var ev      = dc.Context.Activity.AsEventActivity();

            if (!string.IsNullOrWhiteSpace(ev.Name))
            {
                switch (ev.Name)
                {
                case Events.TimezoneEvent:
                {
                    try
                    {
                        var timezone    = ev.Value.ToString();
                        var tz          = TimeZoneInfo.FindSystemTimeZoneById(timezone);
                        var timeZoneObj = new JObject();
                        timeZoneObj.Add(TimeZone, JToken.FromObject(tz));

                        var skillContext = await _skillContextAccessor.GetAsync(dc.Context, () => new SkillContext());

                        if (skillContext.ContainsKey(TimeZone))
                        {
                            skillContext[TimeZone] = timeZoneObj;
                        }
                        else
                        {
                            skillContext.Add(TimeZone, timeZoneObj);
                        }

                        await _skillContextAccessor.SetAsync(dc.Context, skillContext);
                    }
                    catch
                    {
                        await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Timezone passed could not be mapped to a valid Timezone. Property not set."));
                    }

                    forward = false;
                    break;
                }

                case Events.LocationEvent:
                {
                    var location    = ev.Value.ToString();
                    var locationObj = new JObject();
                    locationObj.Add(Location, JToken.FromObject(location));

                    var skillContext = await _skillContextAccessor.GetAsync(dc.Context, () => new SkillContext());

                    if (skillContext.ContainsKey(Location))
                    {
                        skillContext[Location] = locationObj;
                    }
                    else
                    {
                        skillContext.Add(Location, locationObj);
                    }

                    await _skillContextAccessor.SetAsync(dc.Context, skillContext);

                    forward = false;
                    break;
                }

                case TokenEvents.TokenResponseEventName:
                {
                    forward = true;
                    break;
                }

                default:
                {
                    await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Unknown Event {ev.Name} was received but not processed."));

                    forward = false;
                    break;
                }
                }
            }

            if (forward)
            {
                var result = await dc.ContinueDialogAsync();

                if (result.Status == DialogTurnStatus.Complete)
                {
                    await CompleteAsync(dc);
                }
            }
        }
Beispiel #21
0
        protected override async Task OnEventAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
        {
            // Indicates whether the event activity should be sent to the active dialog on the stack
            var forward    = true;
            var ev         = dc.Context.Activity.AsEventActivity();
            var parameters = await _parametersAccessor.GetAsync(dc.Context, () => new Dictionary <string, object>());

            if (!string.IsNullOrEmpty(ev.Name))
            {
                // Send trace to emulator
                var trace = new Activity(type: ActivityTypes.Trace, text: $"Received event: {ev.Name}");
                await dc.Context.SendActivityAsync(trace);

                switch (ev.Name)
                {
                case Events.TimezoneEvent:
                {
                    try
                    {
                        var timezone = ev.Value.ToString();
                        var tz       = TimeZoneInfo.FindSystemTimeZoneById(timezone);

                        parameters[ev.Name] = tz;
                    }
                    catch
                    {
                        await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Timezone passed could not be mapped to a valid Timezone. Property not set."));
                    }

                    forward = false;
                    break;
                }

                case Events.LocationEvent:
                {
                    parameters[ev.Name] = ev.Value;
                    forward             = false;
                    break;
                }

                case Events.TokenResponseEvent:
                {
                    forward = true;
                    break;
                }

                case Events.ActiveLocationUpdate:
                case Events.ActiveRouteUpdate:
                {
                    var matchedSkill = _skillRouter.IdentifyRegisteredSkill(Dispatch.Intent.l_PointOfInterest.ToString());

                    await RouteToSkillAsync(dc, new SkillDialogOptions()
                        {
                            SkillDefinition = matchedSkill,
                        });

                    forward = false;
                    break;
                }

                case Events.ResetUser:
                {
                    await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Reset User Event received, clearing down State and Tokens."));

                    // Clear State
                    await _onboardingState.DeleteAsync(dc.Context, cancellationToken);

                    // Clear Tokens
                    var adapter = dc.Context.Adapter as BotFrameworkAdapter;
                    await adapter.SignOutUserAsync(dc.Context, null, dc.Context.Activity.From.Id, cancellationToken);

                    forward = false;

                    break;
                }

                default:
                {
                    await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Unknown Event {ev.Name} was received but not processed."));

                    forward = false;
                    break;
                }
                }

                if (forward)
                {
                    var result = await dc.ContinueDialogAsync();

                    if (result.Status == DialogTurnStatus.Complete)
                    {
                        await CompleteAsync(dc);
                    }
                }
            }
        }
Beispiel #22
0
        protected override async Task <DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
        {
            var status = await OnInterruptDialogAsync(innerDc, cancellationToken).ConfigureAwait(false);

            if (status == InterruptionAction.Resume)
            {
                // Resume the waiting dialog after interruption
                await innerDc.RepromptDialogAsync().ConfigureAwait(false);

                return(EndOfTurn);
            }
            else if (status == InterruptionAction.Waiting)
            {
                // Stack is already waiting for a response, shelve inner stack
                return(EndOfTurn);
            }
            else
            {
                var activity = innerDc.Context.Activity;

                if (activity.IsStartActivity())
                {
                    await OnStartAsync(innerDc).ConfigureAwait(false);
                }

                switch (activity.Type)
                {
                case ActivityTypes.Message:
                {
                    // Note: This check is a workaround for adaptive card buttons that should map to an event (i.e. startOnboarding button in intro card)
                    if (activity.Value != null)
                    {
                        await OnEventAsync(innerDc).ConfigureAwait(false);
                    }
                    else
                    {
                        var result = await innerDc.ContinueDialogAsync().ConfigureAwait(false);

                        switch (result.Status)
                        {
                        case DialogTurnStatus.Empty:
                        {
                            await RouteAsync(innerDc).ConfigureAwait(false);

                            break;
                        }

                        case DialogTurnStatus.Complete:
                        {
                            // End active dialog
                            await innerDc.EndDialogAsync().ConfigureAwait(false);

                            break;
                        }

                        default:
                        {
                            break;
                        }
                        }
                    }

                    // If the active dialog was ended on this turn (either on single-turn dialog, or on continueDialogAsync) run CompleteAsync method.
                    if (innerDc.ActiveDialog == null)
                    {
                        await CompleteAsync(innerDc).ConfigureAwait(false);
                    }

                    break;
                }

                case ActivityTypes.Event:
                {
                    await OnEventAsync(innerDc).ConfigureAwait(false);

                    break;
                }

                case ActivityTypes.Invoke:
                {
                    // Used by Teams for Authentication scenarios.
                    await innerDc.ContinueDialogAsync().ConfigureAwait(false);

                    break;
                }

                default:
                {
                    await OnSystemMessageAsync(innerDc).ConfigureAwait(false);

                    break;
                }
                }

                return(EndOfTurn);
            }
        }
        protected override async Task <DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
        {
            var status = await OnInterruptDialogAsync(innerDc, cancellationToken);

            if (status == InterruptionAction.MessageSentToUser)
            {
                // Resume the waiting dialog after interruption
                await innerDc.RepromptDialogAsync().ConfigureAwait(false);

                return(EndOfTurn);
            }
            else if (status == InterruptionAction.StartedDialog)
            {
                // Stack is already waiting for a response, shelve inner stack
                return(EndOfTurn);
            }
            else
            {
                var activity = innerDc.Context.Activity;

                if (activity.IsStartActivity())
                {
                    await OnStartAsync(innerDc);
                }

                switch (activity.Type)
                {
                case ActivityTypes.Message:
                {
                    var result = await innerDc.ContinueDialogAsync();

                    switch (result.Status)
                    {
                    case DialogTurnStatus.Empty:
                    {
                        await RouteAsync(innerDc);

                        break;
                    }

                    case DialogTurnStatus.Complete:
                    case DialogTurnStatus.Cancelled:
                    {
                        await CompleteAsync(innerDc, result);

                        break;
                    }

                    default:
                    {
                        break;
                    }
                    }

                    break;
                }

                case ActivityTypes.Event:
                {
                    await OnEventAsync(innerDc);

                    break;
                }

                default:
                {
                    await OnSystemMessageAsync(innerDc);

                    break;
                }
                }

                return(EndOfTurn);
            }
        }
Beispiel #24
0
        // Runs on every turn of the conversation to check if the conversation should be interrupted.
        protected override async Task <InterruptionAction> OnInterruptDialogAsync(DialogContext dc, CancellationToken cancellationToken)
        {
            var activity    = dc.Context.Activity;
            var userProfile = await _userProfileState.GetAsync(dc.Context, () => new UserProfileState());

            var dialog = dc.ActiveDialog?.Id != null?dc.FindDialog(dc.ActiveDialog?.Id) : null;

            if (activity.Type == ActivityTypes.Message && !string.IsNullOrEmpty(activity.Text))
            {
                // Check if the active dialog is a skill for conditional interruption.
                var isSkill = dialog is SkillDialog;

                // Get Dispatch LUIS result from turn state.
                var dispatchResult = dc.Context.TurnState.Get <DispatchLuis>(StateProperties.DispatchResult);
                (var dispatchIntent, var dispatchScore) = dispatchResult.TopIntent();

                // Check if we need to switch skills.
                if (isSkill)
                {
                    if (dispatchIntent.ToString() != dialog.Id && dispatchScore > 0.9)
                    {
                        var identifiedSkill = SkillRouter.IsSkill(_settings.Skills, dispatchResult.TopIntent().intent.ToString());

                        if (identifiedSkill != null)
                        {
                            var prompt = _templateEngine.GenerateActivityForLocale("SkillSwitchPrompt", new { Skill = identifiedSkill.Name });
                            await dc.BeginDialogAsync(_switchSkillDialog.Id, new SwitchSkillDialogOptions(prompt, identifiedSkill));

                            return(InterruptionAction.Waiting);
                        }
                    }
                }

                if (dispatchIntent == DispatchLuis.Intent.l_General)
                {
                    // Get connected LUIS result from turn state.
                    var generalResult = dc.Context.TurnState.Get <GeneralLuis>(StateProperties.GeneralResult);
                    (var generalIntent, var generalScore) = generalResult.TopIntent();

                    if (generalScore > 0.5)
                    {
                        switch (generalIntent)
                        {
                        case GeneralLuis.Intent.Cancel:
                        {
                            // Suppress completion message for utility functions.
                            dc.SuppressCompletionMessage(true);

                            await dc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("CancelledMessage", userProfile));

                            await dc.CancelAllDialogsAsync();

                            return(InterruptionAction.End);
                        }

                        case GeneralLuis.Intent.Escalate:
                        {
                            await dc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("EscalateMessage", userProfile));

                            return(InterruptionAction.Resume);
                        }

                        case GeneralLuis.Intent.Help:
                        {
                            // Suppress completion message for utility functions.
                            dc.SuppressCompletionMessage(true);

                            if (isSkill)
                            {
                                // If current dialog is a skill, allow it to handle its own help intent.
                                await dc.ContinueDialogAsync(cancellationToken);

                                break;
                            }
                            else
                            {
                                await dc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("HelpCard", userProfile));

                                return(InterruptionAction.Resume);
                            }
                        }

                        case GeneralLuis.Intent.Logout:
                        {
                            // Suppress completion message for utility functions.
                            dc.SuppressCompletionMessage(true);

                            // Log user out of all accounts.
                            await LogUserOut(dc);

                            await dc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("LogoutMessage", userProfile));

                            return(InterruptionAction.End);
                        }

                        case GeneralLuis.Intent.Repeat:
                        {
                            // No need to send the usual dialog completion message for utility capabilities such as these.
                            dc.SuppressCompletionMessage(true);

                            // Sends the activities since the last user message again.
                            var previousResponse = await _previousResponseAccessor.GetAsync(dc.Context, () => new List <Activity>());

                            foreach (var response in previousResponse)
                            {
                                // Reset id of original activity so it can be processed by the channel.
                                response.Id = string.Empty;
                                await dc.Context.SendActivityAsync(response);
                            }

                            return(InterruptionAction.Waiting);
                        }

                        case GeneralLuis.Intent.StartOver:
                        {
                            // Suppresss completion message for utility functions.
                            dc.SuppressCompletionMessage(true);

                            await dc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("StartOverMessage", userProfile));

                            // Cancel all dialogs on the stack.
                            await dc.CancelAllDialogsAsync();

                            return(InterruptionAction.End);
                        }

                        case GeneralLuis.Intent.Stop:
                        {
                            // Use this intent to send an event to your device that can turn off the microphone in speech scenarios.
                            break;
                        }
                        }
                    }
                }
            }

            return(InterruptionAction.NoAction);
        }
Beispiel #25
0
        protected override async Task <DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
        {
            var activity = innerDc.Context.Activity;

            switch (activity.Type)
            {
            case ActivityTypes.Message:
            {
                var result = await innerDc.ContinueDialogAsync();

                switch (result.Status)
                {
                case DialogTurnStatus.Empty:
                {
                    // await RouteAsync(innerDc);
                    break;
                }

                case DialogTurnStatus.Complete:
                {
                    await CompleteAsync(innerDc);

                    // End active dialog
                    await innerDc.EndDialogAsync();

                    break;
                }

                default:
                {
                    break;
                }
                }

                break;
            }

            case ActivityTypes.Event:
            {
                await OnEventAsync(innerDc);

                break;
            }

            case ActivityTypes.ConversationUpdate:
            {
                await OnStartAsync(innerDc);

                break;
            }

            default:
            {
                await OnSystemMessageAsync(innerDc);

                break;
            }
            }

            return(EndOfTurn);
        }
Beispiel #26
0
        protected override async Task <DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
        {
            var status = await OnInterruptDialogAsync(innerDc, cancellationToken).ConfigureAwait(false);

            if (status == InterruptionAction.MessageSentToUser)
            {
                // Resume the waiting dialog after interruption
                await innerDc.RepromptDialogAsync().ConfigureAwait(false);

                return(EndOfTurn);
            }
            else if (status == InterruptionAction.StartedDialog)
            {
                // Stack is already waiting for a response, shelve inner stack
                return(EndOfTurn);
            }
            else
            {
                var activity = innerDc.Context.Activity;

                if (activity.IsStartActivity())
                {
                    await OnStartAsync(innerDc).ConfigureAwait(false);
                }

                switch (activity.Type)
                {
                case ActivityTypes.Message:
                {
                    // Note: This check is a workaround for adaptive card buttons that should map to an event (i.e. startOnboarding button in intro card)
                    if (activity.Value != null)
                    {
                        await OnEventAsync(innerDc).ConfigureAwait(false);
                    }
                    else if (!string.IsNullOrEmpty(activity.Text))
                    {
                        var result = await innerDc.ContinueDialogAsync().ConfigureAwait(false);

                        switch (result.Status)
                        {
                        case DialogTurnStatus.Empty:
                        {
                            await RouteAsync(innerDc).ConfigureAwait(false);

                            break;
                        }

                        case DialogTurnStatus.Complete:
                        {
                            await CompleteAsync(innerDc).ConfigureAwait(false);

                            // End active dialog
                            await innerDc.EndDialogAsync().ConfigureAwait(false);

                            break;
                        }

                        default:
                        {
                            break;
                        }
                        }
                    }

                    break;
                }

                case ActivityTypes.Event:
                {
                    await OnEventAsync(innerDc).ConfigureAwait(false);

                    break;
                }

                default:
                {
                    await OnSystemMessageAsync(innerDc).ConfigureAwait(false);

                    break;
                }
                }

                return(EndOfTurn);
            }
        }
Beispiel #27
0
        protected override async Task <DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
        {
            var activity = innerDc.Context.Activity;

            if (activity.IsStartActivity())
            {
                await OnStartAsync(innerDc);
            }

            switch (activity.Type)
            {
            case ActivityTypes.Message:
            {
                if (activity.Value != null)
                {
                    await OnEventAsync(innerDc);
                }
                else if (!string.IsNullOrEmpty(activity.Text))
                {
                    var result = await innerDc.ContinueDialogAsync();

                    switch (result.Status)
                    {
                    case DialogTurnStatus.Empty:
                    {
                        await RouteAsync(innerDc);

                        // Waterfalls with no turns should Complete.
                        if (innerDc.Stack.Count == 0)
                        {
                            await CompleteAsync(innerDc);
                        }
                        break;
                    }

                    case DialogTurnStatus.Complete:
                    {
                        await CompleteAsync(innerDc);

                        // End active dialog
                        await innerDc.EndDialogAsync();

                        break;
                    }

                    default:
                    {
                        break;
                    }
                    }
                }

                break;
            }

            case ActivityTypes.Event:
            {
                await OnEventAsync(innerDc);

                break;
            }

            default:
            {
                await OnSystemMessageAsync(innerDc);

                break;
            }
            }

            return(EndOfTurn);
        }
Beispiel #28
0
        private async Task HandleMessageAsync(ITurnContext turnContext, CancellationToken cancellationToken)
        {
            DialogContext dc = await _beerDialogs.CreateContextAsync(turnContext, cancellationToken);

            var result = await dc.ContinueDialogAsync(cancellationToken);

            if (result.Status == DialogTurnStatus.Empty || result.Status == DialogTurnStatus.Cancelled)
            {
                var model = await _luisRecognizer.RecognizeAsync <BeerBotLuisModel>(turnContext, cancellationToken);

                var topIntent = model.TopIntent().intent;

                switch (topIntent)
                {
                case BeerBotLuisModel.Intent.Greet:
                    await dc.BeginDialogAsync(BeerDialogs.Dialogs.Greet, cancellationToken : cancellationToken);

                    break;

                case BeerBotLuisModel.Intent.RandomBeer:
                    await dc.BeginDialogAsync(BeerDialogs.Dialogs.RandomBeer, cancellationToken : cancellationToken);

                    break;

                case BeerBotLuisModel.Intent.RecommendBeer:
                    await dc.BeginDialogAsync(BeerDialogs.Dialogs.RecommendBeer, cancellationToken : cancellationToken);

                    break;

                case BeerBotLuisModel.Intent.OrderBeer:
                {
                    var beerOrderModel = model.Entities.beerorder?.FirstOrDefault();
                    var beerOrder      = new BeerOrder
                    {
                        BeerName = beerOrderModel?.beername?.FirstOrDefault(),
                        Chaser   = SafeParse <Chaser>(beerOrderModel?.chaser?.FirstOrDefault()?.FirstOrDefault()),
                        Side     = SafeParse <SideDish>(beerOrderModel?.sidedish?.FirstOrDefault()?.FirstOrDefault())
                    };
                    await dc.BeginDialogAsync(BeerDialogs.Dialogs.OrderBeer, beerOrder, cancellationToken);

                    break;

                    T SafeParse <T>(string value) where T : struct
                    {
                        if (value == null)
                        {
                            return(default(T));
                        }
                        return(Enum.Parse <T>(value, true));
                    }
                }

                case BeerBotLuisModel.Intent.GetHelp:
                    await dc.BeginDialogAsync(BeerDialogs.Dialogs.MainMenu, cancellationToken : cancellationToken);

                    break;

                case BeerBotLuisModel.Intent.Bye:
                    await dc.BeginDialogAsync(BeerDialogs.Dialogs.Exit, cancellationToken : cancellationToken);

                    break;

                case BeerBotLuisModel.Intent.None:
                    break;

                default:
                    await turnContext.SendActivityAsync(
                        $"Something must be wrong with my language circuits... {Emoji.Coffee}",
                        "Something must be wrong with my language circuits...",
                        cancellationToken : cancellationToken);

                    break;
                }
            }
        }
        /// <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);
        }
        protected async Task <DialogTurnResult> ContinueActionsAsync(DialogContext dc, object options, CancellationToken cancellationToken)
        {
            if (options is CancellationToken)
            {
                throw new ArgumentException("You cannot pass a cancellation token as options");
            }

            // Apply any queued up changes
            var sequenceContext = ToSequenceContext(dc);
            await sequenceContext.ApplyChangesAsync(cancellationToken).ConfigureAwait(false);

            // Get a unique instance ID for the current stack entry.
            // We need to do this because things like cancellation can cause us to be removed
            // from the stack and we want to detect this so we can stop processing actions.
            var instanceId = GetUniqueInstanceId(sequenceContext);

            // Execute queued actions
            var actionContext = CreateChildContext(sequenceContext) as SequenceContext;

            while (actionContext != null)
            {
                // Continue current step
                // DEBUG: To debug step execution set a breakpoint on line below and add a watch
                //        statement for sequenceContext.Actions.
                var result = await actionContext.ContinueDialogAsync(cancellationToken).ConfigureAwait(false);

                // Start step if not continued
                if (result.Status == DialogTurnStatus.Empty && GetUniqueInstanceId(sequenceContext) == instanceId)
                {
                    // Call begin dialog on our next step, passing the effective options we computed
                    var nextAction = actionContext.Actions.First();
                    result = await actionContext.BeginDialogAsync(nextAction.DialogId, nextAction.Options, cancellationToken).ConfigureAwait(false);
                }

                // Is the step waiting for input or were we cancelled?
                if (result.Status == DialogTurnStatus.Waiting || GetUniqueInstanceId(sequenceContext) != instanceId)
                {
                    return(result);
                }

                // End current step
                await EndCurrentActionAsync(sequenceContext, cancellationToken).ConfigureAwait(false);

                // Check for changes to any of our parents
                var           parentChanges = false;
                DialogContext root          = sequenceContext;
                var           parent        = sequenceContext.Parent;
                while (parent != null)
                {
                    var sc = parent as SequenceContext;
                    if (sc != null && sc.Changes != null && sc.Changes.Count > 0)
                    {
                        parentChanges = true;
                    }

                    root   = parent;
                    parent = root.Parent;
                }

                // Execute next step
                if (parentChanges)
                {
                    // Recursively call ContinueDialogAsync() to apply parent changes and continue
                    // execution.
                    return(await root.ContinueDialogAsync(cancellationToken).ConfigureAwait(false));
                }

                // Apply any local changes and fetch next action
                await sequenceContext.ApplyChangesAsync(cancellationToken).ConfigureAwait(false);

                actionContext = CreateChildContext(sequenceContext) as SequenceContext;
            }

            return(await OnEndOfActionsAsync(sequenceContext, cancellationToken).ConfigureAwait(false));
        }