Example #1
0
        /// <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);
        }
Example #2
0
        /// <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);
        }
Example #3
0
        /// <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));
        }
Example #4
0
        /// <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);
        }
Example #5
0
        /// <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);
        }
Example #7
0
        /// <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));
        }