How to build a simple conversation bot with Microsoft Bot Framework

Lets build a simple conversation bot who will decode our emotions & will try to cheer us.

Basic Idea is to get, how the user is feeling now, then pass the feelings to Cognitive services & get the sentiment score.
If the sentiment score is high or neutral then pop a joke to the user.
If the sentiment score is low, try to show a motivational message.

Hope everyone has the environment setup for the bot app, else just check my earlier blog post

First we need to create a new bot project. Choose Bot Application


Give it a name & lets start exploring.

The project will create a controller - MessagesController.cs which is the starting point for our bot.
Controller consists of a task Post which handles the messages received by the bot.
It should look like below.
I am just trying to pass the flow to a RootDialog which is bot framework dialog.

public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
await Conversation.SendAsync(activity, () => new RootDialog());
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}


The RootDialog looks like this

public class RootDialog : IDialog<object>
{
public async Task StartAsync(IDialogContext context)
{
context.Wait(this.MessageReceivedAsync);
}
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
{
var message = await result;
await this.SendWelcomeMessageAsync(context);
}
private async Task SendWelcomeMessageAsync(IDialogContext context)
{
await context.PostAsync("Hi there, How are you feeling now?");
context.Wait(GetUserFeelings);
}
private async Task GetUserFeelings(IDialogContext context, IAwaitable<IMessageActivity> result)
{
var message = await result;
const string apiKey = "Microsoft Cognitive services API Key";
const string queryUri = "https://westus.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment";
var client = new HttpClient
{
DefaultRequestHeaders = {
{"Ocp-Apim-Subscription-Key", apiKey},
{"Accept", "application/json"}
}
};
DocumentRequest test = new DocumentRequest { Id = "1", Language = "en", Text = message.Text };
var sentimentInput = new BatchInput
{
documents = new List<DocumentInput> {
new DocumentInput {
id = 1,
text = message.Text,
}
}
};
var sentimentPost = await client.PostAsync(queryUri, new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(sentimentInput), Encoding.UTF8, "application/json"));
var sentimentRawResponse = await sentimentPost.Content.ReadAsStringAsync();
object JsonConvert = null;
var sentimentJsonResponse = Newtonsoft.Json.JsonConvert.DeserializeObject<BatchResult>(sentimentRawResponse);
var sentimentScore = sentimentJsonResponse?.documents?.FirstOrDefault()?.score ?? 0;
if (sentimentScore > 0.7)
{
context.Call<object>(new HappyDialog(sentimentScore), AfterChildDialogIsDone);
}
else if (sentimentScore < 0.3)
{
context.Call<object>(new SadDialog(sentimentScore), AfterChildDialogIsDone);
}
else
{
context.Call<object>(new NeutralDialog(sentimentScore), AfterChildDialogIsDone);
}
}
private async Task AfterChildDialogIsDone(IDialogContext context, IAwaitable<object> result)
{
context.Wait(MessageReceivedAsync);
}
}
public class BatchInput
{
public List<DocumentInput> documents { get; set; }
}
public class DocumentInput
{
public double id { get; set; }
public string text { get; set; }
}
// Classes to store the result from the sentiment analysis
public class BatchResult
{
public List<DocumentResult> documents { get; set; }
}
public class DocumentResult
{
public double score { get; set; }
public string id { get; set; }
}
public class quote
{
public int Id { get; set; }
public string Quote { get; set; }
}
view raw RootDialog.cs hosted with ❤ by GitHub


RootDialog welcomes the user & asks about how he/she is feeling now.
Those feelings get passed to cognitive services in GetUserFeelings task.
Once the SentimentScore is received, depending on the score we will popup Happy, Neutral or Sad dialogs.

HappyDialog will look like this.

public class HappyDialog : IDialog<string>
{
private double userSentiment;
public HappyDialog (double sentiment)
{
userSentiment = sentiment;
}
public async Task StartAsync(IDialogContext context)
{
PromptDialog.Choice(context, OnOptionSelected,
new List<string>() { "Yes", "No" }, "That's great to hear! Do you want to read a joke?", "Not a valid option", 3);
}
private async Task OnOptionSelected(IDialogContext context, IAwaitable<string> result)
{
try
{
string optionSelected = await result;
switch (optionSelected)
{
case "Yes":
List<quote> jokes = JsonConvert.DeserializeObject<List<quote>>(File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + @"\" + @"jokes.json"));
Random random = new Random();
string joke = jokes[random.Next(102)].Quote;
PromptDialog.Choice(context, OnOptionSelected,
new List<string>() { "Yes", "No" }, joke + "\n\n" + "Do you want to read one more?", "Not a valid option", 3);
break;
case "No":
context.Done(new object());
break;
}
}
catch (TooManyAttemptsException ex)
{
await context.PostAsync($"Ooops! Too many attemps :(. But don't worry, I'm handling that exception and you can try again!");
context.Done(new object());
}
}
}
view raw HappyDialog.cs hosted with ❤ by GitHub


Here I am popping up a question to user if he/she wants to read a Joke? (using PromptDialog restricting user inputs to Yes or No).
If answer is Yes, i read a local JSON file containing jokes & present a random one.
We then ask user if he/she want to read another & the cycle will go on.
User can disengage by choosing No.

Same process will happen for Neutral & Sad Dialogs.

To Test the bot, run your project from Visual Studio. It will fire up IISExpress & host the bot locally.
Use Bot Framework Emulator to connect to the running bot.
The url to connect the bot should look like below, change could be the port.

http://localhost:3979/api/messages

Try saying Hi to the Bot & enjoy.

You can try this with my Bot Emo.
Add him to your Skype Contacts.


or chat with him on Bing
Try on Bing


Happy Coding,
Parshuram


Comments

Popular posts from this blog

6000 KM Road Trip

Export MS Access report to Excel..Font Problem

Testing AWS Rekognition from POSTMAN