private async Task <DialogTurnResult> GetFundDocumentURLStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var documentModel = (FundDocumentModel)stepContext.Values[FundDocumentModelValue]; var result = (FoundChoice)stepContext.Result; if (result != null) { documentModel.FundDocument = result.Value.Trim().ToLower(); } var fundDocumentModel = APIService.GetFundDocumentUrl(documentModel); //no document was found. if (fundDocumentModel == null) { await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, "The requested document is not available.")); } else { //get the fund document's attributes and send a formatted response. var month = fundDocumentModel.Month == default ? "" : new DateTime(2000, fundDocumentModel.Month, 1).ToString("MMM", CultureInfo.InvariantCulture); var year = fundDocumentModel.Year == default ? "" : $"{fundDocumentModel.Year}"; var quarter = fundDocumentModel.Quarter == default ? "" : $"Q{fundDocumentModel.Quarter}"; var parnFund = fundDocumentModel.FundName == null ? "" : $"{CultureInfo.InvariantCulture.TextInfo.ToTitleCase(fundDocumentModel.FundName)}"; var url = fundDocumentModel.HasKenticoURL ? APIService.domain + fundDocumentModel.DocumentURL : fundDocumentModel.DocumentURL; var link = ChannelFormattingService.FormatLinkMessageAndSaveToState(stepContext.Context, url, _botService, cancellationToken); await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"You can view the {month} {year} {quarter} {parnFund} {documentModel.FundDocument} " + $"by clicking {link}")); } return(await stepContext.EndDialogAsync(null, cancellationToken)); }
private async Task <DialogTurnResult> GetFundNameStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var documentModel = (FundDocumentModel)stepContext.Values[FundDocumentModelValue]; //if no fund is needed if (!((bool)stepContext.Result)) { return(await stepContext.NextAsync(null, cancellationToken)); } //generate choices with the list of funds var SuggestedActions = SuggestedActionGenerator.GenerateSuggestedActions(Common.PIFundNames); var reply = MessageFactory.Text(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"Which fund would you like to see the {documentModel.FundDocument} for?")); reply.SuggestedActions = SuggestedActions; var retryReply = MessageFactory.Text(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"Please select a valid fund to view its {documentModel.FundDocument}")); retryReply.SuggestedActions = SuggestedActions; //ask for fund name return(await stepContext.PromptAsync($"{nameof(FundDocumentsDialog)}.askFundName", new PromptOptions { Prompt = reply, RetryPrompt = retryReply }, cancellationToken)); }
private async Task <DialogTurnResult> GetDocumentAssociatedWithFundNameStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var fundName = ((string)stepContext.Result); var documentModel = (FundDocumentModel)stepContext.Values[FundDocumentModelValue]; //get response from user, if any, and save it to the model if (fundName != null) { fundName = fundName.Trim().ToLower(); if (fundName != Common.PIFundNames[Common.PIFundIndexInNamesList].ToLower()) { fundName = "PI " + fundName; } documentModel.FundName = fundName; stepContext.Values[FundDocumentModelValue] = documentModel; } if (!string.IsNullOrEmpty(documentModel.FundDocument)) { //wants general PI Fund document i.e annual report return(await stepContext.NextAsync(null, cancellationToken)); } var documentChoices = Common.DocumentsRequireFundName.ToList().ConvertAll(s => CultureInfo.InvariantCulture.TextInfo.ToTitleCase(s)); //if no document was specified, but a fund was, ask to select which document. return(await stepContext.PromptAsync($"{nameof(FundDocumentsDialog)}.askFundDocument", new PromptOptions { Prompt = MessageFactory.Text(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"Which {CultureInfo.InvariantCulture.TextInfo.ToTitleCase(documentModel.FundName)} document would you like to see?")), RetryPrompt = MessageFactory.Text(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"Please select a valid document option")), Choices = ChoiceFactory.ToChoices(documentChoices) }, cancellationToken)); }
public async Task <DialogTurnResult> GetAttributionsAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var fundName = (string)stepContext.Result; var attributionModel = (FundAttributionModel)stepContext.Values[FundAttributionModelValue]; //save given fund name (if any) to the model if (fundName != null) { fundName = fundName.Trim().ToLower(); //if selected choice was "Mid cap fund" etc, we must add PI to the front. (does not apply to PI Fund) if (fundName != Common.PIFundNames[Common.PIFundIndexInNamesList].ToLower()) { fundName = "PI " + fundName; } attributionModel.FundName = fundName; } //get fund contributors or detractors var fundAttributions = APIService.GetFundAttributions(attributionModel).Result; //format it in a header -> subtitle -> data var placeholder = attributionModel.ContributorsOrDetractors == 0 ? "contributors" : "detractors"; var response = ChannelFormattingService.FormatHeaderSubtitleAndList(stepContext.Context, $"{attributionModel.FundTicker} top {placeholder}:", fundAttributions); await stepContext.Context.SendActivityAsync(response, null, null, cancellationToken); return(await stepContext.EndDialogAsync(null, cancellationToken)); }
private async Task <DialogTurnResult> ProcessQnaIntentAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { //send message to QnA Maker var results = await _luisService.QnaRecognizer.GetAnswersAsync(stepContext.Context); //if an answer was found, respond with the answer. //otherwise, respond with error. if (results.Any()) { ConversationData conversationData = await _botService.conversationDataAccessor.GetAsync(stepContext.Context, () => new ConversationData()); conversationData.FailedAttemptsCount = 0; await stepContext.Context.SendActivityAsync(MessageFactory.Text(results.First().Answer), cancellationToken); await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatMessages(stepContext.Context, "If this does not answer your question, please try structuring your question in a " + "different way and/or to be more specific", new List <Func <string, string> > { ToHtml.MessageWrapInSpan }), cancellationToken : cancellationToken); } else { await ProcessRecognitionError(ChannelFormattingService.FormatMessages(stepContext.Context, "Sorry, I was not able to find an answer to your question. Please try structuring your question in a " + "different way and/or to be more specific", new List <Func <string, string> > { ToHtml.MessageWrapInSpan }), stepContext, cancellationToken); } return(await stepContext.NextAsync(null, cancellationToken)); }
private async Task <DialogTurnResult> DispatchRecognitionStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { UserProfile profile = await _botService.profileStateAccessor.GetAsync(stepContext.Context, () => new UserProfile()); ConversationData conversationState = await _botService.conversationDataAccessor.GetAsync(stepContext.Context, () => new ConversationData()); conversationState.IsCancellable = true; //get the intent from LUIS Dispatch. Identifies whether message should be passed onto the main LUIS app or QnA Maker. var recognizerResult = await _luisService.Dispatch.RecognizeAsync(stepContext.Context, cancellationToken); (string intent, double score) = recognizerResult.GetTopScoringIntent(); var luisResult = recognizerResult.Properties["luisResult"] as LuisResult; switch (intent) { case /* [redacted] */: return(await ProcessQnaIntentAsync(stepContext, cancellationToken)); case /* [redacted] */: return(await ProcessLuisIntentAsync(stepContext, cancellationToken, luisResult)); default: await ProcessRecognitionError(ChannelFormattingService.FormatMessages(stepContext.Context, "Sorry, I do not know what you mean.", new List <Func <string, string> > { ToHtml.MessageWrapInSpan }), stepContext, cancellationToken); return(await stepContext.NextAsync(null, cancellationToken)); } }
private async Task <DialogTurnResult> ParseGivenParametersAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var attrModel = new FundAttributesModel(); var luisResult = (LuisResult)stepContext.Options; /*find the attribute entity types that were recognized. * i.e. If I send "I want the PARMX expense ratio", this step will * find that the user requested FundBasicAttributeType and save it within the FundAttributesModel */ FindFundNameAndAttributeEntities(attrModel, luisResult); //save the model stepContext.Values[FundAttributesModelValue] = attrModel; //Prompt for fund name by giving a list of choices. This makes it so the user doesn't get prompted with an error if he/she tries to type the fund themselves if (string.IsNullOrEmpty(attrModel.PIFundName)) { var SuggestedActions = SuggestedActionGenerator.GenerateSuggestedActions(Common.PIFundNames); var reply = MessageFactory.Text(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"Which fund would you like to see your requested attributes for?")); reply.SuggestedActions = SuggestedActions; var retryReply = MessageFactory.Text(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"Please select a valid fund to view its attributes")); retryReply.SuggestedActions = SuggestedActions; return(await stepContext.PromptAsync($"{nameof(FundSpecificAttributesDialog)}.askFundName", new PromptOptions { Prompt = reply, RetryPrompt = retryReply }, cancellationToken)); } return(await stepContext.NextAsync(null, cancellationToken)); }
public AdapterFrameworkHandler(IConfiguration configuration, ILogger <BotFrameworkHttpAdapter> logger, BotStateService botService, ConversationState conversationState = null) : base(configuration, logger) { _logger = logger; _botService = botService; //This method is triggered when an exception is thrown somewhere within a Dialog. OnTurnError = async(turnContext, exception) => { // Log any leaked exception from the application. logger.LogError($"Exception caught : {exception.Message} {JsonConvert.SerializeObject(exception)}"); // Send a catch-all apology to the user. await turnContext.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(turnContext, "Sorry, it looks like something went wrong. Please refresh the page and try again.")); 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. await conversationState.DeleteAsync(turnContext); } catch (Exception e) { logger.LogError($"Exception caught on attempting to Delete ConversationState : {e.Message}"); } } }; }
private async Task <DialogTurnResult> ParseGivenParametersAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var luisResult = (LuisResult)stepContext.Options; var documentModel = new FundDocumentModel(); //Get all necessary entities to perform query for fund documents var parsedDate = GetDateTimeEntity(luisResult); //try get year documentModel.SetDate(parsedDate); documentModel.SetQuarter(GetEntityModelResolution(luisResult, QuarterDateTime)); //try get quarter documentModel.FundName = GetEntityModelResolution(luisResult, FundName); //try get fund name documentModel.FundDocument = GetEntityModelResolution(luisResult, DocumentType); //try get fund document //if no document and no fund was specified, direct user to fund document page if (string.IsNullOrEmpty(documentModel.FundDocument) && string.IsNullOrEmpty(documentModel.FundName)) { var link = ChannelFormattingService.FormatLinkMessageAndSaveToState(stepContext.Context, Common.FundDocumentsURL, _botService, cancellationToken); await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"You can view all fund documents by clicking {link}")); return(await stepContext.EndDialogAsync(null, cancellationToken)); } var needsFund = false; //if no fund was given, but the document requires a fund to be specified if (string.IsNullOrEmpty(documentModel.FundName) && Common.DocumentsRequireFundName.Contains(documentModel.FundDocument)) { needsFund = true; } stepContext.Values[FundDocumentModelValue] = documentModel; return(await stepContext.NextAsync(needsFund, cancellationToken)); }
/* * triggers every time a new conversation is created * i.e when the web app is refreshed, a new conversation is created and this is why you see these messages appear * new members added to the conversation stored in membersAdded */ protected override async Task OnMembersAddedAsync(IList <ChannelAccount> membersAdded, ITurnContext <IConversationUpdateActivity> turnContext, CancellationToken cancellationToken) { foreach (var member in membersAdded) { //check if the user who joined the conversation is not the Bot if (member.Id != turnContext.Activity.Recipient.Id) { await turnContext.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(turnContext, "Hello, I'm Jerry, the PI Investments AI Chatbot!")); await turnContext.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(turnContext, "How can I help you?")); } } }
//this method checks for user interruptions. specifically returns a non-null value if the user says cancel or help private async Task <DialogTurnResult> InterruptAsync(DialogContext innerDc, CancellationToken cancellationToken) { var conversationData = await _botService.conversationDataAccessor.GetAsync(innerDc.Context, () => new ConversationData()); //if the current activity is a message if (innerDc.Context.Activity.Type == ActivityTypes.Message) { var text = innerDc.Context.Activity.Text.ToLowerInvariant(); //send message to LUIS var recognizerResult = await _luisService.Dispatch.RecognizeAsync(innerDc.Context, cancellationToken); var topIntent = recognizerResult.GetTopScoringIntent(); if (topIntent.intent == "luis_intent") { var luisResult = recognizerResult.Properties["luisResult"] as LuisResult; switch (luisResult.ConnectedServiceResult.TopScoringIntent.Intent) { case "Utilities.Help": await innerDc.Context.SendActivityAsync(ChannelFormattingService.FormatMessages(innerDc.Context, $"Showing help...", new List <Func <string, string> > { ToHtml.MessageWrapInSpan }), cancellationToken : cancellationToken); return(await innerDc.CancelAllDialogsAsync()); case "Utilities.Cancel": await innerDc.Context.SendActivityAsync(ChannelFormattingService.FormatMessages(innerDc.Context, $"Alright!", new List <Func <string, string> > { ToHtml.MessageWrapInSpan }), cancellationToken : cancellationToken); await _botService.conversationDataAccessor.SetAsync(innerDc.Context, conversationData); await _botService.ConversationState.SaveChangesAsync(innerDc.Context, false, cancellationToken); return(await innerDc.CancelAllDialogsAsync()); } } } return(null); }
private async Task <DialogTurnResult> GetSectorWeightingsAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var fundName = (string)stepContext.Result; var sectorModel = (FundSectorWeightsModel)stepContext.Values[FundSectorModelValue]; //if a fund was selected from the previous step, save it to the model. if (fundName != null) { fundName = fundName.Trim().ToLower(); if (fundName != "all funds" && fundName != Common.PIFundNames[Common.PIFundIndexInNamesList].ToLower()) { fundName = "PI " + fundName; } sectorModel.AddFund(fundName); } //if the funds requested contains the fixed income fund, tell the user that no sector weightings exist and remove it. if (sectorModel.Funds.Any(s => s == "PRFIX")) { await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, "The PI Fixed Income Fund does not contain sector weightings")); sectorModel.Funds.RemoveAll(s => s == "PRFIX"); stepContext.Values[FundSectorModelValue] = sectorModel; //if the fixed income fund was the only fund requested, end the dialog. if (sectorModel.Funds.Count == 0) { return(await stepContext.EndDialogAsync(null, cancellationToken)); } } //get the fund sector weights var fundSectorWeights = APIService.GetFundSectorWeights(sectorModel).Result; //format the sector weights in header -> subtitles -> list. var response = ChannelFormattingService.FormatHeaderSubtitleAndList(stepContext.Context, $"{CultureInfo.InvariantCulture.TextInfo.ToTitleCase(sectorModel.Sector)} sector weights", fundSectorWeights); await stepContext.Context.SendActivityAsync(response, null, null, cancellationToken); return(await stepContext.EndDialogAsync(null, cancellationToken)); }
private async Task <DialogTurnResult> ParseGivenParametersAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var luisResult = (LuisResult)stepContext.Options; var sectorModel = new FundSectorWeightsModel(); sectorModel.Funds = new List <string>(); //find fund names and sector GetEntityResolutions(luisResult, sectorModel); stepContext.Values[FundSectorModelValue] = sectorModel; //if no sector was given if (string.IsNullOrEmpty(sectorModel.Sector)) { await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, "Please select a valid sector to view weighting information")); return(await stepContext.EndDialogAsync(null, cancellationToken)); } //if no funds were given, prompt the user to select a fund. else if (sectorModel.Funds.Count == 0) { var choices = Common.PIFundNames.ToList(); choices.Insert(0, "All funds"); var suggestedActions = SuggestedActionGenerator.GenerateSuggestedActions(choices); var reply = MessageFactory.Text(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"Which fund would you like to see " + $"{CultureInfo.InvariantCulture.TextInfo.ToTitleCase(sectorModel.Sector)} sector weightings for?")); var retryReply = MessageFactory.Text(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, "Please select a valid choice")); reply.SuggestedActions = suggestedActions; retryReply.SuggestedActions = suggestedActions; return(await stepContext.PromptAsync($"{nameof(FundSectorWeightsDialog)}.fundName", new PromptOptions { Prompt = reply, RetryPrompt = retryReply }, cancellationToken)); } return(await stepContext.NextAsync(null, cancellationToken)); }
private async Task <DialogTurnResult> GetHoldingsStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var fundName = ((string)stepContext.Result); var holdingModel = (FundHoldingsModel)stepContext.Values[FundHoldingModelValue]; //if a fund name was selected from the previous step, save it to the model if (fundName != null) { fundName = fundName.Trim().ToLower(); if (fundName == "all funds") { holdingModel.AllFunds = true; } else if (fundName != Common.PIFundNames[Common.PIFundIndexInNamesList].ToLower()) { fundName = "PI " + fundName; } holdingModel.FundName.Add(fundName); stepContext.Values[FundHoldingModelValue] = holdingModel; } //get all holdings var allHoldings = await APIService.GetFundHoldingsAttributes(holdingModel); //if none were found,the company is not a holding in the requested funds. if (allHoldings == null) { await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"{CultureInfo.InvariantCulture.TextInfo.ToTitleCase(holdingModel.Company)} is not a holding in the requested fund")); return(await stepContext.EndDialogAsync(null, cancellationToken)); } //format the holdings in a header -> subititle -> list var response = ChannelFormattingService.FormatHeaderSubtitleAndList(stepContext.Context, $"{CultureInfo.InvariantCulture.TextInfo.ToTitleCase(holdingModel.Company)}" + " holding information:", allHoldings); await stepContext.Context.SendActivityAsync(response, null, null, cancellationToken); return(await stepContext.EndDialogAsync(null, cancellationToken)); }
private async Task <DialogTurnResult> ParseGivenParametersAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var luisResult = (LuisResult)stepContext.Options; var holdingModel = new FundHoldingsModel(); holdingModel.HoldingAttributes = new List <string>(); holdingModel.FundName = new List <string>(); //get the fund names, company, and (optional) holding attributes requested GetEntityModelResolution(luisResult, holdingModel); stepContext.Values[FundHoldingModelValue] = holdingModel; // no company was recognized if (string.IsNullOrEmpty(holdingModel.Company)) { await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, "Please specify a company to see holding information.")); return(await stepContext.EndDialogAsync(null, cancellationToken)); } //if no funds were selected, prompt user to select a fund or select all funds. else if (holdingModel.FundName.Count == 0) { var choices = Common.PIFundNames.ToList(); choices.Insert(0, "All funds"); var suggestedActions = SuggestedActionGenerator.GenerateSuggestedActions(choices); var reply = MessageFactory.Text(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, "Which fund would you like to see holding information for?")); var retryReply = MessageFactory.Text(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, "Please select a valid choice")); reply.SuggestedActions = suggestedActions; retryReply.SuggestedActions = suggestedActions; return(await stepContext.PromptAsync($"{nameof(FundHoldingsDialog)}.fundName", new PromptOptions { Prompt = reply, RetryPrompt = retryReply }, cancellationToken)); } return(await stepContext.NextAsync(null, cancellationToken)); }
private async Task ProcessRecognitionError(string message, WaterfallStepContext stepContext, CancellationToken cancellationToken) { ConversationData conversationData = await _botService.conversationDataAccessor.GetAsync(stepContext.Context, () => new ConversationData()); //incremene the failed counter conversationData.FailedAttemptsCount += 1; //if the user has failed more than 3 times if (conversationData.FailedAttemptsCount >= 3) { await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatMessages(stepContext.Context, "Sorry, I am still unable to understand your question. Please call Shareholder Services at " + "(800) 999-3505 for further asssistance.", new List <Func <string, string> > { ToHtml.MessageWrapInSpan }), null, null, cancellationToken); } //otherwise respond with "sorry, I do not know what you mean." (this message may be variated so it is passed as a paramter) else { await stepContext.Context.SendActivityAsync(message, cancellationToken : cancellationToken); } }
private async Task <DialogTurnResult> ParseGivenParametersAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var luisResult = (LuisResult)stepContext.Options; var attributionModel = new FundAttributionModel(); //find all entities found by LUIS and save it to the model GetEntityResolutions(luisResult, attributionModel); //if the user requested "any fund" if (attributionModel.FundName == "any fund") { attributionModel.FundName = null; await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, "You must select a fund to view top contributors/detractors")); return(await stepContext.EndDialogAsync(null, cancellationToken)); } stepContext.Values[FundAttributionModelValue] = attributionModel; //if no fund name is given, we need to ask the user if (string.IsNullOrEmpty(attributionModel.FundName)) { var choices = Common.PIFundNames.ToList(); var suggestedActions = SuggestedActionGenerator.GenerateSuggestedActions(choices); var placeholder = attributionModel.ContributorsOrDetractors == 0 ? "top contributors" : "top detractors"; var reply = MessageFactory.Text(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"Which fund would you like to see {placeholder} for?")); var retryReply = MessageFactory.Text(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, "Please select a valid choice")); reply.SuggestedActions = suggestedActions; retryReply.SuggestedActions = suggestedActions; return(await stepContext.PromptAsync($"{nameof(FundAttributionDialog)}.fundName", new PromptOptions { Prompt = reply, RetryPrompt = retryReply }, cancellationToken)); } return(await stepContext.NextAsync(null, cancellationToken)); }
private async Task <DialogTurnResult> ParseGivenParametersAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { //get luisResult containing all entities and the attribute model from the options sent from the parent dialog LuisResult luisResult = (LuisResult)((List <object>)stepContext.Options)[0]; FundAttributesModel attrModel = (FundAttributesModel)((List <object>)stepContext.Options)[1]; attrModel.FundBasicAttributes = new List <string>(); // store recognized entities into the Attribute model ParseEntities(attrModel, luisResult); //get fund basic attributes requested Dictionary <string, Dictionary <string, string> > basicAttributes = await APIService.GetFundBasicsAttributes(attrModel); //send response in a subtitle > list format var message = ChannelFormattingService.FormatSubtitleAndList(stepContext.Context, basicAttributes); await stepContext.Context.SendActivityAsync(message, null, null, cancellationToken); return(await stepContext.EndDialogAsync(true, cancellationToken)); }
private async Task <DialogTurnResult> DispatchIraAccountDocumentAsync(WaterfallStepContext stepContext, AccountDocumentModel documentModel, CancellationToken cancellationToken) { //if no document was specified for the account, lead the user to the general documents page if (string.IsNullOrEmpty(documentModel.AccountDocument)) { var link = ChannelFormattingService.FormatLinkMessageAndSaveToState(stepContext.Context, Common.PIIraDocumentUrl, _botService, cancellationToken); await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"You can view all Ira-Related Account documents by clicking {link}. " + $"You can also ask for a specific document in the same fashion and I can direct you right to it.")); } //if document was originally specified else { //get the URL and respond. var link = ChannelFormattingService.FormatLinkMessageAndSaveToState(stepContext.Context, APIService.GetAccountDocumentURL(documentModel), _botService, cancellationToken); await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"You can view the IRA {documentModel.AccountDocument} document by clicking {link}")); } return(await stepContext.NextAsync(null, cancellationToken)); }
private async Task <DialogTurnResult> ProcessLuisIntentAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken, LuisResult luisResult) { UserProfile profile = await _botService.profileStateAccessor.GetAsync(stepContext.Context, () => new UserProfile()); ConversationData conversationData = await _botService.conversationDataAccessor.GetAsync(stepContext.Context, () => new ConversationData()); //get the connected service result from the LUIS Main App. This will contain all the specific entities and intents. var intent = luisResult.ConnectedServiceResult.TopScoringIntent.Intent.Trim(); //if user is sending a greeting, greet back if (intent == /* [redacted] */) { await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatMessages(stepContext.Context, $"Hello, how can I help you today?", new List <Func <string, string> > { ToHtml.MessageWrapInSpan })); conversationData.FailedAttemptsCount = 0; return(await stepContext.NextAsync(null, cancellationToken)); //if the user has a specific intent, find the dialog ID associated with the intent in the Dictionary and begin } else if (IntentToDialogId.ContainsKey(intent)) { conversationData.FailedAttemptsCount = 0; return(await stepContext.BeginDialogAsync(IntentToDialogId[intent], luisResult, cancellationToken)); //otherwise... } else { await ProcessRecognitionError(ChannelFormattingService.FormatMessages(stepContext.Context, "Sorry, I do not know what you mean.", new List <Func <string, string> > { ToHtml.MessageWrapInSpan }), stepContext, cancellationToken); return(await stepContext.NextAsync(null, cancellationToken)); } }
private async Task <DialogTurnResult> DispatchNonIraAccountDocumentAsync(WaterfallStepContext stepContext, AccountDocumentModel documentModel, CancellationToken cancellationToken) { var sendGeneralUrl = false; //if the user requested a Standard acct transfer form. if (Common.IraOnlyDocumentTypes.Contains(documentModel.AccountDocument)) { await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"Sorry, there is currently not a {documentModel.AccountDocument} document/form for Standard accounts.")); sendGeneralUrl = true; } //the user requested a specific document, find the URL and respond. else if (!string.IsNullOrEmpty(documentModel.AccountDocument)) { var link = ChannelFormattingService.FormatLinkMessageAndSaveToState(stepContext.Context, APIService.GetAccountDocumentURL(documentModel), _botService, cancellationToken); await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"You can view the Standard {documentModel.AccountDocument} " + $"document by clicking {link}")); } else { sendGeneralUrl = true; } //if the user did not specify a document, or the user requested a standard acct. transfer form, lead them to the general document page. if (sendGeneralUrl) { var link = ChannelFormattingService.FormatLinkMessageAndSaveToState(stepContext.Context, Common.PINonIraDocumentUrl, _botService, cancellationToken); await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, $"You can view all Standard Account related documents by clicking {link}. " + $"You can also ask for a specific document in the same fashion and I can direct you right to it.")); } return(await stepContext.NextAsync(null, cancellationToken)); }
private async Task <DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var conversationData = await _botService.conversationDataAccessor.GetAsync(stepContext.Context, () => new ConversationData()); conversationData.IsCancellable = true; //this condition is satisfied when the user sends "cancel" or "help" if (conversationData.DidCancel) { await stepContext.Context.SendActivityAsync(ChannelFormattingService.FormatMessages(stepContext.Context, "Please enter something I can help you with!", new List <Func <string, string> > { ToHtml.MessageWrapInSpan })); conversationData.DidCancel = false; await _botService.conversationDataAccessor.SetAsync(stepContext.Context, conversationData); await _botService.ConversationState.SaveChangesAsync(stepContext.Context, false, cancellationToken); } return(await stepContext.EndDialogAsync(null, cancellationToken)); }
private async Task <DialogTurnResult> ParseAllGivenInformationStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var luisResult = (LuisResult)stepContext.Options; var documentModel = new AccountDocumentModel { //get ira or standard account type AccountType = GetEntityModelResolution(luisResult, AccountTypeEntity), //get account document AccountDocument = GetEntityModelResolution(luisResult, DocumentTypeEntity) }; documentModel.SetIsIra(); //determines if account is an IRA acct or Standard //if any account type was specified. if (documentModel.IsIra.HasValue) { stepContext.Values[DocumentModelValue] = documentModel; //the account requested is an IRA if (documentModel.IsIra == 1) { return(await DispatchIraAccountDocumentAsync(stepContext, documentModel, cancellationToken)); } //account is standard return(await DispatchNonIraAccountDocumentAsync(stepContext, documentModel, cancellationToken)); } else { //no account has been supplied //if the document specified is an IRA transfer form, but the user did not specify IRA if (Common.IraOnlyDocumentTypes.Contains(documentModel.AccountDocument)) { documentModel.AccountType = "ira"; stepContext.Values[DocumentModelValue] = documentModel; return(await DispatchIraAccountDocumentAsync(stepContext, documentModel, cancellationToken)); } //otherwise, prompt for which account type. var msg = "Which type of account would you like to see "; if (string.IsNullOrEmpty(documentModel.AccountDocument)) { msg += " documents for?"; } else { msg += $" the {documentModel.AccountDocument} application/form for?"; } msg = ChannelFormattingService.FormatSimpleMessage(stepContext.Context, msg); stepContext.Values[DocumentModelValue] = documentModel; return(await stepContext.PromptAsync($"{nameof(AccountDocumentsDialog)}.accountType", new PromptOptions { Prompt = MessageFactory.Text(msg), RetryPrompt = MessageFactory.Text(ChannelFormattingService.FormatSimpleMessage(stepContext.Context, "Please select a valid account type")), Choices = ChoiceFactory.ToChoices(AccountTypeChoices) }, cancellationToken)); } }