Develop Chatbot On NodeJS Platform Using Microsoft Bot Framework (Part Three) - Manage Conversation Using Multiple Dialogs

In article Develop ChatBot On NodeJS Platform Using Microsoft Bot Framework (Part Two) - Manage Conversation Using Root Dialog, we have discussed how to handle conversation using root dialog in chatbot developed using Microsoft Bot Framework NodeJs SDK. In this article, we are going to handle the conversation flow with multiple dialogs instead of root dialog. We are also going to use trigger for dialogs.

In the article Develop ChatBot On NodeJS Platform Using Microsoft Bot Framework (Part Two) - Manage Conversation Using Root Dialog, we discuss how to handle conversation using root dialog in chatbot developed using Microsoft Bot Framework Node.js SDK. In this article, we are going to handle the conversation flow with multiple dialogs instead of the root dialog. We are also going to use a trigger for dialogs.

Prerequisite

We are going to extend the example we have created in the previous article. We are going to create a bot which will help the user to order grocery items.

You can pull code from GitHub or the file attached with the article.

Grocery Order Form - Multiple dialogs

We will add a new file to our solution as ‘groceryOrderForm.js’.
  1. var groceryOrder = function (builder) {  
  2.   
  3.   var groceryMenuItems = ["Rice""Soap""Corn Flakes"];  
  4.   ...  
  5. };  
  6.   
  7. module.exports = function (builder) {  
  8.   return new groceryOrder(builder);  
  9. };  
Define a class groceryOrder which will take botbuilder object as parameter and export the new object of it when we will call require.
  1. this.welcomeDialog = {  
  2.   title: "Welcome",  
  3.   functions: [  
  4.     function (session) {  
  5.       builder.Prompts.text(session, "Welcome, may I know your good name?");  
  6.     },  
  7.     function (session, results) {  
  8.       session.userData.User = results.response;  
  9.       session.send("Hello %(User)s,<br/>I am here to take your order!", session.userData);  
  10.       session.beginDialog("Menu");  
  11.     }  
  12.   ]  
  13. };  
Now, let's add welcomeDialog object with properties tile and functions. The first function in the array will greet welcome to the user and will ask for his/her name. The second function will be called when the user gives input. It will save name to User property. Then, we will call the menu dialog.
  1. this.menuDialog = {  
  2.   title: "Menu",  
  3.   functions: [  
  4.     function (session, flags) {  
  5.       if (flags && flags.IsMoreOrder) {  
  6.         builder.Prompts.choice(session, "Select more..", groceryMenuItems, { listStyle: builder.ListStyle.button });  
  7.       }  
  8.       else {  
  9.         session.userData.groceryItems = [];  
  10.         builder.Prompts.choice(session, "Please select grocery item from list:", groceryMenuItems, { listStyle: builder.ListStyle.button });  
  11.       }  
  12.     },  
  13.     function (session, results) {  
  14.       session.userData.groceryItems.push(results.response.entity);  
  15.       session.replaceDialog("Menu", { IsMoreOrder: true });  
  16.     }  
  17.   ]  
  18. };  
For Menu dialog, we will add menuDialog. First function in array will check flags and IsMoreOrder property. If it is true, then it will prompt the user for more selection with the list of groceries. Else, it prompts with different text for first time. Second function will be called on user input and it will push the user selection to the groceryItems array of userData. Also, it replaces the dialog with new Menu dialog but with IsMoreGrocery property as true. 
  1. this.checkoutDialog = {  
  2.   title: "Checkout",  
  3.   functions: [  
  4.     function (session) {  
  5.       builder.Prompts.text(session, "Where should we deliver your order?");  
  6.     },  
  7.     function (session, results) {  
  8.       session.userData.Address = results.response;  
  9.       builder.Prompts.time(session, "What time will you prefer?");  
  10.     },  
  11.     function (session, results) {  
  12.       session.userData.deliveryTime = builder.EntityRecognizer.resolveTime([results.response]);  
  13.       session.send("Thanks for your order %(User)s.", session.userData);  
  14.       console.log(session.userData.groceryItems);  
  15.       session.send("Your order of %(groceryItems)s will be delivered by %(deliveryTime)s", session.userData);  
  16.       session.endDialog();  
  17.     }  
  18.   ],  
  19. };  

At the last, we will add checkoutDialog for handling checkout functionality. First function will prompt the user for address of delivery, while the second function will save that address to the user data and prompt for preferred time for delivery. Third function will save the delivery time to the user data and prompt the user with Thank you and list of selected groceries.

Now, we are ready with our grocery order form. Open starter.js. We will modify the code to add dialogs to our universal bot object.
  1. var restify = require('restify');  
  2. var builder = require('botbuilder');  
  3.   
  4. // Setup Restify Server  
  5. var server = restify.createServer();  
  6. server.listen(process.env.port || process.env.PORT || 3979, function () {  
  7.     console.log('Bot Application is avalable at (%s)', server.url);  
  8. });  
  9.   
  10. // Create chat connector for communicating with the Bot Framework Service  
  11. var connector = new builder.ChatConnector({ appId: process.env.MICROSOFT_APP_ID, appPassword: process.env.MICROSOFT_APP_PASSWORD });  
  12.   
  13. // Listen for messages from users   
  14. server.post('/api/order_your_grocery', connector.listen());  
  15.   
  16. // Load grocery order form   
  17. var groceryOrderForm = require('./groceryOrderForm.js')(builder);  
  18.   
  19. // Initialize bot with connector and default dialog  
  20. bot = new builder.UniversalBot(connector, [  
  21.     function (session) {  
  22.         session.beginDialog(groceryOrderForm.welcomeDialog.title);  
  23.     }  
  24. ]);  
  25.   
  26. bot.dialog(groceryOrderForm.welcomeDialog.title, groceryOrderForm.welcomeDialog.functions);  
  27. bot.dialog(groceryOrderForm.menuDialog.title, groceryOrderForm.menuDialog.functions);  
  28. bot.dialog(groceryOrderForm.checkoutDialog.title, groceryOrderForm.checkoutDialog.functions).triggerAction({  
  29.     matches: /^check out$/i,  
  30.     confirmPrompt: "This will cancel your request. Are you sure?"  
  31. });  

Here, we called the "require" function for groceryOrdeForm.js. We will initialize the universal bot with a root function which will begin a welcome dialog. Then, we will add all dialogs from groceryorderForm to our bot object by calling bot.dialog function.

While adding checkout dialog, we have added trigger action. It will take two parameters ‘matches’ and ‘confirmPrompt’. Whenever a user writes checkout to chat window, it will remove all the dialogs from the stack and add checkout dialog to stack for execution.

Test it

Now, open the terminal and run node starter.js command. It will start our bot application and host it on a specified port. Open emulator app and connect with the URL ‘http://localhost:3979/api/order_your_grocery’ to start a conversation.



This is how we can manage a conversation using multiple dialogs. In the next articles, we will discuss LUIS integration and mood detection in chatbot application. Till then, keep developing bots!