The backchannel mechanism allows a client app and the bot to exchange information that is invisible to the user. Examples of this could be from requesting the client's time zone to reading a GPS location or what the user is doing on a web page. The bot can even guide the user by automatically filling out parts of a web form and so on. The backchannel closes the gap between JavaScript client apps and bots. This mechanism is implemented by using the Direct Line API, which allows activities to be sent back and forth between the client and the bot.
In this exercise, you will add a Web Page to your app. The bot and web page will use the backchannel mechanism to communicate. The bot will send the user's ticket to the web page, which will display related KB articles for that ticket. The goal would be that a human supervisor agent can monitor the conversation and by using the web page decide if there is an article that can help the user and avoid the creation of a ticket. If he finds an article, the supervisor agent can click it to display it in the user conversation with the bot.
The backchannel bot pattern is further explained in this article.
Inside this folder you will find a solution with the code that results from completing the steps in this exercise. You can use this solution as guidance if you need additional help as you work through this exercise. Remember that for using it, you first need to complete the values of the LUIS Model and Azure Search Index name and key in web.config
. Also, you need to replace the {DIRECTLINE_SECRET}
and {BOT_ID}
placeholders in default.htm.
This diagram outlines the components of this exercise:
The following software is required for completing this exercise:
- Visual Studio 2017 Community or higher
- An Azure subscription
- The Bot Framework Emulator (make sure it's configured with the
en-US
Locale) - ngrok for local development
-
Sign in to the Bot Framework Portal.
-
Click the My bots button and click on your bot for editing it.
NOTE: This exercise assumes that you have already registered your bot in the Bot Framework Portal. If you didn't you can find instructions in Exercise 5.
-
Click on the Edit () link for the Web Chat channel. In the opened window, click Add new site. Type a site name (for example, Help Desk Ticket Search).
-
Click Done and you should see the following page. Notice that you have two Secret Keys. Save one of them for later. Click Done.
In this task you will add a HTML page to your app which contains the web chat control and the code to send/receive event
messages to your bot. Next, you will add the BackChannel capability to send event
activities from your bot to the Web Page.
-
Open the app you've obtained from the previous exercise. Alternatively, you can use the solution from the exercise7-HandOffToHuman folder.
NOTE: If you use the solution provided remember to replace:
- the BotId, MicrosoftAppId and MicrosoftAppPassword in
Web.config
with your Bot Id, App ID and Password (as explained in exercise 5) - the [LuisModel("{LUISAppID}", "{LUISKey}")] attribute placeholders in
RootDialog.cs
with your LUIS App Id and Programmatic API Key (as explained in exercise 3) - the TextAnalyticsApiKey in
Web.config
with your Text Analytics Key (as explained in exercise 6) - the AzureSearchAccount and AzureSearchKey in
Web.config
with your search account name and key (as explained in exercise 4)
- the BotId, MicrosoftAppId and MicrosoftAppPassword in
-
Replace the
default.htm
with this template. -
Below the
botchat.js
script element add a new script element with the following code which creates a DirectLine object with the Web Channel Secret. Replace the{DIRECTLINE_SECRET}
placeholder with your Secret Key previously obtained and the{BOT_ID}
placeholder with the bot handle ID (eg. help-desk-bot).<script> var botConnection = new BotChat.DirectLine({ secret: '{DIRECTLINE_SECRET}' }); var resPanel = document.getElementById('results'); BotChat.App({ botConnection: botConnection, user: { id: 'WebChatUser' }, bot: { id: '{BOT_ID}' }, locale: 'en-us', }, document.getElementById('bot')); </script>
NOTE: The open source Web Chat Control communicates with bots by using the Direct Line API, which allows
activities
to be sent back and forth between client and bot. The most common type of activity ismessage
, but there are other types as well. For example, the activity typetyping
indicates that a user is typing or that the bot is working to compile a response. -
In the same script element, add a bot activity listener for incoming
event
activities and show the article list.NOTE: The web chat control will automatically ignore any activities of
type="event"
, which allows the page to communicate directly with the bot, and the bot to communicate with the page.botConnection.activity$ .filter(function (activity) { return activity.type === 'event' && activity.name === 'searchResults'; }) .subscribe(function (activity) { updateSearchResults(activity.value) }); function updateSearchResults(results) { resPanel.innerHTML = ''; // clear results.forEach(function (result) { resPanel.appendChild(createSearchResult(result)); }); } function createSearchResult(result) { var el = document.createElement('div'); el.innerHTML = '<h3>' + result.Title + '</h3>' + '<p>' + result.Text.substring(0, 140) + '...</p>'; return el; }
NOTE: For simplicity purposes the Web Chat control with the user conversation and the search results are displayed on the same page. However, ideally these should be two separate things. The supervisor web site should display the list of the conversations in progress so an agent can monitor one and send the article recommendations.
In this task, you will add the ability to send and receive event
messages to your bot.
-
Open
Dialogs\RootDialog.cs
. Add theSendSearchToBackchannel
method to create and send thesearchResults
events.private async Task SendSearchToBackchannel(IDialogContext context, IMessageActivity activity, string textSearch) { var searchService = new AzureSearchService(); var searchResult = await searchService.Search(textSearch); if (searchResult != null && searchResult.Value.Length != 0) { var reply = ((Activity)activity).CreateReply(); reply.Type = ActivityTypes.Event; reply.Name = "searchResults"; reply.Value = searchResult.Value; await context.PostAsync(reply); } }
-
Add the following using statement.
using HelpDeskBot.Services;
-
Update the
SubmitTicket
method to call the newSendSearchToBackchannel
method when the bot receive the ticket's description. You will need to introduce themessageActivity
parameter.[LuisIntent("SubmitTicket")] public async Task SubmitTicket(IDialogContext context, IAwaitable<IMessageActivity> messageActivity, LuisResult result) { ... await this.EnsureTicket(context); var activity = await messageActivity; await this.SendSearchToBackchannel(context, activity, this.description); }
-
Run the app clicking in the Run button.
-
Open a new console window where you've downloaded ngrok and type
ngrok http 3979 -host-header="localhost"
. Notice that3979
is the port number where your bot is running. Change it if you are using another port number. Next, save for later the Forwarding https URL.NOTE: Because IIS Express uses the
Host
header for determining which development site to display, you need to use the-host-header
modifier. More info here. -
Sign in to the Bot Framework Portal.
-
Click the My bots button and next click on your bot for editing it. Click on the Settings tab and update the Messaging endpoint URL with the Forwarding https URL you have obtained from ngrok (remember to keep the
/api/messages
). Click in the Save changes button. -
In a Web Browser, navigate to your bot URL (http://localhost:3979/ as usual). On the Web Chat Control, type
I need to reset my password, this is urgent
. You should see that the article list in the right is populated based on the description you entered.
-
Open the
default.htm
file. In the<style>
section at the top of the file, replace the#results h3
selector with the following CSS.#results h3 { margin-top: 0; margin-bottom: 0; cursor: pointer; }
-
Update the
createSearchResult
function with the following code that posts anevent
activity to the bot when user clicks on the article title.function createSearchResult(result) { var el = document.createElement('div'); el.innerHTML = '<h3>' + result.Title + '</h3>' + '<p>' + result.Text.substring(0, 140) + '...</p>'; el.getElementsByTagName('h3')[0] .addEventListener('click', function () { botConnection .postActivity({ type: 'event', value: this.textContent.trim(), from: { id: 'user' }, name: 'showDetailsOf' }) .subscribe(function (id) { console.log('event sent', id); }); }); return el; }
-
Open
Controllers\MessagesController.cs
and add following using statements.using System; using HelpDeskBot.Services;
-
Update the
Post
method with the code below to handle theevent
messages, called when user clicks in an article's title.public async Task<HttpResponseMessage> Post([FromBody]Activity activity) { if (activity.Type == ActivityTypes.Message) { await Conversation.SendAsync(activity, () => new RootDialog()); } else if (activity.Type == ActivityTypes.Event) { await this.HandleEventMessage(activity); } else { this.HandleSystemMessage(activity); } var response = Request.CreateResponse(HttpStatusCode.OK); return response; }
-
Add the following code to handle the
showDetailsOf
event. This method will search for article's title in the Knowledge Base and send the result to the user in the Web Chat Control.private async Task HandleEventMessage(Activity message) { if (string.Equals(message.Name, "showDetailsOf", StringComparison.InvariantCultureIgnoreCase)) { AzureSearchService searchService = new AzureSearchService(); var searchResult = await searchService.SearchByTitle(message.Value.ToString()); string reply = "Sorry, I could not find that article."; if (searchResult != null && searchResult.Value.Length != 0) { reply = "Maybe you can check this article first: \n\n" + searchResult.Value[0].Text; } // return our reply to the user Activity replyActivity = message.CreateReply(reply); ConnectorClient connector = new ConnectorClient(new Uri(message.ServiceUrl)); await connector.Conversations.ReplyToActivityAsync(replyActivity); } }
-
Run the app clicking in the Run button. Make sure that
ngrok
is still running (ngrok http 3979 -host-header="localhost"
). -
In a Web Browser, navigate to your bot URL (http://localhost:3979/ as usual). On the Web Chat Control, type
My computer is not working
. -
Click on the title of any article and you should see the article content displayed in the Web Chat Control.
- Integrate bot to human handoff with backchannel to allow an agent to see all current users talking with the bot, and then allow the agent to connect to a specific user.