Azure Functions: Integrating LUIS Application With Azure Function Apps To Predict Intent in User Utterances
Introduction
Any business which transacts online requires providing 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 solve 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 the real-time basis. Or in 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 LUIS API or it can be consumed to get the predictions by calling the LUIS app from the logic app. This article will discuss the consumption of the LUIS app from an Azure Function App.
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
- Utterance: This is the actual command spoken/written by the User /APP
- Intents: Intents describes the actual intention behind the command given by the user.
e.g. when the User says "Find me all the Push made on the PublicWorks Repository", what user wants is the list of the Push made on the PublicWorks repository, hence Push made is the intent here. - Entity: This is extra information that is present in the utterance which helps the LUIS to understand the utterance more. In above e.g PublicWorks is the name of the repository and hence is the entity which gives the name of the repository on which the Push is to be queried.
Scope
This article focuses on creating a LUIS app which understands the various functions that can be performed on the repository. Once the intent to identify the action on the repository is created and the LUIS app trained and published, the LUIS app will be consumed from the Azure Function App which will pass the utterance to the LUIS app and get the prediction form the LUIS app.
Design
LUIS App
Following are the steps that need to be performed to create a LUIS app.
Log on to the LUIS portal (https://www.LUIS.ai) using the Azure credentials.
Create a LUIS application. Refer sample screenshot below.
Create New Simple Entities RepoName and **ActionAskedAbout **as per the sample below.
Create a composite Entity RepoAction which will encapsulate the entities created above. Refer following screen shot.
Create an intent ActionsOnRepo to understand that the intent behind the utterance is to do/query certain action on a certain repository.
The list of utterances used to train the app is as follows.
Map the Composite entity created above to the Utterances entered above.
Trains the LUIS app using the Train button in the portal. Once the App is trained, it can be tested using sample inputs.
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 the Azure. Refer to following steps to set up the account.
Publish LUIS App
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.
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.
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.
Azure Function App
There are some steps that need to be undertaken to create the Azure function to consume the LUIS app. Following are the steps that should be undertaken to create the Azure Function.
Select the Azure Functions from the Compute Section and Provide the details like the app name, resource group, consumption plan and storage account details. .
Add a new function called as ConsumeLUISApplication. Refer below screenshots for sample.
In order to access the LUIS application from the Azure Function App, LUIS application id, LUIS subscription key, and the LUIS endpoint are required. The LUIS application Id and the LUIS URL can be obtained from the Publish section of the LUIS app that was created earlier. These values are stored in the app settings of the Azure Function app and accessed in the code later on. The following set of screenshots depicts how to add the app settings keys.
This completes the basic set up for the Azure Function App. Once this is completed, the next step is to set up the code for the Azure Function App. Following is the code used in the function app.
#r "System.Web"
using System.Net;
using System.Configuration;
using System.Web;
using System.Threading.Tasks;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
//Read the utterance from the Request.
string utteredText = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "Utterance", true) == 0)
.Value;
if(utteredText == null)
{
dynamic data = await req.Content.ReadAsAsync<object>();
utteredText = data?.Utterance;
}
log.Info("Uttered Text is :" + utteredText );
string luisPrediction = string.Empty;
luisPrediction = await GetPredictions(utteredText, log);
if(String.IsNullOrEmpty(luisPrediction))
{
luisPrediction = "Unable to Fetch the LUIS prediction at the Moment. Please try again";
}
return utteredText == null
? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a utterance on the query string or in the request body")
: req.CreateResponse(HttpStatusCode.OK, luisPrediction);
}
private static async Task<string> GetPredictions(string utteredText, TraceWriter log)
{
string luisPrediction;
try
{
string LUISAppId = ConfigurationManager.AppSettings["LUISAppId"];
string LUISSubscriptionKey = ConfigurationManager.AppSettings["LUISSubscriptionKey"];
string LUISUri = ConfigurationManager.AppSettings["LUISUri"];
var client = new HttpClient();
var queryString = System.Web.HttpUtility.ParseQueryString(string.Empty);
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", LUISSubscriptionKey);
queryString["q"] = utteredText;
queryString["timezoneOffset"] = "0";
queryString["verbose"] = "false";
queryString["spellCheck"] = "false";
queryString["staging"] = "false";
var uri = LUISUri + LUISAppId + "?" + queryString;
log.Info("Calling the LUIS app to Get the Predections");
var response = await client.GetAsync(uri);
luisPrediction = await response.Content.ReadAsStringAsync();
log.Info(luisPrediction);
}
catch(Exception ex)
{
luisPrediction = string.Empty;
log.Info("Exception Caught while calling LUIS");
}
return luisPrediction;
}
Above code makes the use of the asynchronous programming in C# and the concepts of C# script which are used in writing Azure Functions. (Refer See Also section). The code is self-explanatory and easy to understand. Copy the code into the function editor and save the code, The online editor will show errors if any that occur while compiling the code.
Testing
Once the Azure Function created above is saved, it can be tested using a tool like POSTMAN or SOAPUI. Url to the function can be obtained from the "Get Function Url" which is next to the Run button in the online editor.
Following are the request and the responses that were fed to the Azure app.
**Request **
{
}
Response
"Please pass a utterance on the query string or in the request body"
Request
{
"Utterance": "Please bring me all the pulls done on the PublicWorks repository"
}
Response
"{\r\n \"query\": \"Please bring me all the pulls done on the PublicWorks repository\",\r\n \"topScoringIntent\": {\r\n \"intent\": \"ActionsOnRepo\",\r\n \"score\": 0.9880099\r\n },\r\n \"entities\": [\r\n {\r\n \"entity\": \"pulls\",\r\n \"type\": \"ActionAskedAbout\",\r\n \"startIndex\": 24,\r\n \"endIndex\": 28,\r\n \"score\": 0.9956364\r\n },\r\n {\r\n \"entity\": \"pulls\",\r\n \"type\": \"RepoAction\",\r\n \"startIndex\": 24,\r\n \"endIndex\": 28,\r\n \"score\": 0.9969615\r\n },\r\n {\r\n \"entity\": \"publicworks\",\r\n \"type\": \"RepoAction\",\r\n \"startIndex\": 42,\r\n \"endIndex\": 52,\r\n \"score\": 0.84949106\r\n },\r\n {\r\n \"entity\": \"publicworks\",\r\n \"type\": \"RepoName\",\r\n \"startIndex\": 42,\r\n \"endIndex\": 52,\r\n \"score\": 0.73795265\r\n }\r\n ],\r\n \"compositeEntities\": [\r\n {\r\n \"parentType\": \"RepoAction\",\r\n \"value\": \"pulls\",\r\n \"children\": [\r\n {\r\n \"type\": \"ActionAskedAbout\",\r\n \"value\": \"pulls\"\r\n }\r\n ]\r\n },\r\n {\r\n \"parentType\": \"RepoAction\",\r\n \"value\": \"publicworks\",\r\n \"children\": [\r\n {\r\n \"type\": \"RepoName\",\r\n \"value\": \"publicworks\"\r\n }\r\n ]\r\n }\r\n ]\r\n}"
The response can now be serialized into other classes or json objects as required.
Conclusion
The request and responses generated by the azure function show that it is very easy to integrate the LUIS application in an azure function.
See Also
Refer following links to read more about the topics discussed in this article
- Logic Apps: Integrating LUIS Application With Logic Apps To Predict Intent in User Utterances
- Create your first function in the Azure portal
- Azure Functions C# script (.csx) developer reference
- await (C# Reference)
- Unity3d - Using LUIS for voice activated commands
- Azure Cognitive Services - Bing Speech API and Language Understanding Intelligent Service (LUIS)
References
Following articles were referred while writing this article.
- About Language Understanding (LUIS)
- Introducing Azure Functions
- Asynchronous programming
- Asynchronous programming with async and await (C#)