Пример #1
0
        private void RegisterSkills(List <SkillDefinition> skillDefinitions)
        {
            foreach (var definition in skillDefinitions)
            {
                AddDialog(new SkillDialog(definition, _services.SkillConfigurations[definition.Id], _proactiveState, _endpointService, TelemetryClient, _backgroundTaskQueue));
            }

            // Initialize skill dispatcher
            _skillRouter = new SkillRouter(_services.SkillDefinitions);
        }
        public async Task TestIsSkillHelper()
        {
            using (StreamReader sr = new StreamReader(@".\Skills\manifestTemplate.json"))
            {
                string manifestBody = await sr.ReadToEndAsync();

                var skillManifest = JsonConvert.DeserializeObject <SkillManifest>(manifestBody);

                List <SkillManifest> skillManifests = new List <SkillManifest>();
                skillManifests.Add(skillManifest);

                Assert.IsNotNull(SkillRouter.IsSkill(skillManifests, "calendarSkill/createEvent"));
                Assert.IsNotNull(SkillRouter.IsSkill(skillManifests, "calendarSkill/updateEvent"));
                Assert.IsNull(SkillRouter.IsSkill(skillManifests, "calendarSkill/MISSINGEVENT"));
            }
        }
Пример #3
0
        public MainDialog(BotServices services, ConversationState conversationState, UserState userState)
            : base(nameof(MainDialog))
        {
            _services          = services ?? throw new ArgumentNullException(nameof(services));
            _conversationState = conversationState;
            _userState         = userState;
            _onboardingState   = _userState.CreateProperty <OnboardingState>(nameof(OnboardingState));
            _userInfoAccessor  = _userState.CreateProperty <Dictionary <string, object> >("userInfo");

            AddDialog(new OnboardingDialog(_services, _onboardingState));
            AddDialog(new EscalateDialog(_services));
            AddDialog(new CustomSkillDialog(_services));

            // Initialize skill dispatcher
            _skillRouter = new SkillRouter(_services.RegisteredSkills);
        }
Пример #4
0
        // Runs when the dialog stack is empty, and a new message activity comes in.
        protected override async Task OnMessageActivityAsync(DialogContext innerDc, CancellationToken cancellationToken = default)
        {
            var activity    = innerDc.Context.Activity.AsMessageActivity();
            var userProfile = await _userProfileState.GetAsync(innerDc.Context, () => new UserProfileState());

            if (!string.IsNullOrEmpty(activity.Text))
            {
                // Get current cognitive models for the current locale.
                CognitiveModelSet localizedServices = _services.GetCognitiveModels();

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

                // Check if the dispatch intent maps to a skill.
                var identifiedSkill = SkillRouter.IsSkill(_settings.Skills, dispatchIntent.ToString());

                if (identifiedSkill != null)
                {
                    // Start the skill dialog.
                    await innerDc.BeginDialogAsync(identifiedSkill.Id);
                }
                else if (dispatchIntent == DispatchLuis.Intent.q_Faq)
                {
                    await innerDc.BeginDialogAsync("Faq");
                }
                else if (dispatchIntent == DispatchLuis.Intent.q_Chitchat)
                {
                    innerDc.SuppressCompletionMessage(true);

                    await innerDc.BeginDialogAsync("Chitchat");
                }
                else if (dispatchIntent == DispatchLuis.Intent.q_HRBenefits)
                {
                    innerDc.SuppressCompletionMessage(true);

                    await innerDc.BeginDialogAsync("HRBenefits");
                }
                else
                {
                    innerDc.SuppressCompletionMessage(true);

                    await innerDc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("UnsupportedMessage", userProfile));
                }
            }
        }
Пример #5
0
        public MainDialog(BotServices services, BotConfiguration botConfig, ConversationState conversationState, UserState userState, EndpointService endpointService)
            : base(nameof(MainDialog))
        {
            _services           = services ?? throw new ArgumentNullException(nameof(services));
            _botConfig          = botConfig;
            _conversationState  = conversationState;
            _userState          = userState;
            _endpointService    = endpointService;
            _onboardingState    = _userState.CreateProperty <OnboardingState>(nameof(OnboardingState));
            _parametersAccessor = _userState.CreateProperty <Dictionary <string, object> >("userInfo");
            var dialogState = _conversationState.CreateProperty <DialogState>(nameof(DialogState));

            AddDialog(new OnboardingDialog(_services, _onboardingState));
            AddDialog(new EscalateDialog(_services));
            AddDialog(new CustomSkillDialog(_services.SkillConfigurations, dialogState, endpointService));

            // Initialize skill dispatcher
            _skillRouter = new SkillRouter(_services.SkillDefinitions);
        }
Пример #6
0
        protected override async Task RouteAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
        {
            // Get cognitive models for locale
            var locale          = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
            var cognitiveModels = _services.CognitiveModelSets[locale];

            // Check dispatch result
            var dispatchResult = await cognitiveModels.DispatchService.RecognizeAsync <DispatchLuis>(dc.Context, CancellationToken.None);

            var intent = dispatchResult.TopIntent().intent;

            // Identify if the dispatch intent matches any Action within a Skill if so, we pass to the appropriate SkillDialog to hand-off
            var identifiedSkill = SkillRouter.IsSkill(_settings.Skills, intent.ToString());

            if (identifiedSkill != null)
            {
                // We have identiifed a skill so initialize the skill connection with the target skill
                var result = await dc.BeginDialogAsync(identifiedSkill.Id);

                if (result.Status == DialogTurnStatus.Complete)
                {
                    await CompleteAsync(dc);
                }
            }
            else if (intent == DispatchLuis.Intent.l_General)
            {
                // If dispatch result is General luis model
                cognitiveModels.LuisServices.TryGetValue("General", out var luisService);

                if (luisService == null)
                {
                    throw new Exception("The General LUIS Model could not be found in your Bot Services configuration.");
                }
                else
                {
                    var result = await luisService.RecognizeAsync <GeneralLuis>(dc.Context, CancellationToken.None);

                    var generalIntent = result?.TopIntent().intent;

                    // switch on general intents
                    switch (generalIntent)
                    {
                    case GeneralLuis.Intent.Escalate:
                    {
                        // start escalate dialog
                        await dc.BeginDialogAsync(nameof(EscalateDialog));

                        break;
                    }

                    case GeneralLuis.Intent.None:
                    default:
                    {
                        // No intent was identified, send confused message
                        await _responder.ReplyWith(dc.Context, MainResponses.ResponseIds.Confused);

                        break;
                    }
                    }
                }
            }
            else if (intent == DispatchLuis.Intent.q_Faq)
            {
                cognitiveModels.QnAServices.TryGetValue("Faq", out var qnaService);

                if (qnaService == null)
                {
                    throw new Exception("The specified QnA Maker Service could not be found in your Bot Services configuration.");
                }
                else
                {
                    var answers = await qnaService.GetAnswersAsync(dc.Context, null, null);

                    if (answers != null && answers.Count() > 0)
                    {
                        await dc.Context.SendActivityAsync(answers[0].Answer, speak : answers[0].Answer);
                    }
                    else
                    {
                        await _responder.ReplyWith(dc.Context, MainResponses.ResponseIds.Confused);
                    }
                }
            }
            else if (intent == DispatchLuis.Intent.q_Chitchat)
            {
                cognitiveModels.QnAServices.TryGetValue("Chitchat", out var qnaService);

                if (qnaService == null)
                {
                    throw new Exception("The specified QnA Maker Service could not be found in your Bot Services configuration.");
                }
                else
                {
                    var answers = await qnaService.GetAnswersAsync(dc.Context, null, null);

                    if (answers != null && answers.Count() > 0)
                    {
                        await dc.Context.SendActivityAsync(answers[0].Answer, speak : answers[0].Answer);
                    }
                    else
                    {
                        await _responder.ReplyWith(dc.Context, MainResponses.ResponseIds.Confused);
                    }
                }
            }
            else
            {
                // If dispatch intent does not map to configured models, send "confused" response.
                // Alternatively as a form of backup you can try QnAMaker for anything not understood by dispatch.
                await _responder.ReplyWith(dc.Context, MainResponses.ResponseIds.Confused);
            }
        }
Пример #7
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);
        }