In the previous LUIS article, I introduced how to set up and train (and publish) a LUIS language interpreting web service, getting an “intent” and extracting “entities” from a given “utterance”
In this article I’ll use LUIS to enhance your botframework chatbot
If you haven’t done so already, create your bot using botframework, and set up a LUIS application.
Now that we’ve laid the foundations, let’s build a house. A ..um. chatbot house.. yeah.
LUIS entry point
Botframework has a special type of Dialog especially for interacting with LUIS; the imaginatively titled LuisDialog
!
Create a new class that extends LuisDialog<object>
and add the LuisModel
attribute, adding in your Model Id and Subscription Key from LUIS; an easy way to get these values is to hit “PUBLISH” and “Publish web service” for your LUIS app:
Then check the URL and copy the SubscriptionKey
and id
(for your ModelId
) values.
[LuisModel("<LuisModelId>","<LuisSubscriptionKey>")]
public class RootLuisDialog : LuisDialog<object>
{
}
(You can get these values elsewhere within the LUIS pages, but this was the easiest method for me)
Now edit your MessagesController
such that the conversation is now started using the static Conversation.SendAsync
method, passing in the incoming message activity as the first param and your new dialog as the result of a function for the 2nd param:
await Conversation.SendAsync(activity, () => new RootLuisDialog());
Your MessagesController
should now look a bit like this:
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
// return our reply to the user
await Conversation.SendAsync(activity, () => new RootLuisDialog());
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
Right now there won’t be any actual functionality since our new dialog class is empty. Let’s rectify that!
As well as having an attribute to map our LUIS app to a Dialog in our codebase, there is another attribute to map a LUIS intent to a method; the attribute just needs the intent name from our LUIS app:
[LuisIntent("local.weather")]
public async Task StartWeatherDialog(IDialogContext context, LuisResult result)
{
}
The method signature needs to take an IDialogContext
and a LuisResult
and return a Task
.
Assuming you’ve TRAINed and PUBLISHed your LUIS app, and you’ve got the Model, Subscription, and Intent attribute values entered correctly, then we can set a breakpoint in that empty method and start debugging.
Open up the bot emulator and enter a phrase that you know LUIS will map to your intent, e.g. “will it rain in London tomorrow?”
As per usual the message hits theMessagesController
, but this time we start a Conversation
with the RootLuisDialog
.
Since you’ve got your LuisModel
attribute set up this message will now be posted to your LUIS app’s endpoint.
The resulting json is used to route the response to a method; if the response from LUIS contains the intent local.weather
and if I have a method with a matching LuisIntent
attribute, then the json response will be mapped to a LuisResult
and passed in as a parameter.
Let’s dig into the LuisResult
a bit – I’ll ask “is it going to rain in bristol this weekend?”:
That’s our query – nice. There are our entities! How handy.
What else is in there?
Looks like we have the three intents as defined within the LUIS app:
local.news
gets the lowest score..
Then None
…
And local.weather
gets the highest score – as it should do. Which is why the method that gets called is the one with a `LuisIntent` attribute configured with the value `local.weather`
No match?
You should always be sure to add in a method that will be called if LUIS fails to match the input to any intent. Use the attribute with an empty string if you haven’t set up a “catch all” in your LUIS app, and add on you “catch all” intent as well if you have one, e.g.
[LuisIntent("")]
[LuisIntent("None")]
public async Task DidntUnderstand(IDialogContext context, LuisResult result){
}
This will ensure you’re always able to respond, perhaps with a “Sorry, I didn’t understand that – can you try saying it in a different way?”
Summary
Hopefully this article has shown you how to take a LUIS app and wire it up to your botframework code, extracting the entities from the utterance and using these to create a dynamic response.
Let me know how you get on!
Hey Robin,
thanks for taking the time to write this.
I am playing with the Bot Framework and Luis and I can’t seem to figure out where you get the ModelID from?
I can see an ApplicationID and a SubscriptionID in the URL but not the model and the AppID doesn’t seem to be the ID I am after 🙂