Thursday, June 30, 2016

Unit Converter Bot

Unit Converter Bot converts from one unit to another. You can use it by asking questions like “How many liters in 3 quarts?” or “Please convert 5 pounds to kilograms.”

image

My goals for Unit Converter Bot were to have a limited scope, use natural language processing, and handle unknown conditions.

Limited Scope

The reason I wanted limited scope is to be able to create a bot in a decent amount of time, make building it manageable, and give potential users a definitive reason to use the bot. I think there are concepts out there where people are building bots with a wide array of features. If I had embarked on something like that, I wouldn’t be writing this blog post right now because I would still be building the bot. Limiting scope also increases the quality of Unit Converter Bot because it reduces the number of possibilities of what people can say to the bot. What I’ve learned so far is that even with simple conversions, there are many ways to request the same thing. Combined with the number of possible conversions, the complexity increases. Limiting scope reduces this complexity. Users would benefit from the bot’s limited scope because they know that this bot does one thing and won’t be confused in what’s it’s purpose is. By focusing on one thing, my bot has the potential to be awesome for conversions only and thus more useful.

Natural Language

Engaging in conversation is the sweet spot for bots. In the future, people won’t want to constantly learn new UI’s, they’ll just want to ask a question and get an answer. Many current bots aren’t much more than a messaging based imitation of an app or Web site – and that’s okay because I’m not advocating a one-size-fits-all approach to bots. What I am saying is that the conversational aspect of bots is so compelling that it should be strongly considered in addition to buttons and menus. Unit Converter Bot uses natural language processing and is pretty decent at understanding the question. Considering the vast number of possibilities of how someone could ask a conversion question, there’s undoubtedly questions that the bot won’t understand. However, it will continue to improve to the point that not understanding a conversion question will be a rare occurrence.

Graceful Recovery

People ask bots all kinds of things. If someone were to ask about the weather, Unit Converter Bot will politely let it know that it doesn’t understand the request. However, stopping at the point of misunderstanding is a missed opportunity. You have to think, “what is the goal of the bot?” In this case it’s unit conversions and the bot needs to do everything it can to help the person reach their goal. So, Unit Converter Bot has a backup strategy where it takes the user step-by-step through a set of questions to perform the conversion. This increases the possibility that the user will have a successful experience with the bot. My goal was to not just leave people hanging when the bot doesn’t understand them, but to take extra measures to help them achieve their goal.

Parting Thoughts

This was a great exercise in designing and building a bot that I thought should stand up to higher standards than the demo’s I’ve been blogging about. It’s been a good learning experience and I expect to learn more from it. I built this on the Microsoft Bot Framework. Though it resides on all supported channels, a few channels are pending final approval.

@JoeMayo

Thursday, May 26, 2016

LUIS and the Bot Framework: A Natural Language Match

My previous Bot Framework posts have concentrated on the sophisticated conversation management facilities of Bot Connector and Bot Builder. While those are amazing capabilities, they don’t offer much more in user interaction than could be handled by a command line utility. For a bot to be truly conversational, it needs to move beyond primitive single word grunts and understand more naturally spoken language.

Language Understanding Intelligent Service (LUIS) is a natural language service that helps your bot be more conversational. It works by building models that classify utterances (language statements) and extracts data from those utterances, providing actionable results for your bot code. The Bot Framework has types that integrate smoothly with LUIS to help your bot understand natural language statements. This post will describe a model I created with LUIS and show you how to integrate that model into a bot.

The LUIS Model

To get started with LUIS, you need to build a model. A LUIS model is a service that uses machine learning to recognize utterances and provide a probability score of how close it thinks that utterance is to Intents and Entities. Intents are things that a user wants to accomplish or obtain information on. Entities are the data points associated with those intents. In your Bot Framework code, you map Intents to methods and use Entities like they were parameters. The LUIS Help pages has an excellent video that explains how to get started, building a LUIS model.

For this demo, I created a ContactInfo model. The purpose of the model is to support a contact management bot. The BotDemos source code for this post includes a LUIS Models folder that contains the ContactInfo.json file that contains the ContactInfo model. This model has a couple intents: None and ChangeInfo. The None intent is the default for catching unrecognized utterances. The ChangeInfo intent supports utterances for when the user wants to change some of their contact information. The ChangeInfo model has a single entity named ContactType, which could be an address, name, phone number, or email. Make sure your train and publish your model before trying to access it via the Bot Framework. After you publish your model, the App Settings on your page will contain an App Id and Subscription Key, which are necessary to add to your Bot code that integrates with LUIS, which is covered next.

Implementing a LuisDialog

To get started with using LUIS, I created a new Bot Framework project. If you don’t know how to do this yet, you can learn from one of my earlier posts, Pig Latin Bot. To start, I created a ContactInfoDialog class that derives from LuisDialog<object> like this:

    [Serializable]
    [LuisModel(
        "<your App ID goes here>",
        "<your subscription key goes here>")]
    public class ContactInfoDialog : LuisDialog<object>
    {
        public const string ContactType = "ContactType";
        string currentEntity = "";
    }

As is typical of Bot Framework dialogs, you need to make it Serializable if you wish to retain state. The LuisModel attribute allows logic in LuisDialog to communicate with LUIS, using the App ID and Subscription Key from your model, ContactInfo in this case. The LuisDialog type parameter is the result type of the dialog, which contains collected information for a stateful bot. Since we aren’t maintaining state in this simple demo bot, I set the LuisDialog type to object. ContactType is the entity we’ll work with and it’s a const to avoid working with strings. Since later code navigates between methods, I’ll keep the name of the current ContactType entity in the currentEntity field. The ContactInfoDialog class has methods that handle intents and you’ll see what happens when LUIS doesn’t recognize an utterance in the next section.

Handling Unrecognized Utterances

You can set up a method in a LuisDialog to handle cases where your LUIS model doesn’t recognize an utterance. Just create the method and decorate it with a LuisIntent attribute containing an empty string. Here’s an example:

        [LuisIntent("")]
        public async Task None(
             IDialogContext context,
             LuisResult result)
        {
            string userUtterance = result.Query;
            await context.PostAsync(
                $"Sorry, I didn't understand \"{userUtterance}\".");
            context.Wait(MessageReceived);
        }

As mentioned, the LuisIntent attribute with the empty string parameter indicates that LUIS didn’t understand what the user said. The None method has IDialogContext and LuisResult parameters. The IDialogContext parameter is the same as used in all dialogs and you can see how the method uses it to call context.PostAsync to let the user know that the bot couldn’t understand them and then context.Wait to wait for the next message. LuisDialog has an implementation of MessageReceived that it uses to interact with LUIS when the next message from the user arrives. You can use LuisResult to extract information about the user’s utterance, as None does by reading result.Query.

Note: You can visit the LUIS model, click on Review Labels, and classify utterances that aren’t part of your training set. This lets you continuously improve your LUIS model with real data.

Next, we’ll handle an utterance that LUIS does recognize.

Handling Valid Intents

To match methods to intents, decorate the method with a LuisIntent attribute containing a parameter matching the intent name from the LUIS model to handle. Then add the logic you need to handle what the user asks for. Here’s an example for the ChangeInfo intent:

        [LuisIntent("ChangeInfo")]
        public async Task ChangeInfo(
            IDialogContext context,
            LuisResult result)
        {
            EntityRecommendation entityRec;
            result.TryFindEntity(ContactType, out entityRec);

            currentEntity = entityRec.Entity;

            PromptDialog.Text(
                context: context,
                resume: ResumeAndHandleTextAsync,
                prompt: 
                    $"What would you like to change your” +
                    $” {currentEntity} to?",
                retry: "I didn't understand. Please try again.");
        }

        public async Task ResumeAndHandleTextAsync(
            IDialogContext context,
            IAwaitable<string> argument)
        {
            string newEntityValue = await argument;

            await context.PostAsync(
                $"Your {currentEntity} is now {newEntityValue}");

            context.Wait(MessageReceived);
        }

The ChangeInfo method handles the LUIS ChangeInfo intent. The IDialogContext and LuisResult parameters serve the same purpose as described earlier, except that this time we need to read the associated entity to implement appropriate logic. Here, the code uses result.TryFIndEntity to obtain a reference to the ContactType entity. In real code, you would want to have more logic for recognition and validation of the entity.

The code performs a prompt for the text to change the bit of contact info to and then waterfalls to ResumeAndHandleTextAsync to work with the user’s response. Again, this code calls context.Wait(MessageRecieved) to continually wait for the user’s input.

Here’s an interaction with ContactInfo bot, showing how it responds to various utterances.

image

Summary

Now you know how to integrate a LUIS model with the Microsoft Bot Framework. Create and publish the model, create a class derived from LuisDialog, add App ID and Subscription Key to the LuisModel attribute, and use the LuisIntent attribute to decorate methods that handle LUIS model intents. For more information on running and testing a bot, you can visit previous posts in my blog. You can also find the code (including the ContactInfo model) on my GitHub site.

 

@JoeMayo

Friday, May 6, 2016

Dynamic FormFlow Forms in Bot Builder

In a previous post on Bot Builder FormFlow, I described how to automatically construct a dialog with just a class, properties, and a few other methods. The demo was a bit rigid because I used enums to define choices. In practice, you won’t always know ahead of time what choices will be available or the choices could change over time. So, you need a data-driven approach. This post shows how to dynamically define those choices and still have the benefits of FormFlow. This is nearly identical to my previous FormFlow post, except for a couple items that I’ll describe in this post.

Specifying the Dynamic Property

The previous FormFlow example defined the Product property as a Product enum. This is a good candidate for a dynamic data-driven property because over time a bug report will need to accommodate all of the products you support. Here’s the updated BugReport class.

    [Serializable]
    public class BugReport
    {
        public string Product { get; set; }

        public List<PlatformOptions> Platform { get; set; }

        public string ProblemDescription { get; set; }
    }

Here you can see the Product is a string so that it can hold the value that the user enters. The following method simulates a data-driven approach to obtaining the values that can be assigned to Product.

        static List<string> GetProducts()
        {
            return new List<string>
            {
                "Office",
                "SQL Server",
                "Visual Studio"
            };
        }

The GetProducts method returns a collection of strings that can be assigned to the Product property. Now, let’s see how to use these strings in a FormFlow dialog.

Adding a Dynamic Field

In this demo, we’ll modify the BuildForm method, which is a member of the BugReport class. In the previous example, the BuildForm implementation was pretty simple by showing a message, specifying an OnCompletionAsync handler, and initiating the dialog. The difference in this demo is that the code specifically directs which fields/properties to display. Here’s the changed BuildForm method.

        public static IForm<BugReport> BuildForm()
        {
            return new FormBuilder<BugReport>()
                    .Message("Welcome to Bug Report bot!")
                    .Field(new FieldReflector<BugReport>(nameof(Product))
                            .SetType(null)
                            .SetDefine((state, field) =>
                            {
                                foreach (var prod in GetProducts())
                                    field
                                        .AddDescription(prod, prod)
                                        .AddTerms(prod, prod);

                                return Task.FromResult(true);
                            }))
                    .Field(nameof(Platform))
                    .AddRemainingFields()
                    .OnCompletionAsync(async (context, bugReport) => 
                     {
                        await context.PostAsync("Thanks for the report!");
                     })
                    .Build();
        }

In this code, the Field methods describe exactly which properties to display and in what order. FormFlow uses reflection, which the FieldReflector class helps with. The SetDefine method dynamically defines the field. It uses the GetProducts method, shown earlier, and iterates through the list of strings. This is just a demo, so AddDescription and AddTerms use the same string as the parameter key and value. If this was a real bot, GetProducts would read from a database table and return a custom class that contained all of the meta-data required to populate description and terms with more useful values.

Since FormBuilder is a fluent interface, you can continue specifying fields to add and optionally use AddRemainingFields for FormFlow to work normally on any following fields. The rest of the program works the same ways as my previous post on FormFlow.

Summary

This post explained why the default FormFlow wasn’t flexible enough for all scenarios. I defined a string type property and a method that returned all the values that could be assigned to that property. Then you saw how to modify the BuildForm method to specify fields and dynamically define a field with custom data. Now, you’re able to make a bot more adaptable to changes with dynamic fields.

The code for this post is available via my BotDemos GitHub repository.

@JoeMayo

Monday, May 2, 2016

Bot Builder FormFlow

In a previous post on Bot Builder Dialogs, I discussed how you could manage conversations with users. While this wasn’t too hard, consider the amount of complexity involved with a larger conversation. To help simplify the conversation, Bot Builder has another library named FormFlow. In this post, I’ll introduce FormFlow and show you how it can help simplify bot conversations.

What is FormFlow?

FormFlow is a Bot Builder SDK library that lets you declare the type of information you need and then it does the bulk of the work of managing the conversation and moving the user from question to question automatically. In Dialogs, you have the responsibility of writing the methods to prompt the user and collect the results, but FormFlow simplifies the entire process. Another benefit of FormFlow is that it automatically formats questions to be more readable and it tries to process partial answers if it can. Here’s a screen shot of the Bug Report Bot.

image

To implement FormFlow, define a class with properties and/or methods, decorate the class and members with attributes for customization, and initialize the form when the user communicates with your bot. Because this is only an intro, I’ll limit the scope of the demo to only show how to get FormFlow working and some basic control flow. The demo program is a modification of the Bug Report example from my Bot Builder Dialogs post. The next section explains how to create a form.

Creating a FormFlow Form

As mentioned earlier, a Form is a class with fields and/or properties to hold the information you need. For the Bug Report demo, I just need to know the product, platform, and description, as shown in the following code.

    [Serializable]
    public class BugReport
    {
        public ProductOptions Product { get; set; }

        public List<PlatformOptions> Platform { get; set; }

        public string ProblemDescription { get; set; }
    }

To properly manage state, your form must be serializable, which is why the BugReport class has a Serializable attribute. The property types are enums, with a member for each valid choice a user could make. Each property holds the value of the choice that the user makes. If the choice type is a List, FormFlow allows the user to enter multiple items for that answer.

One of the benefits of FormFlow is it’s conventions for readable options. e.g. When the bot asks the user for the value it will place into the ProblemDescription property, it will break words by capitalization and print “Problem Description” to the user. Same thing with the enum values.

Configuring the Form

To make the BugReport class a form, instantiate a FormBuilder and tell it the type of form to work with.  Here’s a basic example of how to do that.

        public static IForm<BugReport> BuildForm()
        {
            return new FormBuilder<BugReport>()
                    .Message("Welcome to Bug Report bot!")
                    .OnCompletionAsync(async (context, bugReport) => 
                     {
                        await context.PostAsync("Thanks for the report!");
                     })
                    .Build();
        }

The BuildForm method returns an FormBuilder<BugReport> instance. The FormBuilder gives you a fluent interface, where you can chain several methods together. Message shows a message to the user, which is when the bot starts communicating. There are many methods you could add to this chain to customize the FormFlow conversation and there’s more explanation for those that I won’t cover in this post. FormBuilder will manage the conversation, using the BugReport class.

When the bot finishes, the lambda passed to OnCompletionAsync communicates with the user again. This is where you could take action to do something with the report, like save it in a database or submit to a Web service. The context is the DialogContext, as explained in my Bot Builder Dialogs post and the lambda uses context to send a final message to the user. The lambda’s bugReport parameter holds the BugReport class instance, holding the state that FormFlow collected, which you can use to extract user answers.

I put the BuildForm method inside the BugReport class. The next section shows how to call BuildForm to start bot communication.

Starting the FormFlow Conversation

Now that you have a form (class used as a form) and that form is configured with FormBuilder, you need to start the the conversation. The following example is from the MessageController and shows the flow of control that occurs when the user communicates with your bot.

    public class MessagesController : ApiController
    {
        internal static IDialog<BugReport> MakeRootDialog()
        {
            return Chain.From(() => FormDialog.FromForm(BugReport.BuildForm))
                        .Loop();
        }

        public async Task<Message> Post([FromBody]Message message)
        {
            return await Conversation.SendAsync(message, MakeRootDialog);
        }
    }

Just as with Dialog conversations, the Post handler method in MessagesController calls Conversation.SendAsync. This argument references a method, MakeRootDialog, to instantiate the dialog. Inside the Chain.From lambda, FormDialog.FromForm references the BuildForm method, from the previous section. It’s saying that as the dialog for this conversation, use the BugReport form.

Chain is interesting in that it has convenience methods for managing forms. This example only uses From and Loop, but there are more that help manage more sophisticated conversations. Loop allows the user to start at the beginning again after the current BugReport form has completed.

Summary

Now you’ve seen how FormFlow makes it easy to manage conversations. You create a class with properties, configure that class with a FormBuilder, and create an instance of the FormBuilder when the user communicates with your bot. In addition to knowing how to start the conversation, you also saw how to handle the end of the conversation via the OnCompletionAsync  method.

 

@JoeMayo

Thursday, April 21, 2016

Bot Builder Dialogs


The Bot Framework includes a Bot Builder SDK that helps you manage conversations with users, including Dialogs, Form Flow, and other supporting types. The Bot Builder SDK is open source, supporting both C# and Node.js, and you can visit the source code on GitHub.

This post is an introduction to Dialogs and shows you how to use types that prompt a user, move between questions, and manage state. The example I’m using is a Bug Report Bot. It isn’t very sophisticated, but is designed to show you how to manage a simple conversation, using dialogs.

Project Set-Up

You can get started with the normal Bot Framework template, described on the Bot Framework Getting started page. The template already gives you a reference to the Microsoft.Bot.Connector library and now you’ll need a reference to the Microsoft.Bot.Builder library, which you can load via NuGet. Here’s the Package Manager console command if you prefer:
PM> Install-Package Microsoft.Bot.Builder
With your project set up and configured, you can start building dialogs.

Getting Started

A dialog is a class with state and methods that use Bot Builder types to manage interactions between bot and user. For the Bug Report Bot, I’ll create a class that contains fields and methods. State is important because it holds important information about an ongoing conversation. The following BugReportDialog class shows how to code for managing state.
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;

namespace BugDialogBot
{
    [Serializable]
    class BugReportDialog : IDialog<object>
    {
        ProductOptions productOptions;
        PlatformOptions platformOptions;
        string description;
        
        // other members omitted until later
    }
}
The Bot Framework manages conversations by sending JSON messages through the Bot Connector and to/from user and bot. These messages hold the state of an ongoing conversation. To facilitate managing state with the Bot Framework, your dialog type must be serializable. To support this, the code decorates the BugReportDialog class with the Serializable attribute. Additionally, the class contains fields, representing the state of the conversation. Besides making your dialog class serializable and storing values in serializable fields and/or properties, you don’t have to do anything extra to manage state, because that’s one of the benefits of Bot Framework Dialogs. Both ProductOptions and PlatformOptions are enum types, shown below:
    public enum ProductOptions
    {
        Office,
        SQLServer,
        VisualStudio
    }

    public enum PlatformOptions
    {
        Linux,
        Mac,
        Windows
    }
These enum typess represent options that the user can select when prompted. The fields will hold the user’s response so that we have all of the user’s responses when reaching the end of the conversation/dialog.
Another interesting part of the BugReportDialog is the fact that it implements IDialog<object>, which I’ll discuss next.

The Dialog Entry Point

For IDialog<T>, you implement its single member, StartAsync, which is the entry point for the dialog. Within StartAsync, you’ll specify which dialog method the Bot Framework calls to initiate a conversation. The following code shows the StartAsync implementation for the Bug Report Bot:
    [Serializable]
    class BugReportDialog : IDialog<object>
    {
        ProductOptions productOptions;
        PlatformOptions platformOptions;
        string description;
        
        public async Task StartAsync(IDialogContext context)
        {
            context.Wait(ConversationStartedAsync);
        }
        
        // other members omitted until later

    }
The StartAsync method accepts an IDialogContext parameter, context, which has members to help you manage state and various aspects of a conversation. It’s essentially a convenient hook for various services in the Bot Framework. You’ll see IDialogContext again in later parts of this post because the Bot Framework passes it to every other dialog method. The StartAsync method for BugReportDialog uses the Wait method of context to specify the starting method, ConversationStartedAsync, to call when the user initiates a conversation with the bot. The next section shows how to write that starting method.

Interacting with the User

When the user initiates a conversation with the bot, the StartAsync method specifies which dialog method to start with. In the previous code, that was ConversationStartedAsync, which is shown below:
        public async Task ConversationStartedAsync(IDialogContext context, IAwaitable<Message> argument)
        {
            Message message = await argument;
            await context.PostAsync(message.Text);

            PromptDialog.Choice(
                context: context,
                resume: ResumeAndPromptPlatformAsync,
                options: Enum.GetValues(typeof(ProductOptions)).Cast<ProductOptions>().ToArray(),
                prompt: "Welcome to the Bug Report Bot! Please select the product you're having a problem with (SQLServer or VisualStudio):",
                retry: "I didn't understand. Please try again.");
        }
As mentioned earlier, every dialog method receives a IDialogContext parameter, context. They also receive an IAwaitable<T>, argument. The T is whatever type the method is expecting. Since StartAsync called context.Wait(ConversationStartedAsync), the T will be Message. The T will be specified by the previous method in the dialog chain and you’ll see how that works when covering subsequent methods in this post.
Since argument is awaitable, the code awaits to reference the Message passed by the Bot Framework. This lets you evaluate the value of the argument and build logic to handle the information that the user provided. In this example, we’re interested in the message.Text that the user typed. This is normally “Hi” or “Hello” and the code echoes that back to the user by calling the context.PostAsync method.
PromptDialog is a type in the Bot Builder SDK that manages an interaction with the user. There are different types of prompts, such as Yes/No, string, and number. The Choice prompt lets the user pick one of a number of options. Notice the Enum array passed as the options parameter. The user can choose one of the ProductOption types, mentioned earlier in this post. The prompt dialog uses a convention of breaking the words at capitalized letters in each Enum value – so ProductOptions.VisualStudio becomes “Visual Studio” to the user.
On the other PromptDialog parameters, context is the IDialogContext that I discussed earlier where the Bot Framework passes that to dialog methods. The prompt is the question the bot asks the user and retry is the message the bot uses if it doesn’t understand what the user typed.
What’s interesting here is the resume parameter. When you have a series of interactions, you can specify each of those interactions with a dialog method. The resume parameter specifies which dialog method to call after the user responds. In this case, the next dialog method is ResumeAndPromptPlatformAsync, which I’ll describe in the next section.

Managing Conversation Flow

As the user interacts with a bot, the Bot Framework routes those interactions to the dialog method you specified to handle the next user message. Since the ConversationStartedAsync method called PromptDialog the user’s response goes to the ResumeAndPromptPlatformAsync method as the argument parameter, shown below:
        public async Task ResumeAndPromptPlatformAsync(IDialogContext context, IAwaitable<ProductOptions> argument)
        {
            productOptions = await argument;

            PromptDialog.Choice(
                context: context,
                resume: ResumeAndPromptDescriptionAsync,
                options: Enum.GetValues(typeof(PlatformOptions)).Cast<PlatformOptions>().ToArray(),
                prompt: "Which platform did the problem occur on? (Linux, Mac, or Windows):",
                retry: "I didn't understand. Please try again.");
        }

        public async Task ResumeAndPromptDescriptionAsync(IDialogContext context, IAwaitable<PlatformOptions> argument)
        {
            platformOptions = await argument;

            PromptDialog.Text(
                context: context,
                resume: ResumeAndPromptSummaryAsync,
                prompt: "Please provide a detailed description of the problem:",
                retry: "I didn't understand. Please try again.");
        }
public async Task ResumeAndPromptSummaryAsync(IDialogContext context, IAwaitable<string> argument) { description = await argument; PromptDialog.Confirm( context: context, resume: ResumeAndHandleConfirmAsync, prompt: $"You entered '{productOptions}', '{platformOptions}', and '{description}'. Is that correct?", retry: "I didn't understand. Please try again."); }
There are three dialog methods above, each with their own argument handling and PromptDialog. All three methods store the argument in a class field, which is part of the state of the dialog class, so we can remember the user’s choices. A couple of the PromptDialogs are different from what you’re seen previously. PromptDialog.Text takes a freeform string from the user and PromptDialog.Confirm takes a Yes or No answer. The PromptDialog accepts a certain type and when the user responds, the argument parameter for the resumed dialog method is the type of the previous PromptDialog. Eventually, you’ll reach the end of the report.

Completing the Report

The PromptDialog.Confirm in the previous section summarized the options the user chose and asked them if that was correct. The next dialog method, ResumeAndHandleConfirmAsync, evaluates their response, replies accordingly, and re-starts the Bug Report Bot at the beginning so the user can add another Bug Report, if they like:
        public async Task ResumeAndHandleConfirmAsync(IDialogContext context, IAwaitable<bool> argument)
        {
            bool choicesAreCorrect = await argument;

            if (choicesAreCorrect)
                await context.PostAsync("Your bug report has been submitted. Thanks for the feedback!");
            else
                await context.PostAsync("I see. You're welcome to try again.");

            context.Wait(ConversationStartedAsync);
        }
Here, I’m doing more work with the argument, using an if statement to determine an appropriate response to the user. Since I don’t need a response from the user, I don’t use a PromptDialog. The IDialogContext has a helper method, PostAsync, that lets you send a message to the user. This would have been a good opportunity to put additional logic that submitted the bug report and cleaned up state. The IDialogContext has another method, Wait, which will set which dialog method the Bot Framework sends the next message to, which is the ConversationStartedAsync that you saw at the beginning of this post.

Summary

This post described how to use Bot Framework Dialogs. You saw how to configure dependencies and create a dialog class. The StartAsync method is the entry point to a dialog conversation and you build a chain of dialog methods from there. There are several types of PromptDialog methods, each allowing you to obtain different types of information from a user. You saw how to manage state, which allowed summarizing choices at the end of the dialog to complete the operation. In a later blog post, I’ll build on dialogs with an even more powerful Bot Builder tool named FormFlow.

@JoeMayo

Sunday, April 10, 2016

Using the Bot Framework Chat Control

One of the places you can use a Microsoft Bot Framework bot is on your own Web page. There is a Chat control you can use and this post discusses this and shows an example.
Note: If you had trouble with the chat control earlier, there was a bug, but that is now fixed and the Chat control documentation is updated.
This post shows an implementation with the MVC Web API. Essentially, there are two techniques: insecure and secure, but let’s look at the HTML page setup first.

Setting up the HTML Page

The Bot Framework template includes a default.htm page and this is where I load the Chat control. I’m building on the Pig Latin Bot and the following shows the default.htm implementation:
<!DOCTYPE html>
<html>
<head>
    <title>Pig Latin Bot</title>
    <meta charset="utf-8" />
</head>
<body style="font-family:'Segoe UI'">
    <img src="images/PigLatinBot.png" alt="Pig Latin Bot"/>
    <h1>Pig Latin Bot</h1>
    <p>Translates your text to Pig Latin.</p>

    <div id="webChatControl">

    </div>

    <script src="https://code.jquery.com/jquery-1.12.0.min.js"></script>
    <script type="text/javascript">
        $("#webChatControl").load("api/WebChat");
    </script>
</body>
</html>
The location of the Chat control is in the div with the webChatControl id. After loading the script from MaxCDN, the next script block loads the chat control via jQuery. Notice the call to the relative api/WebChat endpoint. I’ll explain that next.

Using a Secret Key

The endpoint, the page calls, addresses an MVC Web API. It handles GET requests and returns the <iframe/> HTML for injection into the page. Here’s the implementation:
    public class WebChatController : ApiController
    {
        public async Task<string> Get()
        {
            string webChatSecret = ConfigurationManager.AppSettings["WebChatSecret"];

            return $"<iframe width='400px' height='400px' src='https://webchat.botframework.com/embed/PigLatinBotJoeMayo?s={webChatSecret}'></iframe>";
        }
    }
The WebChatSecret is a key in Web.config appSettings that contains a value for the secret key of the Chat control. You can get this key from your Bot Framework My bots page, edit the Web Chat channel, and generate keys. In the <iframe/> HTML string, replace PigLatinBotJoeMayo with the App ID of your bot. Notice that the parameter is s and it holds your bot’s secret key.
Rather than all of the ceremony for calling the Web API, reading secret key configuration, and injecting the result into the page, I could have coded the HTML directly into the page and been done with it. However, I have a point to make. Earlier, I mentioned that there were two techniques: insecure and secure. This was the insecure technique because whether you paste the HTML into the page or return HTML via a Web API call, the secret key is still part of the page that the user can see, which is insecure.
That said, security is relative. In this case, it depends on whether you intend for anyone in the world to load the Chat control onto their own page and use your key. In that case, this practice isn’t insecure at all. However, if this isn’t your intention, the next section explains a more secure way to handle keys.

Using a Token

If you don’t want to share your secret key with the world, another option is to use a token. It works like this:
  1. Add your secret key as a header value in an HTTP GET request
  2. Send the request and receive a token as a response
  3. Use that token as a parameter in the <iframe/> src URL
Here’s an updated WebChatController that shows how to do this:
    public class WebChatController : ApiController
    {
        public async Task<string> Get()
        {
            string webChatSecret = ConfigurationManager.AppSettings["WebChatSecret"];

            var request = new HttpRequestMessage(HttpMethod.Get, "https://webchat.botframework.com/api/tokens");
            request.Headers.Add("Authorization", "BOTCONNECTOR " + webChatSecret);

            HttpResponseMessage response = await new HttpClient().SendAsync(request);
            string token = await response.Content.ReadAsStringAsync();
            token = token.Replace("\"", "");

            return $"<iframe width='400px' height='400px' src='https://webchat.botframework.com/embed/PigLatinBotJoeMayo?t={token}'></iframe>";
        }
    }
Instantiating an HttpRequestMessage sets up the GET request to the Bot Framework api/tokens endpoint. Set the Authorization with BOTCONNECTOR and your secret key. In this scenario, the only time you’ll use your secret key is to request a token.
The SendAsync method uses that request, makes the call and returns the token. In previous versions, the documentation called for doing a POST that returned JSON. Now, the response contains just a token as a string. In the current implementation, the Bot Framework is returning a quoted token. e.g. “\”<token>\”” That’s the reason for the Replace call, to strip those quotes out. I’m not sure if the token will have those quotes in the future because they feel unnecessary, but you can hit a breakpoint and look at the value  of token in case it changes in the future and you might not need the Replace.
Finally use the token in the <iframe/> src query string parameter. Notice that the parameter is not s, as it was in the previous example for using the secret key, but is now t because you are using a token.
You might say that now anyone can read the token, and that would be true. The reason this is more secure is because that token will expire and can’t be used across sessions.

Summary

The Bot Framework Chat control is a convenient way to add a Bot to your Web site. You have a couple ways to use it via a secret key alone or by exchanging the secret key for a token. The implementation described in this blog post was to use jQuery to call an MVC Web API, return the HTML for the Web Chat control, and inject that control into the page. That is more secure by not exposing your secret key to the world.
@JoeMayo

PC Bot

The PC in PC Bot means Politically Correct – because it reacts to every event. During its lifetime, a (Microsoft Bot Framework) bot can have many different types of messages, in addition to a normal text message from the user. You can know when a user or bot is added or removed, when a conversation ends, and a couple other message types. This post explains PC Bot and discusses a few interesting aspects of message type handling.
Note: PC Bot doesn’t overreact, as you would expect of proper botiquette.

What are the Message Types?

The Bot Framework documents several Message Types. A lot of folks would probably feel like I do that the names are pretty descriptive. To handle these messages, I created a MessageHandler class, containing the following React method:
        public Message React(Message eventMessage)
        {
            Message responseMessage = null;

            BotEvent eventType = GetBotEvent(eventMessage.Type);

            switch (eventType)
            {
                case BotEvent.BotAddedToConversation:
                    responseMessage = ReactToBotAdded(eventMessage);
                    break;
                case BotEvent.BotRemovedFromConversation:
                    responseMessage = ReactToBotRemoved(eventMessage);
                    break;
                case BotEvent.DeleteUserData:
                    responseMessage = ReactToDeleteUser(eventMessage);
                    break;
                case BotEvent.EndOfConversation:
                    responseMessage = ReactToEndConversation(eventMessage);
                    break;
                case BotEvent.Message:
                    responseMessage = ReactToMessage(eventMessage);
                    break;
                case BotEvent.Ping:
                    responseMessage = ReactToPing(eventMessage);
                    break;
                case BotEvent.UserAddedToConversation:
                    responseMessage = ReactToUserAdded(eventMessage);
                    break;
                case BotEvent.UserRemovedFromConversation:
                    responseMessage = ReactToUserRemoved(eventMessage);
                    break;
                case BotEvent.Unknown:
                default:
                    responseMessage = ReactToUnknown(eventMessage);
                    break;
            }

            responseMessage.Text += 
                ", JSON: " + JsonConvert.SerializeObject(eventMessage);

            return responseMessage;
        }
The listing above contains a switch statement with a case for each message type. Although this is a demo, I showed a little bit of defensive programming, by adding the BotEvent.Unknown case with a fall-through to the default case. Each case calls a method, specifically for that message type. I’ll explain the JSON part of the message, at the bottom of the method in an upcoming section.
Notice that each of the cases are an enum member. The BotEvent enum isn’t part of the Bot Framework – I added it myself. That’s why the React method calls the GetBotEvent method, shown below, ahead of the switch statement.
        BotEvent GetBotEvent(string eventType)
        {
            BotEvent botEvent;

            if (!Enum.TryParse<BotEvent>(eventType, out botEvent))
                botEvent = BotEvent.Unknown;

            return botEvent;
        }
The GetBotEvent method above tries to convert the message type from a string to a BotEvent type. If that doesn’t work, it returns BotEvent.Unknown. I could have simply created case statements as strings, but if you prefer a more strongly typed approach, this is one.
You might ask, “Why aren’t the messages already strongly typed?”. The reason has to do with the fact that the Bot Framework is cross-platform. As long as you give it a compatible interface (e.g. Post endpoint with appropriately formatted JSON content and message types), the Bot Framework is okay with that. In other platforms, strongly typed could mean something very different, but strings are well-known. A perfect example of another platform is node.js, for which the Bot Framework already has a Node.js SDK.

Handling Message Types

The messages called in the switch case statements receive a request message and return a response message, containing acknowledgement and some diagnostic details. Here’s an example of methods to handle UserAddedToConversation and UserRemovedFromConversation messages:
        Message ReactToUserAdded(Message eventMessage)
        {
            return eventMessage.CreateReplyMessage(
                $"User Added From - Address: {eventMessage.From.Address}, Name: {eventMessage.From.Name}");
        }

        Message ReactToUserRemoved(Message eventMessage)
        {
            return eventMessage.CreateReplyMessage(
                $"User removed From - Address: {eventMessage.From.Address}, Name: {eventMessage.From.Name}");
        }
Each method uses the CreateReplyMessage method to build a response message, but notice the interpolated string expressions. They’re reading the From property of the eventMessage, which contains additional information. Some bots might want to keep track of who they’re speaking with for proper conversation context and this would be an easy way to do so. There are many other properties of the Message type to obtain information on the particular event.
Additionally, you can also collect state for debugging and diagnostics.

Debugging?

To test your logic on most of these messages, you can use the Bot Framework Emulator, shown below:
image
Tip: When you’re working with multiple bots, it’s convenient to change the bot’s port number. The port number, in the emulator, for PC Bot is 3977 (not the default 3978).
The gray toolbar, above the JSON window, has a drop-down list with various message types. Select the message you want and click the Send button. In the figure, I selected the User Removed From Conversation message type. The chat window shows the response from the bot, which corresponds to the ReactToUserRemoved method response above.
You also see a lot of JSON in the response message, repeated below, which came from the bottom of the React method, before returning the responseMessage:
            responseMessage.Text += 
                ", JSON: " + JsonConvert.SerializeObject(eventMessage);
You see, the Bot Framework Message type serializes to JSON very easily. One problem this solves is when learning how to work with a new channel. There are only a few channels available as I write this blog post, but there will be more in the future. Each channel has it’s own unique characteristics. The Bot Framework accounts for this via a channelData property where you can read meta-data specific to that channel. The emulator doesn’t have this property, but the Slack channel and others do. You need a way to see what the channel is sending your bot. You could say, “Well, I’ll just read the documentation.” and you would be right, until you’re not. Documentation gets old, changes, and sometimes doesn’t exist and being able to inspect those values can be helpful.

Using MessageHandler

Here’s how I use the MessageHandler class:
        public async Task<Message> Post([FromBody]Message message)
        {
            return new MessageHandler().React(message);
        }
Because this bot is PC, it will react to every message.
@JoeMayo