/// <summary> /// Builds the action from a contextual action. /// </summary> /// <param name="action">The contextual action.</param> /// <param name="intentName">The LUIS intent name of the parent action.</param> /// <returns>The parent action.</returns> public static ILuisAction BuildContextForContextualAction(ILuisAction action, out string intentName) { if (action == null) { throw new ArgumentNullException(nameof(action)); } if (!LuisActionResolver.IsContextualAction(action)) { intentName = null; return(null); } var contextType = action .GetType() .GetInterfaces() .First(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ILuisContextualAction <>)) .GetGenericArguments()[0]; var result = Activator.CreateInstance(contextType) as ILuisAction; intentName = LuisActionResolver.GetActionDefinition(result).IntentName; var isContextual = false; LuisActionResolver.IsValidContextualAction(action, result, out isContextual); return(result); }
/// <summary> /// If the action is contextual and related to the current context action, set the contextual action to the current context. /// </summary> /// <param name="action">The contextual action to validate.</param> /// <param name="context">The current action context.</param> /// <param name="isContextual">Indicates if the contextual action is related to the current action.</param> public static bool IsValidContextualAction(ILuisAction action, ILuisAction context, out bool isContextual) { if (action == null) { throw new ArgumentNullException(nameof(action)); } if (context == null) { throw new ArgumentNullException(nameof(context)); } isContextual = LuisActionResolver.IsContextualAction(action); if (!isContextual) { return(false); } var validContextualType = typeof(ILuisContextualAction <>).MakeGenericType(context.GetType()); if (validContextualType.IsAssignableFrom(action.GetType())) { var prop = validContextualType.GetProperty("Context", BindingFlags.Public | BindingFlags.Instance); prop.SetValue(action, context); return(true); } return(false); }
/// <summary> /// Tries to extract intent and entities from the input utterance and validates if the the current parameter should be updated or if a context switch is needed. /// </summary> /// <param name="service">Instance of Microsoft.Bot.Builder.Luis.ILuisService to use for extracting intent and entities.</param> /// <param name="action">The current action and context.</param> /// <param name="paramName">The parameter to try to assign.</param> /// <param name="paramValue">The parameter value to assign.</param> /// <param name="token">Cancellation Token.</param> /// <param name="entityExtractor">Optional: EntityExtractor to disambiguate multiple values into a single one.</param> /// <returns>Indicates if the Action Parameter was validated (and set) or a if a Context Switch should occur.</returns> public static async Task <QueryValueResult> QueryValueFromLuisAsync( ILuisService service, ILuisAction action, string paramName, object paramValue, CancellationToken token, Func <PropertyInfo, IEnumerable <EntityRecommendation>, EntityRecommendation> entityExtractor = null) { var originalValue = paramValue; if (service == null) { throw new ArgumentNullException(nameof(service)); } if (action == null) { throw new ArgumentNullException(nameof(action)); } if (string.IsNullOrWhiteSpace(paramName)) { throw new ArgumentNullException(nameof(paramName)); } if (paramValue == null) { throw new ArgumentNullException(nameof(paramValue)); } var result = await service.QueryAsync(paramValue.ToString(), token); var queryIntent = result.Intents.FirstOrDefault(); if (queryIntent != null && !Intents.None.Equals(queryIntent.Intent, StringComparison.InvariantCultureIgnoreCase)) { var newIntentName = default(string); var newAction = new LuisActionResolver(action.GetType().Assembly).ResolveActionFromLuisIntent(result, out newIntentName); if (newAction != null && !newAction.GetType().Equals(action.GetType())) { return(new QueryValueResult(false) { NewAction = newAction, NewIntent = newIntentName }); } } var properties = new List <PropertyInfo> { action.GetType().GetProperty(paramName, BindingFlags.Public | BindingFlags.Instance) }; if (!LuisActionResolver.AssignEntitiesToMembers(action, properties, result.Entities, entityExtractor)) { return(new QueryValueResult(AssignValue(action, properties.First(), originalValue))); } return(new QueryValueResult(true)); }
/// <summary> /// Returns an action based on the LUIS intent. /// </summary> /// <param name="luisResult">The LUIS Result containing intent and extracted entities.</param> /// <param name="intentName">The LUIS intent name.</param> /// <param name="intentEntities">The LUIS extracted entities.</param> /// <param name="entityExtractor">Optional: EntityExtractor to disambiguate multiple values into a single one.</param> /// <returns>The matched action plus its parameters filled with the extracted entities, or Null if no action was matched.</returns> public ILuisAction ResolveActionFromLuisIntent( LuisResult luisResult, out string intentName, out IList <EntityRecommendation> intentEntities, Func <PropertyInfo, IEnumerable <EntityRecommendation>, EntityRecommendation> entityExtractor = null) { intentEntities = default(IList <EntityRecommendation>); if (luisResult == null) { throw new ArgumentNullException(nameof(luisResult)); } // Has Intent? intentName = (luisResult.TopScoringIntent ?? luisResult.Intents?.MaxBy(i => i.Score ?? 0d)).Intent; if (string.IsNullOrWhiteSpace(intentName)) { return(null); } // Set out intent entities reference intentEntities = luisResult.Entities; // Get Actions that map to this intent var actionType = default(Type); if (!this.luisActions.TryGetValue(intentName, out actionType)) { return(null); } // Get the action instance and check if it implements ILuisAction var luisAction = Activator.CreateInstance(actionType) as ILuisAction; if (luisAction == null) { return(null); } // Try complete parameters from entities var properties = luisAction.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); LuisActionResolver.AssignEntitiesToMembers(luisAction, properties, luisResult.Entities, entityExtractor); return(luisAction); }
/// <summary> /// Indicates if the action can be started, either is not a contextual action or it can create the contextual action directly. /// </summary> /// <param name="action">The action to validate.</param> /// <param name="actionDefinition">The action definition.</param> public static bool CanStartWithNoContextAction(ILuisAction action, out LuisActionBindingAttribute actionDefinition) { if (action == null) { throw new ArgumentNullException(nameof(action)); } if (!LuisActionResolver.IsContextualAction(action)) { actionDefinition = null; return(true); } actionDefinition = LuisActionResolver.GetActionDefinition(action); return(actionDefinition.CanExecuteWithNoContext); }
/// <summary> /// Validates if the current action's context is valid, based on the Action properties set so far and their validation attributes. /// </summary> /// <param name="validationResults">List of validation errors.</param> /// <returns>True if context is valid, False otherwise.</returns> public virtual bool IsValid(out ICollection <ValidationResult> validationResults) { var context = new ValidationContext(this, null, null); validationResults = new List <ValidationResult>(); var result = Validator.TryValidateObject(this, context, validationResults, true); // do order properties validationResults = validationResults .OrderBy(r => { var paramAttrib = LuisActionResolver.GetParameterDefinition(this, r.MemberNames.First()); return(paramAttrib != null ? paramAttrib.Order : int.MaxValue); }) .ThenBy(r => r.MemberNames.First()) .ToList(); return(result); }
/// <summary> /// If the action is contextual and related to the current context action, set the contextual action to the current context. /// </summary> /// <param name="action">The contextual action to validate.</param> /// <param name="context">The current action context.</param> /// <param name="isContextual">Indicates if the contextual action is related to the current action.</param> public static bool UpdateIfValidContextualAction(ILuisAction action, ILuisAction context, out bool isContextual) { if (action == null) { throw new ArgumentNullException(nameof(action)); } if (context == null) { throw new ArgumentNullException(nameof(context)); } isContextual = false; if (!LuisActionResolver.IsContextualAction(context)) { return(true); } var prop = context.GetType().GetProperty("Context", BindingFlags.Public | BindingFlags.Instance); var actionContext = prop.GetValue(context) as ILuisAction; return(LuisActionResolver.IsValidContextualAction(action, actionContext, out isContextual)); }