Microsoft Bot Framework - Part 3

By: Rachel Scanlon on 10/18/2017

In the third and final part of this tutorial, we will walk through how you integrate LUIS into an existing ASP.NET MVC Application. We will demonstrate how you would allow the user to ask basic questions about their order.

First of all, we need to log in to the LUIS account that you should have created in the first part of this tutorial.

https://www.luis.ai/

Select “New App”

Enter the name you want to give your app, along with the other relevant details as shown below and create your application.

After we create the application, the first thing we will do is create some entities. For our example we are going to allow our application to ask intelligent questions about products and orders, so we will create some relevant entities in LUIS. I will demonstrate how to create an entity below.

Select the + sign next to the Entities.

Add a new entity and save it.

Go ahead and create the following entities in the same way.

  1. Product Name – This should be the one you already created above.
  2. Product Code
  3. Order Name
  4. Order Email
  5. Order Number
  6. Order Date




Then we will need to add a couple of “Intents”. These are a way to categorize utterances which will be made up of potential user inputs which contain instances of the entities that we just added. This should become clearer after we have added these entities and utterances.

Select the + sign next to “Intents”.

Add the Intent below and hit “Save”. For clarity the second text box allows you to associate your first Utterance with the intent.

Add the following Intent in the same way.

Now we will add some more specific utterances which will include the Entities we added.

Add the sample below being sure to select the correct Entity from the menu. Associate it with the “Place Order” Intent and hit Submit.

Go ahead and add the following new utterances under each Intent.

“Place Order” - Intent

Associate all the Utterances below with the “Product Name” Entity

  • I would like to place an order for a Product Name
  • I would like to place an order for an Product Name
  • I would like to order a Product Name
  • I would like to order a Product Name
  • I want to place an order for a Product Name
  • I want to place an order for an Product Name
  • I want to order a Product Name
  • I want to order an Product Name
  • I need to place an order for a Product Name
  • I need to place an order for an Product Name
  • I need to order a Product Name
  • I need to order Product Name

Associate all the Utterances below with the “Product Code” Entity

  • I would like to place an order for Product Code
  • I would like to order the Product Code
  • I want to place an order for Product Code
  • I want to order the Product Code
  • I need to place an order for Product Code
  • I need to order the Product Code

“Search Orders” - Intent

Associate all the Utterances below with the “Order Number” Entity

  • What is the status of my order?
  • What is the status of my order? The order number is Order Number.
  • I placed an order and haven’t received it. The order number is Order Number.

When you have entered all the utterances, you must “train” the service to detect the entities.

For this tutorial, we will be using Azure. If you have been following the first two parts of this tutorial, you will already have an Azure account. If not, you will need to set one up. Refer to the first part of this tutorial for instructions. Then go to “App Settings” on the top left of the LUIS interface.

As you can see, I already have a key set up for my endpoint. You will need to click on the link “Click here to buy a key from Azure” and follow the prompts to get an Azure subscription to LUIS.

Then select the endpoint key from the dropdown list.

You can then hit “Publish” as shown below.

Select “Publish web service”.

This will generate the published endpoint. Store the application id and the subscription key somewhere as you will need these later for the web application we will build.

The web application in this tutorial will demonstrate how to intelligently communicate with a user and search for the status of their order in a SQL Server database.

I will not be walking through the database creation part because that is outside the scope of this tutorial. However, I will include scripts to create the database and populate it with some dummy data along with the source code for the application.

Below is a diagram of the database structure. Obviously, in an enterprise application, you would have ASP.NET Identity set up in your database and application and a much more complex database schema. However, for this tutorial, I have a “quick and dirty” database structure.

Creating a web application to intelligently communicate with your users.

  1. Create an MVC project in Visual Studio




Install Newton.Json via the package manager


Add the following keys to the web.config. Obviously you need to use the ones from your LUIS account.

Next, we need to create the classes to hold the results from our LUIS application. To do this, we work copy the endpoint URL from LUIS.

Paste the URL into a web browser and add your query (one of your utterances from LUIS). I am going to use “This is Rachel Scanlon. I would like to know the status of my order. The order number is 123.” as my query. You will then see the JSON data for your query.

Go to http://jsonutils.com/ and paste this JSON the window. This will create some of the classes you need.

Add a “Models” folder to your web application and add a LuisAi class to it. Paste the contents below into it.

public class Value
    {
        public string entity { get; set; }
        public string type { get; set; }
    }

    public class Parameter
    {
        public string name { get; set; }
        public bool required { get; set; }
        public IList<value> value { get; set; }
    }

    public class Action
    {
        public bool triggered { get; set; }
        public string name { get; set; }
        public IList<parameter> parameters { get; set; }
    }

    public class TopScoringIntent
    {
        public string intent { get; set; }
        public double score { get; set; }
        public IList<action> actions { get; set; }
    }

    public class Entity
    {
        public string entity { get; set; }
        public string type { get; set; }
        public int startIndex { get; set; }
        public int endIndex { get; set; }
        public double score { get; set; }
    }

    public class Dialog
    {
        public string prompt { get; set; }
        public string parameterName { get; set; }
        public string contextId { get; set; }
        public string status { get; set; }
    }

    public class Luis
    {
        public string query { get; set; }
        public TopScoringIntent topScoringIntent { get; set; }
        public IList<entity>; entities { get; set; }
        public Dialog dialog { get; set; }
    }
    public class Query
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string OrderNumber { get; set; }

        public string CapitilizeFirstName => System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(FirstName);
        public string CapitilizeLastName => System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(LastName);

        public string OrderStatus { get; set; }

    }

First we will set up Entity Framework to interface with our database with a “code first” model. If you don’t have Entity Framework installed in your project, you will need to install it, by selecting Tools > Nuget Package Manager > Manage Nuget Packages For Solution. The latest version is fine.

For the purpose of this example, I am assuming the reader already had an basic understanding of Entity Framework.

Add a new folder named “Model” then add a new “ADO.NET Entity Model”.

Because we already have a sample database ready, we will select “Code First From Database”.



Set up your connectionstring to the database

On the next screen, select all the tables needed in the model and then select “Finish”.

Finally, please got to the Home controller and the Home/Index view and add the following.

    public class HomeController : Controller
    {
         
        #region public async Task<actionresult> Index(string searchString)
        public async Task<actionresult> Index(string searchString)
        {
            var Return = new Query();
            var db = new Models.Model1();
            try
            {
                if (searchString != null)
                {
                    var objLuisResult = await QueryLuis(searchString);
                    foreach (var item in objLuisResult.entities)
                    {
                        if (item.type == "Name::First Name")
                        {
                            Return.FirstName = item.entity;
                        }
                        if (item.type == "Name::Last Name")
                        {
                            Return.LastName = item.entity;
                        }
                        if (item.type == "Order Number")
                        {
                            Return.OrderNumber = item.entity;
                        }
                    }

                    Return.OrderStatus = db.Orders.Where(x => x.Id == 1).Select(y => y.OrderStatus).FirstOrDefault();
                }
                return View(Return);
            }
            catch (Exception ex)
            {
                ModelState.AddModelError(string.Empty, "Error: " + ex);
                return View(Return);
            }
        }
        #endregion
        // Utility
        #region private static async Task<luis> QueryLUIS(string Query)
        private static async Task<luis> QueryLuis(string query)
        {
            Luis luisResult = new Luis();
            var luisQuery = Uri.EscapeDataString(query);
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                // Get key values from the web.config
                string luisUrl = WebConfigurationManager.AppSettings["LUIS_Url"];
                string luisSubscriptionKey = WebConfigurationManager.AppSettings["LUIS_Subscription_Key"];
                string requestUri = $"{luisUrl}?subscription-key={luisSubscriptionKey}&q={luisQuery}";
                System.Net.Http.HttpResponseMessage msg = await client.GetAsync(requestUri);
                if (msg.IsSuccessStatusCode)
                {
                    var jsonDataResponse = await msg.Content.ReadAsStringAsync();
                    luisResult = JsonConvert.DeserializeObject<luis>(jsonDataResponse);
                }
            }
            return luisResult;
        }
        #endregion
    }
@model JSONUtils.Query
@{ ViewBag.Title = "Index"; }
<div class="form-horizontal">@Html.ValidationSummary(true, "", new { @class = "text-danger" }) @using (Html.BeginForm()) {
<div class="form-group">
<div class="col-md-offset-2 col-md-10">@Html.TextArea("SearchString", "", new {style = "width: 600px; Height:200px;"}) <br /> <input type="submit" value="Search" /></div>
</div>
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">@if (!string.IsNullOrEmpty(Model?.FirstName)) { @Html.LabelForModel("Hi " + Model.CapitilizeFirstName + ". The status of your order " + Model.OrderNumber + " is " + Model.OrderStatus) }</div>
</div>
</div>

Run the project, and you should see this screen.

Cool isn't it? There you have the final post in this series and hopefully, you can see the power of the Microsoft Bot and LUIS language for use in your next project.

Source Code