Microsoft Bot Framework - Building Intelligent Chat Bot Using Azure Functions And LUIS

This article focuses on creating an intelligent chat bot using Microsoft Azure Function Apps and Language Understanding Intelligent Service

Introduction

Any business that does online transactions needs to provide some kind of chat support for the issues related to their business. This can be done by developing chat applications where the consumers directly chat with the agent of the business who then solves their problems. A new alternative to answering frequently asked questions is the use of the Chat Bot which is intelligent enough to understand the questions raised by the user and determine the solutions to them on a real-time basis. Or in the case of an administrator, if they are managing a lot of operative tasks or a lot of source code bases, then an intelligent bot is of great help.

For the bot to become intelligent, the important step is that the bot should understand the language in which humans communicate with the bot (e.g English, French, Hindi etc.). To facilitate this understanding Microsoft has provided developers with a powerful feature called as Language Understanding (LUIS). This feature can be used to understand the language by comparing the uttered sentence against the intents and the entities defined while creating the LUIS application.

When the bot is being developed, the LUIS app can be consumed from the Azure functions using the Bot Builder Framework SDK. This Azure Function Bot can then be coded to perform various function after detecting the intents behind the user commands.

What are Azure Functions?

As per Microsoft,

"Azure Functions is an event-driven, compute-on-demand experience that extends the existing Azure application platform with capabilities to implement code triggered by events occurring in Azure or third party service as well as on-premises systems. Azure Functions allows developers to take action by connecting to data sources or messaging solutions thus making it easy to process and react to events. Developers can leverage Azure Functions to build HTTP-based API endpoints accessible by a wide range of applications, mobile and IoT devices. Azure Functions is scale-based and on-demand, so you pay only for the resources you consume."

What is LUIS?

As per Microsoft,

"Language Understanding (LUIS) allows your application to understand what a person wants in their own words. LUIS uses machine learning to allow developers to build applications that can receive user input in natural language and extract meaning from it. A client application that converses with the user can pass user input to a LUIS app and receive relevant, detailed information back."

Key Concepts In LUIS

  1. Utterance
    This is the actual command spoken/written by the User /APP

  2. Intents
    Intents describe the actual intention behind the command given by the user.; e.g. when the user says, "Find me all the Pushes made on the PublicWorks Repository", what the user wants is the list of the Pushes made on the PublicWorks repository, hence Push made is the intent here.

  3. Entity
    This is extra information that is present in the utterance which helps LUIS to understand the utterance more. In above, PublicWorks is the name of the repository and hence it is the entity which gives the name of the repository on which the Push is to be queried.

Scope

This article discusses the use of the .NET Bot Builder SDK along with the Azure function to create an Azure function bot which detects the user's intent and brings back the list of all the repositories from the GIT for that particular user.

Design

The design for the bot can be broken down into the following steps.

  1. Creating a LUIS application To Detect the Intents and Entities in the user utterance.
  2. Creating LUIS cognitive services account.
  3. Publishing the LUIS app.
  4. Creating an Azure function app to take appropriate actions based upon the user intents
  5. Registering the bot with various channels.

Creating a LUIS Application

The main reason behind creating a LUIS application is to make the bot intelligent so that it can understand what the user wants and then reply back accordingly. The LUIS application will help the bot to understand the intent from the statements where the user greets the bot to the statements where the user wants the bot to fetch the list of the repositories etc. Each of the Intents created should have as many different variations of the utterances so that when the LUIS application is trained, it will be more intelligent. This training process should be undertaken frequently to keep the bot evolving.

The following steps will highlight how to create the LUIS application.

Note
For each of the created intents, utterances should be provided to train the app. A minimum of five should be provided but the more the merrier.

  1. Log On to the LUIS portal at https://www.luis.ai
  2. Create a LUIS application named GitAssistantBotLuisApp. Refer to the sample screenshot below.

    Azure
     
  3. Create an intent called WelcomeIntent as shown below. This intent will detect if the user is greeting the bot.

    Azure
     
  4. Create an intent called as HelpIntent as per the following screenshot. This intent will detect if the user requires help from bot.

    Azure
     
  5. Create an intent called as SupportedFunctionsIntent as shown below. This intent will detect if the user wants to know the functions supported by the bot.

    Azure
     
  6. Create an intent called as ListRepositoryIntent. This intent will detect if the user wants to know the list of all the repositories under the account.

    Azure
     
  7. Create an intent called as the ActionOnRepositoryIntent . This intent will detect if the user wants to perform any action on any particular repository.

    Azure
     
  8. Create an Entity called as ActionEntity. This entity is used to record the action detected in the user utterance.  If user says "Bring me all the commits on AdventureWorks repository" the commits is detected as ActionEntity as it denotes the action that needs to be performed against the repository.

    Azure
     
  9. Create an Entity called RepositoryEntity. This entity is used to record the action detected in the user utterance.  If user says "Bring me all the commits on AdventureWorks repository" the AdventureWorks is detected as RepositoryEntity as it denotes the action that needs to be performed against the repository.

    Azure
     
  10. Map the entities created above to the utterances added to the ActionOnRepositoryIntent . Refer to the sample screenshot.

    Azure
     
  11. Train the App using the Train button in the portal.

Creating a LUIS Cognitive Service Account

In order to consume the LUIS app from the logic apps, the LUIS app must be published to the Resource group so that logic app connectors can use it, in order to do so, a LUIS cognitive services account need to be set up in Azure. Refer to the following steps to set up the account.

  1. Select the Cognitive Services blade.

    Azure
     
  2. Create the Account.

    Azure

Publishing the LUIS Application

Once an account for LUIS is created, the publication of the app becomes very easy. Navigate to the Publish Tab in the LUIS portal and select the environment (Production/Staging) and the time zone.

Azure
 
Select the region where the LUIS app needs to be Hosted and click Add Keys, this will allow the LUIS portal to link the LUIS app to the LUIS account created above.

Azure

Once done, click on the publish button, this will publish the LUIS app into the LUIS account created earlier.

 

The LUIS app is now available to be consumed by the Azure Function App.

Creating Azure Function

Azure function can be created from the Azure portal and the code for the function app can be editied in the online editor itself.

Following are the steps that are to be undertaken to create the Azure function app bot.

  1. Log on to the Azure portal at https://www.portal.azure.com

  2. Select the FunctionApp Bot as shown below. It is available under the AI + Cognitive Services tab.

    Azure
     
  3. Create the Bot by providing details asked. Refer a sample below.

    Azure

  4. Once the bot is deployed, open the bot in Azure functions as shown in reference below.

    Azure

Function App Code

The function App project for the bot contains following C# script files.

  1. run.csx 
    This file is the main driving file for the azure function app and contains the code for accepting and replying back with the messages, responds to the user.

  2. BasicLuisDialog.csx
    This file has the logic to select the messages based upon the intent detected.

  3. GitHelper.csx
    This class contains the helper methods which can be used to consume the GitHub api. In this example the helper contains only the method to get the repositories related to the account (based upon a standrard user access token).

The reader should get familar with the concepts of bot and the classes and the Interfaces used to understand the code posted below. The user is urged to refer to the See Also section to get the idea about the classes and interfaces and then return to the code.

run.csx

  1. #r "Newtonsoft.Json"#  
  2. load "BasicLuisDialog.csx"  
  3. using System;  
  4. using System.Net;  
  5. using System.Threading;  
  6. using Newtonsoft.Json;  
  7. using Microsoft.Bot.Builder.Azure;  
  8. using Microsoft.Bot.Builder.Dialogs;  
  9. using Microsoft.Bot.Connector;  
  10. public static async Task < object > Run(HttpRequestMessage req, TraceWriter log) {  
  11.     log.Info($ "Webhook was triggered!");  
  12.     // Initialize the azure bot  
  13.     using(BotService.Initialize()) {  
  14.         // Deserialize the incoming activity  
  15.         string jsonContent = await req.Content.ReadAsStringAsync();  
  16.         var activity = JsonConvert.DeserializeObject < Activity > (jsonContent);  
  17.         // authenticate incoming request and add activity.ServiceUrl to MicrosoftAppCredentials.TrustedHostNames  
  18.         // if request is authenticated  
  19.         if (!await BotService.Authenticator.TryAuthenticateAsync(req, new [] {  
  20.                 activity  
  21.             }, CancellationToken.None)) {  
  22.             return BotAuthenticator.GenerateUnauthorizedResponse(req);  
  23.         }  
  24.         if (activity != null) {  
  25.             // one of these will have an interface and process it  
  26.             switch (activity.GetActivityType()) {  
  27.                 case ActivityTypes.Message:  
  28.                     await Conversation.SendAsync(activity, () => newBasicLuisDialog());  
  29.                     break;  
  30.                 case ActivityTypes.ConversationUpdate:  
  31.                     var client = new ConnectorClient(new Uri(activity.ServiceUrl));  
  32.                     IConversationUpdateActivity update = activity;  
  33.                     if (update.MembersAdded.Any()) {  
  34.                         var reply = activity.CreateReply();  
  35.                         var newMembers = update.MembersAdded ? .Where(t => t.Id != activity.Recipient.Id);  
  36.                         foreach(var newMember in newMembers) {  
  37.                             reply.Text = "Welcome";  
  38.                             if (!string.IsNullOrEmpty(newMember.Name)) {  
  39.                                 reply.Text += $ " {newMember.Name}";  
  40.                             }  
  41.                             reply.Text += "!";  
  42.                             await client.Conversations.ReplyToActivityAsync(reply);  
  43.                         }  
  44.                     }  
  45.                     break;  
  46.                 case ActivityTypes.ContactRelationUpdate:  
  47.                 case ActivityTypes.Typing:  
  48.                 case ActivityTypes.DeleteUserData:  
  49.                 case ActivityTypes.Ping:  
  50.                 default:  
  51.                     log.Error($ "Unknown activity type ignored: {activity.GetActivityType()}");  
  52.                     break;  
  53.             }  
  54.         }  
  55.         return req.CreateResponse(HttpStatusCode.Accepted);  
  56.     }  
  57. }  

 

The above code is auto generated when the bot gets created.

BasicLuisDialog.csx

  1. #load "GitHelper.csx"  
  2. using System;  
  3. using System.Configuration;  
  4. using System.Threading.Tasks;  
  5. using Microsoft.Bot.Builder.Azure;  
  6. using Microsoft.Bot.Builder.Dialogs;  
  7. using Microsoft.Bot.Builder.Luis;  
  8. using Microsoft.Bot.Builder.Luis.Models;  
  9. // For more information about this template visit http://aka.ms/azurebots-csharp-luis  
  10. [Serializable]  
  11. public class BasicLuisDialog: LuisDialog < object > {  
  12.     public BasicLuisDialog(): base(new LuisService(new LuisModelAttribute(ConfigurationManager.AppSettings["LuisAppId"], ConfigurationManager.AppSettings["LuisAPIKey"], domain: ConfigurationManager.AppSettings["LuisAPIHostName"]))) {}  
  13.         [LuisIntent("None")]  
  14.     public async Task NoneIntent(IDialogContext context, LuisResult result) {  
  15.         await this.ShowLuisResult(context, result);  
  16.     }  
  17.     // Go to https://luis.ai and create a new intent, then train/publish your luis app.  
  18.     // Finally replace "Greeting" with the name of your newly created intent in the following handler  
  19.     [LuisIntent("WelcomeIntent")]  
  20.     public async Task WelcomeIntent(IDialogContext context, LuisResult result) {  
  21.         await this.ShowLuisResult(context, result);  
  22.     }  
  23.     [LuisIntent("HelpIntent")]  
  24.     public async Task HelpIntent(IDialogContext context, LuisResult result) {  
  25.         await this.ShowLuisResult(context, result);  
  26.     }  
  27.     [LuisIntent("SupportedFunctionsIntent")]  
  28.     public async Task SupportedFunctionsIntent(IDialogContext context, LuisResult result) {  
  29.         await this.ShowLuisResult(context, result);  
  30.     }  
  31.     [LuisIntent("ActionOnRepositoryIntent")]  
  32.     public async Task ActionOnRepositoryIntent(IDialogContext context, LuisResult result) {  
  33.         await this.ShowLuisResult(context, result);  
  34.     }  
  35.     [LuisIntent("ListRepositoryIntent")]  
  36.     public async Task ListRepositoryIntent(IDialogContext context, LuisResult result) {  
  37.         await this.ShowLuisResult(context, result);  
  38.     }  
  39.     private async Task ShowLuisResult(IDialogContext context, LuisResult result) {  
  40.         string detectedIntent = result.Intents[0].Intent;  
  41.         string messageToUser = string.Empty;  
  42.         switch (detectedIntent) {  
  43.             case "WelcomeIntent":  
  44.                 messageToUser = $ "Hola Amigo, I am chat bot of the Wonderland account.";  
  45.                 break;  
  46.             case "HelpIntent":  
  47.                 messageToUser = $ "Fear Not!! I can help you with activties like getting repositories in wonderland account. \n I can get the list of commit on a particular reposotory too!";  
  48.                 break;  
  49.             case "ListRepositoryIntent":  
  50.                 string repositoryList = await GetRepositories();  
  51.                 messageToUser = $ "I will now bring you the list of the repositories in Wonderland. \n" + repositoryList;  
  52.                 break;  
  53.             case "ActionOnRepositoryIntent":  
  54.                 messageToUser = $ "I will bring you the {result.Entities[0].Entity} for the respository {result.Entities[1].Entity}";  
  55.                 break;  
  56.             case "SupportedFunctionsIntent":  
  57.                 messageToUser = $ "I can perform following operations. \n 1. Get all the repositories in WOnderland \n 2. Get the list of commits, pulls on any particular repository present in Wonderland";  
  58.                 break;  
  59.             case "None":  
  60.                 messageToUser = $ "I detected no intent in your command";  
  61.                 break;  
  62.         }  
  63.         await context.PostAsync(messageToUser);  
  64.         context.Wait(MessageReceived);  
  65.     }  
  66. }  

 

The above class implements the LuisDialog from the Microsoft Bot Builder SDK and generates the responses based upon the detected intents.

GitHelper.csx

  1. #r "System.Web"#  
  2. "Newtonsoft.Json"  
  3. using System.Net;  
  4. using System.Configuration;  
  5. using System.Web;  
  6. using System.Threading.Tasks;  
  7. using Newtonsoft.Json;  
  8. using Newtonsoft.Json.Linq;  
  9. public static async Task < string > GetRepositories() {  
  10.     string repositoriesList = string.Empty;  
  11.     try {  
  12.         string GitAccessToken = ConfigurationManager.AppSettings["GitAccessToken"];  
  13.         string GitHubApi = ConfigurationManager.AppSettings["GitHubApi"];  
  14.         var client = new HttpClient();  
  15.         var queryString = System.Web.HttpUtility.ParseQueryString(string.Empty);  
  16.         client.DefaultRequestHeaders.Add("User-Agent""Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");  
  17.         var uri = GitHubApi + "/user/repos?access_token=" + GitAccessToken;  
  18.         var response = await client.GetAsync(uri);  
  19.         var jsonResponseString = await response.Content.ReadAsStringAsync();  
  20.         var repositoriesArray = JArray.Parse(jsonResponseString);  
  21.         foreach(var repository in repositoriesArray) {  
  22.             repositoriesList = repositoriesList + (string) repository["name"] + "\n";  
  23.         }  
  24.     } catch (Exception ex) {  
  25.         repositoriesList = ex.Message;  
  26.     }  
  27.     return repositoriesList;  
  28. }  

 

The task in this script file consumes the GIT HUB api, fetches a Json response containing repository details, parses the response so the user only gets fed with the names of the repository.

Registering ChatBot To Skype Channel

The chat bot can be easily added to various channels. The following steps are used to add the chat bot to Skype.

  1. On the Channel tab of the Bot project, select the Skype channel.

    Azure
  2. Configure the details like the messaging, calling, publishing by filling out the basic details and saving the channel (Refer to the Reference section).

  3. Click on the Skype Icon so that it can be added to Skype for testing. Refer to the following screenshots.

    Azure

    Azure
  4. Performing the above steps adds the bot to the Skype Account.

    Azure
Testing Using Web Chat Client

Azure

Skype Chat

Azure
Conclusion

As evident from the above process, it can be concluded that we can set up a server less intelligent bot in much less time. The bot can be configured to receive messages in other formats like images and sounds and then the other cognitive services can be used in conjunction with LUIS to create an intelligent bot. It is also evident that once the bot is created it is very easy to integrate the bot with different channels like Facebook Messenger, Skype, Skype for Business, Microsoft Teams etc.

See Also

Refer to the following links to read more about the topics discussed in this article

References

The following articles were referenced while writing this article.