Extracting an Entity from LUIS in Bot Framework

Recent changes to the supporting LUIS libraries in the Bot Framework have puzzled me. I find that whilst getting the Top Intent from the RecognizerResult recognizerResult?.GetTopScoringIntent(); is easy, getting hold of an Entity seems very strange. I’m not sure if it’s my SDK, LUIS models or what, but this is the code I’m currently having to use…and I confess I still find it all very odd;

public static class RecognizerResultExtensions
{
    public static T GetEntity<T>(this RecognizerResult luisResult, string entityKey)
    {
        if (luisResult != null)
        {
            var data = luisResult.Entities as IDictionary<string, JToken>;

            if (data.TryGetValue(entityKey, out JToken value))
            {
                // wuuuh?
                return value.First.First.Value<T>();
            }
        }

        return default(T);
    }
}

Hope it helps

Advertisements

Tip to improving your LUIS with Entities model

When creating an Intent that includes Entities, especially personName, then you may have to increase the number of utterances to achieve a match with a high confidence score. However, try to avoid using the specific test as your utterance. For example;

Consider the Intent, ‘WhenIsTheirBirthday’. You might provide utterances such as, ‘When is Jane’s Birthday’, ‘When is Bert’s Birthday’, etc. When you Test the phrases you might find a test that only results in a very low confidence score, e.g. ‘When is Tim’s Birthday’. Don’t be tempted to add that as an utterance, if you do you will be providing very specific training and you cannot be certain that your are really improving the model. In that example, you would just add some more utterances that are similar, but not the same, and re-train. Keep doing that and you should see, ‘When is Tim’s Birthday’ confidence start to rise until it goes above your required confidence level.

LUIS now understands people’s names

This one managed to slip past me, but recently Microsoft Language Understand Intelligent Service (LUIS) has been updated with a pre-built entity to match people’s names. Seems like an obvious requirement but is pretty tricky to implement. To match people’s names;

  1. Open your KB in the LUIS UI of your choice
  2. Go to the Entity menu
  3. select Add Prebuilt entity
  4. choose personName

Now you can create an Intent such as “Call” with “Call Jane” and “Jane” will be matched to personName. So far (and testing is difficult) I’ve thrown all my usual problematic name variants (Western, Nordic, Chinese, Indian) and it’s managed them all, even “Call peter phoxterd-hemmington-smythe” 🙂

Gotcha with Skype, Bot Framework and LUIS

I hit a very annoying problem today with one of my Bots. It uses LUIS to react to the intent of what the user is saying. Two of the intents are “Weather” and “HowAreYou”. I’d run through the emulator and all the flows were working well. The user says something like;

  • “What’s up?” and the Bot responds with, “Ok, thanks how are you?”
  • “What’s the weather like?”, you receive, “lovely and sunny”

I published to Skype and suddenly the flows were broken.

  • “What’s up?” – “Cold today, brrrr”
  • “What’s the weather like?” – “lovely and sunny”

Why has that broken? Well the problem is that when Skype sends a request it is NOT sending the text in plain, it’s HTML encoding it. So rather than LUIS receiving "What's up?" it’s actually receiving, "what&pos;s up". This is then mapped to the Weather intent rather than “HowAreYou”. This is frustrating because the LUIS support is via a Middleware service and I haven’t found an option that allows me to tell it to decode the in-bound text. So my solution is to place a decoder in the Middleware pipe *before* the LUIS Middleware;

 public class HtmlDecoderMiddleware : IMiddleware
    {
        public async Task OnTurn(ITurnContext context, MiddlewareSet.NextDelegate next)
        {
            var text = context.Activity.Text;
            context.Activity.Text = WebUtility.HtmlDecode(text);
            await next();
        }
    }

Matching names in LUIS

I recently hit a thorny issue with allowing my Bot to understand names via LUIS. I tried to train the LUIS model with various utterances of, ‘how is ‘ but it really wasn’t getting anywhere. There are just so many variations of names that unless I retrieved a large name data set then this really wasn’t going to work. So I fell back to using a very specific match. Yes, that is not really in the spirit of LUIS but at least it keeps all the language models in one place. My trick is pretty simple;

  • Create your Intent; e.g. HowIs
  • Add your *specific* utterance; e.g. how is paul
  • Go to the Entities options and create a new Entity called ‘Name’…
  • Set the Entity Type to RegEx…
  • Add your RegEx, e.g. (?<=^.{7})(.*)
  • Hit train
  • Now when you visit your Intent you should see the name aspect labelled as ‘Name’. As I say, it’s pretty crude and frankly you don’t need LUIS to do such a match. But if you believe there is value in keeping all your language matching models in the same place then it’s the best solution I currently have.

    NB I tried using a training list and Pattern and neither seemed to help

    MS Bot framework / LUIS gotcha

    I’ve been training the LUIS service for use with the Microsoft Bot Framework and I did the cardinal sin of changing two things in my code; add some ‘clever’ OO stuff and add a new set of LUIS Intents. When I tested my Bot I kept getting, ‘The given key was not present in the dictionary’ when instantiating my LUIS Dialog. Turns out that if you have an Intent in LUIS but you have not YET implemented the handler in your LUIS Dialog then this is the error you get should the user hit that Intent. I suspect there is someway of specifying a default handler but I’ve yet to find it.