{"id":2117,"date":"2017-01-21T02:00:00","date_gmt":"2017-01-21T02:00:00","guid":{"rendered":"https:\/\/www.microsoft.com\/reallifecode\/index.php\/2017\/01\/21\/orchestrating-multiple-bots-with-multilingual-support\/"},"modified":"2020-03-15T05:52:44","modified_gmt":"2020-03-15T12:52:44","slug":"orchestrating-multiple-bots-with-multilingual-support","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/ise\/orchestrating-multiple-bots-with-multilingual-support\/","title":{"rendered":"Orchestrating Multiple Bots with Multilingual Support"},"content":{"rendered":"<p>This code story describes how my team at Microsoft collaborated with <a href=\"http:\/\/uk.sageone.com\/\">Sage<\/a> to find imaginative solutions for their bot-related challenges. <strong>Sage<\/strong> was setting out to develop a large collection of bots that would be offered in a variety of languages, locations, and needs. But in order to build them, they first needed good design and infrastructure.<\/p>\n<h2 id=\"the-challenge\">The Challenge<\/h2>\n<p><strong>Sage<\/strong> wanted to develop a platform where they could offer bots in multiple languages and through numerous channels such as Facebook Messenger, Slack, etc.<\/p>\n<p>Prior to our engagement, this partner supported its localization and channel needs by writing multiple copies of the same bot for every language and every channel. Each of these bots needed to be registered and maintained separately.<\/p>\n<p>That\u2019s a lot of code to maintain!<\/p>\n<p>However, we can enable support for multiple channels as part of the registration process by using Microsoft Bot Framework. In this way, we can support publishing a single bot that:<\/p>\n<ul>\n<li>Enables context switching, which means that the user can switch between different child bots, like for example <em>Credit Card Bot<\/em> and <em>Health Checkup Bot<\/em>.<\/li>\n<li>Enables development with a multilingual approach using language resources and <a href=\"https:\/\/www.luis.ai\/\">LUIS<\/a><\/li>\n<\/ul>\n<h2 id=\"general-solution\">General Solution<\/h2>\n<p>In our solution, the <strong>Orchestration Bot<\/strong> (a.k.a. <strong>Parent Bot<\/strong>) manages the place in the conversation where the user can decide on general context actions like:<\/p>\n<ul>\n<li>Changing the language<\/li>\n<li>Showing what bots are available<\/li>\n<\/ul>\n<p>The <strong>Child Bot<\/strong> is a bot managing its own conversation with the user. Once the user enters a conversation with the <strong>Child Bot<\/strong> (<em>Credit Card<\/em> Bot for example), commands like <code class=\"highlighter-rouge\">help<\/code> and <code class=\"highlighter-rouge\">tell me my balance<\/code> will be handled by the <strong>Child Bot<\/strong>. If the user wants to return to the <strong>Parent Bot<\/strong> he or she can say something like <code class=\"highlighter-rouge\">exit<\/code> or <code class=\"highlighter-rouge\">go home<\/code>. They can also jump directly to a different <strong>Child Bot<\/strong> with a command like <code class=\"highlighter-rouge\">go to health bot<\/code>.<\/p>\n<p>We made use of the following features in Microsoft Bot Framework to help with the technological challenges of creating and maintaining a multilingual, context-switching bot:<\/p>\n<ol>\n<li>Microsoft Bot Framework Middleware<\/li>\n<li>Microsoft Bot Framework Libraries<\/li>\n<li>Microsoft Bot Framework Localization<\/li>\n<\/ol>\n<h3 id=\"conversational-flow\">Conversational Flow<\/h3>\n<p> <img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2017\/01\/diagram.png\" alt=\"Image diagram\" width=\"787\" height=\"638\" class=\"aligncenter size-full wp-image-11037\" srcset=\"https:\/\/devblogs.microsoft.com\/ise\/wp-content\/uploads\/sites\/55\/2017\/01\/diagram.png 787w, https:\/\/devblogs.microsoft.com\/ise\/wp-content\/uploads\/sites\/55\/2017\/01\/diagram-300x243.png 300w, https:\/\/devblogs.microsoft.com\/ise\/wp-content\/uploads\/sites\/55\/2017\/01\/diagram-768x623.png 768w\" sizes=\"(max-width: 787px) 100vw, 787px\" \/><\/p>\n<p>The sections below delve into these specific parts of the solution.<\/p>\n<h2 id=\"using-middleware-to-intercept-messages\">Using middleware to intercept messages<\/h2>\n<p><em><a href=\"https:\/\/docs.botframework.com\/en-us\/node\/builder\/whats-new\/#middleware\">Middleware<\/a><\/em> is implemented in Microsoft Bot Framework as a message interceptor for messages sent to the bot. Our solution uses middleware to intercept all messages and look for special ones like:<\/p>\n<ul>\n<li><em>\u201cgo home\u201d<\/em> &#8211; exit the current bot and return to the top-level bot.<\/li>\n<li><em>\u201cgo feedback\u201d<\/em> &#8211; exit the current bot and enter the \u201cfeedback\u201d bot.<\/li>\n<\/ul>\n<p>This method can be used to intercept messages that should be relevant for all bots.<\/p>\n<p>The following is an example of how to intercept a \u201cgo home\u201d message:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">var<\/span> <span class=\"nx\">builder<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"s1\">'botbuilder'<\/span><span class=\"p\">);<\/span>\r\n\r\n<span class=\"nx\">bot<\/span><span class=\"p\">.<\/span><span class=\"nx\">use<\/span><span class=\"p\">({<\/span>\r\n    <span class=\"na\">botbuilder<\/span><span class=\"p\">:<\/span> <span class=\"kd\">function<\/span> <span class=\"p\">(<\/span><span class=\"nx\">session<\/span><span class=\"p\">,<\/span> <span class=\"nx\">next<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\r\n\r\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">message<\/span><span class=\"p\">.<\/span><span class=\"nx\">text<\/span> <span class=\"o\">===<\/span> <span class=\"s1\">'go home'<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\r\n            \r\n            <span class=\"c1\">\/\/ In case a dialog is currently active, end it and activate dialog with id '\/'<\/span>\r\n            <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">sessionState<\/span><span class=\"p\">.<\/span><span class=\"nx\">callstack<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">sessionState<\/span><span class=\"p\">.<\/span><span class=\"nx\">callstack<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\r\n                <span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">cancelDialog<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"s1\">'\/'<\/span><span class=\"p\">);<\/span>\r\n\r\n            <span class=\"c1\">\/\/ activate dialog with id '\/'<\/span>\r\n            <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\r\n                <span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">beginDialog<\/span><span class=\"p\">(<\/span><span class=\"s1\">'\/'<\/span><span class=\"p\">);<\/span>\r\n            <span class=\"p\">}<\/span>\r\n        <span class=\"p\">}<\/span>\r\n    <span class=\"p\">}<\/span>\r\n<span class=\"p\">});<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>Middleware is used in the code to orchestrate exits from and entrances to conversations from anywhere in the application which enables the user to change his or her mind and switch between bots.<\/p>\n<h2 id=\"microsoft-bot-framework-libraries\">Microsoft Bot Framework Libraries<\/h2>\n<p>The use of libraries helps separate the contexts of <strong>the parent<\/strong> bot and <strong>child bots<\/strong> and enables different teams to maintain their own code bases.<\/p>\n<p><a href=\"https:\/\/docs.botframework.com\/en-us\/node\/builder\/chat-reference\/classes\/_botbuilder_d_.library\">Libraries<\/a> is a feature in Microsoft Bot Framework that enables the creation of segregated dialogs and intents that can function as a subcontext for the bot. That is, a child bot orchestrated by the parent bot.<\/p>\n<p>In our scenario, each child bot handles a topic or domain, credit card, history, alarm, or giving feedback. By separating these domains into individual child bots, we enable the team responsible for each one to work independently in their own code base. Each child uses a library to manage the intents for the domain.<\/p>\n<p>Placing the library inside a separate directory ensures that it is self-contained. The following code is an example of how to create a library inside a dedicated file:<\/p>\n<p><code class=\"highlighter-rouge\">\/bots\/feedback\/index.js<\/code>:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">var<\/span> <span class=\"nx\">feedbackBot<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"kd\">function<\/span> <span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\r\n\r\n  <span class=\"kd\">var<\/span> <span class=\"nx\">_intents<\/span><span class=\"p\">;<\/span>\r\n  <span class=\"kd\">var<\/span> <span class=\"nx\">_lib<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">builder<\/span><span class=\"p\">.<\/span><span class=\"nx\">Library<\/span><span class=\"p\">(<\/span><span class=\"s1\">'feedbackBot'<\/span><span class=\"p\">);<\/span>\r\n  \r\n  <span class=\"nx\">_lib<\/span><span class=\"p\">.<\/span><span class=\"nx\">dialog<\/span><span class=\"p\">(<\/span><span class=\"s1\">'hello'<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span>\r\n      <span class=\"kd\">function<\/span> <span class=\"p\">(<\/span><span class=\"nx\">session<\/span><span class=\"p\">,<\/span> <span class=\"nx\">results<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\r\n          <span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">endDialog<\/span><span class=\"p\">(<\/span><span class=\"s1\">'hello from feedback bot'<\/span><span class=\"p\">);<\/span>\r\n      <span class=\"p\">}<\/span>\r\n  <span class=\"p\">]);<\/span>\r\n\r\n  <span class=\"kd\">function<\/span> <span class=\"nx\">createLibrary<\/span> <span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\r\n      <span class=\"k\">return<\/span> <span class=\"nx\">_lib<\/span><span class=\"p\">;<\/span>\r\n  <span class=\"p\">}<\/span>\r\n\r\n  <span class=\"kd\">function<\/span> <span class=\"nx\">initialize<\/span> <span class=\"p\">(<\/span><span class=\"nx\">locale<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\r\n      <span class=\"nx\">intents<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">builder<\/span><span class=\"p\">.<\/span><span class=\"nx\">IntentDialog<\/span><span class=\"p\">();<\/span>\r\n      <span class=\"nx\">intents<\/span><span class=\"p\">.<\/span><span class=\"nx\">matches<\/span><span class=\"p\">(<\/span><span class=\"sr\">\/^<\/span><span class=\"se\">(<\/span><span class=\"sr\">hello<\/span><span class=\"se\">)<\/span><span class=\"sr\">\/i<\/span><span class=\"p\">,<\/span> <span class=\"s2\">\"feedbackBot:hello\"<\/span><span class=\"p\">);<\/span>\r\n      <span class=\"k\">return<\/span> <span class=\"nx\">intents<\/span><span class=\"p\">;<\/span>\r\n  <span class=\"p\">};<\/span>\r\n\r\n  <span class=\"k\">return<\/span> <span class=\"p\">{<\/span>\r\n    <span class=\"na\">createLibrary<\/span><span class=\"p\">:<\/span> <span class=\"nx\">createLibrary<\/span><span class=\"p\">,<\/span>\r\n    <span class=\"na\">initialize<\/span><span class=\"p\">:<\/span> <span class=\"nx\">initialize<\/span>\r\n  <span class=\"p\">};<\/span>\r\n\r\n<span class=\"p\">})();<\/span>\r\n\r\n<span class=\"nx\">module<\/span><span class=\"p\">.<\/span><span class=\"nx\">exports<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">feedbackBot<\/span><span class=\"p\">;<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>Each bot creates and manages a <code class=\"highlighter-rouge\">Library<\/code> object and exposes an <code class=\"highlighter-rouge\">intents<\/code> array. The parent bot will have to perform the following steps to consume the library:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"c1\">\/\/ 1. Declare the library<\/span>\r\n<span class=\"nx\">bot<\/span><span class=\"p\">.<\/span><span class=\"nx\">library<\/span><span class=\"p\">(<\/span><span class=\"nx\">childBot<\/span><span class=\"p\">.<\/span><span class=\"nx\">createLibrary<\/span><span class=\"p\">());<\/span>\r\n\r\n<span class=\"c1\">\/\/ 2. Initialize the library and receive intents<\/span>\r\n<span class=\"kd\">var<\/span> <span class=\"nx\">botIntents<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">selectedBot<\/span><span class=\"p\">.<\/span><span class=\"nx\">initialize<\/span><span class=\"p\">(<\/span><span class=\"cm\">\/*...*\/<\/span><span class=\"p\">);<\/span>\r\n\r\n<span class=\"c1\">\/\/ 3. Create a new dialog with the received intents<\/span>\r\n<span class=\"nx\">bot<\/span><span class=\"p\">.<\/span><span class=\"nx\">dialog<\/span><span class=\"p\">(<\/span><span class=\"s1\">'bot_name'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">botIntents<\/span><span class=\"p\">);<\/span>\r\n\r\n<span class=\"c1\">\/\/ 4. Enter the dialog when needed<\/span>\r\n<span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">beginDialog<\/span><span class=\"p\">(<\/span><span class=\"s1\">'bot_name'<\/span><span class=\"p\">);<\/span>\r\n<\/code><\/pre>\n<\/div>\n<h3 id=\"automatic-loading-of-bots\">Automatic Loading of Bots<\/h3>\n<p>Since we will potentially need to support an extensive collection of bots, we looked for an approach that didn\u2019t require us to declare each bot separately. To apply this method, we require each bot to implement an interface that exposes the following methods:<\/p>\n<ul>\n<li><code class=\"highlighter-rouge\">createLibrary<\/code> &#8211; creates and returns the library object for declaration.<\/li>\n<li><code class=\"highlighter-rouge\">getName<\/code> &#8211; returns the name of the bot that can be presented to the user.<\/li>\n<li><code class=\"highlighter-rouge\">welcomeMessage<\/code> &#8211; returns a welcome message that will be displayed to the user when the conversation begins.<\/li>\n<li><code class=\"highlighter-rouge\">initialize<\/code> &#8211; initializes the library with any runtime parameters and returns the library\u2019s intents.<\/li>\n<\/ul>\n<p>In addition to the interface we also assume that all bot directories are found under the <code class=\"highlighter-rouge\">\/bots\/<\/code> directory, enabling automatic loading:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"c1\">\/\/ Declare all libraries directly under '\/bots' directory<\/span>\r\n<span class=\"kd\">var<\/span> <span class=\"nx\">bots<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[];<\/span>\r\n<span class=\"kd\">var<\/span> <span class=\"nx\">botDirectories<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">getDirectoriesUnder<\/span><span class=\"p\">(<\/span><span class=\"s1\">'.\/bots'<\/span><span class=\"p\">);<\/span>\r\n<span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"kd\">var<\/span> <span class=\"nx\">dirIdx<\/span> <span class=\"k\">in<\/span> <span class=\"nx\">botDirectories<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\r\n\r\n    <span class=\"kd\">var<\/span> <span class=\"nx\">dirName<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">botDirectories<\/span><span class=\"p\">[<\/span><span class=\"nx\">dirIdx<\/span><span class=\"p\">];<\/span>\r\n    <span class=\"kd\">var<\/span> <span class=\"nx\">childBot<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"nx\">path<\/span><span class=\"p\">.<\/span><span class=\"nx\">join<\/span><span class=\"p\">(<\/span><span class=\"nx\">__dirname<\/span><span class=\"p\">,<\/span> <span class=\"s1\">'bots'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">dirName<\/span><span class=\"p\">));<\/span>\r\n    <span class=\"nx\">bots<\/span><span class=\"p\">.<\/span><span class=\"nx\">push<\/span><span class=\"p\">(<\/span><span class=\"nx\">childBot<\/span><span class=\"p\">);<\/span>\r\n    <span class=\"nx\">bot<\/span><span class=\"p\">.<\/span><span class=\"nx\">library<\/span><span class=\"p\">(<\/span><span class=\"nx\">childBot<\/span><span class=\"p\">.<\/span><span class=\"nx\">createLibrary<\/span><span class=\"p\">());<\/span>\r\n<span class=\"p\">}<\/span>\r\n<\/code><\/pre>\n<\/div>\n<h3 id=\"creating-and-starting-a-bot\">Creating and starting a bot<\/h3>\n<p>To decide which bot we want to activate we offer the user a choice from the collection of loaded bots:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">var<\/span> <span class=\"nx\">botNames<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">bots<\/span><span class=\"p\">.<\/span><span class=\"nx\">map<\/span><span class=\"p\">(<\/span><span class=\"kd\">function<\/span> <span class=\"p\">(<\/span><span class=\"nx\">bot<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"k\">return<\/span> <span class=\"nx\">bot<\/span><span class=\"p\">.<\/span><span class=\"nx\">getName<\/span><span class=\"p\">(<\/span><span class=\"nx\">session<\/span><span class=\"p\">);<\/span> <span class=\"p\">});<\/span>\r\n<span class=\"nx\">builder<\/span><span class=\"p\">.<\/span><span class=\"nx\">Prompts<\/span><span class=\"p\">.<\/span><span class=\"nx\">choice<\/span><span class=\"p\">(<\/span><span class=\"nx\">session<\/span><span class=\"p\">,<\/span> <span class=\"s1\">'Which bot would you like to choose?'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">botNames<\/span><span class=\"p\">);<\/span>\r\n<\/code><\/pre>\n<\/div>\n<blockquote><p>Note: This implementation was chosen for simplicity even though it doesn\u2019t hide the \u201cbotness\u201d of the bot application from the user. Another better solution would be to use LUIS to understand which child bot is the appropriate one to process the received message and direct the message to it.<\/p><\/blockquote>\n<p>Then we create and launch their chosen bot:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">var<\/span> <span class=\"nx\">selectedBot<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">bots<\/span><span class=\"p\">.<\/span><span class=\"nx\">find<\/span><span class=\"p\">(<\/span><span class=\"kd\">function<\/span> <span class=\"p\">(<\/span><span class=\"nx\">bot<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span> <span class=\"k\">return<\/span> <span class=\"nx\">bot<\/span><span class=\"p\">.<\/span><span class=\"nx\">getName<\/span><span class=\"p\">(<\/span><span class=\"nx\">session<\/span><span class=\"p\">)<\/span> <span class=\"o\">==<\/span> <span class=\"nx\">requestedBot<\/span><span class=\"p\">;<\/span> <span class=\"p\">});<\/span>\r\n<span class=\"kd\">var<\/span> <span class=\"nx\">locale<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">preferredLocale<\/span><span class=\"p\">();<\/span>\r\n<span class=\"kd\">var<\/span> <span class=\"nx\">botKey<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">'locale-'<\/span> <span class=\"o\">+<\/span> <span class=\"nx\">locale<\/span> <span class=\"o\">+<\/span> <span class=\"s1\">'-'<\/span> <span class=\"o\">+<\/span> <span class=\"nx\">requestedBot<\/span><span class=\"p\">;<\/span>\r\n<span class=\"kd\">var<\/span> <span class=\"nx\">localeIntents<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">selectedBot<\/span><span class=\"p\">.<\/span><span class=\"nx\">initialize<\/span><span class=\"p\">(<\/span><span class=\"nx\">locale<\/span><span class=\"p\">);<\/span>\r\n\r\n<span class=\"nx\">bot<\/span><span class=\"p\">.<\/span><span class=\"nx\">dialog<\/span><span class=\"p\">(<\/span><span class=\"nx\">botKey<\/span><span class=\"p\">,<\/span> <span class=\"nx\">localeIntents<\/span><span class=\"p\">);<\/span>\r\n<span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">send<\/span><span class=\"p\">(<\/span><span class=\"nx\">selectedBot<\/span><span class=\"p\">.<\/span><span class=\"nx\">welcomeMessage<\/span><span class=\"p\">(<\/span><span class=\"nx\">session<\/span><span class=\"p\">));<\/span>\r\n<span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">beginDialog<\/span><span class=\"p\">(<\/span><span class=\"nx\">botKey<\/span><span class=\"p\">);<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>We used the selected locale in the bot name to enable the same bot to be declared and launched in different languages.<\/p>\n<h2 id=\"enabling-multiple-languages\">Enabling Multiple Languages<\/h2>\n<p>To communicate with a user in a way he or she understands, we need to \u201clisten\u201d and \u201creply\u201d in his or her language. Fortunately, Microsoft Bot Framework has a solid approach for storing and displaying texts in multiple languages.<\/p>\n<p>However, one major gap that is yet to be addressed in the framework is expanding LUIS, a service for intent and entity recognition, to support multiple languages through one model. To do that with Microsoft Bot Framework using Node.js, we needed to take the following requirements into account:<\/p>\n<ol>\n<li>Enable the user to change the bot language in real time.<\/li>\n<li>Use LUIS models that are paired with the <code class=\"highlighter-rouge\">LuisRecognizer<\/code> and <code class=\"highlighter-rouge\">IntentDialog<\/code> objects after creation.<\/li>\n<\/ol>\n<p>The following are three solutions we used to enable multilingual support.<\/p>\n<h3 id=\"choosing-a-language\">Choosing a Language<\/h3>\n<p>To communicate with the user in his or her desired language, we begin by offering them a collection of supported languages. If the user already has a supported language in their <code class=\"highlighter-rouge\">session.userData<\/code>, that language is automatically used. Alternatively, if the user requests to \u201cchange language\u201d we prompt them to select a new one. This logic is implemented in the parent bot since it is relevant to all parent and child bots in the application.<\/p>\n<p>To set the default language for the Microsoft Bot Framework, we use the following code:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code>    <span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">preferredLocale<\/span><span class=\"p\">(<\/span><span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">userData<\/span><span class=\"p\">[<\/span><span class=\"s2\">\"BotBuilder.Data.PreferredLocale\"<\/span><span class=\"p\">]);<\/span>\r\n    <span class=\"nx\">bot<\/span><span class=\"p\">.<\/span><span class=\"nx\">settings<\/span><span class=\"p\">.<\/span><span class=\"nx\">localizerSettings<\/span><span class=\"p\">.<\/span><span class=\"nx\">defaultLocale<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">preferredLocale<\/span><span class=\"p\">();<\/span>\r\n<\/code><\/pre>\n<\/div>\n<h3 id=\"parent-bot-level-multilingual-support\">Parent Bot-Level Multilingual Support<\/h3>\n<p>Microsoft Bot Framework enables saving JSON format resource files under <code class=\"highlighter-rouge\">\/locale\/{lang}\/index.json<\/code> where <code class=\"highlighter-rouge\">lang<\/code> is a two-digit locale.<\/p>\n<p>Example of storing a value and retrieving it:<\/p>\n<p><code class=\"highlighter-rouge\">\/locale\/en\/index.json<\/code><\/p>\n<div class=\"language-json highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"p\">{<\/span>\r\n    <span class=\"nt\">\"welcome-message\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"Hello and welcome to our bot!\"<\/span>\r\n<span class=\"p\">}<\/span>\r\n<\/code><\/pre>\n<\/div>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"kd\">function<\/span> <span class=\"nx\">promptWelcomeLocale<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\r\n    <span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">send<\/span><span class=\"p\">(<\/span><span class=\"s1\">'welcome-message'<\/span><span class=\"p\">);<\/span>\r\n<span class=\"p\">}<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>It is also possible to override default Microsoft Bot Framework messages by adding the file <code class=\"highlighter-rouge\">\/locale\/{lang}\/BotBuilder.json<\/code>. Possible values are <a href=\"https:\/\/github.com\/Microsoft\/BotBuilder\/blob\/master\/Node\/core\/lib\/locale\/en\/BotBuilder.json\">available on GitHub<\/a>.<\/p>\n<h3 id=\"child-bot-level-multilingual-support\">Child Bot-Level Multilingual Support<\/h3>\n<p>The same method for the root level can also be applied at the library level when adding the locale file under <code class=\"highlighter-rouge\">\/{bot lib}\/locale\/{lang}\/index.json<\/code>.<\/p>\n<p>When initializing the library, call the following code:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code>  <span class=\"kd\">var<\/span> <span class=\"nx\">_lib<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">builder<\/span><span class=\"p\">.<\/span><span class=\"nx\">Library<\/span><span class=\"p\">(<\/span><span class=\"s1\">'feedbackBot'<\/span><span class=\"p\">);<\/span>\r\n  <span class=\"nx\">_lib<\/span><span class=\"p\">.<\/span><span class=\"nx\">localePath<\/span><span class=\"p\">(<\/span><span class=\"s1\">'.\/bots\/bot_name\/locale\/'<\/span><span class=\"p\">);<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>This code ensures that this directory is added to the available locale. At the time of writing this article, values in such locale files are registered at the global level and override existing values. To add new values, it is advisable to use the format <code class=\"highlighter-rouge\"><span class=\"p\">{<\/span><span class=\"err\">bot<\/span> <span class=\"err\">name<\/span><span class=\"p\">}<\/span><span class=\"err\">:<\/span><span class=\"p\">{<\/span><span class=\"err\">locale<\/span> <span class=\"err\">value<\/span><span class=\"p\">}<\/span><\/code> or any other similar format.<\/p>\n<h3 id=\"luis-models\">LUIS models<\/h3>\n<p>A bigger challenge on the language front is using LUIS models. It\u2019s one thing to <em>display<\/em> text for a user in their preferred language, but it\u2019s quite another to <em>understand<\/em> a user in multiple languages. At the time of writing this article, LUIS does not support multilingual features.<\/p>\n<p>This issue means that several LUIS models have to be trained in order to add multilingual support, including one for each different language. Additionally, building LUIS intent-based dialogs in Microsoft Bot Framework requires the declaration of the model in the instantiation:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code>    <span class=\"nx\">recognizer<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">builder<\/span><span class=\"p\">.<\/span><span class=\"nx\">LuisRecognizer<\/span><span class=\"p\">(<\/span><span class=\"nx\">LUIS_MODEL_URL<\/span><span class=\"p\">);<\/span>\r\n    <span class=\"nx\">intents<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">builder<\/span><span class=\"p\">.<\/span><span class=\"nx\">IntentDialog<\/span><span class=\"p\">({<\/span> <span class=\"na\">recognizers<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"nx\">recognizer<\/span><span class=\"p\">]<\/span> <span class=\"p\">});<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>Since the flow of dialogs in Microsoft Bot Framework is designed as a stack, you can create dialogs and route a conversation into them in runtime. To ensure that the LUIS model is available when bots are created, <a href=\"#microsoft-bot-framework-libraries\">each library exposes an initialization method<\/a> that accepts a locale and returns a collection of intents.<\/p>\n<p>Having an initialization method enables the dynamic creation of the intent using a locale chosen by the user:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code>    <span class=\"kd\">var<\/span> <span class=\"nx\">botKey<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">'locale-'<\/span> <span class=\"o\">+<\/span> <span class=\"nx\">locale<\/span> <span class=\"o\">+<\/span> <span class=\"s1\">'-'<\/span> <span class=\"o\">+<\/span> <span class=\"nx\">requestedBot<\/span><span class=\"p\">;<\/span>\r\n    <span class=\"kd\">var<\/span> <span class=\"nx\">localeIntents<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">selectedBot<\/span><span class=\"p\">.<\/span><span class=\"nx\">initialize<\/span><span class=\"p\">(<\/span><span class=\"nx\">locale<\/span><span class=\"p\">);<\/span>\r\n    <span class=\"nx\">rootBot<\/span><span class=\"p\">.<\/span><span class=\"nx\">dialog<\/span><span class=\"p\">(<\/span><span class=\"nx\">botKey<\/span><span class=\"p\">,<\/span> <span class=\"nx\">localeIntents<\/span><span class=\"p\">);<\/span>\r\n    <span class=\"nx\">session<\/span><span class=\"p\">.<\/span><span class=\"nx\">beginDialog<\/span><span class=\"p\">(<\/span><span class=\"nx\">botKey<\/span><span class=\"p\">);<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>Using the user\u2019s locale and dialog id we can route him or her request to the relevant bot.<\/p>\n<h2 id=\"opportunities-for-reuse\">Opportunities for Reuse<\/h2>\n<p>You could reuse the code presented here in any project involving any bot situations similar to these:<\/p>\n<ol>\n<li>A bot for managing multiple contexts or child bots (see example below)<\/li>\n<li>A bot that needs multilingual support (with or without LUIS)<\/li>\n<li>A bot that requires runtime creation and triggering of dialogs<\/li>\n<\/ol>\n<p>It would also be beneficial to reuse the knowledge gained from this case study when implementing a bot that involves one or more of the following scenarios:<\/p>\n<ul>\n<li>A credit card context with actions like <code class=\"highlighter-rouge\">balance inquiry<\/code>, <code class=\"highlighter-rouge\">money transfer<\/code> and <code class=\"highlighter-rouge\">action history<\/code><\/li>\n<li>A music context in which the user can ask things like <code class=\"highlighter-rouge\">who wrote candle in the wind<\/code>, <code class=\"highlighter-rouge\">when was the wall by Pink Floyd published<\/code> and <code class=\"highlighter-rouge\">purchase Bad by Michael Jackson<\/code><\/li>\n<li>An entertainment context that enables requests like <code class=\"highlighter-rouge\">tell me a joke<\/code>, <code class=\"highlighter-rouge\">how much is 4 times 3<\/code>, <code class=\"highlighter-rouge\">how old is China<\/code> and <code class=\"highlighter-rouge\">give me a riddle<\/code><\/li>\n<\/ul>\n<h2 id=\"repository\">Repository<\/h2>\n<p><a href=\"https:\/\/github.com\/morsh\/multilingual-uber-bot\">https:\/\/github.com\/morsh\/multilingual-uber-bot<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Using Microsoft Bot Framework, we were able to create an easy to maintain &#8220;Orchestration Bot&#8221; that can both manage sub-bots and provide multilingual support.<\/p>\n","protected":false},"author":21371,"featured_media":11038,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[13],"tags":[],"class_list":["post-2117","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-bots"],"acf":[],"blog_post_summary":"<p>Using Microsoft Bot Framework, we were able to create an easy to maintain &#8220;Orchestration Bot&#8221; that can both manage sub-bots and provide multilingual support.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2117","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/users\/21371"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/comments?post=2117"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2117\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media\/11038"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media?parent=2117"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/categories?post=2117"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/tags?post=2117"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}