I want my bot to process LUIS and QnAMaker utterance by users when there is no active dialog.
I ended up with this code and its working, the only problem is, its only working for one turn. the second time the user type anything the bot start the main dialog again.
End here is cancel all dialogs. The answer from who made you is from QnAMaker.
How can i prevent the bot from auto starting main dialog?
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
await base.OnTurnAsync(turnContext, cancellationToken);
var recognizerResult = turnContext.TurnState.Get<RecognizerResult>("recognizerResult");
var topIntent = turnContext.TurnState.Get<string>("topDispatchIntent");
var dc = await Dialogs.CreateContextAsync(turnContext, cancellationToken);
var dialogResult = await dc.ContinueDialogAsync();
if (!dc.Context.Responded)
{
switch (dialogResult.Status)
{
//dispatch to luis or qna when there is no active dialog
case DialogTurnStatus.Empty:
await DispatchToLUISorQnAMakerAsync(turnContext, topIntent, recognizerResult, cancellationToken);
break;
case DialogTurnStatus.Waiting:
break;
case DialogTurnStatus.Complete:
await dc.EndDialogAsync();
break;
default:
await dc.CancelAllDialogsAsync();
break;
}
}
// Save any state changes that might have occured during the turn.
await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
await UserState.SaveChangesAsync(turnContext, false, cancellationToken);
}
private async Task DispatchToTopIntentAsync(ITurnContext turnContext, string intent, RecognizerResult recognizerResult, CancellationToken cancellationToken)
{
switch (intent)
{
case "none":
await turnContext.SendActivityAsync("Sorry i did not get that.");
break;
case "q_SabikoKB":
await DispatchToQnAMakerAsync(turnContext, cancellationToken);
break;
case "l_SabikoV2":
await DispatchToLuisModelAsync(turnContext, recognizerResult.Properties["luisResult"] as LuisResult, cancellationToken);
break;
}
}
private async Task DispatchToQnAMakerAsync(ITurnContext turnContext, CancellationToken cancellationToken)
{
if (!string.IsNullOrEmpty(turnContext.Activity.Text))
{
var results = await BotServices.QnaService.GetAnswersAsync(turnContext);
if (results.Any())
{
await turnContext.SendActivityAsync(MessageFactory.Text(results.First().Answer), cancellationToken);
}
else
{
await turnContext.SendActivityAsync(MessageFactory.Text("Sorry, could not find an answer in the Q and A system."), cancellationToken);
}
}
}
private async Task DispatchToLuisModelAsync(ITurnContext turnContext, LuisResult luisResult, CancellationToken cancellationToken)
{
var result = luisResult.ConnectedServiceResult;
var topIntent = result.TopScoringIntent.Intent;
switch (topIntent)
{
case "Greeting":
//..
default:
break;
}
}
main dialog
namespace BotV2.DialogsV2.Main_Menu
{
public class MainDialog : InterruptDialog
{
private const string InitialId = nameof(MainDialog);
private readonly IStatePropertyAccessor<BasicUserState> _userProfileAccessor;
public MainDialog(UserState userState, ConversationState conversationState, IConfiguration config)
: base(nameof(MainDialog),userState)
{
_userProfileAccessor = userState.CreateProperty<BasicUserState>("UserProfile");
InitialDialogId = InitialId;
WaterfallStep[] waterfallSteps = new WaterfallStep[]
{
CheckWelcomeMessageStepAsync,
FirstStepAsync,
SecondStepAsync,
};
AddDialog(new WaterfallDialog(InitialId, waterfallSteps));
//AddDialogs..
}
private async Task<DialogTurnResult> CheckWelcomeMessageStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var userstate = await _userProfileAccessor.GetAsync(stepContext.Context, () => new BasicUserState(), cancellationToken);
if (!userstate.DialogCheckers.SentWelcomeMessage)
{
return await stepContext.BeginDialogAsync(nameof(WelcomeMessageDialog));
}
return await stepContext.NextAsync(cancellationToken: cancellationToken);
}
private async Task<DialogTurnResult> FirstStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var userstate = await _userProfileAccessor.GetAsync(stepContext.Context, () => new BasicUserState(), cancellationToken);
//only suggestions, interruption will trigger the dialog to begin them.
return await stepContext.PromptAsync(
nameof(TextPrompt),
new PromptOptions
{
Prompt = new Activity
{
Type = ActivityTypes.Message,
Text = $"So {userstate.FirstName}, What can i do for you?",
SuggestedActions = new SuggestedActions()
{
Actions = new List<CardAction>()
{
new CardAction() { Title = "Financial Literacy", Type = ActionTypes.ImBack, Value = "Financial Literacy" },
new CardAction() { Title = "My Compass", Type = ActionTypes.ImBack, Value = "My Compass" },
},
},
},
});
}
private static async Task<DialogTurnResult> SecondStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
return await stepContext.EndDialogAsync();
}
}
}
Startup
services.AddSingleton<ICredentialProvider, ConfigurationCredentialProvider>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();
services.AddSingleton<IBotServices, BotServices>();
services.AddSingleton<ConcurrentDictionary<string, ConversationReference>>();
services.AddTransient<MainDialog>();
services.AddTransient<WelcomeMessageDialog>();
services.AddTransient<IBot, DialogBot<MainDialog>>();
EndDialogAsync
at the end? And can you clarify, is the bot restarting the main dialog for every message? – mdrichardson