2017年4月27日 星期四

[Chatbot] Reply message with LUIS

 ChatBot      Microsoft Bot framework      facebook



Introduction


After we have a bot, we would like to analyze the messages from user and reply to the users with meaningful messages.
So a Language Understanding engine is a must.
Here we will integrate Microsoft Cognitive Service: Language Understanding Intelligent Service (LUIS) to support understanding the human messages.


Related articles



Environment
MS Bot Framework v3.0
Visual Studio 2017
Azure Cognitive service



Microsoft Cognitive Service : LUIS


Buy key

First of all, we have to know pricing of the service and get a key from Azure: Cognitive Services.





After create the Cognitive service on Azure, we can get two keys on it. Copy one of them for later using.



Register LUIS App

Go to https://www.luis.ai/home/index and add the key from previous step.
PS. If you don’t have one, click [Buy key on Azure].



Create a new App.



Complete the form and choose the right key.




Set Intent and Entity

Here comes the funniest step!
We are going to create Intent (What scenario of the message) and Entity (What type of words belong to) for our LUIS App.

The following easy sample will help you understand how to use Intents and Entities.

Entities

I added three custom entities, Behavior, Something and Count.






Intents



After adding the Intent, we will add Utterances within it.
For example, “I want to eat three apples”




Now click on the word to set the mapping entity on it.




Final result …



Keep creating more Utterances in order to train LUIS later, such as
“I want to have 4 pies”
“I want to watch 1 movie”

Save it when the entities are set.


Train and Test

Go to [Train & Test], train our LUIS App with the previous settings on Intent and Entities.



We will do a test after the training is done.
Send a message “I want to buy two hotdogs”, and we find that LUIS returns the Top scoring intent as Scenario1.

The result about Intent matches our expectation!
How about the Entities? Did they match as well?



Okay, if you want to see the detail, which is JSON format, of what LUIS returns, we have to publish our LUIS App.

Go to [Publish App] and publish it. Then back to [Train & Test] and make another test with [Enable published model].



This time the Published version results are included, and we can see the returned JSON by clicking Raw JSON view.




In the JSON, the entities are parsed correctly.
But if the entities are not correct or empty, that means we have to create more Utterances for training the LUIS model.

Another test way is using the endpoint url.





We completed the LUIS settings, we are going to update our messaging endpoint codes to support LUIS.


Implement


Install packages



Authentication

ID & Key factory

public static class LuisAppFactory
{
        static LuisAppFactory()
        {
            AppId = ConfigurationManager.AppSettings["LuisAppId"];
            AppKey = ConfigurationManager.AppSettings["LuisAppKey"];
            MinScore = 0;
        }

        public static string AppId { get; private set; }
        public static string AppKey { get; private set; }
}


Web.config

<appSettings>
    <add key="MicrosoftAppId" value="" />
    <add key="MicrosoftAppPassword" value="" />
    <add key="LuisAppId" value="XXXXXX" />
    <add key="LuisAppKey" value="YYYYY" />
</appSettings>


Get LUIS result

Call LUIS Api and get LUIS result

private async Task<LuisResult> getLuisResult(Activity activity)
{
      //Create LUIS Client
      var lc = new Microsoft.Cognitive.LUIS.LuisClient(LuisAppFactory.AppId, LuisAppFactory.AppKey);

      //Call Luis API
      var ret = await lc.Predict(activity.Text);
return ret; //回傳得分最高的Intent
}


Web API - ApiController

[HttpPost]
[Route("api/Msg/Hook/")]
public async Task<HttpResponseMessage> Hook([FromBody]Activity activity)
{
       var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
       var reply = activity.CreateReply();
                         
if (activity.Type == ActivityTypes.Message)
       {
        
            var replyMsg = string.Empty;
            
           
//Get the LUIS result
            var ret = await this.getLuisResult(activity);
           
            //Get the Intent with top score
            Intent topIntent = ret.Intents.OrderByDescending(x => x.Score).Take(1).FirstOrDefault();

           
//Set reply message
            replyMsg = ReplyMsgFactory.CreateIntentReplyMsg(ret, topIntent);
           
            reply = activity.CreateReply(replyMsg);      

            await connector.Conversations.ReplyToActivityAsync(reply);
            var response = new HttpResponseMessage(HttpStatusCode.OK);
            return response;
      }
}

The above codes will send the client’s message to LUIS Api and get the response JSON with Intents and Entities.

In the next step, we will use the TOP Intent to decide what message should Bot returns.


Reply strategy

The following reply strategy will reply the total cost when an user want to buy something.

public static string CreateIntentReplyMsg(LuisResult ret, Intent topIntent)
{
            //Convert Entities to IDictionary
            IDictionary<string, string> entities = new Dictionary<string, string>();
            foreach (var item in ret.Entities)  //Entities
            {
                item.Value.Each(ent =>
                {
                    entities.Add(new KeyValuePair<string, string>(ent.Name, ent.Value));
                });
            }

            string behavior = entities.Where(x => x.Key.Equals("Behavior", StringComparison.OrdinalIgnoreCase)).FirstOrDefault().Value;
            string count = entities.Where(x => x.Key.Equals("Count", StringComparison.OrdinalIgnoreCase)).FirstOrDefault().Value;
            string something = entities.Where(x => x.Key.Equals("Something", StringComparison.OrdinalIgnoreCase)).FirstOrDefault().Value;

            //The follwoing strategy is just for test,
//Create your own strategy here
            int cnt = int.Parse(count);
            if (behavior == "buy" && (something == "apple" || something == "apples"))
            {
                var sum = cnt * 50;
                return $"The {something} cost ${sum.ToString()}!";
            }
            else {
                return $"Sorry! Dunno!";
            }
}



Test




Summary


This tutorial shows the basic concept and usage of LUIS.
The frameworks are easy to use, what matters is what service you can provide and the reply precision. So the unit test and scenario test are very important for developing a ChatBot business.

Have fun talking to you Bot!