<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Geoff Innis</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/geoffreyinnis/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/geoffreyinnis/feed.xml</link>
    <description>Driving innovation in the Service pillar of Dynamics 365</description>
    <lastBuildDate>Fri, 15 Mar 2019 04:03:03 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Lightweight Geospatial in Dynamics 365 for Phones</title>
      <link>https://docs.microsoft.com/archive/blogs/geoffreyinnis/lightweight-geospatial-in-dynamics-365-for-phones</link>
      <pubDate>Wed, 13 Mar 2019 17:05:45 GMT</pubDate>
      <dc:creator><![CDATA[Geoff Innis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/geoffreyinnis/?p=2585</guid>
      <description><![CDATA[Bringing geospatial insights to business solutions is certainly nothing new; mapping and spatial...]]></description>
      <content:encoded><![CDATA[Bringing geospatial insights to business solutions is certainly nothing new; mapping and spatial searching are core components of the <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/field-service/turn-on-auto-geocoding#geocode-the-address-on-an-account-record" rel="noopener" target="_blank">Dynamics 365 for Field Service</a>, and many <a href="https://appsource.microsoft.com/en-us/?product=dynamics-365-business-central%3Bdynamics-365-for-customer-services%3Bdynamics-365-for-field-services%3Bdynamics-365-for-finance-and-operations%3Bdynamics-365-for-project-service-automation%3Bdynamics-365-for-sales&amp;search=map" rel="noopener" target="_blank">ISV solutions are available</a> to glean location-based insights to optimize operations in Dynamics.

In this post, we will see how we can quickly and easily bring lightweight geospatial capabilities to the <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/mobile-app/dynamics-365-phones-tablets-users-guide" rel="noopener" target="_blank">Dynamics 365 for Phones</a> application, with nothing more than a <a href="https://docs.microsoft.com/en-us/bingmaps/getting-started/bing-maps-dev-center-help/getting-a-bing-maps-key" rel="noopener" target="_blank">Bing Maps key</a>, and a Web Resource that we will create. This 60 second video (with voice-over) shows our end-result in action:

[video width="1920" height="1080" mp4="https://msdnshared.blob.core.windows.net/media/2019/03/MapsOnMobile.mp4"][/video]

&nbsp;

We will enable our users in the field to:

<ul>
<li>Quickly open account records based on proximity, saving time and increasing adoption</li>
<li>Visualize customer buildings and sites to streamline visits</li>
<li>Identify nearby accounts for ad-hoc visits, to optimize time in the field</li>
</ul>

We will create an <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/webpage-html-web-resources" rel="noopener" target="_blank">HTML Web Resource</a> that will identify the user’s location, search the <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/clientapi/reference/xrm-webapi" rel="noopener" target="_blank">Web API</a> to find nearby accounts, then plot those accounts (with corresponding entity images) on a map. While in the field, users can launch their app, and immediately bring up account records as they approach.

&nbsp;

<strong>Prerequisites</strong>

The prerequisites for building and deploying our account mapping in D365 for Phones include:

<ul>
<li>An instance of Dynamics 365 (Online)
<ul><li>You can request a trial of Dynamics 365 <a href="https://trials.dynamics.com/" rel="noopener" target="_blank">here</a></li></ul>
</li>
<li>Geocoded Account Records, with <strong>address1_latitude</strong> and <strong>address1_longitude</strong> attributes populated (note that the Field Service module for Dynamics includes in-built geocoding capabilities)</li>
<li>The<a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/mobile-app/install-dynamics-365-for-phones-and-tablets" rel="noopener" target="_blank"> Dynamics 365 for Phones</a> app installed on your mobile device</li>
<li>The text editor of your choice</li>
<li>A Bing Maps for Enterprise key</li>
<ul><li>You can obtain a key using the instructions found <a href="https://docs.microsoft.com/en-us/bingmaps/getting-started/bing-maps-dev-center-help/getting-a-bing-maps-key" rel="noopener" target="_blank">here</a></li></ul>
</li>
</ul>

&nbsp;

<strong>Creating our HTML Web Resource</strong>

In a Web Resource, we can use JavaScript to not only access the <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/clientapi/reference" rel="noopener" target="_blank">Dynamics Client API</a>, but also the <a href="https://docs.microsoft.com/en-us/bingmaps/v8-web-control/">Bing Maps v8 control</a> for interactive mapping. As a result, most of our work will be done in JavaScript.

Using the text editor of our choice, we will begin building our web resource. We start with our HTML document, in which we include the JavaScript library for our Dynamics Client API, along with some global variables defined in JavaScript:

&nbsp;

[snippet slug=maps-on-mobile-web-resource-start line_numbers=false lang=html]

&nbsp;

<strong>Creating our Map</strong>

We define our <strong>GetMap </strong>function (to be called when the Bing Maps JavaScript library has loaded) such that it will:
<ul><li>find the user’s location using the <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/clientapi/reference/xrm-device/getcurrentposition" rel="noopener" target="_blank">Xrm.Device.getCurrentPosition method</a></li>
<li>instantiate an interactive map in our HTML page, and</li>
<li>call the <strong>getNearbyAccounts </strong>function, passing the user's location</li>

&nbsp;

[snippet slug=maps-on-mobile-getmap line_numbers=false lang=js]

&nbsp;

<strong>Finding Nearby Accounts</strong>

Our <strong>getNearbyAccounts </strong>function will receive the user's location as parameters, and will then:

<ul><li>build and execute a <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/clientapi/reference/xrm-webapi/retrievemultiplerecords" rel="noopener" target="_blank">retrieveMultipleRecords </a>call against the D365 Web API using a bounding box around our user’s location</li>
<li>load the <a href="https://docs.microsoft.com/en-us/bingmaps/v8-web-control/modules/spatial-math-module/" rel="noopener" target="_blank">Microsoft.Maps.SpatialMath</a> module to enable us to readily determine distances between locations</li>
<li>sort our locations by distance, using the <strong>compareDistance </strong>function</li>
<li>call our <strong>AddPushpinCanvas </strong>function for each account</li>
<li>set the map view to optimally display all accounts and the user’s location</li>
</ul>

&nbsp;

[snippet slug=maps-on-mobile-getnearbyaccounts line_numbers=false lang=js]

&nbsp;

<strong>Adding Pushpins with Account Images and Click Handlers</strong>

Our <strong>AddPushpinCanvas </strong>function will accept the account and callback function as parameters, and will then:

<ul><li>define a function to call after our account entity image has been loaded, to:
<ul><li>create a Canvas element</li>
<li>add the entity image to the canvas, cropped to a circle</li>
<li>add a border to the canvas</li>
<li>create a Pushpin using the Canvas we created as the icon</li>
<li>add a click handler to the pushpin, to open the appropriate account record</li>
<li>call the specified callback function, which will then add the pushpin to the map</li></ul>
</li>
<li>load the entity image for the account, subsequently triggering the <strong>onload </strong>function</li>
</ul>

&nbsp;

[snippet slug=maps-on-mobile-addpushpincanvas line_numbers=false lang=js]

&nbsp;

<strong>Our HTML Web Resource Body</strong>

The body of our HTML document is minimal:

<ul><li>a DIV to present messages to the user as an overlay</li>
<li>a DIV to host our interactive map</li>
<li>a SCRIPT tag to load the Bing Maps v8 map control, with our <strong>GetMap </strong>function specified as the function to call upon load</li>
</ul>

&nbsp;

[snippet slug=maps-on-mobile-body line_numbers=false lang=html]

&nbsp;

<strong>Creating a Dashboard</strong>

We will now create a basic dashboard containing our web resource. First, we will upload our HTML document as a new web resource, navigating in the Web Client to <strong>Settings &gt; Customizations &gt; Customize the System &gt; Web Resources &gt; New</strong>:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2019/03/WebResource-800x766.jpg" alt="" style="border-style: solid;border-width: 1px" width="800" height="766" class="aligncenter size-medium wp-image-2635" />

&nbsp;

<strong>Note:</strong> Ensure you select Enable for Mobile.

We then navigate to Settings &gt; Customizations &gt; Customize the System &gt; Dashboards &gt; New, and create a new Dashboard. We can choose any layout, but we then remove all but one component, which we populate with our web resource. Ensure you <strong>Enable Mobile</strong> for the Dashboard:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2019/03/dashboard_mobile-800x637.jpg" alt="" style="border-style: solid;border-width: 1px" width="800" height="637" class="aligncenter size-medium wp-image-2605" />

&nbsp;


And Enable Mobile for the Web Resource in the dashboard:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2019/03/enablewrformobile-800x610.jpg" alt="" style="border-style: solid;border-width: 1px" width="800" height="610" class="aligncenter size-medium wp-image-2615" />

&nbsp;

In the App Designer for your desired Hub App, ensure your newly created dashboard has been added, then save and publish:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2019/03/saleshub-800x587.jpg" alt="" style="border-style: solid;border-width: 1px" width="800" height="587" class="aligncenter size-medium wp-image-2625" />

&nbsp;

Now, on your mobile device, launch the Dynamics 365 for Phones app, and navigate to <strong>Settings &gt; Mobile Settings</strong>, ensuring that you have enabled <strong>User Content and Location</strong>:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2019/03/mobilesettings-450x800.jpg" style="border-style: solid;border-width: 1px" alt="" width="450" height="800" class="aligncenter size-medium wp-image-2715" />

&nbsp;

Now, if you navigate to the newly created dashboard in the app, you should be able to see your location, and any accounts in the vicinity:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2019/03/finalscreenshot-425x800.png" alt="" style="border-style: solid;border-width: 0px" width="425" height="800" class="aligncenter size-medium wp-image-2655" />

&nbsp;


With this simple web resource, we can increase adoption, and empower our field teams with relevant geo-centric efficiency.

The full Web Resource code for this sample can be found <a href="https://1drv.ms/u/s!Aui7CDzJQqg_jQxao0-6-EvNLi5h" rel="noopener" target="_blank">here</a>.





]]></content:encoded>
    </item>
    <item>
      <title>Phone Call Transcription and Insights with Video Indexer and Dynamics 365 (Part 2)</title>
      <link>https://docs.microsoft.com/archive/blogs/geoffreyinnis/phone-call-transcription-and-insights-with-video-indexer-and-dynamics-365-part-2</link>
      <pubDate>Thu, 30 Aug 2018 15:04:15 GMT</pubDate>
      <dc:creator><![CDATA[Geoff Innis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/geoffreyinnis/?p=2495</guid>
      <description><![CDATA[This post is the second in a series in which we explore how we can leverage Microsoft’s Cognitive...]]></description>
      <content:encoded><![CDATA[This post is the second in a series in which we explore how we can leverage Microsoft’s <strong>Cognitive Services</strong> to greatly enhance the insights we can derive from phone call recordings in an automated way. We can leverage the investments Microsoft has been making in machine learning and artificial intelligence to automatically extract metadata from audio and video files, including conversation keywords, a sentiment timeline, a call transcript, and more.

In <strong>Part 2</strong>, we will build upon the Custom Actions and Workflow that we built in <a href="https://blogs.msdn.microsoft.com/geoffreyinnis/2018/07/10/phone-call-transcription-and-insights-with-video-indexer-and-dynamics-365-part-1/" rel="noopener" target="_blank">Part 1</a> by bringing in rich Insights, Transcript, and Call Audio widgets directly into our Phone Call record in Dynamics, with the ability to view our full transcript, visualize our sentiment timeline, and search the call, with an integrated media player allowing us to jump to and listen to key moments in the call:

&nbsp;

<em>Insights Widget, including interactivity with Audio Widget</em>
<img src="https://msdnshared.blob.core.windows.net/media/2018/07/InsightsWidget1-800x465.png" alt="" width="800" height="465" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2155" />

&nbsp;

<em>Transcript Widget, including interactivity with Audio Widget</em>
<img src="https://msdnshared.blob.core.windows.net/media/2018/07/InsightsWidget2-800x465.png" alt="" width="800" height="465" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2145" />

&nbsp;

In order to <a href="https://docs.microsoft.com/en-us/azure/cognitive-services/video-indexer/video-indexer-embed-widgets" rel="noopener" target="_blank">embed the Video Indexer Cognitive Insights and Player widgets</a> into our Phone Call form in Dynamics, we need to first obtain a Video Access Token from the Video Indexer API, and use that token in our widget URLs.

As part of our earlier post, we already have a <strong>Custom Workflow Activity</strong> that will retrieve a Video Access Token for us. In order to be able to access it from our Web Resource, we will create an <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/webapi/use-web-api-actions#use-a-custom-action" rel="noopener" target="_blank">Action that is callable from the Dynamics Web API</a>.

&nbsp;

<strong>Custom Action to Retrieve Token</strong>

Logged in to the Dynamics 365 web client with our administrator credentials, we navigate to <strong>Settings &gt; Customizations &gt; Customize the System</strong>. We choose <strong>Processes </strong>from the left navigation, and choose <strong>New</strong>.

We specify that we are creating an <strong>Action </strong>type of process that is not applicable to a specific entity:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2018/08/NewActionToken-800x601.png" alt="" width="800" height="601" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2535" />

&nbsp;

Our Input and Output arguments for the Action will be:
<ul><li><strong>Input</strong>
<ul><li>VideoId (String)</li></ul></li>
<li><strong>Output</strong>
<ul><li>VideoAccessToken (String)</li>
<li>VideoIndexerAccountId (String)</li></ul></li>
</ul>

&nbsp;

Our Action will include the following logic:
<ul><li>we call our <strong>GetVideoToken </strong>Custom Workflow Activity</li>
<li>we check to ensure that our activity completed successfully, and that we have values for our Account ID and Access Token, and if so, we assign values to our <strong>VideoAccessToken </strong>and <strong>VideoIndexerAccountId </strong>output arguments</li>
</ul>

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2018/08/ActionDefinition-800x642.png" alt="" width="800" height="642" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2505" />

&nbsp;

We set the input parameters to the <strong>GetVideoToken </strong>activity like so:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2018/08/GetVideoTokenInput-800x309.png" alt="" width="800" height="309" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2515" />

&nbsp;

After we <strong>Save </strong>and <strong>Activate </strong>our process, we are now ready to build our <strong>Web Resource</strong> that will call it.

&nbsp;

<strong>Phone Call Insights Web Resource</strong>

We now create an <strong>HTML Web Resource</strong> that will be embedded in our Phone Call form in Dynamics, and will present rich and interactive Insights, Transcript and Call Audio widgets.

Our Web Resource code contains:
<ul><li>two Iframes to hold the Cognitive Insights Widget and Player Widget</li>
<li>an included Mediator JavaScript file, to manage the interactions between the two widgets</li>
<li>our included ClientGlobalContext JavaScript file to aid our Dynamics client scripting</li>
<li>JavaScript code that will execute on the onload event of our document body, and:
<ul><li>Retrieve the Video Indexer ID from our Phone Call record</li>
<li>Build and Execute a request to the Dynamics Web API to call our newly-created Action to obtain a Video Token, via the XMLHttpRequest object</li>
<li>Obtain the Video Token and Video Indexer Account ID from the response</li>
<li>Build URLs for the Insights Widget and Player widget using the account ID, video ID, and token</li>
<li>Use the built URLs to set the Source for the two widget Iframes</li></ul></li></ul>

&nbsp;

[snippet slug=phonecallinsightswebresource line_numbers=false lang=html]

&nbsp;

Logged in to the Dynamics 365 web client with our administrator credentials, we navigate to <strong>Settings &gt; Customizations &gt; Customize the System</strong>. We choose <strong>Web Resources</strong> from the left navigation, and choose <strong>New</strong>, and we can now provide a name, upload our code, and <strong>Save </strong>and <strong>Publish</strong>.

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2018/08/WebResourceCreate-800x624.png" alt="" width="800" height="624" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2555" />

&nbsp;

<strong>Updating our Phone Call Form</strong>

We now add our newly-created Web Resource to our desired Phone Call form.

Logged in to the Dynamics 365 web client with our administrator credentials, we navigate to <strong>Settings &gt; Customizations &gt; Customize the System</strong>. We choose <strong>Entities &gt; Phone Call &gt; Forms</strong> from the left navigation, and select our <strong>Phone Call for Interactive experience</strong> form.

To the form, we add a new <strong>Tab</strong>, and within that Tab, we add our <strong>Web Resource</strong>:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2018/08/PhoneCallForm.png" alt="" width="769" height="708" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-2545" />

&nbsp;

We save our form, publish our customizations, and are now ready to view our Phone Call Insights. We can navigate to our Phone Call record from <strong>Part 1</strong>, and we can now open and view our interactive Insights, Transcript and Player widgets:

&nbsp;
<em>Insights Widget, including interactivity with Audio Widget</em>
<img src="https://msdnshared.blob.core.windows.net/media/2018/07/InsightsWidget1-800x465.png" alt="" width="800" height="465" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2155" />

&nbsp;
<em>Transcript Widget, including interactivity with Audio Widget</em>
<img src="https://msdnshared.blob.core.windows.net/media/2018/07/InsightsWidget2-800x465.png" alt="" width="800" height="465" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2145" />

&nbsp;

We can now:
<ul><li>View our call sentiment timeline, and jump to any point in the call audio</li>
<li>View call keywords, and jump to any instances of those keywords in the call audio</li>
<li>View and Search our transcript, playing audio from any point in the transcript or search results</li>
<li>Translate our transcript into a variety of languages</li>
</ul>

&nbsp;

By deriving call recording insights from the Video Indexer service and bringing them into Dynamics, we can now have a greater understanding of key support issues, customer sentiment, and call quality, not only for individual customers and calls, but across our organization. We can leverage this to help us optimize our support operations, and customer interactions on an ongoing basis.








]]></content:encoded>
    </item>
    <item>
      <title>Phone Call Transcription and Insights with Video Indexer and Dynamics 365 (Part 1)</title>
      <link>https://docs.microsoft.com/archive/blogs/geoffreyinnis/phone-call-transcription-and-insights-with-video-indexer-and-dynamics-365-part-1</link>
      <pubDate>Tue, 10 Jul 2018 09:29:12 GMT</pubDate>
      <dc:creator><![CDATA[Geoff Innis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/geoffreyinnis/?p=2135</guid>
      <description><![CDATA[In many contact centers, the telephone continues to be one of the primary channels of engagement for...]]></description>
      <content:encoded><![CDATA[In many contact centers, the telephone continues to be one of the primary channels of engagement for customers. Frequently, the only insights we will have about the nature of a call that has taken place will be based on the typed notes or other data manually entered by the contact center agent. 

By leveraging Microsoft’s <strong>Cognitive Services</strong>, we can greatly enhance the insights we can derive from phone call recordings in an automated way. We can leverage the investments Microsoft has been making in machine learning and artificial intelligence to automatically extract metadata from audio and video files, including conversation keywords, a sentiment timeline, a call transcript, and more.

This post will be the first in a series in which we explore how we can leverage the new <a href="https://azure.microsoft.com/en-us/services/cognitive-services/video-indexer/" rel="noopener" target="_blank">Video Indexer service</a> (currently in preview), along with the robust workflow capabilities of Dynamics 365 for Customer Engagement, to automate the indexing of phone call recordings, augment our Phone Call records with metadata about the contents of the call, and provide users with an interactive experience within Dynamics to gain more insights into the conversation. 

This first post will focus on creating <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/custom-workflow-activities-workflow-assemblies" rel="noopener" target="_blank">Custom Workflow Activities</a> that interact with the <a href="https://api-portal.videoindexer.ai/docs/services/operations/operations/Get-Video-Index?" rel="noopener" target="_blank">Video Indexer API</a> to upload and index call recordings, then using those activities within a <strong>Workflow </strong>process to automatically update our Phone Call record with insightful metadata.

In this post, we will build on the sample code available in these two resources:

<ul>
<li><a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/workflow/create-custom-workflow-activity" rel="noopener" target="_blank">Create a custom workflow activity</a> in the Dynamics 365 documentation, and the associated code samples in the D365 SDK</li>
<li>The Video Indexer <a href="https://docs.microsoft.com/en-us/azure/cognitive-services/video-indexer/upload-index-videos" rel="noopener" target="_blank">How-to Guide for Uploading and Indexing Videos</a> in the Cognitive Services documentation</li>
</ul>

&nbsp;

By the end of our first post, we will be able to view some derived insight metadata about our recorded phone call in Dynamics:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2018/07/CallInsightsScreenshot-800x466.png" alt="" width="800" height="466" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2165" />

&nbsp;

And by the end of our series, we will also be able to leverage a rich Insights and Transcript viewer, with the ability to view our full transcript, visualize our sentiment timeline, and search the call, with an integrated media player allowing us to jump to and listen to key moments in the call:

&nbsp;
<em>Insights Widget, including interactivity with Audio Widget</em>
<img src="https://msdnshared.blob.core.windows.net/media/2018/07/InsightsWidget1-800x465.png" alt="" width="800" height="465" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2155" />

&nbsp;
<em>Transcript Widget, including interactivity with Audio Widget</em>
<img src="https://msdnshared.blob.core.windows.net/media/2018/07/InsightsWidget2-800x465.png" alt="" width="800" height="465" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2145" />

&nbsp;

<strong>Notes: </strong>
<ul><li>In this post, we will assume that we have access to a recording of the telephone call, and that the Phone Call record in Dynamics 365 will be updated with a URL where the audio recording can be retrieved. Many telephony providers offer call recording capabilities, and this data can typically be captured through basic CTI integration.</li>
<li>The Video Indexer service brings together a number of cognitive capabilities into a readily-consumable service, minimizing development. We will use the Video Indexer service in this post, but for those seeking greater control over the underlying cognitive capabilities being leveraged, Azure Media Services can enable developers to achieve similar functionality. </li>
</ul>

&nbsp;

<strong>Prerequisites</strong>

The prerequisites for building and deploying our custom workflow activity include:
<ul>
<li>An instance of Dynamics 365 for Customer Service (Online)
<ul><li>You can request a trial of Dynamics 365 for Customer Service <a href="https://go.microsoft.com/fwlink/?linkid=849057" target="_blank">here</a></li></ul>
</li>
<li><a href="https://www.visualstudio.com/en-us/products/vs-2015-product-editions.aspx" target="_blank">Visual Studio</a> 2015 or higher, with <a href="https://docs.microsoft.com/en-us/visualstudio/workflow-designer/developing-applications-with-the-workflow-designer#install-windows-workflow-foundation" rel="noopener" target="_blank">Windows Workflow Foundation</a> installed</li>
<li>Microsoft .NET Framework 4.5.2</li>
<li>The <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/download-tools-nuget" rel="noopener" target="_blank">Dynamics 365 Developer Tools</a></li>
<li>A subscription for the <a href="https://docs.microsoft.com/en-us/azure/cognitive-services/video-indexer/video-indexer-use-apis" rel="noopener" target="_blank">Cognitive Services Video Indexer API</a>
<ul><li>As of the time of writing, you can obtain a free subscription to this preview service API following the instructions found <a href="https://docs.microsoft.com/en-us/azure/cognitive-services/video-indexer/video-indexer-use-apis" rel="noopener" target="_blank">here</a>. </li>
<li>Follow the instructions in the above link to obtain your Account ID, Primary Key and Location parameter (‘trial’ for trial accounts, but may differ if you connect your account to Azure)</li></ul></li>
</ul>

&nbsp;

<strong>Adding Custom Fields to Phone Call Entity</strong>

Before we create our workflow to obtain insights about phone call recordings, we will add some custom fields to the <strong>Phone Call</strong> entity. Many of these will be updated with insights from the Video Indexer service. These fields include:

<ul><li><strong>Call Recording URL</strong> (Single Line of Text): to store the URL where our call recording is stored; it is assumed this will be programmatically set by the telephony provider</li>
<li><strong>Video Indexer ID</strong> (Single Line of Text): to store the ID of our call index in the Video Indexer service</li>
<li><strong>Call Keywords </strong>(Multiple Lines of Text): to store a comma-separated list of keywords from the Video Indexer insights</li>
<li><strong>Negative Sentiment Ratio</strong> (Decimal Number, minimum 0, maximum 100): to store a value representing the percentage of the call recording in which negative sentiment was detected</li>
<li><strong>Positive Sentiment Ratio</strong> (Decimal Number, minimum 0, maximum 100): to store a value representing the percentage of the call recording in which positive sentiment was detected</li>
<li><strong>Neutral Sentiment Ratio</strong> (Decimal Number, minimum 0, maximum 100): to store a value representing the percentage of the call recording in which neutral sentiment was detected</li>
</ul>

&nbsp;

For a detailed walkthrough of adding new fields to D365 for Customer Engagement, see <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/customize/create-edit-fields" rel="noopener" target="_blank">here</a>.

&nbsp;

<strong>Building our Custom Workflow Activities</strong>

In <strong>Visual Studio</strong>, we will first create a new project by selecting <strong>Workflow </strong>under <strong>Visual C#</strong> in the <strong>Installed Templates</strong> pane, and then select <strong>Activity Library</strong>. We will name our project <strong>CallAudioAnalysis</strong>.

<img src="https://msdnshared.blob.core.windows.net/media/2018/07/CreateAudioAnalysisProject-800x554.png" alt="" width="800" height="554" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2345" />

In our <strong>Project Properties</strong>, on the <strong>Application </strong>tab, we specify <strong>.NET Framework 4.5.2</strong> as the target framework.

&nbsp;

<strong>Adding References </strong>

We add references to our project by right-clicking the <strong>CallAudioAnalysis </strong>project in the Solution Explorer, and adding the following:
<ul><li>Microsoft.Xrm.Sdk</li>
<li>Microsoft.Xrm.Sdk.Workflow</li>
<li>System.Net</li>
<li>System.Net.Http</li>
<li>System.Runtime.Serialization
</li>
</ul>

Note that the Microsoft.Xrm.Sdk and Microsoft.Xrm.Sdk.Workflow assemblies can be retrieved via NuGet, by obtaining the following packages using the <strong>NuGet Package Manager Console</strong>:
<ul><li>https://www.nuget.org/packages/Microsoft.CrmSdk.Workflow</li>
<li>https://www.nuget.org/packages/Microsoft.CrmSdk.CoreAssemblies</li>
</ul>

&nbsp;

<strong>Adding a Data Contract for the Video Indexer API</strong>

To facilitate interacting with the <strong>Video Indexer Service</strong>, we add a new item to our project: a <strong>Visual C# class</strong> which we will name <strong>VideoIndexer.JSON.cs</strong>. We will populate this file with JSON data contracts for the data that comes back in the responses for the <a href="https://api-portal.videoindexer.ai/docs/services/operations/operations/Upload-video?" rel="noopener" target="_blank">Upload Video operation</a>, and the <a href="https://api-portal.videoindexer.ai/docs/services/operations/operations/Get-Video-Index?" rel="noopener" target="_blank">Get Video Index operation</a>.

<em>Data Contract Code Excerpt Due to Length; for full Data Contract, click <a href="https://1drv.ms/u/s!Aui7CDzJQqg_jQNBf65RINWMH5Wf" rel="noopener" target="_blank">here</a></em>
[snippet slug=video-indexer-json-data-contract line_numbers=false lang=c-sharp height=500]

&nbsp;

<strong>Adding Our C# Code - UploadVideo.cs</strong>

We can delete the <strong>Activity1.xaml</strong> file in the project, and <strong>Add </strong>a new <strong>Class </strong>to the project, which we name <strong>UploadVideo.cs</strong>. This custom action will be responsible for uploading our call recording to the service.

To our new class, we:
<ul><li>add some <strong>using </strong>statements</li>
<li>make the class inherit from the <strong>CodeActivity </strong>class and give it a public access modifier</li>
<li>add functionality to the class by adding an <strong>Execute </strong>method</li>
</ul>

&nbsp;

We define our input and output parameters for our custom activity:

<ul><li><strong>viAccountId </strong>as an <strong>input </strong>parameter: this is the Account ID of our Video Indexer API account, retrieved in our prerequisites</li>
<li><strong>viApiKey </strong>as an <strong>input </strong>parameter: this is the Primary Key for our Video Indexer API account</li>
<li><strong>viApiLocationString </strong>as an <strong>input </strong>parameter: this is the Location parameter for our Video Indexer API account</li>
<li><strong>videoUrl </strong>as an <strong>input </strong>parameter: this is the publicly available URL from which the audio file can be retrieved</li>
<li><strong>videoId </strong>as an <strong>output </strong>parameter: this is the ID of the media, after it has been indexed by the service</li>
<li><strong>processStatus </strong>as an <strong>output </strong>parameter: this is an indicator of the success of the video upload</li>
</ul>

&nbsp;

In our <strong>Execute </strong>method, we:

<ul><li>Create our Tracing service for debugging, and our Context</li>
<li>Obtain our input parameters</li>
<li>Prepare and issue an HTTP request to the <a href="https://api-portal.videoindexer.ai/docs/services/authorization/operations/Get-Account-Access-Token" rel="noopener" target="_blank">Video Indexer Authorization API</a>, with our API Key, to obtain an ‘Account Level’ Access Token </li>
<li>Prepare and issue an HTTP request to the <a href="https://api-portal.videoindexer.ai/docs/services/operations/operations/Upload-video?" rel="noopener" target="_blank">Video Indexer Operations API</a>, with our Access Token, to upload our audio file</li>
<li>Read the response, serialize it into an <strong>UploadVideoResponse </strong>object, and retrieve the ID of our uploaded media</li>
<li>Set our <strong>processStatus </strong>and <strong>videoId </strong>output parameters</li>
</ul>

[snippet slug=uploadvideo-cs-custom-action line_numbers=false lang=c-sharp]

&nbsp;

<strong>Adding to Our C# Code - GetVideoIndex.cs</strong>

Just as with our previous custom action, we <strong>Add </strong>another new <strong>Class </strong>to the project, which we name <strong>GetVideoIndex.cs</strong>. This custom action will be responsible for retrieving the insights from our call recording once it has been indexed by the Video Indexer service.

Just as before, to our new class, we:

<ul><li>add some <strong>using </strong>statements</li>
<li>make the class inherit from the <strong>CodeActivity </strong>class and give it a public access modifier</li>
<li>add functionality to the class by adding an <strong>Execute </strong>method</li>
</ul>

&nbsp;


We define our input and output parameters for our custom activity:
<ul><li><strong>viAccountId </strong>as an <strong>input </strong>parameter: this is the Account ID of our Video Indexer API account, retrieved in our prerequisites</li>
<li><strong>viApiKey </strong>as an <strong>input </strong>parameter: this is the Primary Key for our Video Indexer API account</li>
<li><strong>viApiLocationString </strong>as an <strong>input </strong>parameter: this is the Location parameter for our Video Indexer API account</li>
<li><strong>videoId </strong>as an <strong>input </strong>parameter: this is the ID of the media that we are retrieving insights for</li>
<li><strong>keywords </strong>as an <strong>output </strong>parameter: a comma-separated list of keywords from the Video Indexer insights</li>
<li><strong>negativeSentimentRatio </strong>as an <strong>output </strong>parameter: a value representing the percentage of the call recording in which negative sentiment was detected in the insights</li>
<li><strong>positiveSentimentRatio </strong>as an <strong>output </strong>parameter: a value representing the percentage of the call recording in which positive sentiment was detected in the insights</li>
<li><strong>neutralSentimentRatio </strong>as an <strong>output </strong>parameter: a value representing the percentage of the call recording in which neutral sentiment was detected in the insights</li>
<li><strong>durationInMinutes </strong>as an <strong>output </strong>parameter: the duration of the call recording, in minutes</li>
<li><strong>processStatus </strong>as an <strong>output </strong>parameter: this is an indicator of the success of the video upload</li>
</ul>

&nbsp;

In our <strong>Execute </strong>method, we:

<ul><li>Create our Tracing service for debugging, and our Context</li>
<li>Obtain our input parameters</li>
<li>Prepare and issue an HTTP request to the <a href="https://api-portal.videoindexer.ai/docs/services/authorization/operations/Get-Video-Access-Token?" rel="noopener" target="_blank">Video Indexer Authorization API</a>, with our API Key, to obtain a ‘Video Level’ Access Token </li>
<li>Prepare and issue an HTTP request to the <a href="https://api-portal.videoindexer.ai/docs/services/operations/operations/Get-Video-Index?" rel="noopener" target="_blank">Video Indexer Operations API</a>, with our Access Token, to retrieve the indexed insights about our phone call recording</li>
<li>Read the response, serialize it into a <strong>GetVideoIndexResponse </strong>object, and retrieve the various insight components from our phone call</li>
<li>Set our various output parameters</li>
</ul>

&nbsp;

[snippet slug=getvideoindex-cs-custom-action line_numbers=false lang=c-sharp]

&nbsp;

<strong>Adding to Our C# Code - GetVideoToken.cs</strong>

Just as with our previous custom actions, we <strong>Add </strong>another new <strong>Class </strong>to the project, which we name <strong>GetVideoToken.cs</strong>. This custom action will be responsible for simply retrieving a Video Access Token. In our next post, we will use this custom action to help us embed further insights into Dynamics 365.

Just as before, to our new class, we:

<ul><li>add some <strong>using </strong>statements</li>
<li>make the class inherit from the <strong>CodeActivity </strong>class and give it a public access modifier</li>
<li>add functionality to the class by adding an <strong>Execute </strong>method</li>
</ul>

&nbsp;

We define our input and output parameters for our custom activity:

<ul><li><strong>viAccountId </strong>as an <strong>input </strong>parameter: this is the Account ID of our Video Indexer API account, retrieved in our prerequisites</li>
<li><strong>viApiKey </strong>as an <strong>input </strong>parameter: this is the Primary Key for our Video Indexer API account</li>
<li><strong>viApiLocationString </strong>as an <strong>input </strong>parameter: this is the Location parameter for our Video Indexer API account</li>
<li><strong>videoId </strong>as an <strong>input </strong>parameter: this is the ID of the media that we are retrieving insights for</li>
<li><strong>videoAccessToken </strong>as an <strong>output </strong>parameter: this is the Video Access Token, valid for 1 hour</li>
<li><strong>viAccountIdOut </strong>as an <strong>output </strong>parameter: this is the same Account ID, output for use in conjunction with the Access Token</li>
<li><strong>processStatus </strong>as an <strong>output </strong>parameter: this is an indicator of the success of the video upload</li>
</ul>

In our Execute method, we:
<ul><li>Create our Tracing service for debugging, and our Context</li>
<li>Obtain our input parameters</li>
<li>Prepare and issue an HTTP request to the <a href="https://api-portal.videoindexer.ai/docs/services/authorization/operations/Get-Video-Access-Token?" rel="noopener" target="_blank">Video Indexer Authorization API</a>, with our API Key, to obtain a ‘Video Level’ Access Token </li>
<li>Set our various output parameters</li>
</ul>

&nbsp;

[snippet slug=getvideotoken-cs line_numbers=false lang=c-sharp]

&nbsp;

Before compiling our assembly, we sign it. In the project properties, under the <strong>Signing </strong>tab, we select <strong>Sign the assembly</strong> and provide a key file name.

We are now ready to compile the assembly by <strong>Building </strong>the solution.

&nbsp;


<strong>Registering our Assembly</strong>

We now need to register our custom workflow activity assembly on our Dynamics 365 Online instance. To do that, we will use the <strong>Plug-in Registration Tool</strong>. This tool is available in the <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/download-tools-nuget" rel="noopener" target="_blank">Dynamics 365 Developer Tools</a>.

Following the instructions in the documentation, we launch the tool, and authenticate using our administrator credentials for D365. We then select <strong>Register New Assembly</strong> from the <strong>Register </strong>menu.

In the resulting dialog box, we choose the location of our compiled assembly (which should be in the <strong>CallAudioAnalysis\bin\Debug</strong> folder). We select our assembly and our workflow activity for registration. We specify <strong>Sandbox </strong>as the isolation mode, and <strong>Database </strong>as the storage location. Finally, we click <strong>Register Selected Plugins</strong>:

<img src="https://msdnshared.blob.core.windows.net/media/2018/07/RegisterAssembly1-592x800.png" alt="" width="592" height="800" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2445" />

&nbsp;

We now have a custom workflow activity that will allow us to interact with the Video Indexer API to derive insights from call recordings.

&nbsp;

<strong>Creating our Workflow</strong>

We will now create a workflow that will make use of two of our custom actions, to upload our call recording to the service, wait until it has completed processing, then retrieve the indexed insights and update our Phone Call record.

 Logged in to the Dynamics 365 web client with our administrator credentials, we navigate to <strong>Settings &gt; Customizations &gt; Customize the System</strong>. We choose <strong>Processes </strong>from the left navigation, and choose <strong>New</strong>.

We specify that we are creating a <strong>Workflow </strong>type of process that is applicable to the <strong>Phone Call</strong> entity, running in the background, and started when a record is created, or when the <strong>Call Recording URL</strong> field is updated:

<img src="https://msdnshared.blob.core.windows.net/media/2018/07/CreateWorkflowProcess.png" alt="" width="640" height="482" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-2295" />

&nbsp;

Our workflow will include the following logic:

<ul><li>we check to ensure we have a Call Recording URL, and if so:
<ul><li>we use our <strong>UploadVideo</strong> custom action to upload our video</li></ul>
<li>we check to ensure our request to upload the video was successful, and if so:</li>
<ul><li>we update our Phone Call record with the ID from the Video Indexer Service</li>
<li>we wait a nominal duration of 1 hour for our audio to complete processing; this logic could be extended with recursive requests until indexing was complete, to expedite retrieving of the insights, and to avoid problems if processing takes longer than 1 hour</li>
<li>after our wait time, we use our <strong>GetVideoIndex </strong>custom action to retrieve our insights</li>
</ul>
<li>we check to ensure our request for the insights was successful, and if so:
<ul><li>we update the phone call record with the insights</li></ul>
</li></ul>

&nbsp;

The complete workflow logic looks like this:

<img src="https://msdnshared.blob.core.windows.net/media/2018/07/StepForWorkflowUploadVideo-800x413.png" alt="" width="800" height="413" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2175" />

&nbsp;

We set the input parameters to the <strong>UploadVideo </strong>action like so:

<img src="https://msdnshared.blob.core.windows.net/media/2018/07/CustomStepUploadInputs2-800x552.png" alt="" width="800" height="552" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2475" />

&nbsp;

We set the input parameters to the <strong>GetVideoIndex </strong>action like so:

<img src="https://msdnshared.blob.core.windows.net/media/2018/07/InputForIndexerAction-800x530.png" alt="" width="800" height="530" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2265" />

&nbsp;

We update our phone call with insights like so:

<img src="https://msdnshared.blob.core.windows.net/media/2018/07/UpdatePhoneCallwithInsights-800x523.png" alt="" width="800" height="523" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2255" />

&nbsp;

After we <strong>Save </strong>and <strong>Activate </strong>our process, we are now ready to test it. 

We can test the indexing process by creating a <strong>Phone Call</strong> record and setting the <strong>Call Recording URL</strong> attribute to a value containing the URL to a call recording. In this example, we are using a <strong>.M4A audio file</strong>, hosted in Azure Blob Storage. The recording contains a simulated phone call regarding a problem connecting an Xbox One to a network.

We can track the progress of our custom actions using the <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/debug-plugin" rel="noopener" target="_blank">Plug-in Trace Logging</a> feature of Dynamics. After one hour, we should be able to view insights about our phone call in Dynamics 365. This screenshot shows an updated Phone Call form, containing our newly-created custom fields:

<img src="https://msdnshared.blob.core.windows.net/media/2018/07/CallInsightsScreenshot-800x466.png" alt="" width="800" height="466" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2165" />

&nbsp;

Note that the Video Indexer service can provide a wealth of additional insights about our phone call, including the full transcript, the language being spoken, brands mentioned, instances of banned words, and much more. The custom activities and the workflow can be further extended to bring this additional metadata into Dynamics 365, if desired.

In our next post, we will build upon this one, bringing interactive Insights, Transcript, and Call Audio widgets directly into our Phone Call record in Dynamics.












]]></content:encoded>
    </item>
    <item>
      <title>Enhanced Knowledge Base Usage Analytics with Azure Application Insights and Power BI</title>
      <link>https://docs.microsoft.com/archive/blogs/geoffreyinnis/enhanced-dynamics-365-knowledgebase-usage-analytics-with-azure-application-insights-and-power-bi</link>
      <pubDate>Fri, 09 Mar 2018 14:15:28 GMT</pubDate>
      <dc:creator><![CDATA[Geoff Innis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/geoffreyinnis/?p=1915</guid>
      <description><![CDATA[When managing a self-service knowledge base, understanding how customers and employees are searching...]]></description>
      <content:encoded><![CDATA[When managing a self-service knowledge base, understanding how customers and employees are searching for and consuming self-service knowledge is an important part of ensuring your content remains relevant and useful for end users.

Dynamics includes a number of in-built capabilities to help analyze the usage of the knowledge base, including:

<ul><li>Tracking of article views by source</li>
<li>Tracking of article ratings and feedback</li>
<li>Tracking of case deflections from knowledge</li>
<li>Tracking of articles associated with, or used in resolving cases</li></ul>

In some instances, we may wish to extend beyond the in-built capabilities, to understand usage patterns to a greater depth: what your users are searching for, which searches are not returning any results, and how users are navigating through your Dynamics portal, for example. These metrics can help you create targeted content to meet the needs of your users.

In this post, we will walk through an example of how we can track and analyze portal-based knowledge base usage patterns in more detail, with <a href="https://azure.microsoft.com/en-us/services/application-insights/" rel="noopener" target="_blank">Azure Application Insights</a> and <a href="https://powerbi.microsoft.com/en-us/" rel="noopener" target="_blank">Power BI</a>.

We will augment the in-built analytics with reporting on:
<ul><li><strong>Search patterns</strong> – including top searches and top failed searches</li>
<li><strong>Article View patterns</strong> – including views by user and views by referring page</li></ul>

&nbsp;

Our goal will be to empower knowledge managers with a visualization such as this:

<img src="https://msdnshared.blob.core.windows.net/media/2018/03/DashboardInD365-800x450.png" alt="" width="800" height="450" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1965" />

&nbsp;

<strong>Prerequisites</strong>

The prerequisites for building and deploying our enhanced analytics include:

<ul>
<li>An instance of Dynamics 365 for Customer Service (Online)
<ul><li>You can request a trial of Dynamics 365 for Customer Service <a href="https://go.microsoft.com/fwlink/?linkid=849057" target="_blank">here</a></li></ul>
</li>
<li>A <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/portals/provision-portal" target="_blank">Dynamics 365 Portal connected to your Dynamics 365 instance</a></li>
<ul><li>In this walkthrough, we will use a portal configured with <strong>Portal Audience: Customer</strong>, and type of portal as <strong>Customer Self-service Portal</strong></li></ul>
<li>A Microsoft Azure subscription for enabling our Application Insights resource</li>
<li>Power BI Desktop, and a Power BI account, which can be obtained <a href="https://powerbi.microsoft.com/en-us/get-started/" rel="noopener" target="_blank">here</a></li>
</li>
</ul>

&nbsp;

<strong>Setting Up Application Insights</strong>

Azure Application Insights is an extensible Application Performance Management (APM) service that works across multiple platforms. Among its capabilities are the ability to track and understand what users are doing with web applications, to continually improve performance and usability.

We will use it to track and report on specific user actions within the Dynamics 365 portal, leveraging <a href="https://docs.microsoft.com/en-us/azure/application-insights/app-insights-javascript" rel="noopener" target="_blank">Application Insights for web pages</a>, and the <a href="https://github.com/Microsoft/ApplicationInsights-JS/blob/master/API-reference.md" rel="noopener" target="_blank">Application Insights SDK JavaScript API</a>.

First, we authenticate to the Azure Portal, and create a new <strong>Application Insights</strong> resource. <a href="https://portal.azure.com/#create/Microsoft.AppInsights" rel="noopener" target="_blank">This link</a> will take us directly to the Application Insights resource creation blade. We complete the required information, specifying the <strong>Application Type</strong> as <strong>ASP.NET Web Application</strong>, and click the <strong>Create </strong>button:

<img src="https://msdnshared.blob.core.windows.net/media/2018/03/CreateAppInsightsResource-331x800.png" alt="" width="331" height="800" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1955" />

&nbsp;

Once the Application Insights resource has finished deploying, navigate to the resource. Scroll down and click the <strong>Getting Started</strong> button in the resource blade, click <strong>MONITOR AND DIAGNOSE CLIENT SIDE APPLICATION</strong>, then click to copy the JavaScript code snippet to your clipboard:

<img src="https://msdnshared.blob.core.windows.net/media/2018/03/ClickToGetSnippet-800x435.png" alt="" width="800" height="435" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2095" />

&nbsp;

In the <strong>Dynamics 365 Web Client</strong>, we can paste this code into a <strong>Content Snippet</strong> named <strong>Tracking Code</strong>, which is suited for this purpose. The code we are pasting includes our Application Insights key. This code will be included in each page that is rendered on our portal, enabling us to track portal usage:

<img src="https://msdnshared.blob.core.windows.net/media/2018/03/TrackingCodeSnippet-800x606.png" alt="" width="800" height="606" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2045" />

&nbsp;

We will now leverage the <a href="https://github.com/Microsoft/ApplicationInsights-JS/blob/master/API-reference.md" rel="noopener" target="_blank">Application Insights SDK JavaScript API</a> to track specific events that occur on the portal. Within the JavaScript SDK, we are able to make use of the <strong>trackEvent </strong>method to log instances of specific user actions, including our own properties that we can specify. We will use this to log user searches, and knowledgebase article page views. We can also ensure that our events are tracked to the specific portal user by <strong>setAuthenticatedUserContext </strong>method to associate searches and views to individual authenticated portal users.

&nbsp;

<strong>Tracking Searches</strong>

When users search on our portal, we will track what query the user entered when searching, as well as how many results were returned. If we have an authenticated portal user, we will also include that in the context of our event. We do this by editing the default <strong>Web Template</strong> called <strong>Faceted Search – Results Template</strong>, which is used to render the results of the search on the portal. The portal leverages <a href="https://handlebarsjs.com/" rel="noopener" target="_blank">Handlebars</a>, the popular JavaScript templating engine, to render the results.

The updated template code below shows demo-grade updates which will register a Handlebars helper JavaScript function called <strong>logresults</strong>, which can be called from within the Handlebars template, where we have access to the count of search results that are being rendered. The helper will:

<ul>
<li>Receive the result count as a parameter (note that we are tracking the number of results across all types; articles, forums, portal pages, etc.)</li>
<li>Ensure that the count is a numeric value</li>
<li>Set the authenticated user’s GUID into context, if we have an authenticated user (making use of Liquid templating to inject the authenticated user’s ID)</li>
<li>Log a custom event named <strong>search</strong>, with the results count, and the query phrase (also injected vi Liquid) included as custom properties</li>
<li>Use a counter to ensure that the search event is logged only once per page render, and not logged again on subsequent uses of the search faceting</li>
</ul>

&nbsp;

[snippet slug=faceted-search-results-template line_numbers=false lang=js]

&nbsp;

<strong>Tracking Article Views</strong>

Although Dynamics 365 portals track article views as an in-built capability, we can gain more insight into usage patterns by logging custom events. We can track page views by specific users, track how they arrived at the page (by search vs navigation), and more.

To do this, we will navigate to the portal <strong>Web Page</strong> called <strong>Knowledge Base – Article Details</strong> (drill down into the <strong>Localized Content</strong> for the page, if applicable) and we add some <strong>Custom JavaScript</strong> to the page, found under the <strong>Advanced </strong>tab in the default Web Page form.

The following demo-grade JavaScript code will:

<ul>
<li>Use a JavaScript regular expression to obtain the Article ID from the page URL (ensure that the pattern used matches your article public number convention)</li>
<li>Checks the referrer URL against a number of the <strong>Site Settings</strong> pages that we anticipate article traffic to come from, and setting a source variable accordingly</li>
<li>Sets the user’s GUID into event context, if the user is authenticated</li>
<li>Logs a custom event named <strong>view</strong>, with the <strong>articleId </strong>and <strong>source </strong>as parameters
</li>
</ul>

&nbsp;

[snippet slug=knowledge-base-article-details-custom-javascript line_numbers=false lang=js]

&nbsp;

After saving these changes, we can open up our portal in a browser, and start searching and viewing knowledgebase articles, to generate some data for our reporting and analytics.

&nbsp;

<strong>Viewing and Exporting the Event Data in Application Insights</strong>

Back in the Azure portal, on our Application Insights resource blade, we navigate to the <strong>Overview</strong>, which allows us to click the <strong>Analytics </strong>button to open <strong>Analytics</strong>:

<img src="https://msdnshared.blob.core.windows.net/media/2018/03/OpenAnalytics-800x384.png" alt="" width="800" height="384" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2005" />

&nbsp;

<strong>Analytics </strong>is the search and query tool that accompanies Application Insights. It has its own <a href="https://docs.loganalytics.io/docs/Language-Reference/Query-statements" rel="noopener" target="_blank">query language</a>, which can be used to run queries against the data. Queries we write can also be used to export data to Power BI.

In Analytics, we open a new tab to query our data, and type in a query that will return all of our search events. Note how we retrieve the query term and result count from our custom parameters:

<img src="https://msdnshared.blob.core.windows.net/media/2018/03/searchquery-800x570.png" alt="" width="800" height="570" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2025" />

&nbsp;

Note that we also retrieve all data from the last 90 days. Application Insights stores analytics data for up to 90 days. If we wish to report on usage patterns going back further than 90 days, we could make use of the <a href="https://docs.microsoft.com/en-us/azure/application-insights/app-insights-export-telemetry" rel="noopener" target="_blank">Continuous Export</a> feature of Application Insights to export the data to a storage account, and into SQL Azure for continued availability in our analytics reports <em>(not covered in this post)</em>.

We will now export the query for use in Power BI, by selecting <strong>Export to Power BI</strong> from the <strong>Export </strong>menu:

<img src="https://msdnshared.blob.core.windows.net/media/2018/03/exportquery-800x182.png" alt="" width="800" height="182" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1975" />

&nbsp;

We will be prompted to open or save the text-based exported query. We can open and then copy the query to our clipboard, for use in Power BI:

<img src="https://msdnshared.blob.core.windows.net/media/2018/03/copyPowerBIQuery-800x554.png" alt="" width="800" height="554" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1945" />

&nbsp;

We then open <strong>Power BI Desktop</strong>, and click the <strong>Get Data</strong> button, and choose <strong>Blank Query</strong>:

<img src="https://msdnshared.blob.core.windows.net/media/2018/03/GetData_Search-800x713.png" alt="" width="800" height="713" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1985" />

&nbsp;

We insert our search query, and click the <strong>Done </strong>button:

<img src="https://msdnshared.blob.core.windows.net/media/2018/03/PasteSearchQuery-800x660.png" alt="" width="800" height="660" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2015" />

&nbsp;

We can repeat these steps for our article view query, using the following query syntax:

&nbsp;&nbsp;<strong>customEvents | extend source = customDimensions.src, id = customDimensions.id | where timestamp &gt; ago(90d) and name == "view" | order by timestamp desc</strong>

&nbsp;

<strong>Building our Power BI Dashboard</strong>

We can now start building a dashboard in Power BI to help us visualize and understand knowledgebase usage trends.

For example, we can use our Search Query data in a <strong>Bar Chart </strong>visualization, selecting <strong>itemCount </strong>and <strong>query</strong>, with a filter in which <strong>resultcount </strong>is equal to 0, to create a visualization of top failed searches:

<img src="https://msdnshared.blob.core.windows.net/media/2018/03/TopFailedSearches-800x501.png" alt="" width="800" height="501" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2035" />

&nbsp;

We can continue to build out a dashboard, creating visualizations that will help us understand our users’ search and article viewing patterns, using attributes such as authenticated user, timestamp, user location, and more. We can also pull data from Dynamics 365 into Power BI to augment our visualizations further:

<img src="https://msdnshared.blob.core.windows.net/media/2018/03/CompleteDashboard-800x429.png" alt="" width="800" height="429" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-2055" />

&nbsp;

Finally, we can use the process <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/admin/use-power-bi#embed-includepnpowerbiforoffice365shortincludespn-power-bi-for-office-365-shortmd-visualizations-on-personal-dashboards" rel="noopener" target="_blank">outlined here</a> to embed our dashboard in Dynamics 365:

<img src="https://msdnshared.blob.core.windows.net/media/2018/03/DashboardInD365-800x450.png" alt="" width="800" height="450" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1965" />

&nbsp;

We can now analyze the patterns of usage in our knowledge base on an ongoing basis, to make informed decisions about how best to augment our knowledge, and how to optimize our end-users' self-service experiences.

These same techniques can be extended to track and analyze many other aspects of user behavior on Dynamics 365 portals as well.]]></content:encoded>
    </item>
    <item>
      <title>Bots as Chat Agents, with Escalation to Live Agents</title>
      <link>https://docs.microsoft.com/archive/blogs/geoffreyinnis/bots-as-chat-agents-with-escalation-to-live-agents</link>
      <pubDate>Thu, 19 Oct 2017 09:50:56 GMT</pubDate>
      <dc:creator><![CDATA[Geoff Innis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/geoffreyinnis/?p=1596</guid>
      <description><![CDATA[Update, Jul. 2018: With the QnA Maker service now in GA, it is now necessary to pass in an...]]></description>
      <content:encoded><![CDATA[<em>Update, Jul. 2018: With the QnA Maker service now in GA, it is now necessary to pass in an additional parameter to the QnAMakerDialog if using a GA QnA Maker Service: <strong>"endpoint hostname"</strong>; see <a href="https://blog.botframework.com/2018/05/07/announcing-general-availability-of-qnamaker/" rel="noopener" target="_blank">this link</a> (scroll to <strong>QnAMakerDialog </strong>heading, and <strong>CSharp </strong>code sample for details)</em>
<em>Update, Feb. 2018: This post has been updated to reflect the new Bot Channels Registration process in the Azure Portal.</em>

&nbsp;

Bots offer organizations a means of scaling customer service and customer engagement through natural and intuitive conversational experiences, as we’ve seen in some of our <a href="https://blogs.msdn.microsoft.com/geoffreyinnis/2016/07/28/bringing-bots-into-an-omni-channel-customer-service-strategy-part-2-creating-cases/" target="_blank">earlier posts</a>. But bots will not always be able to meet all of our customers’ needs during an interaction. Being able to seamlessly transition a customer from a conversation with a bot to an actual live agent can be a key capability in realizing scale while also ensuring high-quality customer engagements.

In this post, we will see how we can implement seamless escalations from bots to live agents leveraging the capabilities of <a href="https://www.liveassistfor365.com/en/" target="_blank">Live Assist</a> from Microsoft partner <strong>CafeX</strong>.

This one-minute video (no sound) shows our intended functionality in action:

[video width="1920" height="1040" mp4="https://msdnshared.blob.core.windows.net/media/2017/10/QnA_Bot_wEscalation_wCallouts.mp4"][/video]

&nbsp;

<strong>Escalation Options with Live Assist</strong>

With the <a href="https://www.liveassistfor365.com/en/new-release/" target="_blank">latest release</a> of Live Assist for Dynamics 365, we have two options available to us in implementing Bot to Agent escalations:

<ol><li>Create a bot and enable it as an agent in Live Assist, with the ability to transfer/escalate to other agents; this is enabled through the Live Assist <a href="https://www.liveassistfor365.com/en/support/knowledge-base/bot-agent-connector-quickstart/" target="_blank">Bot Agent Connector</a>, and will enable end users to engage with your bot via the Live Assist end-user interface, just as if engaging via Live Assist chat with a Live Agent</li>
<li>Create a bot and enable it on the Bot Framework channels of your choice, adding the ability for chats to be escalated to Live Assist agents via the <a href="https://www.liveassistfor365.com/en/support/knowledge-base/bot-esclalation-sdk-dotnet-quickstart/" target="_blank">Live Assist Escalation SDK</a>; this option will enable end users to engage with your bot on the Bot Framework channels of your choice, though not through the Live Assist end-user chat experience</li></ol>


In this post, we will implement the <strong>first option</strong>: a bot that is enabled as a Live Assist agent, with the ability to transfer or escalate to other “real” agents in Live Assist.

We will create a bot that can:

<ul><li>be accessed via the standard Live Assist end-user chat interface</li>
<li>provide answers to customer questions via the Cognitive Services QnA Maker API</li>
<li>detect the sentiment of all customer input via the Cognitive Services Text Analytics API</li>
<li>initiate a transfer to other agents or skills when negative sentiment is detected</li></ul>

Note that we will be building our bot using the <a href="https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-overview" target="_blank">Bot Builder SDK for .NET</a>. If you are working with Node.js, CafeX offers sample code for enabling a Bot Agent that can provide answers via QnA Maker <a href="https://www.liveassistfor365.com/en/support/knowledge-base/qna-maker-bot-with-transfer-to-live-assist-sample/" target="_blank">here</a>. 

&nbsp;

<strong>Prerequisites</strong>

The prerequisites for building and deploying our escalation bot include:

<ul>
<li>An instance of Dynamics 365 for Customer Service (Online)
<ul><li>You can request a trial of Dynamics 365 for Customer Service <a href="https://go.microsoft.com/fwlink/?linkid=849057" target="_blank">here</a></li></ul>
</li>
<li>A <a href="https://www.liveassistfor365.com/en/support/knowledge-base/how-to-start-a-trial/" target="_blank">Live Assist for Dynamics 365 Trial</a> that has been activated for your Dynamics 365 organization </li>
<li><em>Optional:</em> you may wish to provision and configure a <a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/portals/provision-portal" target="_blank">Dynamics 365 Portal</a>, and <a href="https://www.liveassistfor365.com/en/support/knowledge-base/how-to-embed-chat-in-the-customer-portal/" target="_blank">embed Live Assist chat in your portal</a> </li>
<li>A Microsoft Azure subscription for hosting our bot, and for enabling our Cognitive Services resources</li>
<li><a href="https://docs.microsoft.com/en-us/visualstudio/install/install-visual-studio" target="_blank">Visual Studio 2017</a></li>
<li>Microsoft .NET Framework 4.6.1</li>
<li>The <a href="https://docs.microsoft.com/en-us/bot-framework/resources-tools-downloads" target="_blank">Bot Builder SDK for .NET</a> </li>
<li>The <a href="https://aka.ms/bf-bc-vstemplate" target="_blank">Bot Application</a>, <a href="https://aka.ms/bf-bc-vscontrollertemplate" target="_blank">Bot Controller</a>, and <a href="https://aka.ms/bf-bc-vsdialogtemplate" target="_blank">Bot Dialog </a>Visual Studio Templates
<ul><li>Save the downloaded zip file to your Visual Studio 201X templates directory, which is typically found in <strong>%USERPROFILE%\Documents\Visual Studio 2017\Templates\ProjectTemplates\Visual C#</strong></li></ul>
</li>
</ul>

&nbsp;

<strong>Setting Up our QnA Maker Service</strong>

Microsoft's Cognitive Services <a href="https://qnamaker.ai/Documentation">QnA Maker</a> provides an easy-to-use tool for the ingestion of "Frequently Asked Questions" (questions and answers), making them available via a service that can be readily consumed within the Bot Framework. Bots can provide answers to end-user questions through the use of a Bot Framework dialog that we will leverage later in our post.

The QnA Maker documentation provides a brief video walkthrough of how to access the QnA Maker service on <a href="https://qnamaker.ai">https://qnamaker.ai</a>, and to create and publish a question and answer service. Rather than recreate the documentation, <strong>follow along with the steps</strong> seen in the <a href="https://qnamaker.ai/Documentation/Quickstart">video here</a>.

While following along with the quick-start video, we obtain our credentials for accessing the knowledge base service we have created, including our:

<ul><li>QnA Maker Subscription Key</li>
<li>The Knowledge Base ID</li>
<li>The Knowledge Endpoint URL</li></ul>

&nbsp;

<strong>Save these credentials</strong> for use later in our setup process.

<strong><em>Optional:</em></strong> If you wish to populate your QnA Maker service with the articles from your Dynamics 365 knowledgebase, you can export your articles from <a href="https://www.microsoft.com/en-us/dynamics/crm-customer-center/export-to-an-excel-dynamic-worksheet.aspx">Dynamics 365 to Excel</a>, then format the articles in the tab-separated Question, Answer and Source format outlined in the <a href="https://qnamaker.ai/Documentation/UpdateKb">QnA Maker documentation</a>, for upload into your QnA Maker knowledge base.

&nbsp;

<strong>Obtaining our Text Analytics Endpoint and Key</strong>

To enable our bot to escalate to an agent when the end user expresses negative sentiment, we will leverage the Cognitive Services <a href="https://azure.microsoft.com/en-us/services/cognitive-services/text-analytics/" target="_blank">Text Analytics API</a>, which is able to be provisioned from the <a href="https://portal.azure.com/" target="_blank">Azure Portal</a> with an Azure subscription.

This <a href="https://portal.azure.com/#create/Microsoft.CognitiveServicesTextAnalytics" target="_blank">deep link</a> will take you to the Text Analytics API resource creation blade in the Azure Portal. Complete the required details, providing your desired resource name, subscription, location, pricing tier, and resource group (either a new or existing one). Accept the terms, and click the <strong>Create </strong>button:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/createtextanalytics.png" alt="" width="340" height="904" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1696" />

&nbsp;

You can then view details of the Text Analytics API resource that you have created, to obtain your endpoint based on the region you selected, and copy one of the two keys that were created for you:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/textanalyticsaccesskeys.png" alt="" width="797" height="198" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1835" />

&nbsp;

Save the endpoint and key for later use.

<em><strong>Important Note: </strong>When we insert the endpoint into our app configurations later on in the post, we will append <strong>'/sentiment'</strong> to the endpoint copied from the Azure portal. More details found below.</em>

&nbsp;

<strong>Building our Bot</strong>

We will now start putting together the code for our bot, using steps found in the <a href="https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-quickstart" target="_blank">Create a bot with the Bot Builder SDK for .NET</a> quickstart.

We Open Visual Studio, and create a new project using the <strong>Bot Application</strong> template that we downloaded as a part of our prerequisites:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/CreateProject-800x555.png" alt="" width="800" height="555" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1686" />

&nbsp;

In our <strong>Project Properties</strong>, on the <strong>Application </strong>tab, we specify <strong>.NET Framework 4.6.1</strong> as the target framework.

&nbsp;

<strong>Installing Packages and Adding References</strong>

We need install several packages that we will leverage as a part of our bot code, and ensure our project is referencing the latest version of the Bot Builder SDK. We can do this via NuGet:

<ul><li>The latest version of the <a href="https://www.nuget.org/packages/Microsoft.Bot.Builder/" target="_blank">Microsoft.Bot.Builder</a> package</li>
<li>The <a href="https://www.nuget.org/packages/Microsoft.Bot.Builder.CognitiveServices/" target="_blank">Microsoft.Bot.Builder.CognitiveServices</a> package, for QnA Maker functionality</li></ul>

&nbsp;

<strong>Adding a Data Contract for the Text Analytics API</strong>

To facilitate interacting with the Cognitive Services Text Analytics API, we add a new item to our project: a <strong>Visual C# class</strong> which we will name <strong>TextAnalytics.JSON.cs</strong>. We will populate this file with the JSON data contracts for the REST Services outlined in the <a href="https://westus.dev.cognitive.microsoft.com/docs/services/TextAnalytics.V2.0/operations/56f30ceeeda5650db055a3c9" target="_blank">Text Analytics API documentation</a>.

[snippet slug=usdsentiment_datacontract line_numbers=false lang=c-sharp]

&nbsp;

<strong>Adding our QnA Maker Dialog</strong>

To our project, we will add a <a href="https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-dialogs" target="_blank">Bot Framework dialog</a> to manage the interaction with our QnA Maker knowledge base. We right-click on our <strong>Dialogs </strong>folder in our project, and choose to <strong>Add New Item</strong>. We will add a C# Class that we name <strong>QnAMakerDialog.cs</strong>.

We will add code to our class using the Basic QnA Maker template found in the Bot Framework documentation <a href="https://docs.microsoft.com/en-us/bot-framework/azure-bot-service-template-question-answer" target="_blank">here</a>. The dialog will inherit from the <strong>QnAMakerDialog </strong>object, and calls the QnA Maker service with the following parameters:

<ul><li><strong>Subscription Key</strong>: this key was obtained earlier, when setting up our QnA Maker service; we will populate this from application configuration parameters in a subsequent step</li>
<li><strong>Knowledge Base ID</strong>: this ID was also obtained while setting up our service; we will populate this from application configuration parameters in a subsequent step</li>
<li><strong>Default Message</strong>: this optional parameter allows us to specify the message to return to the user when no answer has been found with a sufficient match</li>
<li><strong>Score Threshold</strong>: this optional value between 0 and 1 allows us to specify the threshold of the match that must be found from our knowledgebase in order to return an answer to the user</li></ul>

&nbsp;

We add the following code to our new class, to allow the calling of the QnA Maker Service we created:

[snippet slug=qnaescalation_qna-maker-dialog line_numbers=false lang=c-sharp]

&nbsp;

<strong>Adding our Escalation Dialog</strong>

We will also add a simple dialog that will handle escalation scenarios, by confirming that the user wishes to be transferred to an agent, and executing the transfer.

We right-click on our <strong>Dialogs </strong>folder in our project, and choose to <strong>Add New Item</strong>. We will add a C# Class that we name <strong>Escalation.cs</strong>.

Our Escalation dialog will initiate with the <strong>StartAsync </strong>method by requesting confirmation from the user on whether they would like to be transferred to a live agent. The response that the user provides is managed by the <strong>AfterEscalationConfirmation </strong>method. If the user wishes to be transferred (which we test by looking for a response that begins with a ‘y’), a transfer message is constructed and sent, using the transfer message format as outlined in the Live Assist <a href="https://www.liveassistfor365.com/en/support/knowledge-base/bot-agent-connector-quickstart/" target="_blank">Bot Agent Connector documentation</a>. The key information about the transfer is included in the <a href="https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-channeldata" target="_blank">ChannelData </a>property of the message, including the <strong>skill </strong>or <strong>agent </strong>that the chat should be transferred to. In our code, we are transferring the chat to a <strong>Skill </strong>that will be configured in Live Assist called <strong>BotEscalation</strong>. We could also adapt the code to transfer to an agent, by replacing our skill attribute with<strong> 'agent':'AgentNickname'</strong> in our <strong>JObject</strong>. Our <strong>Escalation.cs</strong> code is shown below:

[snippet slug=qnaescalation_escalationdialog line_numbers=false lang=c-sharp]

&nbsp;

<strong>Adapting our Root Dialog</strong>

We will now adapt our <strong>RootDialog.cs</strong> class to examine incoming messages, and respond appropriately depending on the type of Live Assist message it is, and the sentiment expressed if it is a message from the user.

Our Root Dialog will:

<ul><li>Respond with a greeting on initial connection to the user</li>
<li>Check the sentiment of all user messages</li>
<li>Route messages with a sentiment score of less than a nominal value of 0.2 to our escalation dialog</li>
<li>Route messages that don’t have negative sentiment to the QnA Maker dialog</li></ul>

Our Root Dialog class also includes methods to call the Text Analytics API to determine the sentiment of user messages, as used in <a href="https://blogs.msdn.microsoft.com/geoffreyinnis/2016/07/11/sentiment-analysis-in-usd-with-cognitive-services-text-analytics/">previous posts</a> leveraging the API via .NET.

[snippet slug=qnaescalation_rootdialog line_numbers=false lang=c-sharp]

&nbsp;

<strong>Adapting our Message Controller</strong>

We also make minor updates to our <strong>MessageController.cs</strong> class, which controls the flow of incoming user messages. We check to see if our incoming message is on the Direct Line channel (which Live Assist agent bots use), and if so, we direct it to our Root Dialog. Otherwise, we direct it straight to the QnA Maker dialog, so that other channels can still benefit from the QnA Maker knowledge base:

[snippet slug=qnaescalation_messagecontroller line_numbers=false lang=c-sharp]

&nbsp;

Later on we will also update our <strong>Web.config</strong> file with necessary configurations and credentials, but first we need to deploy our bot to Azure, and register our bot.

&nbsp;

<strong>Deploying our Bot to Azure from Visual Studio</strong>

We will now deploy our bot to a <strong>Microsoft Azure App Service</strong>. We right-click on our project in the Visual Studio Solution Explorer, and select <strong>Publish</strong>:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/rightclickpublish.png" alt="" width="697" height="433" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1805" />

&nbsp;

We select <strong>Microsoft Azure App Service</strong> as the project type and click <strong>Publish</strong>:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/choosetypepublish.png" alt="" width="670" height="352" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1646" />

&nbsp;

Next to <strong>App Name</strong>, we click <strong>Change Type</strong> and change the service's type to <strong>Web App</strong>. We enter our desired app name, Azure subscription, Resource Group (new or existing) and App Service Plan (new or existing), and click the <strong>Create </strong>button:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/createappservice-800x599.png" alt="" width="800" height="599" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1665" />

&nbsp;

The creation of the needed resources, and the publishing of our bot to the App Service, should now be initiated. Upon completion, we can obtain the <strong>Site URL</strong> for our bot endpoint, which we can save for later use:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/publishedurl-800x433.png" alt="" width="800" height="433" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1775" />

&nbsp;

<strong>Registering our Bot with the Bot Service</strong>

We will now register our bot with the Bot Service, basing our process on the documentation found <a href="https://docs.microsoft.com/en-us/bot-framework/bot-service-quickstart-registration" target="_blank">here</a>. First, we authenticate to the Azure Portal, with our Azure credentials.

Once authenticated, we create a <strong>Bot Channels Registration</strong>, by clicking the <strong>Create a resource</strong> button found on the upper left-hand corner of the Azure portal, then select <strong>AI + Cognitive Services &gt; Bot Channels Registration</strong>.

When creating our Bot Registration, we include:

<ol>
<li>your bot's <strong>Name</strong>; this is the unique handle for your bot</li>
<li>the Azure subscription, resource group, location, and pricing tier of our choosing</li>
<li>our bot's <strong>Messaging endpoint</strong>, based on the <strong>Site URL</strong> we obtained during the publishing process; Note that we must replace <strong>http </strong>with <strong>https</strong>, and we must append <strong>/api/messages</strong> to our Site URL</li></ol>

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/New_Registration-407x800.png" alt="" width="407" height="800" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1656" />

&nbsp;

We can confirm that the registration has been created by checking the <strong>Notifications </strong>area in the Azure portal. Upon completion of the registration, we can open the newly created resource, and then click on <strong>Settings</strong>.

We can now provide <strong>Bot Profile</strong> details for our bot. Taken from the documentation, we can supply information including:

<ol><li>an icon that will represent your bot in the conversation</li>
<li>your bot's <strong>Display Name</strong>; When users search for this bot, this is the name that will appear in the search results</li>
<li>a <strong>Description </strong>of your bot; This is the description that will appear in search results, so it should accurately describe what the bot does</li></ol>

&nbsp;

We also need to click the <strong>Manage </strong>link to obtain a <strong>Microsoft Application Password</strong>. This is the link appearing by the <strong>Microsoft App ID</strong>:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/New_registrationSettings.png" alt="" width="527" height="372" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1906" />

&nbsp;

This link will open a window where you can generate a new application password. Click <strong>Generate New Password</strong>. This will generate a new password for your bot. Save both the App ID and Password for later use:


<img src="https://msdnshared.blob.core.windows.net/media/2017/10/New_AppRegistrationPassword-800x291.png" alt="" width="800" height="291" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1905" />

&nbsp;

<strong>Updating our Web.config Configurations</strong>

We will now update our project's <strong>Web.config</strong> file with various authentication and configuration values that we have collected.

We add the following <strong>appSettings </strong>settings:

<ul><li><strong>BotId</strong>: our bot’s handle as created during Bot Registration</li>
<li><strong>MicrosoftAppId</strong>: our bot’s App ID as obtained during Bot Registration</li>
<li><strong>MicrosoftAppPassword</strong>: our bot’s App Password, as obtained during Bot Registration</li>
<li><strong>cogTextAnalyticsSubscriptionKey</strong>: our Text Analytics API key, as obtained during the provisioning of our resource in the Azure Portal</li>
<li><strong>cogTextAnalyticsEndpoint</strong>: the endpoint for the Text Analytics API, based on the region we selected during resource provisioning in the Azure Portal. <strong>Important Note: </strong>When we insert the endpoint value into our app configurations, we will append <strong>'/sentiment'</strong> to the endpoint copied from the Azure portal. For example, if you selected the <strong>West US</strong> region when provisioning your Text Analytics resource, the full value to insert in this appSetting would be <strong>https://westus.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment</strong></li>
<li><strong>QnASubscriptionKey</strong>: the QnA Maker subscription key that we obtained while Setting Up our QnA Maker Service</li>
<li><strong>QnAKnowledgebaseId</strong>: the QnA Maker knowledge base ID that we obtained while Setting Up our QnA Maker Service</li></ul>

[snippet slug=qnaescalation_webconfig line_numbers=false lang=c-sharp]

&nbsp;

Once again, we publish our updated bot code to Azure, by right-clicking on our project, and selecting <strong>Publish</strong>, and then clicking on the <strong>Publish </strong>button with our same Azure publishing profile.

&nbsp;

<strong>Setting up the Direct Line Connection</strong>

We will now <a href="https://docs.microsoft.com/en-us/bot-framework/bot-service-channel-connect-directline" target="_blank">enable the Direct Line channel</a> for our bot, which is the channel that Live Assist leverages to enable the bot as a Live Assist agent. Still in the Bot Registration resource blade in the Azure Portal, we click on the <strong>Channels </strong>tab for our bot, and choose to add the <strong>Direct Line</strong> channel:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/New_ChooseDirectLine-800x513.png" alt="" width="800" height="513" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1885" />

&nbsp;

We then show, copy and save our first <strong>Secret key</strong>. Leaving all <strong>Version </strong>options selected, we then click the <strong>Done </strong>button:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/New_GetDirectLineKey-800x464.png" alt="" width="800" height="464" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1895" />

&nbsp;

<strong>Adding our Bot as an Agent in Live Assist</strong>

CafeX has provided instructional steps for adding a bot as an agent in a <a href="https://www.liveassistfor365.com/en/support/knowledge-base/bot-agent-connector-quickstart/" target="_blank">quick-start guide</a>, and we will add our bot as an agent based on those steps. 

First, we log into the Live Assist Administration Portal for the Live Assist-enabled Dynamics 365 organization that we are adding our agent to. The URL for the portal is different for each organization, but you can find your URL either in the “Welcome email” you received upon enabling Live Assist, or from within the Dynamics 365 web client, under <strong>Service &gt; Live Assist Administration</strong>.

We navigate to <strong>USERS &gt; Bots</strong>, and then click the <strong>ADD </strong>button:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/liveassistbotadd-800x264.png" alt="" width="800" height="264" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1755" />

&nbsp;

In the resulting form, we enter:

<ul><li><strong>Nickname</strong>: our desired name for our bot, as displayed to end users</li>
<li><strong>Licenses</strong>: the number of Live Assist licenses to allocate to our bot; for every license, three concurrent chats can be handled by our bot</li>
<li><strong>Connection Type</strong>: we leave this as Ms</li>
<li><strong>Connection Key</strong>: we enter the Direct Line <strong>Secret key</strong> that we obtained earlier when configuring the Direct Line channel</li></ul>

&nbsp;

We then click the <strong>SAVE </strong>button to save our bot.

&nbsp;

<strong>Updating Live Assist Skills and Engagement</strong>

We will now assign appropriate skills to our bot agent and our live escalation agents, along with updating our chat engagement to direct chats to our bot.

We open up our Live Assist <strong>Engagement Administration URL</strong>, which can be found in the Dynamics 365 Web Client, under <strong>Service &gt; Live Assist Supervisor</strong>.

We navigate to <strong>USERS</strong>, and select our newly created bot:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/chooseservicebot-800x445.png" alt="" width="800" height="445" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1645" />

&nbsp;

We add a new <strong>Skill </strong>to our bot user, which we are calling <strong>Bot</strong>. We then click the <strong>Save </strong>button:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/addbotskill.png" alt="" width="776" height="604" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1615" />

&nbsp;

We now select a different “live” agent user who will receive escalations from the bot, and add a <strong>Skill </strong>which we call <strong>BotEscalation</strong>. We then Save the updates to our live agent user:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/escalationskill.png" alt="" width="775" height="609" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1745" />

&nbsp;

We now navigate to the <strong>CAMPAIGNS </strong>tab, and open up our default campaign (typically named <strong>Live Chat on your site</strong>). 

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/choosecampaign-800x340.png" alt="" width="800" height="340" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1635" />

&nbsp;

We click the <strong>Edit </strong>button next to our default engagement:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/editcampaignbutton-800x205.png" alt="" width="800" height="205" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1725" />

&nbsp;

We are brought to the <strong>ENGAGEMENT </strong>step in the Engagement studio process. We click <strong>Next </strong>in the bottom-right to take us to the <strong>WINDOW </strong>step. While on the <strong>WINDOW </strong>step, we click the <strong>Add New</strong> button:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/newwindow-800x305.png" alt="" width="800" height="305" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1766" />

&nbsp;

We provide our new window with a name and description:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/namewindow.png" alt="" width="573" height="566" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1756" />

&nbsp;

In our <strong>Views </strong>dropdown, we enable the <strong>Pre-chat survey</strong> by clicking the toggle, and then edit the pre-chat survey in the resulting window. We will use the pre-chat survey to determine what type of issue the user wishes to get help on, and direct specific types of issues to our bot agent:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/enableprechatsurvey.png" alt="" width="429" height="473" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1735" />

&nbsp;

We use the <strong>Trash </strong>icon to delete any existing questions, then add a new question of type <strong>Routing</strong>. We add our desired question text, and add as many options as desired. For our first option, we add option text, and specify that the option will route to our <strong>Bot </strong>skill. We can add other options that will route to other skills, including directly to the <strong>BotEscalation </strong>skill, if desired:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/routingquestion.png" alt="" width="680" height="551" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1816" />

&nbsp;

We then click the <strong>Done </strong>button in the Pre-chat survey, and click the <strong>Save </strong>button in the bottom-right to save our window. 

With our window now saved and selected, we click the <strong>Publish </strong>button in the bottom-right of the page, to publish our changes.

&nbsp;

<strong>Testing our Bot</strong>

We should now be able to chat with our bot agent from any sites that we have enabled Live Assist chat on, or via the Demo Site that CafeX makes available for testing in the Live Assist Administration Portal (to open portal, go to Dynamics 365 Web Client under <strong>Service &gt; Live Assist Administration</strong>).

We will test using the Demo Site. While in the Live Assist Administration Portal, navigate to <strong>GET STARTED</strong>, use the right chevron to navigate to the <strong>Open Live Assist for Dynamics 365</strong> panel, then click the <strong>DEMO SITE</strong> button:

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/launchtest-800x519.png" alt="" width="800" height="519" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1746" />

&nbsp;

In the resulting sample website, you should see your chat engagement. If you elect to chat, and select the appropriate Routing Question option, you should be able to engage in a conversation with your bot that will be answered via QnA Maker. If sufficiently negative sentiment is expressed by you during the chat, you should be able to escalate to a live agent.

<img src="https://msdnshared.blob.core.windows.net/media/2017/10/testing-800x548.png" alt="" width="800" height="548" style="border-style: solid;border-width: 1px" class="aligncenter size-medium wp-image-1825" />

&nbsp;

<strong>Notes: </strong>Make sure you are logged into Live Assist with a user that has the appropriate <strong>BotEscalation </strong>skill. In addition, if you are still authenticated in the Live Assist Engagement Administration portal, you may find that escalated chats will be directed there.

You can download the full Visual Studio solution code <a href="https://1drv.ms/u/s!Aui7CDzJQqg_hyCR3FjCO3hXLEdJ" target="_blank">here</a>.












]]></content:encoded>
    </item>
    <item>
      <title>The Intelligent Agent Assistant: Bots in the Agent Desktop – Part 2</title>
      <link>https://docs.microsoft.com/archive/blogs/geoffreyinnis/the-intelligent-agent-assistant-bots-in-the-agent-desktop-part-2</link>
      <pubDate>Thu, 13 Jul 2017 17:56:21 GMT</pubDate>
      <dc:creator><![CDATA[Geoff Innis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/geoffreyinnis/?p=1545</guid>
      <description><![CDATA[This post is the second in a series in which we explore how we can leverage natural, conversational...]]></description>
      <content:encoded><![CDATA[This post is the second in a series in which we explore how we can leverage natural, conversational experiences powered by automated intelligence to empower the CSR, by building a contextually-aware Intelligent Agent Assistant, integrated into the Unified Service Desk agent desktop.

We will build upon the bot that we brought into the Unified Service Desk and enabled to communicate with the Unified Service Desk by initiating actions within the desktop in <a href="https://blogs.msdn.microsoft.com/geoffreyinnis/2017/06/28/the-intelligent-agent-assistant-bots-in-the-agent-desktop-part-1/" target="_blank">Part 1</a>.  

<strong>Part 2</strong> of our series will focus on extending this functionality by:

<ul><li>Proactively provide contextually-relevant information and alerts to the CSR via the integrated bot</li>
<li>Enabling administration of the proactive alert content, buttons, and actions from within the Unified Service Desk configurations</li></ul>

To see a 2-minute video that shows the final result we are building towards, check out <a href="https://blogs.msdn.microsoft.com/geoffreyinnis/2017/06/28/the-intelligent-agent-assistant-bots-in-the-agent-desktop-part-1/" target="_blank">Part 1 here</a>.

&nbsp;
<em>Snapshot of Final Result</em>
<img src="https://msdnshared.blob.core.windows.net/media/2017/07/FinalPicOfUSD-1024x549.png" alt="" width="1024" height="549" style="border-style: solid;border-width: 1px" class="aligncenter size-large wp-image-1566" />

&nbsp;

<strong>Extending our Intelligent Agent Assistant</strong>

Now that we have surfaced our bot in USD using the <a href="https://docs.microsoft.com/en-us/bot-framework/channel-connect-directline" target="_blank">Direct Line channel</a>, and the <a href="https://github.com/Microsoft/BotFramework-WebChat" target="_blank">WebChat </a>control in a USD Standard Web Application hosted control, and enabled the bot to trigger actions in USD when buttons are clicked through USD’s event moniker syntax, let’s move on to triggering proactive alerts for the CSR in the bot.

The alerts will be raised in a <strong>three-step process</strong>:

<ol><li>An Action Call in USD will use the RunScript Action  to inject JavaScript into the Bot Assistant control, including JSON data</li>
<li>JavaScript in the Bot Assistant will use the Backchannel to send an event to the bot with the JSON data</li>
<li>The bot will receive the event, and use the received data to create an alert to the user</li>
</ol>

&nbsp;

We’ll see how we can do this for the example of a "High Churn Risk" warning to our agent, based on negative customer sentiment.

&nbsp;

<strong>Initiating Messages to our Bot with a USD Action Call</strong>

First, we create an <strong>Action Call</strong> in USD that will be called whenever we open up a case, initiated from the <strong>BrowserDocumentComplete </strong>event of the <strong>Incident </strong>control which we use to load our cases.

The <strong>Action Call</strong> uses the <strong>RunScript </strong>Action, and passes in a payload of JSON data and other parameters into a postMessage event in the Bot Assistant:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/07/ActionCall-1024x468.png" alt="" width="1024" height="468" style="border-style: solid;border-width: 1px" class="aligncenter size-large wp-image-1546" />

&nbsp;

We add a condition such that the <strong>Action Call</strong> only executes if the <a href="https://blogs.msdn.microsoft.com/geoffreyinnis/2016/07/11/sentiment-analysis-in-usd-with-cognitive-services-text-analytics/" target="_blank">detected sentiment on the case</a> is below a threshold score of 0.35:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/07/ActionCallCondition.png" alt="" width="543" height="147" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1555" />

&nbsp;

The full JavaScript code in our <strong>Action Call</strong> data is shown here. Note how the JSON data contains all of the information required to construct a <a href="https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-add-rich-card-attachments" target="_blank">rich Thumbnail Card</a> in our bot, including URLs for our buttons that use the event moniker syntax from <a href="https://blogs.msdn.microsoft.com/geoffreyinnis/2017/06/28/the-intelligent-agent-assistant-bots-in-the-agent-desktop-part-1/" target="_blank">Part 1</a> to raise events in USD when clicked:

[snippet slug=agentbot2_actioncalljavascript line_numbers=false lang=js]

&nbsp;

<strong>Using the Backchannel to Raise Events with our Bot</strong>

As outlined in the <a href="https://github.com/Microsoft/BotFramework-WebChat#the-backchannel" target="_blank">Backchannel example</a> on Github, by creating a <strong>DirectLine </strong>object in our page, and then sharing it when creating our <strong>WebChat </strong>instance, we are then able to use the <strong>DirectLine </strong>object to post activities such as events to our bot.

We now create our <strong>postMessage </strong>JavaScript function referenced in our <strong>Action Call</strong>. It receives parameters and uses them to post an activity to our bot via <strong>DirectLine</strong>, we will have a means of sending information via activities to our bot programmatically. Our <strong>postMessage </strong>method includes the following parameters:

<ul><li><strong>activityType</strong> – the type of activity, such as event, message, typing, etc; in our example, we will be sending activities of type event</li>
<li><strong>activityText </strong>– the text property for the activity</li>
<li><strong>activityName </strong>– the name of the event we are raising</li>
<li><strong>activityData </strong>– the <strong>channelData </strong>that we will receive in the activity; this will be used to pass important event data that the bot will use</li>
<li><strong>showBotRequest </strong>– a parameter that will dictate whether or not we wish to raise an event in USD which will cause the Intelligent Agent Assistant to be displayed in the agent desktop if it is not already; this will be helpful in our alerts to the agent</li>
</ul>

&nbsp;

The function will receive the parameters, use them to post an activity to the bot, and then will trigger a USD event to display the bot, if appropriate:

[snippet slug=agentbot2_postmessage line_numbers=false lang=js]

&nbsp;

<strong>Receiving Events in our Bot</strong>

We now need to enable our bot to receive our events, and respond appropriately.

We can do this in our Message Controller class. Typical dialog-based samples for the Bot Framework will send received activities that are <strong>Message </strong>type to a dialog class, and will have a separate method to handle other types of messages. This is where we can include our code to handle our incoming events.
We adapt the <strong>HandleSystemMessage </strong>method to include logic to handle events. In this method, we:

<ul><li>check to see what the name of the event is; if it is named botMessageAlert, we will:</li>
<li>create a ConnectorClient</li>
<li>create a message reply</li>
<li>call our FormatGenericMessage method, passing in our reply and our JSON data and receive our formatted message as output</li>
<li>use our ConnectorClient to send the message back to our end-user</li>
</ul>


[snippet slug=agentbot2_messagecontroller line_numbers=false lang=c-sharp]

&nbsp;

Our <strong>FormatGenericMessage </strong>receives our reply message and JSON data, and uses the JSON data to create a well-formatted <strong>Thumbnail </strong>type of rich card:

[snippet slug=agentbot2_formatgenericmessage line_numbers=false lang=c-sharp]

&nbsp;

Now, when we load a case in the Unified Service Desk, our bot will proactively display an alert as shown below, with buttons that will trigger Events and associated Action Calls in USD when clicked:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/07/AlertImage.png" alt="" width="359" height="321" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1565" />

&nbsp;

Stay tuned for more, as we cover:

<ul><li>Making our bot aware of contextual information from USD</li>
<li>Enabling our bot for engagement via speech, in addition to typing</li>
<li>and more</li></ul>]]></content:encoded>
    </item>
    <item>
      <title>The Intelligent Agent Assistant: Bots in the Agent Desktop – Part 1</title>
      <link>https://docs.microsoft.com/archive/blogs/geoffreyinnis/the-intelligent-agent-assistant-bots-in-the-agent-desktop-part-1</link>
      <pubDate>Wed, 28 Jun 2017 06:03:29 GMT</pubDate>
      <dc:creator><![CDATA[Geoff Innis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/geoffreyinnis/?p=1385</guid>
      <description><![CDATA[When we think of how bots fit into a Customer Service strategy, the typical scenario envisioned is...]]></description>
      <content:encoded><![CDATA[When we think of how bots fit into a Customer Service strategy, the typical scenario envisioned is often that of a customer-facing bot, providing customers a conversational support experience powered by automated intelligence. But even with the deployment of a customer-facing bot, most contact centers will still need to support a significant number of customer engagements with the help of a Customer Service Representative (CSR).

This post will be the first in a series in which we explore how we can leverage natural, conversational experiences powered by automated intelligence to empower the CSR, by building a contextually-aware Intelligent Agent Assistant, integrated into the Unified Service Desk agent desktop.

By providing a conversational Agent Assistant experience for the CSR that is tightly integrated into the Unified Service Desk, we can:
<ul><li>Expedite agent productivity with fast and intuitive access to insights and procedures</li>
<li>Provide a natural engagement experience</li>
<li>Proactively provide contextually-relevant information and alerts</li></ul>

&nbsp;

The Intelligent Agent Assistant that we build will have:
<ul><li>Awareness of the context of the agent desktop and current customer interaction</li>
<li>The ability to provide insights, guidance or alerts based on the current context, both proactively and reactively</li>
<li>The ability to trigger and automate actions and activities within the desktop</li>
<li>The ability to be engaged via voice or text/typing</li></ul>

&nbsp;

This 2-minute video shows the types of experiences we will be able to provide for agents at the conclusion of our series <em><strong>(with sound)</strong></em>:

&nbsp;

[video width="1920" height="1040" mp4="https://msdnshared.blob.core.windows.net/media/2017/06/IntelligentAgentAssistant1.mp4"][/video]

&nbsp;

<strong>Building our Intelligent Agent Assistant</strong>

In Part 1 of our series, we will focus on:

<ul><li>Surfacing a bot within the Unified Service Desk</li>
<li>Enabling the bot to communicate with the Unified Service Desk by initiating actions within the desktop</li></ul>

&nbsp;

<strong>Prerequisites:</strong>

The prerequisites for building and deploying our Intelligent Agent Assistant include:

<ul>
<li>An instance of Dynamics 365 for Customer Service (Online)
<ul><li>You can request a trial of Dynamics 365 for Customer Service <a href="https://go.microsoft.com/fwlink/?linkid=849057" target="_blank">here</a></li></ul>
</li>
<li>A Microsoft Azure subscription for hosting your bot</li>
<li>The <a href="https://go.microsoft.com/fwlink/?LinkID=627298" target="_blank">Dynamics 365 Software Development Kit (SDK)</a></li>
<li><a href="https://www.visualstudio.com/en-us/products/vs-2015-product-editions.aspx" target="_blank">Visual Studio 2015</a> or higher</li>
<li>Microsoft .NET Framework 4.6</li>
<li>The <a href="https://docs.microsoft.com/en-us/bot-framework/resources-tools-downloads" target="_blank">Bot Builder SDK for .NET</a> </li>
<li>The <a href="https://emulator.botframework.com/" target="_blank">Bot Framework Emulator</a> (for Windows) </li>
<li>The<a href="https://aka.ms/bf-bc-vstemplate" target="_blank"> Bot Connector Visual Studio Project Template </a>
<ul><li>Save the downloaded zip file to your Visual Studio 201X templates directory, which is typically found in <strong>%USERPROFILE%\Documents\Visual Studio 201X\Templates\ProjectTemplates\Visual C#</strong></li></ul>
</li>
</ul>

&nbsp;

<strong>Surfacing a Bot in USD</strong>

There are several options for incorporating a bot into the Unified Service Desk, including:

<ul><li>Configuring a bot for the <a href="https://docs.microsoft.com/en-us/bot-framework/channel-connect-webchat" target="_blank">Web Chat channel</a>, and hosting it in a USD Standard Web Application hosted control</li>
<li>Configuring a bot for the <a href="https://docs.microsoft.com/en-us/bot-framework/channel-connect-directline" target="_blank">Direct Line channel</a>, and using the <a href="https://github.com/Microsoft/BotFramework-WebChat" target="_blank">WebChat </a>control for your bot client, hosting your control in a USD Standard Web Application hosted control</li>
<li>Configuring a bot for the <a href="https://docs.microsoft.com/en-us/bot-framework/rest-api/bot-framework-rest-direct-line-3-0-concepts" target="_blank">Direct Line channel</a>, and creating your own bot client, hosted in a <a href="https://msdn.microsoft.com/en-us/library/dn864925.aspx" target="_blank">Custom Hosted Control in USD</a></li></ul>

&nbsp;

For our Intelligent Agent Assistant, we will configure a bot for the <a href="https://docs.microsoft.com/en-us/bot-framework/channel-connect-directline" target="_blank">Direct Line channel</a>, and use the <a href="https://github.com/Microsoft/BotFramework-WebChat" target="_blank">WebChat control</a> for the bot client, hosting the control in a USD Standard Web Application hosted control. This option allows us to leverage a pre-built bot client for our user interface, while still allowing us to programmatically communicate with the bot via the Direct Line REST API, sending and receiving event activities, as outlined in the <a href="https://github.com/Microsoft/BotFramework-WebChat/blob/master/samples/backchannel/index.html" target="_blank">Backchannel example on GitHub</a>.

While we will get into more depth on the specifics of our bot code later on you can review some of the basics of <a href="https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-overview" target="_blank">building </a>and <a href="https://docs.microsoft.com/en-us/bot-framework/deploy-bot-visual-studio" target="_blank">deploying </a>a bot using the <strong>Bot Builder SDK for .NET</strong> in some of the previous posts on this blog, and in the <a href="https://docs.microsoft.com/en-us/bot-framework/deploy-bot-visual-studio" target="_blank">Bot Framework documentation</a>.

Once you have deployed a bot and <a href="https://docs.microsoft.com/en-us/bot-framework/portal-register-bot" target="_blank">registered it with the Bot Framework</a>, you can <a href="https://docs.microsoft.com/en-us/bot-framework/channel-connect-directline" target="_blank">enable your bot for the Direct Line channel</a>:
&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/06/directline-addchannel.png" alt="" width="800" height="734" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1416" />

&nbsp;

Ensure you capture your <strong>Bot Application ID</strong> during registration, and your <strong>Direct Line secret</strong> while enabling your bot on the channel.

Next, we will create a basic full-window HTML page that makes use of the WebChat, based on the <a href="https://github.com/Microsoft/BotFramework-WebChat/blob/master/samples/fullwindow/index.html" target="_blank">fullwindow </a>example on GitHub:

[snippet slug=agentbot1_bothtml line_numbers=false lang=html]

&nbsp;

After deploying this page to Azure Blob Storage, or an alternate web server, you should be able to access your bot like so:

<strong>https://&lt;YourAzureSubdomain&gt;.blob.core.windows.net/mycontainer/usdagentbot.html?s=&lt;YourSecret&gt;&amp;botid=&lt;YourBotId&gt;&amp;username=&lt;Username&gt;</strong>

<em>
(As a more secure alternative to using your Direct Line secret directly, you can use a Direct Line token, obtained by calling Direct Line's Generate Token.)</em>

&nbsp;

In the Dynamics 365 Web Client, we now create a new Hosted Control for our bot, using the Standard Web Application type. You can opt to make your control Global, or Session-specific; in our example we will make it Global:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/06/botassistant_control.png" alt="" width="938" height="691" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1405" />

&nbsp;

We want to instantiate our control when USD is launched, so we create an Action Call to navigate our control to our bot URL:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/06/loadbot2.png" alt="" width="909" height="598" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1485" />

&nbsp;

We then add this Action Call to the <strong>DesktopReady </strong>event of the <strong>Global Manager</strong> control. Now when we launch USD, we should see our bot in the <strong>RightPanel</strong>:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/06/BotLoaded-1024x549.png" alt="" width="1024" height="549" style="border-style: solid;border-width: 1px" class="aligncenter size-large wp-image-1475" />

&nbsp;

<strong>Triggering Events and Actions in USD from our Bot</strong>

Now that our bot appears in USD, let’s see how we can enable our bot to use the event model of USD to trigger actions in the desktop, by creating a custom event on our Bot Assistant control, then calling it via a URL that is opened by a Card Action in our bot.

In this basic example, we will show how we can search for contacts by name, and allow our users to initiate a session with that contact.

First, we will add a custom event to our Bot Assistant control, called <strong>ContactSessionRequested</strong>:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/06/customevent.png" alt="" width="927" height="471" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1415" />

&nbsp;

To this event, we can call any actions we wish to in preparation for a new session, and include an Action Call called<strong> DoRoute from Bot</strong>. Note how we are including a Replacement Parameter that references a parameter from our event:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/06/DoRouteFromBot.png" alt="" width="847" height="481" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1425" />

&nbsp;

This will trigger our <strong>Window Navigation Rule</strong>, which in turn will create our session and load our contact:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/06/windowsnavrule.png" alt="" width="834" height="880" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1445" />

&nbsp;

We now need to call the event from our bot. USD provides a means of calling events on hosted controls using an event moniker syntax, as outlined in the <a href="https://msdn.microsoft.com/en-us/library/dn864970.aspx" target="_blank">Unified Service Desk documentation on user-defined events</a>. We can use this syntax to call the event we created in USD:

<strong>https://event/?eventname=ContactSessionRequested&amp;contactid=&lt;contactid&gt;</strong>

&nbsp;

We will now add code to our bot to allow the bot to call the URL above when appropriate. Making use of the code from our <a href="https://blogs.msdn.microsoft.com/geoffreyinnis/2016/07/28/bringing-bots-into-an-omni-channel-customer-service-strategy-part-2-creating-cases/" target="_blank">previous blog post</a> that allows us to query Dynamics 365 data via the Web API, we can use the following code to use our bot dialog context, and a contact search term, to find matching contacts, and return them to our user. In this example, we are using a <a href="https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-add-rich-card-attachments" target="_blank">ThumbnailCard </a>to present our information and <strong>CardAction </strong>objects to allow our user to select a button. When the button is selected, the URL will be opened, and our custom event will be called:

[snippet slug=agentbot1_contact line_numbers=false lang=c-sharp]

&nbsp;

Included in the code is an overloaded <strong>ReadyForNextCommand </strong>method for reusability.

Here is an example of how you can call this method in the context of a dialog that uses <strong>LUIS </strong>for natural language interaction:

[snippet slug=agentbot1_luiscontact line_numbers=false lang=c-sharp]

&nbsp;

<em>(see <a href="https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-luis-dialogs" target="_blank">Enable language understanding with LUIS</a> for more information on LUIS dialogs)</em>

&nbsp;

When our Card Action button that is presented to the user is clicked, the event moniker URL will be called, and a session with the selected contact will be initiated:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/06/usdfinalpic-1024x550.png" alt="" width="1024" height="550" style="border-style: solid;border-width: 1px" class="aligncenter size-large wp-image-1435" />

&nbsp;

Stay tuned for more posts in this series, in which we will cover:

<ul><li>Making our bot aware of contextual information from USD</li>
<li>Enabling our bot to proactively notify our agent of alerts and insights based on the USD context</li>
<li>Enabling our bot for engagement via speech, in addition to typing</li>
<li>and more</li></ul>


]]></content:encoded>
    </item>
    <item>
      <title>Product and Part Identifier Bot using Custom Vision Service</title>
      <link>https://docs.microsoft.com/archive/blogs/geoffreyinnis/product-and-part-identifier-bot-using-custom-vision-service</link>
      <pubDate>Tue, 13 Jun 2017 18:11:04 GMT</pubDate>
      <dc:creator><![CDATA[Geoff Innis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/geoffreyinnis/?p=1266</guid>
      <description><![CDATA[In this post, we will build upon some of the capabilities that have been explored previously,...]]></description>
      <content:encoded><![CDATA[In this post, we will build upon some of the capabilities that have been explored previously, including <a href="https://blogs.msdn.microsoft.com/geoffreyinnis/2016/07/28/bringing-bots-into-an-omni-channel-customer-service-strategy-part-2-creating-cases/" target="_blank">Microsoft’s Bot Framework</a>, and the Cognitive Services <a href="https://blogs.msdn.microsoft.com/geoffreyinnis/2017/05/23/intelligently-routing-cases-by-product-with-cognitive-services-custom-vision/" target="_blank">Custom Vision Service</a>. We will create a Bot that is capable of identifying a part or product from an organization’s Dynamics 365 product catalog, using an organization-specific image classifier that is powered by the Custom Vision Service.

&nbsp;

By enabling part or product identification through an intuitive and mobile-accessible bot, we can facilitate such scenarios as:

<ul><li>Enabling field technicians to quickly identify an unknown part or product while on-site, and providing them instant access to documentation and specifications</li>
<li>Enabling customers to quickly identify a part or product to facilitate service requests or product-specific self-service</li>
</ul>

&nbsp;

This 40 second video shows the functionality in action:

&nbsp;

[video width="370" height="650" mp4="https://msdnshared.blob.core.windows.net/media/2017/06/CustomVisionBot3.mp4"][/video]

&nbsp;

We will build on the sample code available in these two resources:

<ul><li>The <a href="https://github.com/Microsoft/BotBuilder-Samples/tree/master/CSharp/core-ReceiveAttachment" target="_blank">Receive Attachment code sample</a> from the <a href="https://github.com/Microsoft/BotBuilder-Samples" target="_blank">BotBuilder-Samples GitHub repository</a></li>
<li>The <a href="https://docs.microsoft.com/en-us/azure/cognitive-services/custom-vision-service/getting-started-build-a-classifier" target="_blank">Custom Vision Service quickstart guide</a> in the Cognitive Services documentation</li>
</ul>

&nbsp;

<strong>Pre-requisites</strong>

The pre-requisites for building and deploying our Product and Part Identifier Bot include:

<ul>
<li>An instance of Dynamics 365 for Customer Service (Online)
<ul><li>You can request a trial of Dynamics 365 for Customer Service <a href="https://go.microsoft.com/fwlink/?linkid=849057" target="_blank">here</a></li></ul>
</li>
<li>In our Dynamics 365 organization, we need to have configured:
<ul><li>Products in our Products Catalog <em>(ideally populated with product names, descriptions, product numbers, externally-accessible product image URLs, and links to product specifications)</em></li></ul></li>
<li>Administrator credentials to access the O365 Admin Portal for our tenant that our Dynamics 365 instance is connected to</li>
<li>A Microsoft Azure subscription for application registration; A trial account will also work; See <a href="https://blogs.msdn.microsoft.com/geoffreyinnis/2016/06/08/bringing-bots-into-an-omni-channel-customer-service-strategy-part-1/" target="_blank">this previous post</a> for a walkthrough of how to obtain Dynamics 365 Web API credentials</li>
<li>The <a href="https://go.microsoft.com/fwlink/?LinkID=627298" target="_blank">Dynamics 365 Software Development Kit (SDK)</a></li>
<li>A Microsoft Account, for signing into the Custom Vision Service (<a href="https://customvision.ai" target="_blank">https://customvision.ai</a>) </li>
<li><a href="https://www.visualstudio.com/en-us/products/vs-2015-product-editions.aspx" target="_blank">Visual Studio 2015</a> or higher</li>
<li>Microsoft .NET Framework 4.6</li>
<li>The <a href="https://docs.microsoft.com/en-us/bot-framework/resources-tools-downloads" target="_blank">Bot Builder SDK for .NET</a> </li>
<li>The <a href="https://emulator.botframework.com/" target="_blank">Bot Framework Emulator</a> (for Windows) </li>
<li>The<a href="https://aka.ms/bf-bc-vstemplate" target="_blank"> Bot Connector Visual Studio Project Template </a>
<ul><li>Save the downloaded zip file to your Visual Studio 201X templates directory, which is typically found in <strong>%USERPROFILE%\Documents\Visual Studio 201X\Templates\ProjectTemplates\Visual C#</strong></li></ul>
</li>
</ul>

&nbsp;

<strong>Setting Up our Custom Vision Service Project</strong>

The first thing we will do is to set up our own Custom Vision Service project. The process of creating a Custom Vision Service project has been covered in a previous post, so to create our project, we can <a href="https://blogs.msdn.microsoft.com/geoffreyinnis/2017/05/23/intelligently-routing-cases-by-product-with-cognitive-services-custom-vision/" target="_blank">follow the steps outlined here</a> (see <strong>Setting Up our Custom Vision Service Project</strong>).

After we have created, trained and tested our classifier, we can obtain the necessary credentials from the Custom Vision site to call the Prediction API by selecting the <strong>Performance </strong>tab, and clicking <strong>Prediction URL</strong>.

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/05/predictionAPIEndpoint2-1024x401.png" alt="predictionapiendpoint2" width="1024" height="401" style="border-style: solid;border-width: 1px" class="aligncenter size-large wp-image-1146" />

&nbsp;

We can extract our Project GUID from the URL, and our Prediction Key from the <strong>Prediction-Key</strong> header value.

&nbsp;

<strong>Obtaining our Dynamics 365 Web API Credentials</strong>

In order to query our Dynamics 365 Product Catalog, we will also need to have the required credentials to authenticate our requests via the Web API.

In addition to an O365 username and password with sufficient D365 privileges to read our Product Catalog, we require:

<ul><li>Our Application Client ID</li>
<li>Our OAuth 2.0 Authorization Endpoint</li></ul>

&nbsp;

See this <a href="https://blogs.msdn.microsoft.com/geoffreyinnis/2016/06/08/bringing-bots-into-an-omni-channel-customer-service-strategy-part-1/" target="_blank">previous post for a walkthrough</a> of how to obtain these credentials (starting at <strong>Obtaining our CRM Web API Credentials</strong>).

&nbsp;

<strong>Building our Bot</strong>

We will now start putting together the code for our bot, using steps found in the <a href="https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-quickstart" target="_blank">Create a bot with the Bot Builder SDK for .NET</a> quickstart.

We Open Visual Studio, and create a new project using the <strong>Bot Application</strong> template that we downloaded as a part of our pre-requisites:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/06/CreateProject-1024x710.png" alt="" width="1024" height="710" style="border-style: solid;border-width: 1px" class="aligncenter size-large wp-image-1325" />

&nbsp;

In our <strong>Project Properties</strong>, on the Application tab, we specify <strong>.NET Framework 4.6</strong> as the target framework.

&nbsp;

<strong>Installing Packages and Adding References</strong>

We need install several packages that we will leverage as a part of our bot code, and ensure our project is referencing the latest version of the Bot Builder SDK. We can do this via NuGet:

<ul><li>The latest version of the <a href="https://www.nuget.org/packages/Microsoft.Bot.Builder/">Microsoft.Bot.Builder</a> package</li>
<li>Version 2.26 of the <a href="https://www.nuget.org/packages/Microsoft.IdentityModel.Clients.ActiveDirectory/2.26.305102204">Microsoft.IdentityModel.Clients.ActiveDirectory</a> package, to assist with Dynamics 365 Web API authentication</li></ul>

&nbsp;


We also add references to the following assemblies, which we will use in our requests to the Custom Vision Service and Web API:

<ul><li>System.Net</li>
<li>System.Net.Http</li>
<li>System.Runtime.Serialization</li></ul>

&nbsp;

We will place the Custom Vision Service credentials and Dynamics 365 Web API Credentials into our <strong>Web.config</strong> settings. We open the file, and add our credentials as <strong>appSettings </strong>as shown below, to make them accessible throughout our project:

[snippet slug=customvisionbot_webconfig lang=xml]

&nbsp;

<strong>Adding a Data Contract for the Custom Vision Service</strong>

To facilitate interacting with the <strong>Custom Vision Service</strong>, we add a new item to our project: a <strong>Visual C# class</strong> which we will name <strong>CustomVision.JSON.cs</strong>. We will populate this file with JSON data contracts for the data that comes back in the response from the <a href="https://docs.microsoft.com/en-us/azure/cognitive-services/custom-vision-service/use-prediction-api" target="_blank">sample code provided</a> for the Prediction API.

[snippet slug=customvision_datacontract lang=c-sharp]

&nbsp;

<strong>Querying Dynamics 365 via the Web API</strong>

We will also create a separate class to hold our utility <strong>CRMWebAPIRequest </strong>method, used to issue our Web API requests to Dynamics 365, as done in previous posts:

<ul><li>The method accepts not only a request string, but also an <strong>HttpContent </strong>request payload, and request type indicator, to allow for not only querying, but creation of records in Dynamics 365</li>
<li>Dynamics 365 Web API credentials are retrieved from the <strong>Web.config </strong></li>
<li>Depending on whether the request type, there is conditional logic to issue either a <strong>GET </strong>request when we are retrieving Dynamics data, or a <strong>POST </strong>request with content, if we are creating a Dynamics record</li></ul>

[snippet slug=customvisionbot_utilities lang=c-sharp]

&nbsp;

Next, we will adapt our <strong>MessagesController.cs</strong> class to be able to initiate our main dialog with the user. We replace the default Echo Bot code with code that will initiate a new <a href="https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-dialogs" target="_blank">Dialog </a>using a <strong>VisionDialog </strong>class that we will create next:

[snippet slug=customvisionbot_messagecontroller lang=c-sharp]

&nbsp;

Next, we add a new class to our project, which we call <strong>VisionDialog.cs</strong>. This class will manage the interactions with the Custom Vision Service and Dynamics 365 to identify our product.

The code in the class will:

<ul><li>Present the user with the option to upload an image for identification using the <strong>StartingOptionsMessage </strong>method <em>(Note: Options to allow dynamic credential setting and viewing are included as placeholder options)</em></li>
<li>If the user opts to upload an image, the <strong>AfterImageProvided </strong>method will
<ul><li>Validate that an attachment has been included with the message</li>
<li>Use <strong>HttpClient </strong>to retrieve the image as a byte array, using a <strong>JwtToken </strong>if necessary</li>
<li>Issue a request to the <strong>Custom Vision Service</strong>, with the appropriate credentials</li>
<li>Serialize the response using the <strong>CustomVision.JSON.cs</strong> data contract</li>
<li>If a prediction is returned from the <strong>Custom Vision Service</strong>, a request will be made to the <strong>Dynamics 365 Web API</strong> to retrieve a matching product from the <strong>Catalog</strong></li>
<li>If a matching product is found in the catalog, a message with a<strong> Hero Card</strong> will be returned to the user, including product details, and a link to product specifications, if available</li></ul></li></ul>

[snippet slug=customvisionbot_visiondialog lang=c-sharp]

&nbsp;

We are now ready to build and test our bot. As before, we press <strong>F5 </strong>in Visual Studio, which will Start Debugging. Once debugging has started, an Internet Explorer window should pop up, containing your bot endpoint information.

We also launch our <strong>Bot Framework Emulator</strong> which we downloaded earlier. We take the URL from the IE pop-up address bar, append <strong>/api/messages</strong>, and enter this in the URL field of the emulator. We can use the <strong>MicrosoftAppId </strong>and <strong>MicrosoftAppPassword </strong>from the application template <strong>Web.config</strong> file, and add them in the appropriate inputs in the emulator as well. 

We can now test the identification of a product image through our bot emulator:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/06/TestWithEmulator-1022x1024.png" alt="" width="1022" height="1024" style="border-style: solid;border-width: 1px" class="aligncenter size-large wp-image-1335" />

&nbsp;

Our bot is ready to be published to Microsoft Azure, registered with the Bot Framework, and made available across channels. If you wish to walk through the deploying of your bot from Visual Studio, see <a href="https://docs.microsoft.com/en-us/bot-framework/deploy-bot-visual-studio" target="_blank">here</a>.

]]></content:encoded>
    </item>
    <item>
      <title>Intelligently Routing Cases by Product with Cognitive Services Custom Vision</title>
      <link>https://docs.microsoft.com/archive/blogs/geoffreyinnis/intelligently-routing-cases-by-product-with-cognitive-services-custom-vision</link>
      <pubDate>Tue, 23 May 2017 19:42:42 GMT</pubDate>
      <dc:creator><![CDATA[Geoff Innis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/geoffreyinnis/?p=1045</guid>
      <description><![CDATA[Microsoft’s Cognitive Services team recently made available a number of new services at the Build...]]></description>
      <content:encoded><![CDATA[Microsoft’s <a href="https://www.microsoft.com/cognitive-services" target="_blank">Cognitive Services</a> team recently made available a number of new services at the <a href="https://azure.microsoft.com/en-us/blog/at-build-microsoft-expands-its-cognitive-services-collection-of-intelligent-apis/" target="_blank">Build 2017 conference</a>, to further augment the tools available to developers to enhance applications with natural methods of communication. One of these new services is the <a href="https://aka.ms/cvisionservice" target="_blank">Custom Vision Service</a>, currently in public preview, which <em>“is an easy-to-use, customizable web service that learns to recognize specific content in imagery, powered by state-of-the-art machine learning neural networks that become smarter with training.”</em> Domain-specific customizable image recognition has significant applicability to customer service scenarios, allowing us to intelligently automate the identification of products or parts, and to initiate product-specific actions.

&nbsp;

There are a number of ways we can apply this product or part recognition capability, including:

<ul>
<li>Auto-routing cases based on the product or part shown in an attached picture, in instances where the customer is not able to identify the product themselves (as we will show in this post)</li>
<li>Enabling field technicians to identify a part or product while in the field</li>
<li>Enabling customers to easily identify a product by simply taking a photo while engaging with a service-centric bot</li>
</ul>

&nbsp;

In this post, we will see how the Custom Vision Service can be leveraged to automatically identify a product based on a photo that the customer uploads while submitting an issue via a self-service portal, then automatically and intelligently routed to the appropriate team with product expertise. We will create a Custom Workflow Activity that calls the Custom Vision Service to identify the product contained within an image attached to a Case Note. We will then use that activity within a Workflow process to automatically route the case to a product-specific queue.

This 50 second video shows the functionality in action:

&nbsp;

[video width="800" height="450" mp4="https://msdnshared.blob.core.windows.net/media/2017/05/RouteCaseCustomVision.mp4"][/video]

&nbsp;

We will build on the sample code available in these two resources:
<ul>
<li><a href="https://msdn.microsoft.com/en-us/library/gg328515.aspx" target="_blank">Create a custom workflow activity</a> on MSDN, and the associated code samples in the Dynamics 365 SDK</li>
<li>The <a href="https://docs.microsoft.com/en-us/azure/cognitive-services/custom-vision-service/getting-started-build-a-classifier" target="_blank">Custom Vision Service quickstart guide</a> in the Cognitive Services documentation</li>
</ul>

&nbsp;

<strong>Pre-requisites</strong>

The pre-requisites for building and deploying our custom workflow activity include:
<ul>
<li>An instance of Dynamics 365 for Customer Service (Online)
<ul><li>You can request a trial of Dynamics 365 for Customer Service <a href="https://go.microsoft.com/fwlink/?linkid=849057" target="_blank">here</a></li></ul>
</li>
<li>In our Dynamics 365 organization, we need to have configured:
<ul><li>Products in our Products Catalog</li>
<li>Queues that align with our individual products</li>
<li>A Dynamics 365 portal installed and enabled for case creation</li>
<li>A case creation Entity Form that enables the attaching of a single file of the appropriate image MIME type / file extensions</li></ul></li>
<li>The <a href="https://go.microsoft.com/fwlink/?LinkID=627298" target="_blank">Dynamics 365 Software Development Kit (SDK)</a></li>
<li>A Microsoft Account, for signing into the Custom Vision Service (<a href="https://customvision.ai" target="_blank">https://customvision.ai</a>) </li>
<li><a href="https://www.visualstudio.com/en-us/products/vs-2015-product-editions.aspx" target="_blank">Visual Studio</a> 2015 or higher</li>
<li>Microsoft .NET Framework 4.5.2</li>
</ul>

&nbsp;

<strong>Setting Up our Custom Vision Service Project</strong>

The first thing we will do is to set up our own Custom Vision Service project. The Custom Vision Service allows us to go beyond the broader image recognition capabilities of the <a href="https://docs.microsoft.com/en-us/azure/cognitive-services/computer-vision/home" target="_blank">Computer Vision API</a>, and to create our own custom computer vision model, specific to the products or parts that we want it to be able to classify.

The broad steps involved in preparing the Custom Vision Service are:

<ul>
<li>Signing into <a href="https://customvision.ai" target="_blank">https://customvision.ai</a> with your Microsoft Account</li>
<li>Building a Custom Vision Service project (Classifier) </li>
<li>Refining or Improving the Classifier</li>
<li>Testing the Classifier</li>
</ul>

&nbsp;

The Custom Vision Service documentation provides an in-depth, step-by-step guide to this process, so rather than recreate it in this post, it is recommended that you follow the steps outlined <a href="https://docs.microsoft.com/en-us/azure/cognitive-services/custom-vision-service/getting-started-build-a-classifier" target="_blank">here</a>. We will hit on some of the key aspects as it relates to our product identification scenario.

Following the instructions, we log into the Custom Vision Service, and create a new project. When creating a new project, we can choose a specific domain, or choose <strong>General</strong>. If your products are those typically found in a shopping catalog or shopping website, you may wish to select <strong>Retail</strong>. Otherwise, <strong>General </strong>may be more suitable:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/05/domains.png" alt="domains" width="598" height="565" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1135" />

&nbsp;

For each product or part that we wish to be able to identify, we will upload a variety of images, and assign a <strong>Tag </strong>to the images. While it is possible to assign multiple tags, we will assign a single tag to each image. We will use tags that match the names of the products as contained in the Dynamics 365 product catalog:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/05/ProjectAddImagesTags_MouseBest-1024x779.png" width="1024" height="779" style="border-style: solid;border-width: 1px" class="aligncenter size-large wp-image-1125" />

&nbsp;

After we have repeated the process of uploading and tagging photos for each of the products or parts that we will include in our classifier, we can proceed to train, evaluate, and improve our classifier as outlined in the <a href="https://docs.microsoft.com/en-us/azure/cognitive-services/custom-vision-service/getting-started-build-a-classifier" target="_blank">quickstart guide</a>. We also set our desired iteration as the ‘Default’ iteration.

After training our classifier, we can also run a quick test with a local image file, or with an image URL:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/05/RunTestMouse.png" alt="runtestmouse" width="687" height="919" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1115" />

&nbsp;

Assuming our results are satisfactory, we can proceed to creating a <strong>Custom Workflow Activity</strong> that will call the <strong>Prediction API</strong> to classify images attached to Notes.

We can obtain the necessary credentials from the Custom Vision site to call the Prediction API by selecting the <strong>Performance </strong>tab, and clicking <strong>Prediction URL</strong>:

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/05/predictionAPIEndpoint2-1024x401.png" alt="predictionapiendpoint2" width="1024" height="401" style="border-style: solid;border-width: 1px" class="aligncenter size-large wp-image-1146" />

&nbsp;

We can extract our Project GUID from the URL, and our Prediction Key from the <strong>Prediction-Key</strong> header value.

To use the Prediction API, we will build on the <a href="https://docs.microsoft.com/en-us/azure/cognitive-services/custom-vision-service/use-prediction-api" target="_blank">sample C# code</a> provided in the quickstart guide.

&nbsp;

<strong>Building our Custom Workflow Activity</strong>

In <strong>Visual Studio</strong>, we will first create a new project by selecting <strong>Workflow </strong>under <strong>Visual C#</strong> in the <strong>Installed Templates</strong> pane, and then select <strong>Activity Library</strong>. We will name our project <strong>DetermineProduct</strong>:

<img src="https://msdnshared.blob.core.windows.net/media/2017/05/CreateVSProject1.png" alt="createvsproject" width="946" height="657" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1155" />

&nbsp;

In our <strong>Project Properties</strong>, on the <strong>Application </strong>tab, we specify <strong>.NET Framework 4.5.2</strong> as the target framework.

&nbsp;
 
<strong>Adding References </strong>

We add references to our project by right-clicking the <strong>DetermineProduct </strong>project in the Solution Explorer, and adding the following:

<ul>
<li>Microsoft.Xrm.Sdk</li>
<li>Microsoft.Xrm.Sdk.Workflow</li>
<li>System.Net</li>
<li>System.Net.Http</li>
<li>System.Runtime.Serialization</li>
</ul>


Note that the <strong>Microsoft.Xrm.Sdk</strong> and <strong>Microsoft.Xrm.Sdk.Workflow</strong> assemblies are found within the Dynamics 365 SDK.

&nbsp;

<strong>Adding a Data Contract for the Custom Vision Service</strong>

To facilitate interacting with the <strong>Custom Vision Service</strong>, we add a new item to our project: a <strong>Visual C# class</strong> which we will name <strong>CustomVision.JSON.cs</strong>. We will populate this file with JSON data contracts for the data that comes back in the response from the <a href="https://docs.microsoft.com/en-us/azure/cognitive-services/custom-vision-service/use-prediction-api" target="_blank">sample code provided</a> for the Prediction API.

[snippet slug=customvision_datacontract lang=c-sharp]

&nbsp;

<strong>Adding Our C# Code</strong>

Following the instructions outlined in the <a href="https://msdn.microsoft.com/en-us/library/gg328515.aspx" target="_blank">Dynamics 365 documentation</a>, we delete the <strong>Activity1.xaml</strong> file in the project, and <strong>Add </strong>a new <strong>Class </strong>to the project, which we name <strong>DetermineProduct.cs</strong>. 

<em>The full code for our class is shown further below, but first we will walk through the building of the class.</em>

To our new class, we:

<ul><li>add some using statements</li>
<li>make the class inherit from the CodeActivity class and give it a public access modifier</li>
<li>add functionality to the class by adding an Execute method</li>
</ul>

[snippet slug=customvision_usingstatements lang=c-sharp]

&nbsp;

We define our input and output parameters for our custom activity:

<ul><li><strong>note_input</strong> as an <strong>input </strong>parameter
<ul><li>this is the Note that has just been created to initiate our workflow</li></ul></li>
<li><strong>predictionKey </strong>as an <strong>input </strong>parameter
<ul><li>this is the Prediction Key that we obtained earlier</li></ul></li>
<li><strong>projectGuid </strong>as an <strong>input </strong>parameter
<ul><li>this is the identifier for our classifier project that we obtained earlier</li></ul></li>
<li><strong>product </strong>as an <strong>output </strong>parameter
<ul><li>this is a Dynamics 365 EntityReference to the identified product from our catalog</li></ul></li>
<li><strong>probability </strong>as an <strong>output </strong>parameter
<ul><li>this is an indicator of the confidence of the product identification</li></ul></li>
</ul>

[snippet slug=customvision_parameters lang=c-sharp]

&nbsp;

In our <strong>Execute </strong>method, we create our Tracing Service and our Context for our custom workflow activity, then set our default return values:

[snippet slug=customvision_tracingcontext lang=c-sharp]

&nbsp;

Next, we retrieve the note entity and required attributes based on the inbound note <strong>EntityReference</strong>:

[snippet slug=customvision_getnote lang=c-sharp]

&nbsp;

We then confirm that we have an attachment filename, and if so, we convert the document body into a <strong>Byte array</strong>, for use with the Prediction API:

[snippet slug=customvision_bytearray lang=c-sharp]

&nbsp;

Next, we create our <strong>HttpClient</strong>, prepare our request to the Prediction API with the appropriate headers, credentials, and URL structure, and retrieve our response:

[snippet slug=customvision_createclient lang=c-sharp]

&nbsp;

We now:

<ul><li>serialize our response with our data contract</li>
<li>confirm that we have some Predictions of what the product is</li>
<li>use our top-ranking Prediction to build and execute a query to confirm that we have a matching product name in our catalog</li>
<li>set the matching product from the catalog as our output Product EntityReference, and output our prediction Probability as well</li>
</ul>

[snippet slug=customvision_callpredictions lang=c-sharp]

&nbsp;

The full code for our class is shown below:

[snippet slug=customvision_fullsnippet lang=c-sharp]

&nbsp;

Before compiling our assembly, we sign it. In the project properties, under the <strong>Signing </strong>tab, we select <strong>Sign the assembly</strong> and provide a key file name.

We are now ready to compile the assembly by <strong>Building </strong>the solution.

&nbsp;

<strong>Registering our Assembly</strong>

We now need to register our custom workflow activity assembly on our Dynamics 365 instance. To do that, we will use the <strong>Plug-in Registration Tool</strong>. This tool is available in the Dynamics 365 SDK.

Following the instructions in the documentation, we launch the tool, and authenticate using our administrator credentials for Dynamics. We then select <strong>Register New Assembly</strong> from the <strong>Register </strong>menu.

In the resulting dialog box, we choose the location of our compiled assembly (which should be in the <strong>DetermineProduct\bin\Debug</strong> folder). We select our assembly and our workflow activity for registration. We specify <strong>Sandbox </strong>as the isolation mode, and <strong>Database </strong>as the storage location. Finally, we click <strong>Register Selected Plugins</strong>:

<img src="https://msdnshared.blob.core.windows.net/media/2017/05/RegisterAssembly.png" alt="registerassembly" width="604" height="814" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1085" />

&nbsp;

We now have a custom workflow activity that will allow us to determine whether Note attachment images match a product in our catalog, and can use that as a part of our business processes.

&nbsp;

<strong>Routing Cases based on Product Identified in Image</strong>

In our example, we will use our custom workflow activity to create a new workflow process that will attempt to find a product match for any cases created from the portal with an image attachment.

Logged in to the Dynamics 365 web client with our administrator credentials, we navigate to <strong>Settings &gt; Customizations &gt; Customize the System</strong>. We choose <strong>Processes </strong>from the left navigation, and choose <strong>New</strong>.

We specify that we are creating a <strong>Workflow </strong>type of process that is applicable to the <strong>Note </strong>entity, running in the background:

<img src="https://msdnshared.blob.core.windows.net/media/2017/05/NewWorkflow_2.png" alt="newworkflow_2" width="816" height="614" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1075" />

&nbsp;

When defining our process logic, we can now access our <strong>Determine Product</strong> action from the <strong>Add Step</strong> menu:

<img src="https://msdnshared.blob.core.windows.net/media/2017/05/addStep.png" alt="addstep" width="596" height="354" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1076" />

&nbsp;

We continue to design our process such that it is activated when a record is created, and we define our complete logic as described below:
<ul><li>we check to ensure our <strong>Note </strong>contains an attachment, is associated with a <strong>Case</strong>, and was submitted from the portal</li>
<li>if our check passes, we use our custom action to determine the product found in the attachment image
<ul><li>note that we can restrict the MIME types that will be accepted in Case Creation attachments in our Entity Form settings of the portal</li>
<li>we pass in our <strong>Note Entity Reference</strong>, and our <strong>Project and Prediction API credentials</strong>, as shown in the detail below</li></ul>
</li>
<li>we check to see whether our first returned prediction has a probability of greater than the nominal value of 0.7; if so, we:
<ul><li>set the appropriate product lookup value on our case</li>
<li>add another note associated with our case to indicate that the product was auto-determined, and what the calculated probability was</li>
<li>apply our routing rules; these routing rules can be configured to route to specific queues based on the product associated with the case</li></ul>
</li></ul>

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/05/Workflow_2.png" alt="workflow_2" width="955" height="623" style="border-style: solid;border-width: 1px" class="aligncenter size-full wp-image-1055" />

&nbsp;

<em>Detail on Custom Action Step Properties</em>

&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/05/CustomStepProperties-1024x657.png" alt="customstepproperties" width="1024" height="657" style="border-style: solid;border-width: 1px" class="aligncenter size-large wp-image-1065" />

&nbsp;

After we <strong>Save </strong>and <strong>Activate </strong>our process, we are now ready to test it. 

&nbsp;

As shown in the video at the start of the post, we can create a case from our portal, attach a product image as we submit the case, and after a brief time, our case should be added to the appropriate product queue.

With this functionality, we have been able to streamline the process of routing customer issues directly to subject matter experts in our organization, while enabling our customers to intelligently engage with us without requiring them to have extensive product knowledge.












]]></content:encoded>
    </item>
    <item>
      <title>Bringing Bots into an Omni-channel Customer Service Strategy – Part 2: Creating Cases</title>
      <link>https://docs.microsoft.com/archive/blogs/geoffreyinnis/bringing-bots-into-an-omni-channel-customer-service-strategy-part-2-creating-cases</link>
      <pubDate>Thu, 28 Jul 2016 13:15:58 GMT</pubDate>
      <dc:creator><![CDATA[Geoff Innis]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/geoffreyinnis/?p=895</guid>
      <description><![CDATA[This post is the second in a series in which we explore how we can take advantage of the benefits of...]]></description>
      <content:encoded><![CDATA[This post is the second in a series in which we explore how we can take advantage of the benefits of scale and channel breadth with bots, making sure the experiences we create with them build upon the investments that we have made in our customer service strategy, and feed into the consolidated customer 360 view using <strong>Microsoft Service</strong> and <strong>Dynamics CRM</strong> as our underlying customer engagement platform.

We will build upon the bot we built in <a href="https://blogs.msdn.microsoft.com/geoffreyinnis/2016/06/08/bringing-bots-into-an-omni-channel-customer-service-strategy-part-1/" target="_blank">Part 1</a>, which allows users to access self-service knowledge, tapping into the authoritative knowledge that has been curated and published using the robust knowledge management capabilities in the <a href="https://www.microsoft.com/en-US/dynamics/crm-customer-center/user-s-guide-for-the-new-interactive-service-hub.aspx" target="_blank">Dynamics CRM Interactive Service Hub</a>.

<strong>We will <a href="https://docs.botframework.com/en-us/support/upgrade-to-v3/" target="_blank">upgrade our bot</a> from v1 of the Bot Framework to v3. We will also enable our bot to collect the necessary information to create a case in Dynamics CRM, for subsequent follow-up.</strong>

We will use the concept of a <a href="https://docs.botframework.com/en-us/csharp/builder/sdkreference/forms.html" target="_blank">FormFlow </a>dialog within our bot to guide the user through a conversational experience to collect the information we require to submit our case to Dynamics CRM via the <a href="https://msdn.microsoft.com/en-us/library/mt593051.aspx" target="_blank">Web API</a>. We will draw on the following resources:

<ul>
	<li>Documentation on <a href="https://docs.botframework.com/en-us/support/upgrade-to-v3/" target="_blank">upgrading bots from v1 to v3</a> of the Microsoft Bot Framework</li>
	<li>The <a href="https://github.com/Microsoft/BotBuilder/tree/master/CSharp/Samples/AnnotatedSandwichBot" target="_blank">AnnotatedSandwichBot </a>sample bot application on GitHub</li>
</ul>

&nbsp;

<em><strong>Note:</strong> It is recommended that you review the concepts in Part 1 of the series for an introduction and background.</em>

&nbsp;

<strong>Pre-requisites</strong>

The pre-requisites for building our service bot include:
<ul>
	<li>An instance of Dynamics CRM Online; you can request a trial of Dynamics CRM Online <a href="https://www.microsoft.com/en-us/dynamics/crm-free-trial-overview.aspx" target="_blank">here</a></li>
	<li>Administrator credentials to access the O365 Admin Portal for our tenant that our CRM instance is connected to</li>
	<li>A Microsoft Azure subscription for application registration; A trial account will also work; See <a href="https://blogs.msdn.microsoft.com/geoffreyinnis/2016/06/08/bringing-bots-into-an-omni-channel-customer-service-strategy-part-1/" target="_blank">Part 1</a> for a walkthrough of how to obtain CRM Web API credentials</li>
	<li>Dynamics CRM credentials for a user with privileges to allow us to read Knowledge Articles and create Cases in CRM</li>
	<li><a href="https://www.visualstudio.com/en-us/products/vs-2015-product-editions.aspx" target="_blank">Visual Studio 2015</a>
<ul>
	<li>Update all Visual Studio extensions using <strong>Tools-&gt;Extensions and Updates-&gt;Updates</strong></li>
</ul>
</li>
	<li>A Microsoft Account</li>
	<li>The Bot Builder SDK
<ul>
	<li>You can download the SDK on GitHub <a href="https://github.com/Microsoft/botbuilder" target="_blank">here</a></li>
</ul>
</li>
	<li>The <strong>v3</strong> Bot Framework Channel Emulator (for Windows)
<ul>
	<li>You can download the new Bot Framework Channel Emulator from <a href="https://aka.ms/bf-bc-emulator" target="_blank">here</a></li>
</ul>
</li>
	<li>The <strong>v3 </strong>Bot Connector Visual Studio Project Template
<ul>
	<li>You can download the template from <a href="https://aka.ms/bf-bc-vstemplate" target="_blank">here</a></li>
	<li>Save the downloaded zip file to your Visual Studio 2015 templates directory, which is typically found in <strong>%USERPROFILE%\Documents\Visual Studio 2015\Templates\ProjectTemplates\Visual C#</strong></li>
</ul>
</li>
</ul>

&nbsp;

<strong>Updating our Bot to the Bot Framework v3</strong>

In this walkthrough, we will create a new project using the updated <strong>v3 Bot Connector Visual Studio Project Template</strong>, then bring in and adapt our v1 bot code.

We Open Visual Studio, and create a new project using the new <strong>Bot Application</strong> template that we downloaded as a part of our pre-requisites. 

As before, we need install several packages that we will leverage as a part of our bot code. We can do this via NuGet. The packages include:

<ul>
	<li>The <a href="https://www.nuget.org/packages/Microsoft.Bot.Builder/" target="_blank">Microsoft.Bot.Builder</a> package</li>
	<li><ul><li>Note that we no longer need to install the Microsoft.Bot.Connector package, as it has been consolidated into the Microsoft.Bot.Builder package</li></ul></li>
	<li>The latest version of the <a href="https://www.nuget.org/packages/Microsoft.WindowsAzure.ConfigurationManager/" target="_blank">Microsoft.WindowsAzure.ConfigurationManager</a> package</li>
	<li>Version 2.26 of the <a href="https://www.nuget.org/packages/Microsoft.IdentityModel.Clients.ActiveDirectory/2.26.305102204" target="_blank">Microsoft.IdentityModel.Clients.ActiveDirectory</a> package, to assist with CRM Web API authentication</li>
	<li>The <a href="https://www.nuget.org/packages/Microsoft.Bot.Builder.FormFlow.Json/" target="_blank">Microsoft.Bot.Builder.FormFlow.Json</a> package, to assist us with our FormFlow dialog</li>
</ul>

&nbsp;

We will place the CRM Web API Credentials (obtained in Part 1 of the series) into our <strong>Web.config</strong> settings. We open the file, and add our credentials as <strong>appSettings </strong>as shown below, to make them accessible throughout our project:

[snippet slug=botscasecreate_ lang=xml]

&nbsp;

Next, we will adapt our <strong>MessagesController.cs</strong> class to be able to initiate our main dialog with the user, just as in Part 1. With the v3 bot framework, however, the <strong>Message </strong>object has been replaced with the <strong>Activity </strong>object. We replace the default Echo Bot code with code that will initiate a new <a href="https://docs.botframework.com/en-us/csharp/builder/sdkreference/dialogs.html" target="_blank">Dialog </a>using the <strong>ServiceDialog </strong>class from Part 1:

[snippet slug=botscasecreate_messagecontroller lang=c-sharp]

&nbsp;

This time around, we will separate our <strong>ServiceDialog </strong>into a separate class file. To our project, we Add a new C# class called <strong>ServiceDialog.cs</strong>.

Into our class, we insert the code from Part 1, but we make some minor changes:

<ul>
	<li>Any instances of <strong>Message </strong>objects are updated to <strong>Activity </strong>objects</li>
	<li>We make use of the <strong>PostAsync </strong>method to send messages that are not prompting the user for information</li>
	<li>We add two additional parameters to our call to the <strong>CRMWebAPIRequest </strong>method, to allow us to specify our HTTP Method, and pass a payload, to cater for our future requirements to create cases in our bot code</li>
	<li>We set a value in our <strong>ConversationData </strong>with the <strong>Guid </strong>of one of our CRM Contacts</li>
	<li><ul><li>As an extension of this example, we could add code to authenticate our user, and obtain their contact Guid, or alternately, create a new contact record based on data collected from the user</li></ul></li>
</ul>

&nbsp;

At this point, our updated ServiceDialog.cs class should appear as shown below:

[snippet slug=botscasecreate_startservicedialog lang=c-sharp]

&nbsp;

We will also create a separate class to hold utility methods that may be accessed throughout our solution, such as the <strong>CRMWebAPIRequest </strong>method, used to issue our Web API requests to CRM. This method is taken from our Part 1 project, but adapted slightly, with these changes:

<ul>
	<li>The method accepts not only a request string, but also an <strong>HttpContent </strong>request payload, and request type indicator, to allow for not only querying, but creation of records in CRM</li>
	<li>CRM Web API credentials are retrieved from the <strong>Web.config</strong> app </li>
	<li>Depending on whether the request type, there is conditional logic to issue either a <strong>GET </strong>request when we are retrieving CRM data, or a <strong>POST </strong>request with content, if we are creating a CRM record</li>
</ul>

&nbsp;

[snippet slug=botscasecreate_utilities lang=c-sharp]

&nbsp;

With these changes, our bot will now function as before, enabling access to self-service knowledge using the v3 Bot Framework:

<img src="https://msdnshared.blob.core.windows.net/media/2016/07/KBSearchV3-1024x839.png" alt="KBSearchV3" style="border-style: solid;border-width: 1px" width="1024" height="839" class="aligncenter size-large wp-image-1005" />

&nbsp;

<strong>Augmenting our Bot with Case Creation Capabilities</strong>

We will now enhance the functionality of our bot by enabling end-users to log issues via a conversational bot experience, resulting in cases in Dynamics CRM. As noted earlier, we will leverage a different type of dialog called <strong>FormFlow</strong>. FormFlow dialogs offer the ability to gather the information required to achieve a particular objective in a simplified way, based on a definition you (the developer) create in either a C# class or JSON object. The Bot Framework documentation provides a thorough discussion of the <a href="https://docs.botframework.com/en-us/csharp/builder/sdkreference/forms.html" target="_blank">use of FormFlow</a>, and serves as a great reference for in-depth information. The gathering of information required to submit a case is a process well-suited to the FormFlow model.

We will use the <a href="https://docs.botframework.com/en-us/csharp/builder/sdkreference/forms.html#jsonForms" target="_blank">JSON Schema FormFlow</a> in this walkthrough. One benefit of using this option is that, although in our basic example, we will be hard-coding certain attributes we will collect for our CRM Case within our JSON file, we could potentially adapt the entire set of data we need to capture at run-time, based on our CRM schema, through the dynamic creation of our JSON schema, allowing for extensibility.

First, we will add a new file to our project, by right-clicking on the project in the <strong>Visual Studio Solution Explorer</strong>, then selecting <strong>Add… &gt; New Item</strong>. We then select a <strong>JSON Schema File</strong> template, under the <strong>Visual C# &gt; Web</strong> options:

<img src="https://msdnshared.blob.core.windows.net/media/2016/07/NewJSONSchema.png" alt="NewJSONSchema" style="border-style: solid;border-width: 1px" width="940" height="653" class="aligncenter size-full wp-image-1015" />

&nbsp;

We also select our file in the Solution Explorer, and change the <strong>Build Action</strong> property to be <strong>Embedded Resource</strong>, to allow our file to be used to create our FormFlow dialog once built:

<img src="https://msdnshared.blob.core.windows.net/media/2016/07/JSONProperties.png" alt="JSONProperties" style="border-style: solid;border-width: 1px" width="346" height="311" class="aligncenter size-full wp-image-995" />

&nbsp;

In our JSON Schema File, we define the pieces of data that we need to collect. For each attribute we wish to collect, we are able to specify a prompt, a data type, options, validation, and other aspects. We define the information we wish to collect as described below:

<ul>
	<li>a <strong>Title </strong>for the case: a string will be typed by the user</li>
	<li>a <strong>Product </strong>that the case relates to: the user will be prompted to select from three options</li>
	<li><ul><li>Note that the option <strong>values </strong>correspond to the <strong>Guid </strong>values of three of our products in our instance of CRM; we are able to present the appropriate Display Names for the products using the <a href="https://docs.botframework.com/en-us/csharp/builder/sdkreference/dd/d38/class_microsoft_1_1_bot_1_1_builder_1_1_form_flow_1_1_describe_attribute.html" target="_blank">DescribeAttribute </a>in our schema</li>
	<li>As an extension of this example, in a real-world scenario, these options could potentially be populated based on products the customer is known to own</li></ul></li>
        <li>a <strong>Priority </strong>for the case: the user will be prompted to select from four options</li>
	<li><ul><li>Note that the option <strong>values </strong>correspond to the <strong>values </strong>of the<strong> Option Set</strong> used for the <strong>prioritycode </strong>field in our CRM instance; we again provide appropriate Display Names for the options</li></ul></li>
	<li>a <strong>Description </strong>of the issue being experienced: a string will be typed by the user</li>
</ul>

[snippet slug=botcasecreate_json lang=js]

&nbsp;

We now need to instantiate our <strong>Case Creation FormFlow</strong> dialog as a child dialog of our <strong>ServiceDialog </strong>at the appropriate juncture. To do this, we create a new method in our <strong>ServiceDialog.cs</strong> class, called <strong>BuildJsonForm</strong>, which will read the JSON schema we defined, and create and return a new JSON form builder:

[snippet slug=botcasecreate_buildjsonform lang=c-sharp]

&nbsp;

Next, we will add a new <strong>CompletedCaseSubmission </strong>method to our <strong>ServiceDialog.cs</strong> class, which will process the <strong>JObject </strong>that is generated by the FormFlow dialog that gathers the case attributes. This method will receive the context and the case creation JObject as parameters, and will:

<ul>
	<li>Retrieve the contacted <strong>Guid </strong>from conversation data; note that for our example, we are hardcoding a <strong>contactid </strong>in our <strong>Web.config appSettings</strong>, but in a real-world scenario, we would likely authenticate our user, or collect their contact information as a part of the dialog</li>
	<li>Generate some JSON content for our request to the CRM Web API, to allow us to create an incident record in CRM, populating data we collected during our FormFlow dialog</li>
	<li><ul><li><em>Important note:</em> we include a custom <strong>caseorigincode </strong>in our example; If you wish to use the sample code with your instance of CRM, you will need to add a new <strong>caseorigincode Option Set Value</strong> of 100000001</li></ul></li>
	<li>Build a request <strong>Uri </strong>for our request to the CRM Web API<em> (see <a href="https://github.com/jlattimer/CrmWebApiCSharp/blob/master/CrmWebApiCSharp/Program.cs" target="_blank">CrmWebApiCSharp </a>on GitHub for resources on interacting with the CRM Web API via C#)</em></li>
	<li>Issue the request via our <strong>CRMWebAPIRequest </strong>method</li>
	<li>Retrieve the resulting <strong>Guid </strong>for our new incident in CRM from the response</li>
	<li>Use that new incident <strong>Guid </strong>to retrieve our newly-created customer-facing <strong>ticketnumber </strong>value via another “retrieve” request to the CRM Web API</li>
	<li>Present the <strong>ticketnumber </strong>value back to our customer via a message back to the user</li>
	<li>Finish the dialog using the <strong>IDialogStack.Done</strong> method</li>
</ul>

[snippet slug=botcasecreate_completedcasesubmission lang=c-sharp]

&nbsp;

We now adapt our <strong>AfterServiceChoiceAsync </strong>method, to create a child dialog to capture case details and create the case when the user selects <strong>Submit an Issue</strong> from the initial options presented. This is the new augmented method:

[snippet slug=botcasecreate_afterservicechoiceasyncadapted lang=c-sharp]

&nbsp;

We are now ready to build and test our bot. As before, we press <strong>F5 </strong>in Visual Studio, which will Start Debugging. Once debugging has started, an Internet Explorer window should pop up, containing your bot endpoint information. 

We also launch our <strong>v3 Bot Framework Channel Emulator</strong> which we downloaded earlier. We take the URL from the IE pop-up address bar, append <strong>/api/messages</strong>, and enter this in the URL field of the emulator. We can use the default <strong>MicrosoftAppId </strong>(blank by default) and <strong>MicrosoftAppPassword </strong>(also blank by default) from the application template <strong>Web.config</strong> file, and add them in the appropriate inputs in the emulator as well. Note that these parameter names changed from v1 to v3.

We can now have a conversation with our bot, via the emulator, and test out the submission of our case to CRM via the bot:

<img src="https://msdnshared.blob.core.windows.net/media/2016/07/CaseCreateemulatorAdapted-1024x838.png" alt="CaseCreateemulatorAdapted" style="border-style: solid;border-width: 1px" width="1024" height="838" class="aligncenter size-large wp-image-975" />

&nbsp;

The case has now been created and appears in CRM, and we can see that it originated from the bot:

<img src="https://msdnshared.blob.core.windows.net/media/2016/07/CaseInCRM.png" alt="CaseInCRM" style="border-style: solid;border-width: 1px" width="663" height="232" class="aligncenter size-full wp-image-985" />

&nbsp;

Note that if you wish to use a custom icon for cases originating from the bot, as shown above, see <a href="https://technet.microsoft.com/en-us/library/dn660975.aspx" target="_blank">here </a>for instructions.

&nbsp;

Our bot is again ready to be published to Microsoft Azure, registered with the Bot Framework, and made available across channels. If you wish to walk through the publishing of your bot and configuring of channels, you can find details <a href="https://docs.botframework.com/connector/getstarted/" target="_blank">here</a>.

Here is a brief video showing our bot’s behavior when published and deployed to the <strong>Skype </strong>channel:

[video width="384" height="720" mp4="https://msdnshared.blob.core.windows.net/media/2016/07/ServiceBotV3_CaseSubmit.mp4"][/video]

&nbsp;

You can download the full source code for the solution <a href="https://1drv.ms/u/s!AOi7CDzJQqg_hHU" target="_blank">here</a>. Prior to building the sample, ensure you:

<ul>
	<li>Populate your <strong>CRM Web API Credentials</strong> in the <strong>Web.config</strong> file</li>
	<li>Populate a contactid <strong>Guid </strong>from your CRM instance in the <strong>MessageReceivedAsync </strong>method in <strong>ServiceDialog.cs</strong></li>
	<li>Populate three product <strong>Guids </strong>and product names in <strong>CreateCase.json</strong> </li>
	<li>Add a new <strong>caseorigincode Option Set</strong> value of 100000001 via the <strong>Dynamics CRM Settings &gt; Customization &gt; Customize the System</strong> administration</li>
</ul>





]]></content:encoded>
    </item>
  </channel>
</rss>