Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / productivity / team-communication / slack

Your First Chatbot using Microsoft’s Bot Framework and Dialogflow API: Day 2 (Bot using Microsoft’s Bot Framework)

5.00/5 (8 votes)
5 Feb 2019CPOL16 min read 29.4K   1.9K  
Your first Chatbot using Microsoft’s Bot Framework and Dialogflow API. Integrate with Google Assistant.

Table of Contents

Preface

This article is the submission against CodeProject’s Slack API Challenge. The contest officially began on January 7, 2019 and ends on March 7, 2019.

Slack is no doubt the platform that every developer needs nowadays and is trending in a new way.

It is easy to use and manage, and not only this, we can create our own slack app and add a lot of custom functionality to it. You can learn how to create your own slack app in this article. It is very easy and may hardly take 20 minutes to create your first app.

Chatbot Tutorial Roadmap

Since this is a vast topic and beyond the scope of a single article, I have divided the sections into multiple articles. In the first article, we’ll see how to create a chatbot using Google’s Dialogflow and test the bot in Dialogflow console. We’ll also see how it could be integrated with Slack. The second article will demonstrate how to create a custom chatbot using Microsoft’s bot framework and enable the webhooks in Dialogflow and return the response from the custom bot to Dialogflow intents as a fulfillment response. The third article of the series will demonstrate how to integrate the complete created bot in articles two and three with Facebook Messenger and Slack and test the webhook response in the two environments. Following are the three articles of tutorial about learning how to create a custom chatbot.

  1. Your first Chatbot using Microsoft’s Bot Framework and Dialogflow API: Day 1 (Dialogflow and Slack Integration)
  2. Your first Chatbot using Microsoft’s Bot Framework and Dialogflow API: Day 2 (Bot using Microsoft’s Bot Framework)
  3. Your first Chatbot using Microsoft’s Bot Framework and Dialogflow API: Day 3 (Integrate and test the bot on Slack and Facebook Messenger)

Introduction

From Wikipedia,

“A chatbot (also known as a smartbot, talkbot, chatterbot, Bot, IM bot, interactive agent, conversational interface or artificial conversational entity) is a computer program or an artificial intelligence which conducts a conversation via auditory or textual methods.[1] Such programs are often designed to convincingly simulate how a human would behave as a conversational partner, thereby passing the Turing test. ”

In this article, I’ll demonstrate how to create a custom chatbot using Microsoft’s bot framework and enable the webhooks in Dialogflow and return the response from the custom bot to Dialogflow intents as a fulfillment response. The reader of the article needs to know how to create a bot using Dialogflow and for that, one can follow the last article of this series where it is explained how to create a bot in Dialogflow.

Case Study

Let’s imagine a scenario for our bot creation. Let’s say there is a newly opened Restaurant and they have recently launched their website, Facebook page, Twitter handles and integrated their business with other social media accounts. The restaurant wants to come up with a digital solution to book a table in the restaurant online by the user and they want to create an automated bot to do so. An end user can talk to bot and book a table. The bot will ask all the relevant details before table booking in the restaurant like date, time, number of persons, etc. We’ll create the bot and integrate that with few social media accounts.

Setup Dialog Flow Account and Make the Agent working

“Dialogflow is powered by Google’s machine learning and Give users new ways to interact with your product by building engaging voice and text-based conversational interfaces, such as voice apps and chatbots, powered by AI. Connect with users on your website, mobile app, the Google Assistant, Amazon Alexa, Facebook Messenger, and other popular platforms and devices. Read more…

You need to follow the last article of this series to set up the Dialogflow account and create a Bot agent with intents. After completing that, you can proceed with creating webhooks and integrating with the Dialogflow agent in this article.

Create Bot using Microsoft’s Bot Framework

With Microsoft’s Bot Framework, you can “Build, connect, deploy, and manage intelligent bots to naturally interact with your users on a website, app, Cortana, Microsoft Teams, Skype, Slack, Facebook Messenger, and more. Read more..

Installing Bot Framework

We’ll use one prior version of the Bot Framework to create the bot.

  1. Go to the URL: https://docs.microsoft.com/bs-cyrl-ba/bot-framework/dotnet/bot-builder-dotnet-quickstart for taking care of all the prerequisites before we start. You can install Visual Studio 2017 for Windows if you do not already have it, update all the extensions of Visual Studio 2017 if you already have VS 2017 and then download the three zips by clicking on the links as shown below. These zip files serve as templates for creating the Bot. I’ll also attach the zips as downloadable.

    Image 1

  2. Once the three zips, i.e., “Bot Application.zip”, “Bot Controller.zip” and “Bot Dialog.zip” are downloaded, put those into the Templates folder of Visual Studio, usually found under Documents->Visual Studio 2017 -> Templates -> ProjectTemplates -> Visual C#.

    Image 2

    Image 3

Creating A Bot Framework Type Project in Visual Studio 2017

  1. Open Visual Studio and click for creating a new project. You’ll see all the new Bot Framework templates to create the Bot Framework type project if you search with the name bot in the project templates. Choose “BotApplication” as project type, give it a meaningful name, for e.g., “BookATableBot”, choose a location and your solution file name and click OK.

    Image 4

  2. Once the project is created, the solution structure will look like follows. It will have a similar kind of configuration as for any web API project with some modifications like controller name, here is “MessagesController”, there is a Dialogs folder and a class named RootDialog.cs.

    Image 5

Bot Framework Emulator

  1. To test the Bot, we need to have an emulator and we’ll use here a somewhat older version of the emulator. You can use the latest one as well. Go to the URL: https://github.com/Microsoft/BotFramework-Emulator/releases and download and install the emulator for Windows.

    Image 6

  2. Now, simply run the application from Visual Studio by pressing F5.

    Image 7

  3. When the default page is launched which is in my case localhost:3979, then launch the installed emulator and provide the URL for your Messages controller, i.e., by appending api/messages to the launched application URL. So, the URL becomes http://localhost:3979/api/messages. Provide this URL to the emulator.

    Image 8

  4. Once the URL is provided, you can test the bot by typing anything you want for e.g. “Hi” and the application will return the response, “You sent Hi which was 2 characters”. Now where is this response coming from?

    Image 9

  5. If we go back to the solution and see RootDialog.cs class, we see a message there named MessageReceivedAsync which returns this response.

    Image 10

C#
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
// calculate something for us to return
int length = (activity.Text ?? string.Empty).Length;
// return our reply to the user
await context.PostAsync($"You sent {activity.Text} which was {length} characters");
context.Wait(MessageReceivedAsync);
}

Now, use your debugging skills to test how the message is returned when the call was made to the Messages controller.

Publishing the Bot from Visual Studio to Azure

Before we write the response-methods and integrate our bot with Dialogflow, let’s publish the so far created bot to Azure. If you do not have an Azure account, you can create a free trial account. I am also using a free trial account of Azure here.

  1. Right-click the project in solution explorer and click on Publish as shown below:

    Image 11

  2. Choose App Service and you can choose to create new app service here and click on Publish, it will land up on a new page to fill up some user information.

    Image 12

  3. While creating app service, provide the app name of your choice, select the subscription type, resource group (where your related Azure resources will stay), and a hosting plan. Keep hosting plan to the minimal. I have purposely chosen to set Application Insights to None as we do not need it. Click on create.

    Image 13

  4. Once you click on create and again publish the project, the project will compile and publish the source code to Azure and a new page will be launched with the name starting the app name you provided while creating an application, the URL will be like https://bookatablebot.azurewebsites.net.

That means our bot is successfully published to the Azure server. There are more things to do before we see our bot working with Dialogflow, but those are simple things. Now, we need to register our Bot.

Image 14

Register the Bot

  1. So far so good, now for registering the published bot, click on the link shown on the launched page after bot published.

    Image 15

  2. It will open up the page with the URL https://dev/botframework.com.

    Image 16

  3. Go to the URL: https://dev.botframework.com/bots/new to register your bot.

    Image 17

  4. Here, few settings are required to be configured before a bot is registered. Fill in the details like display name of the bot of your choice, for e.g., “Book A Table Bot”, provide bot handle name for e.g., “bookatable” and description which is by the way optional.

    Image 18

  5. Under the Configuration section, provide the messaging endpoint as the URL of the published bot on Azure append “api/messages” to the URL. You also need to create the Microsoft app id and password to associate this new app to it.

    Image 19

  6. Click on the link saying, “Create Microsoft App ID and password”, this will open a new page to where you can see the name of the page and app id generated.

    Image 20

  7. You can generate the password and store app id and password to some safe location as well for future references.

    Image 21

  8. Go back to Visual Studio, and in the Web.config, provide the MicrosoftAppId and MicrosoftAppPassword that we got generated.

    Image 22

  9. Publish again.

    Image 23

  10. Come back to register bot page and put the owners as the email id used for your Azure account and then click on Register button to Register the bot.

    Image 24

  11. You can now test your bot using the Test button as shown below. You can also do this registration process directly on Azure or migrate this registered bot to Azure as shown in the red colored bar message in the following image:

    Image 25

Dialogflow.v2 SDK

It is time now to create a controller to handle the Dialogflow requests. We’ll create controller to handle the requests coming from the agents that we created in Google Dialogflow and return the response from this controller as a fulfillment text.

  1. Open the Nuget Package manager in the solution for the project and install the Google.Apis.Dialogflow.v2 package.

    Image 26

  2. Add a new controller to Controllers folder and name it DialogFlowController. Add a Post method that takes GoogleCloudDialogflowV2WebhookRequest as a parameter and returns back GoogleCloudDialogflowV2WebhookResponse.
  3. Return the response having FulfillmentText and Source as the controller name so that we know that the response is coming from our controller and nowhere else. Add a Get method to just return “Hello DialogFlow!”.

    Image 27

  4. Publish the project again to Azure. Now when the URL is launched, i.e., when the project is published, append “api/dialogflow”, i.e., the URL of the controller method. When we hit enter, we see the response coming from the Get method of the Dialogflow controller.

    Image 28

Webhooks in Dialogflow

  1. Let’s add the controller response as a response to the user in our Dialogflow bot by enabling the webhook configuration and enabling fulfillment for the bot. Go to the Fulfillment in Dialogflow console and enable the Webhook configuration. Provide the URL of the API that got developed by bot framework and published on Azure. Now save the configuration.

    Image 29

  2. Go to the Intents and for WelcomeIntent (I have renamed the Default Welcome Intent to WelcomeIntent), enable the Fulfillment for the webhook call, so that the fulfillment response comes from the webhook call and not from the default response.

    Image 30

    Image 31

  3. Save the intent and try to type something and press enter, the response that you’ll get now is “Hello DialogFlow!”. This response comes from the Post method of the DialogFlow controller as a fulfillment text. So, our Webhook is well integrated and working fine.

Webhook for Table Booking Bot

This section will have real action. In this section, we'll create a basic project structure to handle intents in the code in our project in Visual Studio and provide the responses as per intent requests. We’ll create a Bot model that will maps to the request and response coming from Dialogflow and process the requests accordingly using the Dialogflow SDK v2.

BotModel

First, create a model that could be mapped with the incoming agent requests and outgoing responses from our code. Add a new folder in the project and add a new class named BotModel.cs.

Image 32

Add the following code to the class file:

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace BookTableBot.Models
{
public class BotModel
{
public BotModel()
{
Id = "";
Session = new Session();
Request = new Request();
Response = new Response();
}
public string Id { get; set; }
internal Session Session { get; set; }
internal Request Request { get; set; }
internal Response Response { get; set; }
}
internal class Request
{
public string Id { get; set; }
public string Intent { get; set; }
public string State { get; set; }
public List<KeyValuePair<string,string>> Parameters { get; set; }
}
internal class Response
{
public string Text { get; set; }
public string Event { get; set; }
}
internal class Session
{
public string Id { get; set; }
}
}

Now, this file contains four classes, i.e., BotModel class, Session, Request and Response classes with their properties. BotModel class has properties like Id, Session, Request, and Response which are also initialized inside the BotModel constructor. Request class has Id, State, intent, and Parameters as a key-value pair. Response class has Text and Event properties and Session has an Id property. These classes and properties are kept in a way that match the request and response and session attributes of the Dialogflow API.

Model Mapper

The next step is to create a model mapper class that will map our bot model to GoogleCloudDialogflowV2WebhookResponse and GoogleCloudDialogflowV2WebhookRequest to bot model. So there would be two methods in that class.

  1. Create a folder named utilities in the project and add a class named ModelMapper to that folder.

    Image 33

  2. Add the following class code for the ModelMapper class:
    C#
    using ApiAiSDK.Model;
    using BookTableBot.Models;
    using Google.Apis.Dialogflow.v2.Data;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    namespace BookTableBot.Utilities
    {
    public class ModelMapper
    {
    internal static BotModel DialogFlowToModel(GoogleCloudDialogflowV2WebhookRequest dFlowResponse)
    {
    var botModel = new BotModel()
    {
    Id = dFlowResponse.ResponseId
    };
    botModel.Session.Id = dFlowResponse.Session;
    botModel.Request.Intent = dFlowResponse.QueryResult.Intent.DisplayName;
    botModel.Request.Parameters = dFlowResponse.QueryResult.Parameters.ToList()
    .ConvertAll(p => new KeyValuePair<string, string>(p.Key, p.Value.ToString()));
    return botModel;
    }
    internal static GoogleCloudDialogflowV2WebhookResponse ModelToDialogFlow(BotModel botModel)
    {
    var response = new GoogleCloudDialogflowV2WebhookResponse()
    {
    FulfillmentText = botModel.Response.Text,
    Source = "BookAtableBot",
    };
    return response;
    }
    }
    }

The method DialogFlowToModel maps Dialogflow webhook request to model and the method ModelToDialogFlow maps our model to Dialogflow webhook response.

Intent Handlers

We need to have intent handlers in our project that handles the request for intent, i.e., in our case for WelcomeIntent and BookATable intent. The role of these handlers is to take the parameters from the requested intent and send a response as a fulfillment of the intent.

  1. Add a folder named Handlers in the project and add two classes named BookATableIntent and WelcomeIntent:

    Image 34

  2. In BookATableIntent, add the following code logic to return the response for the requested intent.
    C#
    using BookTableBot.Models;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    namespace BookTableBot.Handlers
    {
    public class BookATableIntent
    {
    internal static BotModel Process(BotModel botModel)
    {
    var time = botModel.Request.Parameters.FirstOrDefault(p => p.Key == "time");
    var date = botModel.Request.Parameters.FirstOrDefault(p => p.Key == "date");
    var number = botModel.Request.Parameters.FirstOrDefault(p => p.Key == "number");
    botModel.Response.Text = "Awesome! Your table for " + number + 
                             " is booked for " + date + " at " + time + "Have a nice day!";
    return botModel;
    }
    }
    }

    Here, the Process method takes the model as a parameter and fetches out the request parameters that we got mapped in mapper class and accordingly performs an action like setting up response text and returns the same bot model with a response text as well.

  3. Similarly, for the WelcomeIntent, add the following class code:
    C#
    using BookTableBot.Models;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    namespace BookTableBot.Handlers
    {
    public class WelcomeIntent
    {
    internal static BotModel Process(BotModel botModel)
    {
    botModel.Response.Text = "Hi! Would you like to book a table? If yes, simply type 'Book a table'";
    return botModel;
    }
    }
    }

The Process method of this intent takes request model and sets up the response text as "Hi! Would you like to book a table? If yes, simply type 'Book a table'". So, if user types in “Book a table”, our BookAtable intent is called from the Dialogflow API.

Intent List

In our case, there are only two intents, but there could be a scenario where you could have thousands of intents in a full-fledged bot application. To manage that number of intents in the code could really be a hassle. To maintain that, we need to have an IntentList class that takes care of all the intents. Add a new class named IntentsList to the Models folder.

Image 35

Add the following class code to that class:

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace BookTableBot.Models
{
public class IntentsList : List<KeyValuePair<string, Func<BotModel, BotModel>>>
{
public void Add(string intentName, Func<BotModel,BotModel> function)
{
var intent = this.FirstOrDefault(i => i.Key.ToLower() == intentName.ToLower());
if (string.IsNullOrWhiteSpace(intent.Key))
{
Add(new KeyValuePair<string, Func<BotModel, BotModel>>(intentName, function));
}
}
}
}

The method Add takes the intent name and the function associated with that and checks if the intent list already has that intent. If not, it adds to the list.

In the WebApi.Config.cs, we’’ have a static IntentHandlers variable of type IntentList that will hold all the intents. So, add a variable named IntentHandlers as follows in the WebApi.Config.cs file.

C#
public static IntentsList IntentHandlers { get; private set; }
And in the Register method, initialize this variable.

IntentHandlers = new IntentsList
{
{
"BookATableIntent", (mo)=>Handlers.BookATableIntent.Process(mo)
},
{
"WelcomeIntent", (mo)=>Handlers.WelcomeIntent.Process(mo)
}
};

We, see that we have intent names matching the name of the intents we have in Dialogflow console. Make sure the names match else proper matching at the code would not happen and intent won’t be called.

WebApi.Config.cs Code

C#
using BookTableBot.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace BookTableBot
{
public static class WebApiConfig
{
public static IntentsList IntentHandlers { get; private set; }
public static void Register(HttpConfiguration config)
{
IntentHandlers = new IntentsList
{
{
"BookATableIntent", (mo)=>Handlers.BookATableIntent.Process(mo)
},
{
"WelcomeIntent", (mo)=>Handlers.WelcomeIntent.Process(mo)
}
};
// Json settings
config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = 
                                           new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Formatting = Newtonsoft.Json.Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
};
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault
                 (t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
}
}
}

Intent Router

We have almost everything in place for our bot. The only thing remaining is to call the process methods of intent handlers from the controller based on the needed intent request. For that, we’ll add an IntentRouter that will be called from the Dialogflow controller based on the request type of the intent.

Add a new class named IntentRouter in the Utilities class and add the following code to that class:

C#
using BookTableBot.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace BookTableBot.Utilities
{
public class IntentRouter
{
public static BotModel Process(BotModel botModel)
{
var intentsList = WebApiConfig.IntentHandlers;
var intent = intentsList.FirstOrDefault(i => i.Key.ToLower() == botModel.Request.Intent.ToLower());
if (!string.IsNullOrWhiteSpace(intent.Key))
{
return intent.Value(botModel);
}
if (string.IsNullOrWhiteSpace(botModel.Response.Text))
{
botModel.Response.Text = "Sorry, I do not understand. please try again.";
}
return botModel;
}
}
}

The process method of intent router class takes bot model and tries to match the name of the intent from the intent handlers list and accordingly return the intent for which the request is made.

Dialogflow Controller

Finally, modify the Post method of the controller to take the webhook request, map the model and call the Process method of IntentRouter.

C#
using ApiAiSDK.Model;
using BookTableBot.Utilities;
using Google.Apis.Dialogflow.v2.Data;
using Microsoft.Bot.Builder.Luis.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace BookTableBot.Controllers
{
public class DialogFlowController : ApiController
{
public GoogleCloudDialogflowV2WebhookResponse Post(GoogleCloudDialogflowV2WebhookRequest obj)
{
var botModel = ModelMapper.DialogFlowToModel(obj);
if(botModel == null)
{
return null;
}
botModel = IntentRouter.Process(botModel);
return ModelMapper.ModelToDialogFlow(botModel);
}
public string Get()
{
return "Hello DialogFlow!";
}
}
}

So far so good, this makes our basic application work. Time to test now but before that, compile the project and publish it again to Azure.

Testing the Bot

Once published to Azure, we can test the bot in the Dialogflow console itself. We’ll also test the bot on Google Assistant as it could directly be done via Google’s Dialogflow console.

Test in Dialogflow Console

Go back to the Dialogflow console. Make sure you got the webhook enabled for fulfillment and the bot API URL inplaced in the webhook. This was explained earlier in this tutorial. Make sure the fulfillment option is enabled for BookATable and Welcome Intent.

  1. Open the WelcomeIntent and in the test window, type “Hi”. The response will come from our intent handler as follows with the response text as "Hi! Would you like to book a table? If yes, simply type 'Book a table'"

    Image 36

  2. Now follow the instruction of Welcome intent response and type “Book a table”. The default response will ask for the date, time and number of persons.

    Image 37

    Image 38

    Image 39

Finally, when you provide the mandatory parameters, i.e., number of persons, time and date, it returns the response as follows:

Image 40

The response is coming from our webhook. To ensure that, click on the Diagnostic Info button at the bottom.

Image 41

We get to see all the requests and response for our intent. Check Fulfillment Response and the Source inside it. It comes from our webhook.

Image 42

And Fulfillment Status as follows which says Webhook execution successful.

Image 43

Bot in Google Assistant

You can test the bot in Google assistant as well.

  1. In Dialogflow console, go to Integrations section and click on “See how it works in Google Assistant” button.

    Image 44

  2. This will open Google Assistant emulator, where you can type in or provide an audio input. Click on “Talk to my test app”.

    Image 45

  3. It returns the response from the welcome intent.

    Image 46

  4. Type, “Book a table”.

    Image 47

  5. It will ask all the mandatory parameters input as follows:

    Image 48

  6. And finally, it will return the response from the webhook. Awesome! 😊

    Image 49

Conclusion

In this detailed article, we learned what a chatbot is, how to create your own bot using Microsoft’s Bot framework. We also learned how to enable webhooks in Dialogflow console for the fulfilments and return the response from the webhook instead of defaulted text. We tested the bot in Dialogflow console and with Google Assistant. In the next article of this series, we’ll learn how to integrate this bot with the social media accounts like Slack, Facebook messenger, etc.

Downloads

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)