From 6c43709d9094ba73d680533241e101ca9fd3e568 Mon Sep 17 00:00:00 2001 From: maurok Date: Thu, 1 Jun 2017 12:29:21 -0300 Subject: [PATCH 1/6] # Simplifying AssignValue logic --- .../LuisActionResolver.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/CSharp/Blog-LUISActionBinding/Microsoft.Cognitive.LUIS.ActionBinding/LuisActionResolver.cs b/CSharp/Blog-LUISActionBinding/Microsoft.Cognitive.LUIS.ActionBinding/LuisActionResolver.cs index b998a5494e..2b9e8a625a 100644 --- a/CSharp/Blog-LUISActionBinding/Microsoft.Cognitive.LUIS.ActionBinding/LuisActionResolver.cs +++ b/CSharp/Blog-LUISActionBinding/Microsoft.Cognitive.LUIS.ActionBinding/LuisActionResolver.cs @@ -348,20 +348,23 @@ private static bool AssignValue(ILuisAction action, PropertyInfo property, objec try { + object value; + if (type.IsArray) { - property.SetValue(action, BuildArrayOfValues(action, property, type.GetElementType(), paramValue)); + value = BuildArrayOfValues(action, property, type.GetElementType(), paramValue); } else if (type.IsEnum) { - property.SetValue(action, Enum.Parse(type, (string)paramValue)); + value = Enum.Parse(type, (string)paramValue); } else { - var value = Convert.ChangeType(paramValue, type); - property.SetValue(action, value); + value = Convert.ChangeType(paramValue, type); } + property.SetValue(action, value); + return true; } catch (FormatException) From 0778c0d4d43771101945cf8ea297d45792f590fb Mon Sep 17 00:00:00 2001 From: maurok Date: Thu, 1 Jun 2017 16:31:18 -0300 Subject: [PATCH 2/6] # Handling LUIS JObjects --- .../LuisActionResolver.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/CSharp/Blog-LUISActionBinding/Microsoft.Cognitive.LUIS.ActionBinding/LuisActionResolver.cs b/CSharp/Blog-LUISActionBinding/Microsoft.Cognitive.LUIS.ActionBinding/LuisActionResolver.cs index 2b9e8a625a..9c5df45c1b 100644 --- a/CSharp/Blog-LUISActionBinding/Microsoft.Cognitive.LUIS.ActionBinding/LuisActionResolver.cs +++ b/CSharp/Blog-LUISActionBinding/Microsoft.Cognitive.LUIS.ActionBinding/LuisActionResolver.cs @@ -350,6 +350,9 @@ private static bool AssignValue(ILuisAction action, PropertyInfo property, objec { object value; + // handle LUIS JObjects + paramValue = SanitizeInputValue(type, paramValue); + if (type.IsArray) { value = BuildArrayOfValues(action, property, type.GetElementType(), paramValue); @@ -405,6 +408,33 @@ private static Array BuildArrayOfValues(ILuisAction action, PropertyInfo propert } } + private static object SanitizeInputValue(Type targetType, object value) + { + object result = value; + + // handle case where input is JArray returned from LUIS + if (value is Newtonsoft.Json.Linq.JArray) + { + var arrayOfValues = value as Newtonsoft.Json.Linq.JArray; + + if (targetType.IsArray) + { + result = arrayOfValues.AsEnumerable(); + } + else + { + if (arrayOfValues.Count > 1) + { + throw new FormatException("Cannot assign multiple values to single field"); + } + + result = arrayOfValues[0]; + } + } + + return result; + } + private static bool AssignEntitiesToMembers( ILuisAction action, IEnumerable properties, From eb63e588b7e9ce48b3fc2137f515e4f06eb843a6 Mon Sep 17 00:00:00 2001 From: maurok Date: Thu, 1 Jun 2017 16:51:34 -0300 Subject: [PATCH 3/6] # Adding action model to showcase advanced usage options --- .../Advanced/AlternativesAction.cs | 56 +++++++++++++++++++ .../LuisActions.Samples.Shared.csproj | 1 + 2 files changed, 57 insertions(+) create mode 100644 CSharp/Blog-LUISActionBinding/LuisActions.Samples.Shared/Advanced/AlternativesAction.cs diff --git a/CSharp/Blog-LUISActionBinding/LuisActions.Samples.Shared/Advanced/AlternativesAction.cs b/CSharp/Blog-LUISActionBinding/LuisActions.Samples.Shared/Advanced/AlternativesAction.cs new file mode 100644 index 0000000000..21ef46ec02 --- /dev/null +++ b/CSharp/Blog-LUISActionBinding/LuisActions.Samples.Shared/Advanced/AlternativesAction.cs @@ -0,0 +1,56 @@ +namespace LuisActions.Samples +{ + using System; + using System.ComponentModel.DataAnnotations; + using System.Threading.Tasks; + using Microsoft.Cognitive.LUIS.ActionBinding; + using Newtonsoft.Json; + + // This sample were added to showcase support to Custom List Entities - default JSON model does not have it + + // Refer to 'List Entities' @ https://docs.microsoft.com/en-us/azure/cognitive-services/luis/add-entities + + // You can create your own model with an 'AlternativeChoose' intent with utterances + // having a 'List Entity' called 'Alternatives' with the canonical forms defined by the + // 'Alternative' enum - or just can simply create your custom list entity, + // intent and update the intent binding here and custom name/type at fields + + public enum Alternative + { + // default (ie. empty choice) + None = 0, + + DomainOption1 = 11, + DomainOption2 = 12, + DomainOption3 = 13, + + ExternalOption1 = 101, + ExternalOption2 = 102 + } + + public class RequiredEnumAttribute : ValidationAttribute + { + public override bool IsValid(object value) + { + return (int)value > 0; + } + } + + [Serializable] + [LuisActionBinding("AlternativeChoose", FriendlyName = "Alternatives Choosing Model Sample")] + public class AlternativesAction : BaseLuisAction + { + [RequiredEnum(ErrorMessage = "Please provide an alternative")] + [LuisActionBindingParam(CustomType = "Alternatives", Order = 1)] + public Alternative FirstAlternative { get; set; } + + [Required(ErrorMessage = "Please provide one or more alternatives")] + [LuisActionBindingParam(CustomType = "Alternatives", Order = 2)] + public Alternative[] SecondaryAlternatives { get; set; } + + public override Task FulfillAsync() + { + return Task.FromResult((object)JsonConvert.SerializeObject(this)); + } + } +} diff --git a/CSharp/Blog-LUISActionBinding/LuisActions.Samples.Shared/LuisActions.Samples.Shared.csproj b/CSharp/Blog-LUISActionBinding/LuisActions.Samples.Shared/LuisActions.Samples.Shared.csproj index 0dbef98449..af8406667f 100644 --- a/CSharp/Blog-LUISActionBinding/LuisActions.Samples.Shared/LuisActions.Samples.Shared.csproj +++ b/CSharp/Blog-LUISActionBinding/LuisActions.Samples.Shared/LuisActions.Samples.Shared.csproj @@ -58,6 +58,7 @@ + From 0fbd43b55a6d879939b06527a46f01045c868b1e Mon Sep 17 00:00:00 2001 From: maurok Date: Thu, 1 Jun 2017 17:13:24 -0300 Subject: [PATCH 4/6] # Supporting resolving multiple matching entities with array values to array parameter value --- .../LuisActionResolver.cs | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/CSharp/Blog-LUISActionBinding/Microsoft.Cognitive.LUIS.ActionBinding/LuisActionResolver.cs b/CSharp/Blog-LUISActionBinding/Microsoft.Cognitive.LUIS.ActionBinding/LuisActionResolver.cs index 9c5df45c1b..c5a29b345f 100644 --- a/CSharp/Blog-LUISActionBinding/Microsoft.Cognitive.LUIS.ActionBinding/LuisActionResolver.cs +++ b/CSharp/Blog-LUISActionBinding/Microsoft.Cognitive.LUIS.ActionBinding/LuisActionResolver.cs @@ -9,6 +9,7 @@ using Microsoft.Bot.Builder.Dialogs.Internals; using Microsoft.Bot.Builder.Luis; using Microsoft.Bot.Builder.Luis.Models; + using Newtonsoft.Json.Linq; [Serializable] public class LuisActionResolver @@ -92,7 +93,7 @@ public static async Task QueryValueFromLuisAsync( { var newIntentName = default(string); var newAction = new LuisActionResolver(action.GetType().Assembly).ResolveActionFromLuisIntent(result, out newIntentName); - if (newAction != null) + if (newAction != null && !newAction.GetType().Equals(action.GetType())) { return new QueryValueResult(false) { @@ -359,7 +360,7 @@ private static bool AssignValue(ILuisAction action, PropertyInfo property, objec } else if (type.IsEnum) { - value = Enum.Parse(type, (string)paramValue); + value = Enum.Parse(type, paramValue.ToString()); } else { @@ -397,7 +398,7 @@ private static Array BuildArrayOfValues(ILuisAction action, PropertyInfo propert var result = Array.CreateInstance(elementType, values.Count()); foreach (var value in values) { - result.SetValue(elementType.IsEnum ? Enum.Parse(elementType, (string)value) : Convert.ChangeType(value, elementType), idx++); + result.SetValue(elementType.IsEnum ? Enum.Parse(elementType, value.ToString()) : Convert.ChangeType(value, elementType), idx++); } return result; @@ -413,9 +414,9 @@ private static object SanitizeInputValue(Type targetType, object value) object result = value; // handle case where input is JArray returned from LUIS - if (value is Newtonsoft.Json.Linq.JArray) + if (value is JArray) { - var arrayOfValues = value as Newtonsoft.Json.Linq.JArray; + var arrayOfValues = value as JArray; if (targetType.IsArray) { @@ -523,6 +524,22 @@ private static bool AssignEntitiesToMembers( result &= AssignValue(action, property, paramValue); } + else if (matchingEntities.Count() > 0 + && matchingEntities.Count(e => e.Resolution != null && e.Resolution.First().Value is JArray) == matchingEntities.Count()) + { + var paramValues = new JArray(); + + foreach (var currentMatchingEntity in matchingEntities) + { + var values = currentMatchingEntity.Resolution.First().Value as JArray; + foreach (var value in values) + { + paramValues.Add(value); + } + } + + result &= AssignValue(action, property, paramValues); + } else { result = false; From 191f940d649ef6059456fd19cf5db69fb4f2dc77 Mon Sep 17 00:00:00 2001 From: maurok Date: Thu, 1 Jun 2017 17:17:17 -0300 Subject: [PATCH 5/6] # Bypassing context switch when entities have the same type --- .../LuisActions.Samples.Console/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CSharp/Blog-LUISActionBinding/LuisActions.Samples.Console/Program.cs b/CSharp/Blog-LUISActionBinding/LuisActions.Samples.Console/Program.cs index 8dae01fd1b..f8f70ad60a 100644 --- a/CSharp/Blog-LUISActionBinding/LuisActions.Samples.Console/Program.cs +++ b/CSharp/Blog-LUISActionBinding/LuisActions.Samples.Console/Program.cs @@ -94,7 +94,7 @@ private static async Task RunActions(ILuisService luisSe { Console.WriteLine($"Cannot execute action '{newActionDefinition.FriendlyName}' in the context of '{currentActionDefinition.FriendlyName}' - continuing with current action"); } - else + else if (!intentAction.GetType().Equals(queryResult.NewAction.GetType())) { var valid = LuisActionResolver.UpdateIfValidContextualAction(queryResult.NewAction, intentAction, out isContextual); if (!valid && isContextual) From 11dc0793fbe823c1918ac31509428f005666fa59 Mon Sep 17 00:00:00 2001 From: maurok Date: Thu, 1 Jun 2017 18:17:51 -0300 Subject: [PATCH 6/6] # Adding note to advanced sample action --- .../LuisActions.Samples.Shared/Advanced/AlternativesAction.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CSharp/Blog-LUISActionBinding/LuisActions.Samples.Shared/Advanced/AlternativesAction.cs b/CSharp/Blog-LUISActionBinding/LuisActions.Samples.Shared/Advanced/AlternativesAction.cs index 21ef46ec02..15cb6e171d 100644 --- a/CSharp/Blog-LUISActionBinding/LuisActions.Samples.Shared/Advanced/AlternativesAction.cs +++ b/CSharp/Blog-LUISActionBinding/LuisActions.Samples.Shared/Advanced/AlternativesAction.cs @@ -6,7 +6,7 @@ using Microsoft.Cognitive.LUIS.ActionBinding; using Newtonsoft.Json; - // This sample were added to showcase support to Custom List Entities - default JSON model does not have it + // This sample were added to showcase support to Custom List Entities // Refer to 'List Entities' @ https://docs.microsoft.com/en-us/azure/cognitive-services/luis/add-entities @@ -15,6 +15,8 @@ // 'Alternative' enum - or just can simply create your custom list entity, // intent and update the intent binding here and custom name/type at fields + // Note: The provided LUIS app @ LUIS_MODEL.json does not have an intent related to it + public enum Alternative { // default (ie. empty choice)