10/2/2016 Webmaster

Implementing Language Understanding Intelligent Service (LUIS) In Microsoft Bot Framework


Using Language Understanding Intelligent Service (LUIS) in your Microsoft Bot Framework application allows you to create chat bots that are easier for your end-users to interact with.


For this example, we will start with the code created in the article, Implementing A SQL Server Database With The Microsoft Bot Framework. This article covers creating a number guessing game and storing, and displaying, the high scores. In that article, the user is required to type in the exact words, ‘high scores’ and they could only see the high scores for the past day.


In this article, we will alter the code to allow the user to see the high scores for the past week, the past month, or the past days that they specify (up to 30 days). Most importantly we will allow the user to type their request, using normal language, and then detect the intent of the user and the important related entities (such as the number of days).

We will do this by creating an application using the Language Understanding Intelligent Service (LUIS) and then interfacing that application with our existing Bot that is programmed using the SDK of, and deployed in, the Microsoft Bot Framework.

Create The LUIS Application


The first step is to go to https://www.luis.ai/ and create an account on the Language Understanding Intelligent Service (LUIS) site, and log in.


Create a New Application.


We will call it HighScores, and after filling out any other fields, we click Add App.


Now we need to create Entities. These are values that we will need to identify and gather so that our Bot can perform operations based on their value. In our example, we want to create two Entities:

  • PeriodOfTime – Detect if the user entered a word describing the amount of days (but not the actual days). For example, ‘week’ or ‘month’
  • Days – Detect if the user entered the actual days such as ‘3’ or ‘three’


Click the plus button next to the Entities label (on the left hand side of the editor) to open a box that will allow you to add each Entity (one at a time).


When you’re done, the Entities will be displayed.


Next, we will add an Intent.

( Note: the ‘none’ Intent , to be triggered when an utterance by the user does not match a programmed intent, will be automatically created)

Click the plus button next to the Intents label.


Enter HighScores for the Intent name.

Enter Show me the high scores for the past week for Enter an example of a command that triggers this intent (this is also known as a sample utterance).

Click Save.


The utterance will now display in the New utterances tab.

We want this utterance to trigger the HighScores Intent, so select it from the dropdown.


We also want to detect the associated Entity .

Click on the word week, it will then be highlighted, and a popup box will appear.

Select PeriodOfTime.


Finally, click Submit.


Continue to enter and label additional utterances.

( Note: remember to label any Entities that indicate a number as the Days Entity)


Continue to train the service.

You will notice that eventually it will start detecting the Entities on its own.

However, many times you will still have to correct it.

Enter and correct at least ten different utterances.


Click the Train button in the bottom left-hand corner of the interface to train the model.


You now need to get an Azure subscription key.

Click the Settings button.


If you don’t already have an Azure subscription to LUIS, click the Click here to buy a key from Azure button to get one.

When that process is completed, you will be able to come back to the screen and add the subscription key.

You will then have the ability to select a subscription key to assign to the application.

For more information, see: https://www.luis.ai/Help#CreatingKeys


Return back to your applications by selecting My Applications.


Select your application.


Next, click the Publish button.


Finally, click the Publish web service button.


The published end-point will be displayed.

Make note of the App ID, and Subscription Key. You will need these later to be used in the Bot application.

Now, we need to update the Bot to call the LUIS service…

Update The Bot Application


Open the project from the article: Implementing A SQL Server Database With The Microsoft Bot Framework (you can get the code on the Downloads page of this site), in Visual Studio .

Add a new file called LUISDialogClass.cs using the following code:

using Microsoft.Bot.Builder.Dialogs; using Microsoft.Bot.Builder.Luis; using Microsoft.Bot.Builder.Luis.Models; using Microsoft.Bot.Connector; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Web; namespace AiNumberGuesserBot {     [LuisModel("{Your App ID}", "{Your Subscription Key}")]     [Serializable]     public class LUISDialogClass : LuisDialog<object>     {         #region public async Task None(IDialogContext context, LuisResult result)         [LuisIntent("")]         [LuisIntent("None")]         public async Task None(IDialogContext context, LuisResult result)         {             // Not a match -- Start a new Game             context.Call(new NumberGuesserDialog(), null);         }         #endregion         #region public async Task HighScores(IDialogContext context, LuisResult result)         [LuisIntent("HighScores")]         public async Task HighScores(IDialogContext context, LuisResult result)         {             // See if the intent has a > .99 match             bool boolIntentMatch = false;             foreach (var objIntent in result.Intents)             {                 // If the HighScores Intent is detected                 // and it's score is greater than or = to .99                  // set boolIntentMatch = true                 if (                     (objIntent.Intent == "HighScores")                     && (objIntent.Score >= .99f)                     )                 {                     boolIntentMatch = true;                 }             }             if (boolIntentMatch)             {                 // ** To Do: Code to handle a Match **             }             else             {                 // Not a match -- Start a new Game                 var objNumberGuesserDialog = new NumberGuesserDialog();                 context.Call(objNumberGuesserDialog, null);             }         }         #endregion     } }

This code will pass text entered into the Bot to the LUIS application and trigger the None or HighScores methods based on what the LUIS application determines the Intent is that the entered text matches.

We decorate each method with a LuisIntent decoration, setting the name of an Intent (for example [LuisIntent("HighScores")] ) to indicate which method should be triggered.

( Note: the code is not complete at this point, we will complete the code in later steps)


Ensure that you enter the App ID and Subscription Key, from your LUIS application, in the LuisModel decoration at the top of the class.

This how the code knows what LUIS application to connect to.


We now need to call LUISDialogClass, instead of the previously configured NumberGuesserDialog class, when a user communicates with the Bot.

The new LUIS code (LUISDialogClass) will call the NumberGuesserDialog class when needed (for example, when the user has not triggered the HighScores intent).

Open the MessagesController.cs file (in the Controllers folder)

Replace the following code:

								// Detect if the user enters the words "high score"     if (activity.Text.ToLower().Contains("high score"))     {         // Call the ShowHighScores method         // passing to it, the current Activity         ShowHighScores(activity);     }     else     {         // Call NumberGuesserDialog         await Conversation.SendAsync(activity, () => new NumberGuesserDialog());     }


								// Call the LUIS Dialog     await Conversation.SendAsync(activity, () => new LUISDialogClass());


There are places where the NumberGuesserDialog will need to call LUISDialogClass (for example, when the user has entered a response that is not a number being guessed as part of the game). The NumberGuesserDialog class will need to return control back to the LUISDialogClass.

Replace the code in the NumberGuesserDialog class that starts (and is encapsulated in the brackets) like the text below:

								// See if a number was passed     if (!int.TryParse(message.Text, out intGuessedNumber))     {         ...     }

With the following code:

								// See if a number was passed     if (!int.TryParse(message.Text, out intGuessedNumber))     {         // A number was not passed           // Call the LUISDialogClass         // Placing it on the dialog stack         // context.Forward allows us to 'send forward'          // the current message to the child dialog         // otherwise the child dialog would start but wait for         // the user to send (another) message         // See:         // http://stackoverflow.com/questions/37522294/calling-forms-from-dialogs         await context.Forward(             new LUISDialogClass(),             null,             message,             System.Threading.CancellationToken.None);     }


The NumberGuesserDialog class is no longer the root class, so we will need to alter it slightly again so that it starts up the game properly when it is triggered by the LUISDialogClass.

Locate the following code in the StartAsync method:

								// Start the Game         context.Wait(MessageReceivedAsync);

Replace it with:

								Activity replyToConversation = (Activity)context.MakeMessage();         replyToConversation.Recipient = replyToConversation.Recipient;         replyToConversation.Type = "message";         string strAiHelpWebsite_Small =             String.Format(@"{0}/{1}",             strBaseURL,             "Images/NumberGuesserCard.png");         List<CardImage> cardImages = new List<CardImage>();         cardImages.Add(new CardImage(url: strAiHelpWebsite_Small));         // Create the Buttons         List<CardAction> cardButtons = CreateButtons();         HeroCard plCard = new HeroCard()         {             Images = cardImages,             Buttons = cardButtons,         };         Attachment plAttachment = plCard.ToAttachment();         replyToConversation.Attachments.Add(plAttachment);         replyToConversation.AttachmentLayout = "list";         await context.PostAsync(replyToConversation);         // Start the Game         context.Wait(MessageReceivedAsync);

This code shows the welcome screen to start the number guessing game.

Implement High Scores


At this point, if we run the application, and connect to it in the emulator (see: Creating a Hello World! Bot Using The Microsoft Bot Framework to see how this is done), we can play the game.

However, if we type anything that triggers the HighScores LUIS Intent, we will receive an error (because the code to handle this has not been implemented yet).


Open the LUISDialogClass.cs file and locate the following code:

								if (boolIntentMatch)     {         // ** To Do: Code to handle a Match **     }

Replace it with:

								if (boolIntentMatch)     {         // Determine the days in the past         // to search for High Scores         int intDays = -1;         #region PeriodOfTime         EntityRecommendation PeriodOfTime;         if (result.TryFindEntity("PeriodOfTime", out PeriodOfTime))         {             switch (PeriodOfTime.Entity)             {                 case "month":                     intDays = -30;                     break;                 case "day":                     intDays = -1;                     break;                 case "week":                     intDays = -7;                     break;                 default:                     intDays = -1;                     break;             }         }         #endregion         #region Days         EntityRecommendation Days;         if (result.TryFindEntity("Days", out Days))         {             // Set Days             int intTempDays;             if (int.TryParse(Days.Entity, out intTempDays))             {                 // A Number was passed                 intDays = (Convert.ToInt32(intTempDays) * (-1));             }             else             {                 // A number was not passed                 // Call ParseEnglish Method                 // From: http://stackoverflow.com/questions/11278081/convert-words-string-to-int                 intTempDays = ParseEnglish(Days.Entity);                 intDays = (Convert.ToInt32(intTempDays) * (-1));             }             // 30 days maximum             if (intDays > 30)             {                 intDays = 30;             }         }         #endregion         await ShowHighScores(context, intDays);         context.Wait(this.MessageReceived);     }

This code will set the number of days the user is asking the high scores to include. It first tries to detect if a period of time was passed (in the PeriodOfTime entity). If it has been, the code converts a known period of time to a number of days.

If a number of days was passed (in the Days entity), the code tries to convert the days into a number. If it cannot, it assumes the number of days was passed as a word not a number. If this is the case, it passes the value to the ParseEnglish method that converts the word to a number.

( Note: You can get the ParseEnglish method from: http://stackoverflow.com/questions/11278081/convert-words-string-to-int )

The number of days (and the current context) is then passed to the ShowHighScores method.

As the final step, paste the following code, to implement the ShowHighScores method, into the LUISDialogClass:

								#region private async Task ShowHighScores(IDialogContext context, int paramDays)     private async Task ShowHighScores(IDialogContext context, int paramDays)     {         // Get the High Scores         Models.BotDataEntities DB = new Models.BotDataEntities();         // Get Yesterday         var ParamYesterday = DateTime.Now.AddDays(paramDays);         var HighScores = (from UserLog in DB.UserLogs                             where UserLog.CountOfTurnsToWin != null                             where UserLog.created > ParamYesterday                             select UserLog)                             .OrderBy(x => x.CountOfTurnsToWin)                             .Take(5)                             .ToList();         System.Text.StringBuilder sb = new System.Text.StringBuilder();         sb.Append("High Scores:\n\n");         foreach (var Score in HighScores)         {             sb.Append(String.Format("Score: {0} - {1} - ({2} {3})\n\n"                 , Score.CountOfTurnsToWin                 , Score.WinnerUserName                 , Score.created.ToLocalTime().ToShortDateString()                 , Score.created.ToLocalTime().ToShortTimeString()));         }         // Create a reply message         var resultMessage = context.MakeMessage();         resultMessage.Type = "message";         resultMessage.Text = sb.ToString();         // Send Message         await context.PostAsync(resultMessage);     }     #endregion

Microsoft Links

Microsoft Bot Framework

Bot Builder (GitHub)

Bot Framework Forum (stack overflow)

LUIS (Help)


You can download the code from the Download page

An error has occurred. This application may no longer respond until reloaded. Reload 🗙