{"id":2125,"date":"2016-11-11T02:08:04","date_gmt":"2016-11-11T02:08:04","guid":{"rendered":"https:\/\/www.microsoft.com\/reallifecode\/index.php\/2016\/11\/11\/extending-microsofts-bot-framework-with-graph-based-dialogs\/"},"modified":"2020-03-15T06:32:10","modified_gmt":"2020-03-15T13:32:10","slug":"extending-microsofts-bot-framework-with-graph-based-dialogs","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/ise\/extending-microsofts-bot-framework-with-graph-based-dialogs\/","title":{"rendered":"Extending Microsoft&#8217;s Bot Framework with Graph-Based Dialogs"},"content":{"rendered":"<p><em>Image: <a href=\"https:\/\/www.flickr.com\/photos\/arthur-caranta\/3061094186\">DNA<\/a> by <a href=\"https:\/\/www.flickr.com\/photos\/arthur-caranta\">Arthur Caranta<\/a>, used by <a href=\"https:\/\/creativecommons.org\/licenses\/by-sa\/2.0\">CC BY 2.0<\/a><\/em><\/p>\n<h1 id=\"background\">Background<\/h2>\n<p><a href=\"https:\/\/pager.com\/\">Pager<\/a> uses technology to help patients better navigate an expansive healthcare landscape and connect them to quality care. The company is exploring using bot technology to automate larger portions of their platform, and we collaborated with them on this project.<\/p>\n<p>Many patients are not aware that the assessment of the nature and severity of their condition begins the moment they to arrange an appointment or walk into a hospital. Whether through a phone call, in person, or online, health systems solicit a patient\u2019s chief complaint in order to understand the urgency of a situation. Patients first identify themselves, and then a representative asks a series of questions in order to understand whether the patient is the right fit for that specific venue of care. For acute conditions, the process follows a triage protocol based on the patient\u2019s description of symptoms. For example, a patient with a headache would be asked details about the type of pain, speed of onset, associated symptoms such as numbness, weakness, or fever.<\/p>\n<p>For experienced nurses and other clinicians, the protocols are second nature and committed to memory and are used to identify potentially unstable conditions that require more immediate attention. Past medical history, risk factors, and other demographic information is used to risk stratify patients. In addition, insurance and other financial data is obtained to determine whether the care will be covered, and together with the medical data, to direct the patient to the most suitable care environment.<\/p>\n<p>For Pager, using human representatives (nurses in this case) to conduct scripted protocols through a text interface is time-consuming, hard to scale, and error prone.<\/p>\n<h1 id=\"the-problem\">The Problem<\/h2>\n<p>Before this engagement, if a developer wanted to build a dialog for a protocol using the <a href=\"https:\/\/dev.botframework.com\/\">Microsoft Bot Framework<\/a>, they had to hard-code each of the individual dialog steps in the bot service. Since Pager has hundreds of different protocols, they wanted to be able to dynamically load the dialogs from an external data source, such as a file, or a database. Dynamic loading of protocols also allows Pager to update their bot without needing to change and redeploy its code.<\/p>\n<p>Additionally, Bot Framework uses a relatively basic waterfall conversation paradigm for modeling conversations:<\/p>\n<ul>\n<li>The developer provides a hard-coded list of steps, where each step is an interaction with the user, and waits for a response.<\/li>\n<li>The framework sends the question to the user. When the user replies, the framework gets the input and transfers it to the next step in the waterfall.<\/li>\n<\/ul>\n<p>The problem is that most types of conversation do not look like a waterfall, but more like a graph. Each interaction with the user is represented as a node, and, according to the user\u2019s input, the conversation should be able to flow to different nodes in that graph. This flow can be implemented using only Bot Framework\u2019s APIs, but it is not a straightforward or easily reusable process to implement.<\/p>\n<h2 id=\"the-engagement\">The Engagement<\/h2>\n<p>We collaborated with Pager to develop an extension for Bot Framework that supports graph-based dialogs and dynamic loading of those dialogs from an external data source. The dialogs are then stored using a JSON schema. The extension is a Node.js module that was implemented using TypeScript.<\/p>\n<p>The following are some of the features that are supported by this extension:<\/p>\n<ul>\n<li><strong>Embedding dialogs<\/strong>: Common dialogs (scenarios) can be separated and embedded as a single step in other dialogs.<\/li>\n<li><strong>Scoring against multiple LUIS APIs<\/strong>: Calling multiple <a href=\"https:\/\/www.luis.ai\/\">LUIS<\/a> models and deciding what to do next based on the scoring. This action can be done in any step of the conversation, not only in the first step as it is demonstrated today using Bot Framework.<\/li>\n<li><strong>Custom code handlers<\/strong>: Providing external handlers (either embedded in the JSON or by providing a <code class=\"highlighter-rouge\">handler loader<\/code> callback to the library).<\/li>\n<li><strong>Extendable schema<\/strong>: Providing custom step handlers to be able to extend the dialog with custom node types beyond the ones that are natively supported by the extension.<\/li>\n<\/ul>\n<p>An example of using the library:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"c1\">\/\/ handler for loading scenarios from external datasource<\/span>\r\n<span class=\"kd\">function<\/span> <span class=\"nx\">loadScenario<\/span><span class=\"p\">(<\/span><span class=\"nx\">scenario<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\r\n    <span class=\"k\">return<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">Promise<\/span><span class=\"p\">((<\/span><span class=\"nx\">resolve<\/span><span class=\"p\">,<\/span> <span class=\"nx\">reject<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\r\n        <span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"s1\">'loading scenario'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">scenario<\/span><span class=\"p\">);<\/span>\r\n\r\n        <span class=\"c1\">\/\/ implement loadScenario from external datasource.<\/span>\r\n        <span class=\"kd\">var<\/span> <span class=\"nx\">scenarioObj<\/span> <span class=\"o\">=<\/span> <span class=\"p\">...<\/span>\r\n        <span class=\"nx\">resolve<\/span><span class=\"p\">(<\/span><span class=\"nx\">scenarioObj<\/span><span class=\"p\">);<\/span>\r\n    <span class=\"p\">});<\/span>\r\n<span class=\"p\">}<\/span>\r\n\r\n\r\n<span class=\"nx\">GraphDialog<\/span><span class=\"p\">.<\/span><span class=\"nx\">fromScenario<\/span><span class=\"p\">({<\/span>\r\n        <span class=\"nx\">bot<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"nx\">loadScenario<\/span><span class=\"p\">,<\/span>\r\n        <span class=\"na\">scenario<\/span><span class=\"p\">:<\/span> <span class=\"s1\">'smoking'<\/span>\r\n    <span class=\"p\">})<\/span>\r\n    <span class=\"p\">.<\/span><span class=\"nx\">then<\/span><span class=\"p\">(<\/span><span class=\"nx\">graphDialog<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">bot<\/span><span class=\"p\">.<\/span><span class=\"nx\">dialog<\/span><span class=\"p\">(<\/span><span class=\"s1\">'\/smoking'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">graphDialog<\/span><span class=\"p\">.<\/span><span class=\"nx\">getDialog<\/span><span class=\"p\">()));<\/span>\r\n<\/code><\/pre>\n<\/div>\n<p>An example of a <code class=\"highlighter-rouge\">smoking<\/code> scenario:<\/p>\n<div class=\"language-json highlighter-rouge\">\n<pre class=\"highlight\"><code><span class=\"p\">{<\/span>\r\n  <span class=\"nt\">\"id\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"smoking\"<\/span><span class=\"p\">,<\/span>\r\n  <span class=\"nt\">\"type\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"sequence\"<\/span><span class=\"p\">,<\/span>\r\n  <span class=\"nt\">\"steps\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\r\n    <span class=\"p\">{<\/span>\r\n      <span class=\"nt\">\"id\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"isSmoking\"<\/span><span class=\"p\">,<\/span>\r\n      <span class=\"nt\">\"type\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"prompt\"<\/span><span class=\"p\">,<\/span>\r\n      <span class=\"nt\">\"data\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span> <span class=\"nt\">\"type\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"confirm\"<\/span><span class=\"p\">,<\/span> <span class=\"nt\">\"text\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"Do you smoke?\"<\/span> <span class=\"p\">},<\/span>\r\n      <span class=\"nt\">\"scenarios\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\r\n        <span class=\"p\">{<\/span>\r\n          <span class=\"nt\">\"condition\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"isSmoking\"<\/span><span class=\"p\">,<\/span>\r\n          <span class=\"nt\">\"steps\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\r\n            <span class=\"p\">{<\/span>\r\n              <span class=\"nt\">\"id\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"smokeTime\"<\/span><span class=\"p\">,<\/span>\r\n              <span class=\"nt\">\"type\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"prompt\"<\/span><span class=\"p\">,<\/span>\r\n              <span class=\"nt\">\"data\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span> <span class=\"nt\">\"type\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"number\"<\/span><span class=\"p\">,<\/span> <span class=\"nt\">\"text\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"For how many years?\"<\/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          <span class=\"nt\">\"condition\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"!isSmoking\"<\/span><span class=\"p\">,<\/span>\r\n          <span class=\"nt\">\"steps\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\r\n            <span class=\"p\">{<\/span>\r\n              <span class=\"nt\">\"id\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"sureNotSmoking\"<\/span><span class=\"p\">,<\/span>\r\n              <span class=\"nt\">\"type\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"prompt\"<\/span><span class=\"p\">,<\/span>\r\n              <span class=\"nt\">\"data\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span> <span class=\"nt\">\"type\"<\/span><span class=\"p\">:<\/span><span class=\"s2\">\"confirm\"<\/span><span class=\"p\">,<\/span> <span class=\"nt\">\"text\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"Are you sure?\"<\/span> <span class=\"p\">},<\/span>\r\n              <span class=\"nt\">\"scenarios\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\r\n                <span class=\"p\">{<\/span>\r\n                  <span class=\"nt\">\"condition\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"!sureNotSmoking\"<\/span><span class=\"p\">,<\/span>\r\n                  <span class=\"nt\">\"nodeId\"<\/span><span class=\"p\">:<\/span> <span class=\"s2\">\"isSmoking\"<\/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      <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<ul>\n<li>Using <code class=\"highlighter-rouge\">\"condition\": \"!sureNotSmoking\"<\/code> relates to the <code class=\"highlighter-rouge\">sureNotSmoking<\/code> node\u2019s boolean value (the input for <code class=\"highlighter-rouge\">\"Are you sure?\"<\/code>)<\/li>\n<li>Using <code class=\"highlighter-rouge\">\"nodeId\": \"isSmoking\"<\/code> means that the dialog will <em>jump<\/em> to step <code class=\"highlighter-rouge\">isSmoking<\/code> to collect that answer again.<\/li>\n<\/ul>\n<p>For more details about the schema, please see the repositories below.<\/p>\n<h1 id=\"the-code\">The Code<\/h2>\n<p>Two repositories are available that include instructions on how to run and use the code in addition to code samples:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/CatalystCode\/bot-graph-dialog\">bot-graph-dialog<\/a>: The actual TypeScript implementation of the Node.js extension<\/li>\n<li><a href=\"https:\/\/github.com\/CatalystCode\/bot-trees\">bot-trees<\/a>: A sample bot service that demonstrates how to use the bot-graph-dialog extension<\/li>\n<\/ul>\n<h1 id=\"opportunities-for-reuse\">Opportunities for Reuse<\/h2>\n<p>The <code class=\"highlighter-rouge\">bot-graph-dialog<\/code> extension can be plugged in to enhance or completely recreate any new or existing Node.js bot running on top of Bot Framework. It can be used to dynamically load dialogs from external data sources and embed these dialogs in any of the existing APIs that get a waterfall array of steps. Also, since the extension itself is extendable, it can be extended with custom types of nodes, with external handlers and much more.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Developing an extension for Microsoft Bot Framework that supports graph-based dialogs and dynamic loading of those dialogs from an external data source.<\/p>\n","protected":false},"author":21349,"featured_media":11075,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[13],"tags":[231,249,275,288],"class_list":["post-2125","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-bots","tag-language-understanding-intelligent-service-luis","tag-microsoft-bot-framework-mbf","tag-node","tag-pager"],"acf":[],"blog_post_summary":"<p>Developing an extension for Microsoft Bot Framework that supports graph-based dialogs and dynamic loading of those dialogs from an external data source.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2125","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\/21349"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/comments?post=2125"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2125\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media\/11075"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media?parent=2125"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/categories?post=2125"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/tags?post=2125"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}