Microsoft Bot Framework is a comprehensive offering to build and deploy high quality bots for your users to enjoy in their favorite conversation experiences. Developers writing bots all face the same problems: bots require basic I/O; they must have language and dialog skills; they must be performant, responsive and scalable; and they must connect to users – ideally in any conversation experience and language the user chooses. Bot Framework provides just what you need to build, connect, manage and publish intelligent bots that interact naturally wherever your users are talking – from text/sms to Skype, Slack, Facebook Messenger, Kik, Office 365 mail and other popular services. This lab will show you how to build a basic bot, connect it to a LUIS model, and get responses back.
This lab will show you how to:
- Create an echo chat Bot
- Create a LUIS model
- Integrate a LUIS model into an existing Bot
- Use the Bot Freamwork Emulator to test your Bot
You must have the following to complete this lab:
- Microsoft Visual Studio (latest update)
- Bot Framework Emulator
- Bot Application Template (if using Windows)
EXERCISE 1: CREATE A BOT
- Register a Bot
- Create a new Bot Application
- Using the Bot Emulator
EXERCISE 2: ADD A LUIS MODEL
EXERCISE 3: CONNECTING THE DOTS
You must perform the following steps to prepare your computer for this lab:
First, install the Bot Framework Emulator.
- Install Visual Studio 2015
- Update all VS extensions to their latest versions
- Install the Bot Application Template
- Save in your VS template directory
%USERPROFILE%\Documents\Visual Studio 2015\Templates\ProjectTemplates\Visual C#
- Save in your VS template directory
- Install Visual Studio for Mac Preview
- Download the
MyFirstBot
project from this workshop's GitHub repo
Install Node JS
Before we begin, we need to register a new bot on the bot framework website.
-
Go to https://dev.botframework.com/ and click “Register a bot” at the top of the screen.
-
Give your bot a name, a bot handle, and give it a small description.
-
In the Configuration section, click “Create Microsoft App ID and password”. On the next page, your App ID will be displayed (write this down).
-
Click “Generate a password to continue”. Write down this password and keep it safe! This is the only time the password will be displayed! Click “Ok” and then click “Finish and go back to Bot Framework”
-
Fill out the rest of the required fields. Then click “Register”.
If you are doing this lab on a MacBook (OSX): as currently there isn't a Bot Framework template for Visual Studio Mac, use the MyFirstBot
project as your starting application for developing a C# bot on OSX. This application is exactly the same result you would get if you follow the steps below on Windows.
-
In a new instance of Visual Studio 2015, choose File > New> Project to open the New Project dialog. Navigate to Installed > Templates > Visual C# and select the Bot Application template.
Name your project MyFirstBot and select the file system location where you will save your solutions. Leave the options selected to Create new solution and Create directory for solution.
-
Set your Solution Configuration to Debug and your Solution Platform to Any CPU. Select your favorite browser from the Debug Target dropdown menu. You can choose to debug/deploy on a phone device connected via USB outside of this lab.
-
Build and run your app. You will see a blank app browser tab displaying the applications Default.htm
Keep note of the port your Bot is running on as well as the API URL to be used for testing your Bot. In this case, this is
http://localhost:3978/api/messages
When the application launches, you may see a 404 Error System.Web.HttpException. The resource cannot be found
. Don't worry about this for now as the application still works and this doesn't prevent you from completing the lab.
Also notice your app is using port 8080. Keep a note of this as you will need to use this address in the bot emulator to communicate with your bot: http://localhost:8080/api/messages
-
Make sure you have Node JS install (link provided in setup section)
-
Open terminal or command prompt
-
Make a new directory (the location you will store your bot application) and then change directory into that folder
- In this case, I've created a new dicrecotry 'myfirstbot' in my Documents
-
Run
npm init
and fill out the fields. Generally, you can just hit enter all the way through. This will create an empty node project. -
Run
npm install --save botbuilder
. This will download the botbuilder package required and save the dependacy to thepackage.json
file. 'botbuilder' is the node bot framework SDK that will provide you with everythign you need to build a bot. -
Run
npm install --save restify
. This will download the restify package required and save the dependacy to thepackage.json
file. Restify is required as we need a server to listen for messages at a given port. -
Open this project in your favourite IDE and you should be able to see the following structure and package.json should also show the dependencies we just installed.
-
Create a new file called
index.js
and paste the following code into it:var builder = require('botbuilder'); var restify = require('restify'); //========================================================= // Bot Setup //========================================================= // Setup Restify Server var server = restify.createServer(); server.listen(process.env.port || process.env.PORT || 3978, function () { console.log('%s listening to %s', server.name, server.url); }); // Create chat bot var connector = new builder.ChatConnector({ appId: process.env.MICROSOFT_APP_ID, appPassword: process.env.MICROSOFT_APP_PASSWORD }); var bot = new builder.UniversalBot(connector); server.post('/api/messages', connector.listen()); //========================================================= // Bots Dialogs //========================================================= bot.dialog('/', function(session){ session.send("You sent %s which was %d characters", session.message.text, session.message.text.length); })
-
Build and run this project. You can do this in terminal or command promptt by calling
node index.js
and you should see the bot running at port3978
. The endpoint you need to communicate with your bot will behttp://localhost:3978/api/messages
-
Keep your bot application running from the previous steps and make a note of the endpoint
- If you've already closed the application, run your bot application again
- Depending on which steps you followed, you endpoint should be
http://localhost:3978/api/messages
orhttp://localhost:8080/api/messages
-
Open the Bot Emulator and enter your endpoint where it says "Enter your endpoint URL"
-
You should then see the same configuration settings as the image below. We go these details from the portol in Task 1. For now you can leave these blank and just press "Connect". If you type a message now, you should see your bot in action.
Remember these settings?
You can fill these fields in with the values we got when we registered our bot in Task 1. You will need to do this when you start live debugging with ngrok (you can find out more about this from the documentation). To do that, first you have to update your application with the App ID and Password too.
-
In C#, open
Web.config
and replace theAppId
andAppPassword
with the correct values from your bot developer portal -
In Node, if your IDE supports environment variables you can use that as a way of setting the
AppId
andAppPassword
(as shown in image 1). Otherwise, just replace the values in index.js (as shown in image 2). -
Finally, you will need to update your bot's endpoint in the bot developer portal
- NB: you only need to do this if you have deployed your bot to a web service or if you are using ngrok. This will not work with localhost
-
Go to luis.ai and log in.
-
Click "My apps” in the top menu bar and click “New App".
-
In the pop up: name your new LUIS model, give it a description, and choose the application culture. Click "Create”.
-
When your application is finished provisioning, it will take you to the main page of your new LUIS model. Next, you will train your LUIS model.
Next, we will add two intents to the application.
-
Navigate to the "Intents" page through the left hand menu then click the “Add Intent” button and make a “BookFlight” intent (name it “BookFlight”)
-
Add an utterance to the "BookFlight" intent, for example "Book flight to Paris”, then click "Save".
-
Now following the same steps as above: add a second intent called “GetWeather”, add the utterance “How is the weather in London”, then click “Save”.
You can have the ability to define relationships between entities based on hereditary hierarchical patterns. The generic entity acts as the parent and the children are the specific types/sub groups under the parent, yet both share the same characteristics. An example of this could be our Location.
-
To add entities, navigate to the "Entities" tab through the left side menu and click the “Add custom entity” button.
-
Name the entity "Location" and select the entity type “Hierarchical”.
-
Click "+ Add Child".
-
Name the first child entity “ToLocation”.
-
Next, click “+ Add Child” again and name the second child entity “FromLocation”.
-
When finished, click “Save”.
Next, we are going to add a Pre-Built datetime entity.
-
To add a Pre-Built Entity, click “Add prebuilt entity”
-
Tick the “datetime” checkbox from the list of Pre-Built entities.
-
Then click “Save”
Now that we have the intents and entities defined, we now need to provide more examples of utterances that illustrate these concepts. Navigate back to the "Intents" page through the left side menu.
Select an intent you have created, click the text box at the top of the screen and start typing in example utterances. You will need to input and label at least 10 examples of each intent in order to get an accurate model, then "Save". The images below show how the "BookFlight" utterances were labeled.
Do the same as above for the "GetWeather" intent. (Notice how in the image below we only set the label for the locations as "Location" and not the children such as "Location::ToLocation", we don't need the child entities in the "GetWeather" scenario).
Next, navigate to “Train & Test” page through the side menu, and click "Train Application".
Once the training has finished, navigate to the "Publish App" page, select your "Endpoint key", select an "Endpoint slot" and click "Publish". If you don't have an endpoint key, follow the steps provided when you click on the "Add a new key to your account" link.
When published, a URL will appear with your application ID and your subscription key (endpoint key). Write these down and keep them safe. You will be using these later.
Now it’s time to connect the dots.
This next section will show you how to connect all the dots together and get your bot to recognize utterances entered into the bot emulator.
-
Go back to the echo bot you made earlier. Add a new folder and name it “TravelApp”. Inside that new file, add a new class named “LUISApp”. This is where the code for your LUIS model will live.
-
Next, we need to add code that will handle LUIS intents that are triggered from phrases entered into the Bot Emulator. Insert the following code snippet into the LUISApp file.
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.Bot.Builder.Dialogs; using Microsoft.Bot.Builder.Luis; using Microsoft.Bot.Builder.Luis.Models; namespace MyFirstBot.TravelApp { [LuisModel("LUIS App ID", "Subscription Key")] [Serializable] public class LUISApp : LuisDialog<object> { //Will run when a None intent is Triggered [LuisIntent("")] public async Task None(IDialogContext context, LuisResult result) { //Add Custom code here. string message = $"No Intent"; await context.PostAsync(message); context.Wait(MessageReceived); } //Will run when a GetWeather intent is Triggered [LuisIntent("GetWeather")] public async Task GetWeather(IDialogContext context, LuisResult result) { //Add Custom code here. string message = $"GetWeather Intent"; await context.PostAsync(message); context.Wait(MessageReceived); } //Will run when a Bookflight intent is Triggered [LuisIntent("BookFlight")] public async Task BookFlight(IDialogContext context, LuisResult result) { //Add Custom code here. string message = $"BookFlight Intent"; await context.PostAsync(message); context.Wait(MessageReceived); } } }
-
Input your App ID and Subscription Key from your LUIS model.
-
Next we need to edit the
MessageController.cs
file and replace thePost
method with the following:public async Task<HttpResponseMessage> Post([FromBody]Activity activity) { if (activity.Type == ActivityTypes.Message){ await Conversation.SendAsync(activity, () => new LUISApp()); } var response = Request.CreateResponse(HttpStatusCode.OK); return response; }
Also make sure the following are imported:
using Microsoft.Bot.Builder.Dialogs; using MyFirstBot.TravelApp;
-
Rebuild your code and run it.
-
Go to the bot emulator and start entering test queries. When an intent of “GetWeather” is triggered, the bot will return “GetWeather”, and the intent of “BookFlight” will return “BookFlight”, and a “None” intent will return “No Intent”.
-
Go back to the echo bot you made earlier and insert the following code into
index.js
(before the bot dialogs, and afterserver.post('/api/messages', connector.listen());
)var model = process.env.LUIS_MODEL; var recognizer = new builder.LuisRecognizer(model); var intents = new builder.IntentDialog({ recognizers: [recognizer] }); bot.dialog('/', intents); intents.matches('None', '/none') .matches('GetWeather', '/getWeather') .matches('BookFlight', '/bookFlight') .onDefault(builder.DialogAction.send("I'm sorry. I didn't understand."))
-
You can either setup an environment variable called
LUIS_MODEL
with your LUIS endpoint or just replaceprocess.env.LUIS_MODEL;
in index.jsThe above code has setup the LUIS model and matched our intents to dialogs in our application i.e. if the intent is
GetWeather
thegetWeather
bot dialog will be launched. Now we need to create the actaul dialogs that will be called. -
Delete any existing dialogs you have in the
Bots Dialogs
section and copy in this code:bot.dialog('/none', function(session){ session.send("No intent"); }) bot.dialog('/getWeather', function(session){ //Add custom code here to implent get weather feature session.send("GetWeather intent"); }) bot.dialog('/bookFlight', function(session){ //Add custom code here to implent book flight feature session.send("BookFlight intent"); })
-
Rebuild your code and run it.
-
Go to the bot emulator and start entering test queries. When the “GetWeather” intent is triggered, the bot will return a message saying “GetWeather intent”; the intent of “BookFlight” will return a message saying “BookFlight intent”; and a “None” intent will return “No Intent”.
Bot Framework Samples for Node and C#
Blog containing a master list of Bot Framework tutorials, samples and projects
By Lilian Kasem, February 2017
Credit for writing the original C# workshop:
- Darren Jefford
- Anthony Sadarangani
- Travis Hilbert
Please submit a pull request if you find mistakes or have something to add, thanks!