{"id":2138,"date":"2016-07-11T17:00:00","date_gmt":"2016-07-12T00:00:00","guid":{"rendered":"https:\/\/www.microsoft.com\/reallifecode\/index.php\/2016\/07\/11\/building-a-low-latency-smart-conversational-client\/"},"modified":"2020-03-18T12:32:30","modified_gmt":"2020-03-18T19:32:30","slug":"building-a-low-latency-smart-conversational-client","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/ise\/building-a-low-latency-smart-conversational-client\/","title":{"rendered":"Building a Low Latency Smart Conversational Client"},"content":{"rendered":"<p><em>Image: <a href=\"https:\/\/zh.wikipedia.org\/wiki\/%E6%B1%A1%E6%B0%B4%E8%99%95%E7%90%86#\/media\/File:Sewer_Plant.jpg\">Sewer_Plant<\/a> used by <a href=\"https:\/\/creativecommons.org\/licenses\/by-sa\/2.0\">CC BY-SA 2.0<\/a><\/em><\/p>\n<h2 id=\"background\">Background<\/h2>\n<p>Voice and natural language provide a level of personalization and comfort that leads to increased trust and productivity.<\/p>\n<p>As part of its cognitive services, Microsoft currently offers LUIS, a natural language intent recognition service, that converts natural language text into structured intents.<\/p>\n<h2 id=\"the-problem\">The Problem<\/h2>\n<p>One of the largest existing barriers to natural conversation processing is the latency caused by network lookups and a dependency on being online.<\/p>\n<p>We recently partnered with the R&amp;D department of <a href=\"http:\/\/www.robo-team.com\/\">Roboteam<\/a>, an innovative global robotics company, that required natural language processing capabilities for its robots. Roboteam was interested in using LUIS on Android to address this need, but required low latency and offline support to provide natural interaction to its users.<\/p>\n<p>The goal of the collaboration was to support Roboteam\u2019s need by providing an end to end open source smart conversational framework, that enables low latency voice interaction, using Microsoft\u2019s intent recognition technologies and a local smart cache.<\/p>\n<h2 id=\"overview-of-the-solution\">Overview of the Solution<\/h2>\n<p>We developed the \u201cSmart Conversational Client\u201d, a framework that enables client side caching and offline support for LUIS.<\/p>\n<p>Our implementation of the Smart Conversational Client enables the following capabilities:<\/p>\n<ul>\n<li>Online\/Offline Speech to Text<\/li>\n<li>Online\/Offline Natural Text to Intent<\/li>\n<li>Local Intent Recognition for faster look up<\/li>\n<li>Knowledge Graph Integration Interface<\/li>\n<\/ul>\n<h3 id=\"smart-conversational-client-architecture\">Smart Conversational Client Architecture<\/h3>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2016-07-12-Smart-Conversational-Client-SmartConversationalClient.jpg\" align=\"middle\" \/><\/p>\n<ol type=\"1\">\n<li><b>Voice\/Text Input<\/b>The speech to text mechanism in our demo application uses the <a href=\"https:\/\/developer.android.com\/reference\/android\/speech\/SpeechRecognizer.html\">Android Speech API<\/a>. The API provides low latency online and offline speech to text. However, unlike the <a href=\"https:\/\/msdn.microsoft.com\/en-us\/windows\/uwp\/input-and-devices\/speech-recognition\">UWP offering<\/a> the API does not support continuous recognition. Once a user\u2019s speech is converted to text, the text is passed to our smart conversational controller for processing.<\/li>\n<li><b>Smart Caching Layer<\/b>The smart caching layer is a persistent cache that combines disk and memory for optimized lookups. When the smart cache is initialized it pulls a set number of values from disk to memory for optimized lookups and generates key rules from known values in the persistent DB layer.The smart caching logic executes the following sequential flow until a result is found:<img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2016-07-12-Smart-Conversational-Client-SmartCacheFlowHorizontal.jpg\" align=\"middle\" \/>\n<ol type=\"A\">\n<li><b>In Memory look up<\/b>&#8211; Check the in memory segment of the cache to see if the query string is a key and if so return the cached value.<\/li>\n<li><b>DB look up<\/b>&#8211; Check the persistent DB segment of the cache to see if the query string is a key and if so return the cached value.<\/li>\n<li><b>Generalized rule look up<\/b>\u2013 Check if the query string matches a key rule and if so extract the known intents and entities from the string.Rule extraction performs as follows.\n<img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2016-07-12-Smart-Conversational-Client-RuleExtraction.png\" \/><\/li>\n<li><b>LUIS Query &amp; Async Cache Insertion<\/b>&#8211; Query LUIS endpoint, asynchronously cache the response and generate rule, then return response to user.Rule generation performs as follows:\n<img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2016-07-12-Smart-Conversational-Client-RuleGeneration.png\" \/><\/li>\n<li><b>Knowledge Graph Query<\/b>&#8211; Send the query to the associated knowledge graph and return the knowledge graph result.<\/li>\n<\/ol>\n<\/li>\n<li><b>Persistent DB Layer<\/b>The smart cache sits on top of a local persistent database layer. In our implementation we used <a href=\"https:\/\/github.com\/nhachicha\/SnappyDB\" target=\"None\" rel=\"noopener noreferrer\">SnappyDB<\/a>, an open source low latency key value database. To allow for extensibility we provide a Persistent DB interface that allows for anyone to use alternative persistent database methods such as SQLite or Realm. One requirement of the PersistentDB interface is that DBValues are serialized in JSON to provide for increased compatibility<\/li>\n<li><b>LUIS Client<\/b>In order to enable intent recognition, users of the system must train a model with the Luis portal. For an introduction on how to train a Luis Model please watch the following video.Our smart conversational controller consumes this model using the <a href=\"https:\/\/dev.projectoxford.ai\/docs\/services\/56d95961e597ed0f04b76e58\/operations\/5739a8c71984550500affdfa\">LUIS Programmatic API<\/a> using the performant <a href=\"https:\/\/developer.android.com\/training\/volley\/index.html\">Volley HttpClient<\/a> and <a href=\"https:\/\/github.com\/FasterXML\/jackson\"> Jackson <\/a>to parse the JSON response into android objects.<\/li>\n<li><b>Knowledge Graph Support<\/b>To provide for general knowledge questions we provide integration to a KnowledgeGraph Interface. The key requirement for implementing the knowledge graph interface is to convert a Query String into a IKnowledgeQuery Result. An IKnoweldgeQuery result must contain the original query string as well as method that generates a spoken text string from which ever knowledge graph it sits upon.<\/li>\n<\/ol>\n<h2 id=\"performance\">Performance<\/h2>\n<p>When combined with a trained LUIS model our smart conversational client provides an end to end framework for integrating low-latency voice and natural language processing in applications.\nThe project provides a large processing speed up over traditional conventional server side approaches with up to a 54x performance increase.<\/p>\n<p>The table below shows the mean, median and max bound recall times on 100 runs in milliseconds<\/p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\"><\/th>\n<th style=\"text-align: left;\">Mean<\/th>\n<th style=\"text-align: center;\">Median<\/th>\n<th style=\"text-align: center;\">Max<\/th>\n<th style=\"text-align: center;\">Min<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\">LUIS Client<\/td>\n<td style=\"text-align: left;\">407.38<\/td>\n<td style=\"text-align: center;\">479<\/td>\n<td style=\"text-align: center;\">4,402<\/td>\n<td style=\"text-align: center;\">54<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\">General Cache<\/td>\n<td style=\"text-align: left;\">296.01<\/td>\n<td style=\"text-align: center;\">124.5<\/td>\n<td style=\"text-align: center;\">1,109<\/td>\n<td style=\"text-align: center;\">&lt; 1<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left;\">Exact Cache<\/td>\n<td style=\"text-align: left;\">17.94<\/td>\n<td style=\"text-align: center;\">&lt; 1<\/td>\n<td style=\"text-align: center;\">123<\/td>\n<td style=\"text-align: center;\">&lt; 1<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"opportunities-for-reuse\">Opportunities for Reuse<\/h2>\n<p>This client is perfect for conversational IoT and bot based scenarios where latency has a big impact on overall user experience and some level of offline support is often required.<\/p>\n<p>All the code is open sourced and can be found on github <a href=\"https:\/\/github.com\/CatalystCode\/SmartConversationalClient\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>An an end to end smart conversational client, that enables low latency voice and text interaction, using Microsoft&#8217;s intent recognition technologies and a local smart cache.<\/p>\n","protected":false},"author":21353,"featured_media":12545,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[17],"tags":[231,268,312],"class_list":["post-2138","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-frameworks","tag-language-understanding-intelligent-service-luis","tag-natural-language-processing","tag-roboteam"],"acf":[],"blog_post_summary":"<p>An an end to end smart conversational client, that enables low latency voice and text interaction, using Microsoft&#8217;s intent recognition technologies and a local smart cache.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2138","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\/21353"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/comments?post=2138"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2138\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media\/12545"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media?parent=2138"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/categories?post=2138"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/tags?post=2138"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}