Skip to content

Commit

Permalink
Merge pull request microsoft#140 from southworkscom/csharp-luis-actio…
Browse files Browse the repository at this point in the history
…ns-assignentitiesfix

[C# - Luis Action Binding] Fix to issue microsoft#139 & improvements
  • Loading branch information
willportnoy authored Sep 14, 2017
2 parents ddbf674 + 11dc079 commit da255e6
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private static async Task<ActionExecutionContext> 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)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
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

// 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

// Note: The provided LUIS app @ LUIS_MODEL.json does not have an intent related to it

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<object> FulfillAsync()
{
return Task.FromResult((object)JsonConvert.SerializeObject(this));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
<Compile Include="GetDataFromPlaceBaseAction.cs" />
<Compile Include="GetTimeInPlaceAction.cs" />
<Compile Include="GetWeatherInPlaceAction.cs" />
<Compile Include="Advanced\AlternativesAction.cs" />
<Compile Include="LocationAttibute.cs" />
<Compile Include="Models\AirportInfo.cs" />
<Compile Include="Models\WeatherInfo.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -92,7 +93,7 @@ public static async Task<QueryValueResult> 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)
{
Expand Down Expand Up @@ -348,20 +349,26 @@ private static bool AssignValue(ILuisAction action, PropertyInfo property, objec

try
{
object value;

// handle LUIS JObjects
paramValue = SanitizeInputValue(type, paramValue);

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, paramValue.ToString());
}
else
{
var value = Convert.ChangeType(paramValue, type);
property.SetValue(action, value);
value = Convert.ChangeType(paramValue, type);
}

property.SetValue(action, value);

return true;
}
catch (FormatException)
Expand Down Expand Up @@ -391,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;
Expand All @@ -402,6 +409,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 JArray)
{
var arrayOfValues = value as JArray;

if (targetType.IsArray)
{
result = arrayOfValues.AsEnumerable<object>();
}
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<PropertyInfo> properties,
Expand Down Expand Up @@ -490,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;
Expand Down

0 comments on commit da255e6

Please sign in to comment.