Esempio n. 1
0
        public AdapterWithErrorHandler(ICredentialProvider credentialProvider, ILogger <BotFrameworkHttpAdapter> logger, ConversationState conversationState = null)
            : base(credentialProvider)
        {
            // combine path for cross platform support
            string[] paths    = { ".", "Resources", "AdapterWithErrorHandler.lg" };
            string   fullPath = Path.Combine(paths);

            _lgEngine   = new TemplateEngine().AddFile(fullPath);
            OnTurnError = async(turnContext, exception) =>
            {
                // Log any leaked exception from the application.
                logger.LogError($"Exception caught : {exception.Message}");

                // Send a catch-all apology to the user.
                await turnContext.SendActivityAsync(ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("SomethingWentWrong", exception)));

                if (conversationState != null)
                {
                    try
                    {
                        // Delete the conversationState for the current conversation to prevent the
                        // bot from getting stuck in a error-loop caused by being in a bad state.
                        // ConversationState should be thought of as similar to "cookie-state" in a Web pages.
                        await conversationState.DeleteAsync(turnContext);
                    }
                    catch (Exception e)
                    {
                        logger.LogError($"Exception caught on attempting to Delete ConversationState : {e.Message}");
                    }
                }
            };
        }
        protected override async Task OnMembersAddedAsync(IList <ChannelAccount> membersAdded, ITurnContext <IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
        {
            // Actions to include in the welcome card. These are passed to LG and are then included in the generated Welcome card.
            var actions = new {
                actions = new List <Object>()
                {
                    new {
                        title = "Get an overview",
                        url   = "https://docs.microsoft.com/en-us/azure/bot-service/?view=azure-bot-service-4.0"
                    },
                    new {
                        title = "Ask a question",
                        url   = "https://stackoverflow.com/questions/tagged/botframework"
                    },
                    new {
                        title = "Learn how to deploy",
                        url   = "https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-deploy-azure?view=azure-bot-service-4.0"
                    }
                }
            };

            foreach (var member in membersAdded)
            {
                // Greet anyone that was not the target (recipient) of this message.
                // To learn more about Adaptive Cards, see https://aka.ms/msbot-adaptivecards for more details.
                if (member.Id != turnContext.Activity.Recipient.Id)
                {
                    await turnContext.SendActivityAsync(ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("WelcomeCard", actions)));
                }
            }
        }
        private Activity InternalGenerateActivity(string templateName, object data, string locale)
        {
            var iLocale = locale == null ? "" : locale;

            if (TemplateEnginesPerLocale.ContainsKey(iLocale))
            {
                return(ActivityBuilder.GenerateFromLG(TemplateEnginesPerLocale[locale].EvaluateTemplate(templateName, data)));
            }
            var locales = new string[] { string.Empty };

            if (!LangFallBackPolicy.TryGetValue(iLocale, out locales))
            {
                if (!LangFallBackPolicy.TryGetValue(string.Empty, out locales))
                {
                    throw new Exception($"No supported language found for {iLocale}");
                }
            }

            foreach (var fallBackLocale in locales)
            {
                if (TemplateEnginesPerLocale.ContainsKey(fallBackLocale))
                {
                    return(ActivityBuilder.GenerateFromLG(TemplateEnginesPerLocale[fallBackLocale].EvaluateTemplate(templateName, data)));
                }
            }
            return(new Activity());
        }
Esempio n. 4
0
        private async Task <DialogTurnResult> NameConfirmStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            stepContext.Values["name"] = (string)stepContext.Result;

            // We can send messages to the user at any point in the WaterfallStep.
            await stepContext.Context.SendActivityAsync(ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("AckName", new {
                Result = stepContext.Result
            })), cancellationToken);

            // WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
            return(await stepContext.PromptAsync(nameof(ConfirmPrompt), new PromptOptions { Prompt = ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("AgeConfirmPrompt")) }, cancellationToken));
        }
Esempio n. 5
0
 private static async Task <DialogTurnResult> TransportStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
 {
     // WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
     // Running a prompt here means the next WaterfallStep will be run when the users response is received.
     return(await stepContext.PromptAsync(nameof(ChoicePrompt),
                                          new PromptOptions
     {
         Prompt = ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("ModeOfTransportPrompt")),
         Choices = ChoiceFactory.ToChoices(new List <string> {
             "Car", "Bus", "Bicycle"
         }),
     }, cancellationToken));
 }
Esempio n. 6
0
        private async Task <DialogTurnResult> ChoiceCardStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            _logger.LogInformation("MainDialog.ChoiceCardStepAsync");

            // Create options for the prompt
            var options = new PromptOptions()
            {
                Prompt  = ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("CardChoice")),
                Choices = new List <Choice>(),
            };

            // Add the choices for the prompt.
            options.Choices.Add(new Choice()
            {
                Value = "Adaptive card"
            });
            options.Choices.Add(new Choice()
            {
                Value = "Animation card"
            });
            options.Choices.Add(new Choice()
            {
                Value = "Audio card"
            });
            options.Choices.Add(new Choice()
            {
                Value = "Hero card"
            });
            options.Choices.Add(new Choice()
            {
                Value = "Receipt card"
            });
            options.Choices.Add(new Choice()
            {
                Value = "Signin card"
            });
            options.Choices.Add(new Choice()
            {
                Value = "Thumbnail card"
            });
            options.Choices.Add(new Choice()
            {
                Value = "Video card"
            });
            options.Choices.Add(new Choice()
            {
                Value = "All cards"
            });

            return(await stepContext.PromptAsync(nameof(ChoicePrompt), options, cancellationToken));
        }
Esempio n. 7
0
        private async Task <DialogTurnResult> ConfirmStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            stepContext.Values["age"] = (int)stepContext.Result;

            var msg = _lgGenerator.GenerateActivity("AgeReadBack", new
            {
                userAge = stepContext.Values["age"]
            }, stepContext);

            // We can send messages to the user at any point in the WaterfallStep.
            await stepContext.Context.SendActivityAsync(ActivityBuilder.GenerateFromLG(msg), cancellationToken);

            // WaterfallStep always finishes with the end of the Waterfall or with another dialog, here it is a Prompt Dialog.
            return(await stepContext.PromptAsync(nameof(ConfirmPrompt), new PromptOptions {
                Prompt = _lgGenerator.GenerateActivity("ConfirmPrompt", stepContext)
            }, cancellationToken));
        }
Esempio n. 8
0
        private async Task <DialogTurnResult> AgeStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            if ((bool)stepContext.Result)
            {
                // User said "yes" so we will be prompting for the age.
                // WaterfallStep always finishes with the end of the Waterfall or with another dialog, here it is a Prompt Dialog.
                var promptOptions = new PromptOptions
                {
                    Prompt      = ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("AskForAge")),
                    RetryPrompt = ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("AskForAge.reprompt")),
                };

                return(await stepContext.PromptAsync(nameof(NumberPrompt <int>), promptOptions, cancellationToken));
            }
            else
            {
                // User said "no" so we will skip the next step. Give -1 as the age.
                return(await stepContext.NextAsync(-1, cancellationToken));
            }
        }
Esempio n. 9
0
        private async Task <DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            // If the child dialog ("BookingDialog") was cancelled or the user failed to confirm, the Result here will be null.
            if (stepContext.Result != null)
            {
                var result = (BookingDetails)stepContext.Result;

                // Now we have all the booking details call the booking service.

                // If the call to the booking service was successful tell the user.

                var timeProperty = new TimexProperty(result.TravelDate);
                result.travelDateMsg = timeProperty.ToNaturalLanguage(DateTime.Now);
                await stepContext.Context.SendActivityAsync(ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("BookingConfirmation", result)), cancellationToken);
            }
            else
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Text("Thank you."), cancellationToken);
            }
            return(await stepContext.EndDialogAsync(cancellationToken : cancellationToken));
        }
Esempio n. 10
0
        /// <summary>
        /// Create an activity through Language Generation using the thread culture or provided override.
        /// </summary>
        /// <param name="templateName">Langauge Generation template.</param>
        /// <param name="data">Data for Language Generation to use during response generation.</param>
        /// <param name="localeOverride">Optional override for locale.</param>
        /// <returns>Activity.</returns>
        public Activity GenerateActivityForLocale(string templateName, object data = null, string localeOverride = null)
        {
            if (templateName == null)
            {
                throw new ArgumentNullException(nameof(templateName));
            }

            // By default we use the locale for the current culture, if a locale is provided then we ignore this.
            var locale = localeOverride ?? CultureInfo.CurrentUICulture.Name;

            // Do we have a template engine for this locale?
            if (TemplateEnginesPerLocale.ContainsKey(locale))
            {
                return(ActivityBuilder.GenerateFromLG(TemplateEnginesPerLocale[locale].EvaluateTemplate(templateName, data)));
            }
            else
            {
                // We don't have a set of matching responses for this locale so we apply fallback policy to find options.
                languageFallbackPolicy.TryGetValue(locale, out string[] locales);
                {
                    // If no fallback options were found then we fallback to the default and log.
                    if (!languageFallbackPolicy.TryGetValue(localeDefault, out locales))
                    {
                        throw new Exception($"No LG responses found for {locale} or when attempting to fallback to '{localeDefault}'");
                    }
                }

                // Work through the fallback hierarchy to find a response
                foreach (var fallBackLocale in locales)
                {
                    if (TemplateEnginesPerLocale.ContainsKey(fallBackLocale))
                    {
                        return(ActivityBuilder.GenerateFromLG(TemplateEnginesPerLocale[fallBackLocale].EvaluateTemplate(templateName, data)));
                    }
                }
            }

            throw new Exception($"No LG responses found for {locale} or when attempting to fallback to '{localeDefault}'");
        }
        public AdapterWithErrorHandler(ICredentialProvider credentialProvider, ILogger <BotFrameworkHttpAdapter> logger, IStorage storage,
                                       UserState userState, ConversationState conversationState, IConfiguration configuration)
            : base(credentialProvider)
        {
            this.UseStorage(storage);
            this.UseState(userState, conversationState);
            this.Use(new RegisterClassMiddleware <IActivityGenerator>(new ActivityBuilder()));
            this.UseDebugger(configuration.GetValue <int>("debugport", 4712));

            string[] paths    = { ".", "AdapterWithErrorHandler.lg" };
            string   fullPath = Path.Combine(paths);

            _lgEngine = new TemplateEngine().AddFile(fullPath);

            OnTurnError = async(turnContext, exception) =>
            {
                // Log any leaked exception from the application.
                logger.LogError($"Exception caught : {exception.Message}");

                // Send a catch-all apology to the user.
                await turnContext.SendActivityAsync(ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("SomethingWentWrong", exception)));

                if (conversationState != null)
                {
                    try
                    {
                        // Delete the conversationState for the current conversation to prevent the
                        // bot from getting stuck in a error-loop caused by being in a bad state.
                        // ConversationState should be thought of as similar to "cookie-state" in a Web pages.
                        await conversationState.DeleteAsync(turnContext);
                    }
                    catch (Exception e)
                    {
                        logger.LogError($"Exception caught on attempting to Delete ConversationState : {e.Message}");
                    }
                }
            };
        }
Esempio n. 12
0
        private async Task <DialogTurnResult> SummaryStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            if ((bool)stepContext.Result)
            {
                // Get the current profile object from user state.
                var userProfile = await _userProfileAccessor.GetAsync(stepContext.Context, () => new UserProfile(), cancellationToken);

                userProfile.Transport = (string)stepContext.Values["transport"];
                userProfile.Name      = (string)stepContext.Values["name"];
                userProfile.Age       = (int)stepContext.Values["age"];

                var msg = _lgGenerator.GenerateActivity("SummaryReadout", userProfile, stepContext);

                await stepContext.Context.SendActivityAsync(ActivityBuilder.GenerateFromLG(msg), cancellationToken);
            }
            else
            {
                await stepContext.Context.SendActivityAsync(_lgGenerator.GenerateActivity("NoProfileReadBack", stepContext), cancellationToken);
            }

            // WaterfallStep always finishes with the end of the Waterfall or with another dialog, here it is the end.
            return(await stepContext.EndDialogAsync(cancellationToken : cancellationToken));
        }
Esempio n. 13
0
        private async Task <DialogTurnResult> InitialStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            var bookingDetails = (BookingDetails)stepContext.Options;
            var timex          = bookingDetails.TravelDate;

            var promptMsg   = _lgEngine.EvaluateTemplate("PromptForTravelDate");
            var repromptMsg = _lgEngine.EvaluateTemplate("InvalidDateReprompt");

            if (timex == null)
            {
                // We were not given any date at all so prompt the user.
                return(await stepContext.PromptAsync(nameof(DateTimePrompt),
                                                     new PromptOptions
                {
                    Prompt = ActivityBuilder.GenerateFromLG(promptMsg),
                    RetryPrompt = ActivityBuilder.GenerateFromLG(repromptMsg)
                }, cancellationToken));
            }
            else
            {
                // We have a Date we just need to check it is unambiguous.
                var timexProperty = new TimexProperty(timex);
                if (!timexProperty.Types.Contains(Constants.TimexTypes.Definite))
                {
                    // This is essentially a "reprompt" of the data we were given up front.
                    return(await stepContext.PromptAsync(nameof(DateTimePrompt),
                                                         new PromptOptions
                    {
                        Prompt = ActivityBuilder.GenerateFromLG(repromptMsg)
                    }, cancellationToken));
                }
                else
                {
                    return(await stepContext.NextAsync(new DateTimeResolution { Timex = timex }, cancellationToken));
                }
            }
        }
Esempio n. 14
0
        private async Task <DialogTurnResult> IntroStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            if (string.IsNullOrEmpty(Configuration["LuisAppId"]) || string.IsNullOrEmpty(Configuration["LuisAPIKey"]) || string.IsNullOrEmpty(Configuration["LuisAPIHostName"]))
            {
                await stepContext.Context.SendActivityAsync(
                    MessageFactory.Text("NOTE: LUIS is not configured. To enable all capabilities, add 'LuisAppId', 'LuisAPIKey' and 'LuisAPIHostName' to the appsettings.json file."), cancellationToken);

                return(await stepContext.NextAsync(null, cancellationToken));
            }
            else
            {
                return(await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("IntroPrompt")) }, cancellationToken));
            }
        }
Esempio n. 15
0
        private async Task <DialogTurnResult> ConfirmStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            var bookingDetails = (BookingDetails)stepContext.Options;

            bookingDetails.TravelDate = (string)stepContext.Result;

            return(await stepContext.PromptAsync(nameof(ConfirmPrompt), new PromptOptions { Prompt = ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("PromptForMissingInformation", bookingDetails)) }, cancellationToken));
        }
Esempio n. 16
0
        private async Task <DialogTurnResult> OriginStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            var bookingDetails = (BookingDetails)stepContext.Options;

            bookingDetails.Destination = (string)stepContext.Result;

            if (bookingDetails.Origin == null)
            {
                return(await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("PromptForMissingInformation", bookingDetails)) }, cancellationToken));
            }
            else
            {
                return(await stepContext.NextAsync(bookingDetails.Origin, cancellationToken));
            }
        }
Esempio n. 17
0
        private static async Task <DialogTurnResult> NameStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            stepContext.Values["transport"] = ((FoundChoice)stepContext.Result).Value;

            return(await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("AskForName")) }, cancellationToken));
        }
Esempio n. 18
0
        private async Task <DialogTurnResult> ShowCardStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            _logger.LogInformation("MainDialog.ShowCardStepAsync");

            // Reply to the activity we received with an activity.
            var reply = stepContext.Context.Activity.CreateReply();

            // Cards are sent as Attachments in the Bot Framework.
            // So we need to create a list of attachments on the activity.
            reply.Attachments = new List <Attachment>();

            // Get the text from the activity to use to show the correct card
            var text = stepContext.Context.Activity.Text.ToLowerInvariant().Split(' ')[0];

            // Decide which type of card(s) we are going to show the user
            if (text.StartsWith("hero"))
            {
                // Display a HeroCard.
                await stepContext.Context.SendActivityAsync(ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("HeroCard")));
            }
            else if (text.StartsWith("thumb"))
            {
                // Display a ThumbnailCard.
                await stepContext.Context.SendActivityAsync(ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("ThumbnailCard")));
            }
            else if (text.StartsWith("sign"))
            {
                // Display a SignInCard.
                await stepContext.Context.SendActivityAsync(ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("SigninCard")));
            }
            else if (text.StartsWith("animation"))
            {
                // Display an AnimationCard.
                await stepContext.Context.SendActivityAsync(ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("AnimationCard")));
            }
            else if (text.StartsWith("video"))
            {
                // Display a VideoCard
                await stepContext.Context.SendActivityAsync(ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("VideoCard")));
            }
            else if (text.StartsWith("audio"))
            {
                // Display an AudioCard
                await stepContext.Context.SendActivityAsync(ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("AudioCard")));
            }
            else if (text.StartsWith("receipt"))
            {
                // Display a ReceiptCard.
                reply.Attachments.Add(Cards.GetReceiptCard().ToAttachment());
                // Send the card(s) to the user as an attachment to the activity
                await stepContext.Context.SendActivityAsync(reply, cancellationToken);
            }
            else if (text.StartsWith("adaptive"))
            {
                await stepContext.Context.SendActivityAsync(ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("AdaptiveCard")));
            }
            else
            {
                // Display a carousel of all the rich card types.
                await stepContext.Context.SendActivityAsync(ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("AllCards")));
            }

            // Give the user instructions about what to do next
            await stepContext.Context.SendActivityAsync(ActivityBuilder.GenerateFromLG(_lgEngine.EvaluateTemplate("CardStartOverResponse")), cancellationToken);

            return(await stepContext.EndDialogAsync());
        }