Building an AI News Feed with Azure Search and the Bot Builder Framework Part 1

Building an AI News Feed with Azure Search and the Bot Builder Framework

During some recent work around a new mobile app called Finwin (it will be open-sourced soon), we came across a requirement to feed news data based on search results for a particular company on the ASX. The idea behind the app is to have the latest finance and business news returned for a particular company.

Simple right?

All we have to do is spin up a Bing News Cognitive Service and query based on stock, company name and news type (business, finance, etc), i.e. “Business commonwealth bank” or “business CBA”

An Introduction to Microsoft’s Bot Builder Framework

A mobile app utilising a chat bot. Pay attention to the grey area, this is what we are going to build for our chat bot.

How do we plan to query the Bing News Service? Let’s build a chat bot.

Say hello to the bot builder framework. Microsoft provides a great flexible SDK for building chat bots. If you want to reduce time and effort with a bot, we have the ability to create a Functions bot. Its serverless without much code and no infrastructure. We also require language understanding so let’s have a look at LUIS.

What is LUIS?

Language Understanding Intelligent Service (LUIS). It comes with the Microsoft Bot Framework, let’s have a look at the LUIS portal. It can be a little daunting at first looking at the above architecture, but its actually simple and fast to implement. All we have to do is deploy a Functions bot or Web App bot and both the client and bot service is deployed for us. We must also spin up a LUIS service for language understanding where we build conversation patterns and how users interact via utterances, entities and intents.

What is an Intent?

Intents are conversation topics, they map to the user’s intent, in this example – to get company news. So we build utterance patterns that users ask to get this information. Each intent also includes their own entities and utterances.

What is an Entity?

Entities are items that a mapped to language typed into the chat bot. For example, if we ask the bot a question:

“Can I have the stock price for CBA”

Our entities may be “CBA” which will be an entity called stock_code. We may also have stock_price mapped to another entity called detail_request. Within the LUIS portal, we can customise our entities according to the questions being asked to the bot. Normally your language patterns are designed from the questions asked to the bot. Its best to start building the questions first that come from the user. In our case with Finwin, we had a bunch of questions down – here are 6 examples of utterances which are mapped to entities:

“can i have news for cba

“may i have news for commonwealth bank

“may i have news for cba

“what is the stock code for cba

“what is the predictedstock for cbatomorrow

All the bold text items in the questions are mapped to entities – stock_code, item, and company. The entities company and stock_code are two different entities that are utilised in the same way – they both reference a company we are querying.

Once we map out a good subset of questions, the entities will be more clear. Within the LUIS portal, once we add both our queries and entities, we click Train in the top right. We can’t deploy the chat bot until we have trained the bot at least once. Once our bot is trained, we can now move ahead and publish the chat bot. This means it will be deployed and we will have an api endpoint to call via POST meaning the bot is now portable to our mobile app.

Building Utterances and Intents using the LUIS portal – http://luis.ai. Unfortunately the portal is only available for deployments in the West US region. For other regions we have to utilise the API to make changes to LUIS applications.

Note

We can deploy the bot into a staging environment or a production environment.

What have we achieved so far?

Now that we have some understanding to the language queried to the bot, we have the ability to pull out the entities required for further processing – this is the AI part. Our bot has the ability to identify our entities. We will now utilise these entities to query our Bing News service.

Creating a Functions Bot

Warning

We have noticed some deployment issues in Functions with redeployments and versioning with new chat bot deployments. During this setup, a simple 10 minute task turned into an hour having to redeploy the same Functions service under the same name. We recommend using a different name for the Functions bot if for some reason you have to shut it down.

When a Functions bot is deployed, we get a function ‘messages’ which is called every time an utterance is sent through the chat bot client.

Remember a bot has two main parts, the physical chat client which takes the queries or utterances and returns results, and a LUIS service which identifies entities from queries. Now that our LUIS service returns the correct entities (stock_code, company, item), we will use this to pass over to the Bing News service using a HTTP client in a Dialog.

What is a Dialog?

Dialogs are used as models for a conversation to control the conversation workflow, i.e. In the case of Finwin, we created a new dialog called NewsDialog. If we are querying the bot for news requirements, we will be directed to the NewsDialog to handle all news requests.

Lets have a look at the code:


        [Serializable]
        [LuisModel("39275a89-60dc-4f91-be8f-d4ddc92b1ea8", "72bd2202e13b47948d4eeac2656b7a04")]
        public class NewsDialog : LuisDialog<object>
        {
            // Name of entity
            public const string company = "company";// fahrenheit";
            public const string companyItem = "company_item";//celsius";
            public const string newsType = "news_type";//100";
            public const string stockCode = "stock_code";//100";

            // methods to handle LUIS intents

            [LuisIntent("")]
            public async Task None(IDialogContext context, LuisResult result)
            {
                string message = $"try 100 f to c";
                await context.PostAsync(message);
                context.Wait(MessageReceived);
            }

            [LuisIntent("News")]
            publicasync Task SerialNumber(IDialogContext context, LuisResult result)
            {
                string tempStockCode = "not found";

                EntityRecommendation entity;

                if (result.TryFindEntity(stockCode, out entity))
                {
                    tempStockCode = entity.Entity;
                }

                if (!string.IsNullOrEmpty(tempStockCode)) 
                {
                    using (var client = new HttpClient())

                    {
                        var url = string.Format("http://finwin.azurewebsites.net/api/QueryBingNews");
                        var query = new { Query = tempStockCode };
                        var content = new StringContent(JsonConvert.SerializeObject(query));
                        var response = await client.PostAsync(url, content);
                        var jsonResponse = await response.Content.ReadAsStringAsync();
                        string message = $"response={jsonResponse}";
                        await context.PostAsync(message);
                    }
                }

                context.Wait(this.MessageReceived);
            }

        }

The SerialNumber function is called every time we pass a message to the NewsDialog. The EntityRecommendation object is used to extract an entity from the LuisResult, this entity being a stock code. We then use this stock code to pass through to an API call to the Bing News Service which ultimately returns news results according to the stock code, and voila we have artificial intelligence (really?).

To pass our utterances from the Function messages to the NewsDialog we add the following to the run.csx file:


switch (activity.GetActivityType())
{
case ActivityTypes.Message:
await Conversation.SendAsync(activity, () => new NewsDialog());
break;

.....

The switch statement above is automatically added into the run.csx file when you deploy a Functions bot. We simply change the ActivityTypes.Message case to pass the utterance to the NewsDialog which will call the function SerialNumber.

Creating a Web App Bot

One downside to a Functions Bot is it inly supports v3.0 of the Bot Builder SDK. There have been a lot of changes to the SDK since v4.0 was released. We recommend staying away from the Functions Bot until it upgrades to v4.0.

Creating a Web App Bot through the Azure Portal.

Deploying a Functions Bot or Web App Bot is simple, jump into the Azure portal and Create a New Resource. We must provide names for both service and resource group, an app service plan or consumption plan, bot template, the region for the LUIS application, and a storage account.

Bot Template

Bot templates include bot source code and services such as Language Understanding (not included in Echo Bot), Bot Analytics and Storage. We can select either v3.0 or v4.0 of the Bot Builder framework, we HIGHLY RECOMMEND staying with v4.0.

When deployment is complete, our bot template is deployed inside an app service, meaning we have a bot service and app service deployed. This also means we have more to manage around scalability and infrastructure underlying the app service plan. Because we are deploying a bot builder project inside the app service, we have to work inside a bot builder project in Visual Studio. Next time let’s look at a bot builder project in Visual Studio, and how we replicate the Functions code above using the bot builder framework v4.0.

Posted in Blog