protected override async Task MessageReceived(IDialogContext context, IAwaitable <IMessageActivity> item) { var message = await item; var messageText = await GetLuisQueryTextAsync(context, message); var tasks = this.services.Select(s => s.QueryAsync(messageText, context.CancellationToken)).ToArray(); var results = await Task.WhenAll(tasks); var winners = from result in results.Select((value, index) => new { value, index }) let resultWinner = this.BestIntentFrom(result.value) where resultWinner != null select new LuisServiceResult(result.value, resultWinner, this.services[result.index]); var winner = this.BestResultFrom(winners); if (winner == null) { throw new InvalidOperationException("No winning intent selected from Luis results."); } var intentName = default(string); var luisAction = this.actionResolver.ResolveActionFromLuisIntent(winner.Result, out intentName); if (luisAction != null) { var executionContextChain = new List <ActionExecutionContext> { new ActionExecutionContext(intentName, luisAction) }; while (LuisActionResolver.IsContextualAction(luisAction)) { var luisActionDefinition = default(LuisActionBindingAttribute); if (!LuisActionResolver.CanStartWithNoContextAction(luisAction, out luisActionDefinition)) { await context.PostAsync($"Cannot start contextual action '{luisActionDefinition.FriendlyName}' without a valid context."); return; } luisAction = LuisActionResolver.BuildContextForContextualAction(luisAction, out intentName); if (luisAction != null) { this.onContextCreation?.Invoke(luisAction, context); executionContextChain.Insert(0, new ActionExecutionContext(intentName, luisAction)); } } var validationResults = default(ICollection <ValidationResult>); //check the validation result if (!luisAction.IsValid(out validationResults)) { var childDialog = new LuisActionMissingEntitiesDialog(winner.LuisService, executionContextChain); context.Call(childDialog, this.LuisActionMissingDialogFinished); } else { await this.DispatchToLuisActionActivityHandler(context, item, intentName, luisAction); } } }
private async Task AfterContextualActionFinished(IDialogContext context, IAwaitable <ActionExecutionContext> executionContext) { var executionContextResult = await executionContext; if (executionContextResult.ChangeRootSignaling) { if (LuisActionResolver.IsContextualAction(this.luisAction)) { context.Done(executionContextResult); return; } else { this.intentName = executionContextResult.Intent; this.luisAction = executionContextResult.Action; } } else { var result = await executionContextResult.Action.FulfillAsync(); if (result is string) { await context.PostAsync(result.ToString()); } } await this.MessageReceivedAsync(context, null); }
public async Task <ActionResult> Index(QueryViewModel model) { if (!model.HasIntent) { var luisService = new LuisService(new LuisModelAttribute(ConfigurationManager.AppSettings["LUIS_ModelId"], ConfigurationManager.AppSettings["LUIS_SubscriptionKey"])); var luisResult = await luisService.QueryAsync(model.Query, CancellationToken.None); var resolver = new LuisActionResolver(typeof(GetTimeInPlaceAction).Assembly); var action = resolver.ResolveActionFromLuisIntent(luisResult); // Triggering Contextual Action from scratch is not supported on this Web Sample if (action != null && !LuisActionResolver.IsContextualAction(action)) { model.LuisAction = action; // TODO: this is dangerous. This should be stored somewhere else, not in the client, or at least encrypted model.LuisActionType = action.GetType().AssemblyQualifiedName; } else { // no action recnogized return(this.View(new QueryViewModel())); } } ModelState.Clear(); var isValid = TryValidateModel(model.LuisAction); if (isValid) { // fulfill var actionResult = await model.LuisAction.FulfillAsync(); if (actionResult == null) { actionResult = "Cannot resolve your query"; } return(this.View("ActionFulfill", actionResult)); } else { // not valid, continue to present form with missing/invalid parameters return(this.View(model)); } }
protected override async Task MessageReceived(IDialogContext context, IAwaitable <IMessageActivity> item) { LuisServiceResult winner = await GetWinner(context, item); if (winner == null) { throw new InvalidOperationException("No winning intent selected from Luis results."); } ILuisAction luisAction = this.actionResolver.ResolveActionFromLuisIntent(winner.Result, out string intentName); if (luisAction != null) { var executionContextChain = new ActionExecutionContext(intentName, luisAction).ToSingleList(); while (LuisActionResolver.IsContextualAction(luisAction)) { if (!LuisActionResolver.CanStartWithNoContextAction(luisAction, out LuisActionBindingAttribute luisActionDefinition)) { await context.PostAsync($"Cannot start contextual action '{luisActionDefinition.FriendlyName}' without a valid context."); return; } luisAction = LuisActionResolver.BuildContextForContextualAction(luisAction, out intentName); if (luisAction != null) { this.onContextCreation?.Invoke(luisAction, context); executionContextChain.Insert(0, new ActionExecutionContext(intentName, luisAction)); } } if (!luisAction.IsValid(out ICollection <ValidationResult> validationResults)) { var childDialog = new LuisActionMissingEntitiesDialog(winner.LuisService, executionContextChain); context.Call(childDialog, this.LuisActionMissingDialogFinished); } else { await this.DispatchToLuisActionActivityHandler(context, item, intentName, luisAction); } } }
private static async Task RunQuery(string query) { // Process message var luisService = new LuisService(new LuisModelAttribute(ConfigurationManager.AppSettings["LUIS_ModelId"], ConfigurationManager.AppSettings["LUIS_SubscriptionKey"])); var luisResult = await luisService.QueryAsync(query, CancellationToken.None); // Try to resolve intent to action var intentName = default(string); var intentEntities = default(IList <EntityRecommendation>); var intentAction = new LuisActionResolver(typeof(GetTimeInPlaceAction).Assembly) .ResolveActionFromLuisIntent(luisResult, out intentName, out intentEntities); if (intentAction != null) { var executionContextChain = new List <ActionExecutionContext> { new ActionExecutionContext(intentName, intentAction) }; while (LuisActionResolver.IsContextualAction(intentAction)) { var luisActionDefinition = default(LuisActionBindingAttribute); if (!LuisActionResolver.CanStartWithNoContextAction(intentAction, out luisActionDefinition)) { Console.WriteLine($"Cannot start contextual action '{luisActionDefinition.FriendlyName}' without a valid context."); return; } intentAction = LuisActionResolver.BuildContextForContextualAction(intentAction, out intentName); if (intentAction != null) { executionContextChain.Insert(0, new ActionExecutionContext(intentName, intentAction)); } } await RunActions(luisService, executionContextChain); } else { Console.WriteLine("Could not understand the input."); } }
private async Task AfterOverrunCurrentActionSelected(IDialogContext context, IAwaitable <bool> result) { if (await result == true) { // if switching from contextual to other root if (LuisActionResolver.IsContextualAction(this.luisAction) && !LuisActionResolver.IsContextualAction(this.overrunData.NewAction)) { context.Done(new ActionExecutionContext(this.overrunData.NewIntent, this.overrunData.NewAction) { ChangeRootSignaling = true }); return; } this.intentName = this.overrunData.NewIntent; this.luisAction = this.overrunData.NewAction; } // clean overrunData - avoid serialization payload this.overrunData = null; await this.MessageReceivedAsync(context, null); }
private static async Task <ActionExecutionContext> RunActions(ILuisService luisService, IList <ActionExecutionContext> actions) { if (actions == null || actions.Count == 0) { Console.WriteLine(">> ERROR: Action chain cannot be null or empty."); return(null); } var actionExecutionContext = actions.First(); var intentAction = actions.First().Action; actions.RemoveAt(0); if (actions.Count > 0) { await RunActions(luisService, actions); } var validationResults = default(ICollection <ValidationResult>); bool isValid = intentAction.IsValid(out validationResults); while (!isValid) { var fieldValidation = validationResults.FirstOrDefault(); if (fieldValidation != null) { var paramName = fieldValidation.MemberNames.First(); Console.Write("({0}) {1}: ", paramName, fieldValidation.ErrorMessage); var input = Console.ReadLine(); var queryResult = await LuisActionResolver.QueryValueFromLuisAsync(luisService, intentAction, paramName, input, CancellationToken.None); if (!queryResult.Succeed && !string.IsNullOrWhiteSpace(queryResult.NewIntent) && queryResult.NewAction != null) { var newActionDefinition = LuisActionResolver.GetActionDefinition(queryResult.NewAction); var currentActionDefinition = LuisActionResolver.GetActionDefinition(intentAction); var isContextual = false; if (LuisActionResolver.IsValidContextualAction(queryResult.NewAction, intentAction, out isContextual)) { var executionContextChain = new List <ActionExecutionContext> { new ActionExecutionContext(queryResult.NewIntent, queryResult.NewAction) }; var executionContext = await RunActions(luisService, executionContextChain); if (executionContext.ChangeRootSignaling) { if (LuisActionResolver.IsContextualAction(intentAction)) { return(executionContext); } else { intentAction = executionContext.Action; } } } else if (isContextual && !LuisActionResolver.IsContextualAction(intentAction)) { Console.WriteLine($"Cannot execute action '{newActionDefinition.FriendlyName}' in the context of '{currentActionDefinition.FriendlyName}' - continuing with current action"); } else if (!intentAction.GetType().Equals(queryResult.NewAction.GetType())) { var valid = LuisActionResolver.UpdateIfValidContextualAction(queryResult.NewAction, intentAction, out isContextual); if (!valid && isContextual) { Console.WriteLine($"Cannot switch to action '{newActionDefinition.FriendlyName}' from '{currentActionDefinition.FriendlyName}' due to invalid context - continuing with current action"); } else if (currentActionDefinition.ConfirmOnSwitchingContext) { Console.Write($"You are about to discard the current action '{currentActionDefinition.FriendlyName}' and start executing '{newActionDefinition.FriendlyName}'\nContinue? "); var response = Console.ReadLine(); if (response.ToUpperInvariant().StartsWith("Y")) { if (LuisActionResolver.IsContextualAction(intentAction) && !LuisActionResolver.IsContextualAction(queryResult.NewAction)) { return(new ActionExecutionContext(queryResult.NewIntent, queryResult.NewAction) { ChangeRootSignaling = true }); } intentAction = queryResult.NewAction; } } else { intentAction = queryResult.NewAction; } } } // re-evaluate isValid = intentAction.IsValid(out validationResults); } } var result = await intentAction.FulfillAsync(); // We just show the ToString() of the result - not care about the result type here Console.WriteLine(result != null ? result.ToString() : "Cannot resolve your query"); return(actionExecutionContext); }
protected virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable <IMessageActivity> item) { var nextPromptIdx = 0; var validationResults = default(ICollection <ValidationResult>); this.luisAction.IsValid(out validationResults); if (item != null) { var message = await item; var paramName = validationResults.First().MemberNames.First(); var paramValue = message.Text; var result = await LuisActionResolver.QueryValueFromLuisAsync(this.luisService, this.luisAction, paramName, paramValue, context.CancellationToken); if (result.Succeed) { nextPromptIdx++; } else if (!string.IsNullOrWhiteSpace(result.NewIntent) && result.NewAction != null) { var currentActionDefinition = LuisActionResolver.GetActionDefinition(this.luisAction); var isContextual = false; if (LuisActionResolver.IsValidContextualAction(result.NewAction, this.luisAction, out isContextual)) { var executionContextChain = new List <ActionExecutionContext> { new ActionExecutionContext(result.NewIntent, result.NewAction) }; var childDialog = new LuisActionMissingEntitiesDialog(this.luisService, executionContextChain); context.Call(childDialog, this.AfterContextualActionFinished); return; } else if (isContextual & !LuisActionResolver.IsContextualAction(this.luisAction)) { var newActionDefinition = LuisActionResolver.GetActionDefinition(result.NewAction); await context.PostAsync($"Cannot execute action '{newActionDefinition.FriendlyName}' in the context of '{currentActionDefinition.FriendlyName}' - continuing with current action"); } else if (!this.luisAction.GetType().Equals(result.NewAction.GetType())) { var newActionDefinition = LuisActionResolver.GetActionDefinition(result.NewAction); var valid = LuisActionResolver.UpdateIfValidContextualAction(result.NewAction, this.luisAction, out isContextual); if (!valid && isContextual) { await context.PostAsync($"Cannot switch to action '{newActionDefinition.FriendlyName}' from '{currentActionDefinition.FriendlyName}' due to invalid context - continuing with current action"); } else if (currentActionDefinition.ConfirmOnSwitchingContext) { // serialize overrun info this.overrunData = result; PromptDialog.Confirm( context, this.AfterOverrunCurrentActionSelected, $"Do you want to discard the current action '{currentActionDefinition.FriendlyName}' and start executing '{newActionDefinition.FriendlyName}' action?"); return; } else { this.intentName = result.NewIntent; this.luisAction = result.NewAction; this.luisAction.IsValid(out validationResults); } } } } if (validationResults.Count > nextPromptIdx) { await context.PostAsync(validationResults.ElementAt(nextPromptIdx).ErrorMessage); context.Wait(this.MessageReceivedAsync); } else { context.Done(new ActionExecutionContext(this.intentName, this.luisAction)); } }