private async Task <DialogTurnResult> FinalStepAsync( WaterfallStepContext stepContext, CancellationToken cancellationToken) { // Retrieve their selection list, the choice they made, and whether they chose to finish. var list = stepContext.Values[CountriesSelected] as List <string>; var choice = (FoundChoice)stepContext.Result; var done = choice.Value == DoneOption; if (!done) { // If they chose a company, add it to the list. list.Add(choice.Value); } if (done) { // If they're done, exit and return their list. ConsoleWriter.WriteLineInfo("Filter for: " + string.Join(", ", list)); FilterForWordDetails filterForWordDetails = new FilterForWordDetails(); filterForWordDetails.columnName = list.ToArray(); ConsoleWriter.WriteLineInfo("ColumnName: " + filterForWordDetails.columnName[0]); await BOT_Api.SendFilterForWord(stepContext, usedColumn, list.ToArray()); return(await stepContext.EndDialogAsync(list, cancellationToken)); } else { // Otherwise, repeat this dialog, passing in the list from this iteration. return(await stepContext.ReplaceDialogAsync(nameof(FilterForWordDialog), list, cancellationToken)); } }
//This function is called every time the user enters an input. The intent is determined in the switch case block. From there we call the needed Dialogs private async Task <DialogTurnResult> ActStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var luisResult = await _luisRecognizer.RecognizeAsync <VisualizationInteraction>(stepContext.Context, cancellationToken); switch (luisResult.TopIntent().intent) { //The user wants to change the charttype case VisualizationInteraction.Intent.ChangeChartType: string[] chartTypeResults = luisResult.ToChartTypeEntity; var changeChartTypeDetails = new ChangeChartTypeDetails() { AmbiguousChartTypes = chartTypeResults, ToChartType = chartTypeResults?[0], }; //Check if changechartTypeDetails is null (in the Dialog) and ask for information if it is null return(await stepContext.BeginDialogAsync(nameof(ChangeChartTypeDialog), changeChartTypeDetails, cancellationToken)); // user wants to filter for country, product or segment (nominal Rows) case VisualizationInteraction.Intent.Filter: (string[] columnnameLuis, string[] filterAttributeLuis, string[] countryLuis, string[] segmentLuis, string[] productLuis) = luisResult.FilterForWordEntities; string usedColumn; if (countryLuis != null) { usedColumn = "Country"; } else if (segmentLuis != null) { usedColumn = "Segment"; } else if (productLuis != null) { usedColumn = "Product"; } else { usedColumn = "Country"; } ConsoleWriter.WriteLineInfo("Column: " + usedColumn); var filterForWordDetails = new FilterForWordDetails { columnName = columnnameLuis, filterAttribute = filterAttributeLuis, country = countryLuis, segment = segmentLuis, product = productLuis, usedColumn = usedColumn }; return(await stepContext.BeginDialogAsync(nameof(FilterForWordDialog), filterForWordDetails, cancellationToken)); //user wants to filter for number (cardinal rows) case VisualizationInteraction.Intent.FilterForNumber: (string[] columnNameLuis, string comparisonOperatorLuis, string filterNumberLuis) = luisResult.FilterForNumberEntities; var filterForNumberDetails = new FilterForNumberDetails { columnName = columnNameLuis, comparisonOperator = comparisonOperatorLuis, filterNumber = filterNumberLuis }; return(await stepContext.BeginDialogAsync(nameof(FilterForNumberDialog), filterForNumberDetails, cancellationToken)); //user input is a complete query to be visualized -> send query to nl4dv case VisualizationInteraction.Intent.Nl4dv: //Gets the whole message from the User to the bot out of the luis result string nl4dvQuery = luisResult.Text; (string queryText, string[] chartType, string[] axis1, string[] axis2) = luisResult.Nl4dvEntities; var nl4dvQueryDetails = new Nl4dvQueryDetails { queryText = queryText, chartType = chartType, axis1 = axis1, axis2 = axis2 }; ConsoleWriter.WriteLineInfo("nl4dvQuery: " + nl4dvQuery); return(await stepContext.BeginDialogAsync(nameof(Nl4dvDialog), nl4dvQueryDetails, cancellationToken)); //Here we would have to call the NL4DV function in the event handler (in the Python project) //BOT_Api.SendNL4DV(nl4dvQuery); break; // user wants to change e.g. legend or y-axis case VisualizationInteraction.Intent.ChangeVisualizationPart: (string visualizationPartLuis, string[] toValueLuis) = luisResult.ChangeVisualizationPartEntities; var changeVisualizationPartDetails = new ChangeVisualizationPartDetails { visualizationPart = visualizationPartLuis, toValue = toValueLuis }; return(await stepContext.BeginDialogAsync(nameof(ChangeVisualizationPartDialog), changeVisualizationPartDetails, cancellationToken)); // user wants to change the aggregate of an axis case VisualizationInteraction.Intent.ChangeAggregate: (string toVisPartLuis, string toAggregateLuis) = luisResult.ChangeAggregateEntities; var changeAggregateDetails = new ChangeAggregateDetails { visualizationPart = toVisPartLuis, toAggregate = toAggregateLuis }; return(await stepContext.BeginDialogAsync(nameof(ChangeAggregateDialog), changeAggregateDetails, cancellationToken)); case VisualizationInteraction.Intent.ClearFilter: await BOT_Api.SendClearFilter(stepContext); break; case VisualizationInteraction.Intent.Help: var helpMessageText = "Here is a quick guide for you: say \"show me sales by country\" to create a new visualization || \"change yaxis to profit\" to change the label of y-axis to profit || \"change aggregate of yaxis to sum\" changes the data aggregation of yaxis to sum (you can say sum, count, average) || \"change charttype to piechart\" changes the visualization to a piechart || \"filter for sales >= 200\" filters the dataset for all rows containing sales >= 200 || \"clear filter\" to clear all added filters"; var helpMessage = MessageFactory.Text(helpMessageText, helpMessageText, InputHints.IgnoringInput); await stepContext.Context.SendActivityAsync(helpMessage, cancellationToken); break; //intent not recognized default: // Catch all for unhandled intents var didntUnderstandMessageText = $"Sorry, I didn't get that. Please try asking in a different way (intent was {luisResult.TopIntent().intent})"; var didntUnderstandMessage = MessageFactory.Text(didntUnderstandMessageText, didntUnderstandMessageText, InputHints.IgnoringInput); await stepContext.Context.SendActivityAsync(didntUnderstandMessage, cancellationToken); break; } return(await stepContext.NextAsync(null, cancellationToken)); }
//Check if input is empty or additionally it is asked to filter for countries, then add country option list private async Task <DialogTurnResult> SelectionStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { // Continue using the same selection list, if any, from the previous iteration of this dialog. var list = stepContext.Options as List <string> ?? new List <string>(); bool filterForCountry = false; if (stepContext.Options.GetType().ToString().Equals("Microsoft.BotBuilderSamples.FilterForWordDetails")) { FilterForWordDetails filterForWordDetails = (FilterForWordDetails)stepContext.Options; usedColumn = filterForWordDetails.usedColumn; // Check if filter for Word Dialog input is empty if (filterForWordDetails.columnName == null) { string messageNull = "I could not recognize what column you want to apply that filter to. Please say something like \"Filter for Germany and Canada\""; var cancelMessage = MessageFactory.Text(messageNull, CancelMsgText, InputHints.IgnoringInput); await stepContext.Context.SendActivityAsync(cancelMessage, cancellationToken); return(await stepContext.CancelAllDialogsAsync(cancellationToken)); } //Filter for country for (int i = 0; i < filterForWordDetails.columnName.Length; i++) { string s = UppercaseFirst(filterForWordDetails.columnName[i]); list.Add(s); //becomes true when you enter "filter for country" if (string.Equals(s, "Country") || string.Equals(s, "Countries")) { filterForCountry = true; } } if ((filterForWordDetails.country == null) && (filterForWordDetails.segment == null) && (filterForWordDetails.product == null) && !filterForCountry) { string messageNull = "I could not recognize what column you want to apply that filter to. Please say something like \"Filter for Germany and Canada\""; var cancelMessage = MessageFactory.Text(messageNull, CancelMsgText, InputHints.IgnoringInput); await stepContext.Context.SendActivityAsync(cancelMessage, cancellationToken); return(await stepContext.CancelAllDialogsAsync(cancellationToken)); } //Breaks if we did not recognize any countries if (!filterForCountry) { filterForWordDetails.columnName = list.ToArray(); ConsoleWriter.WriteLineInfo("Filter for: " + string.Join(", ", list)); ConsoleWriter.WriteLineInfo("ColumnName: " + filterForWordDetails.columnName[0]); await BOT_Api.SendFilterForWord(stepContext, usedColumn, list.ToArray()); return(await stepContext.EndDialogAsync(filterForWordDetails.columnName)); } } //if user entered "FILTER FOR COUNTRY" OR "COUNTRIES": stepContext.Values[CountriesSelected] = list; //Create a prompt message string message; if (list[0] == "Country") { message = $"Please choose a country to filter to finish."; list.Remove("Country"); } else if (list[0] == "Countries") { message = $"Please choose a country to filter to finish."; list.Remove("Countries"); } else { message = $"You have selected **{String.Join(", ", list)}**. You can filter for an additional country, " + $"or choose `{DoneOption}` to finish."; } // Create the list of options to choose from. var options = _countryOptions.ToList(); if (list.Count > 0) { options.Add(DoneOption); options = options.Except(list).ToList(); } var promptOptions = new PromptOptions { Prompt = MessageFactory.Text(message), RetryPrompt = MessageFactory.Text("Please choose an option from the list."), Choices = ChoiceFactory.ToChoices(options), }; // Prompt the user for a choice. return(await stepContext.PromptAsync(nameof(ChoicePrompt), promptOptions, cancellationToken)); }