Microsoft Bot Framework, Set User State From Javascript

Viewed 213

I am attempting to proof of concept a simple support & ticketing bot using Microsoft Bot Framework v4 and Azure. I have successfully created a bot via the Bot Framework Composer and deployed it to Azure using a Web App Bot. I have configured and installed the BotFramework-WebChat component on my test site and successfully connected the bot to it. The BotFramework-WebChat component is installed via cdn.botframework.com. The test site is a single page application and the bot sits alongside this such that it can be accessed at the users convivence.

Everything is working as expected. I would like however to post certain contextual information to the Bot depending on the current browser state. For example, if a user is looking at product ABC when they converse with the bot I'd like the bot to know this. To achieve it I'd like to update the user state on the bot channel, preferably via vanilla JavaScript when the main application state changes. I'd like to do this seamlessly in the background and I do not want to rely on additional frameworks such as React (the Microsoft Documentation references React heavily and I unfortunately have no understanding of the particular product so find it difficult/impossible to follow).

My question is therefore in two parts. Is the above possible using the API provided by the BotFramwork-WebChat component and if so how would one go about doing so? If it is not possible I would also appreciate any assistance on alternative methods should such alternatives exist.

2 Answers

Answer to my own question, this is indeed possible with a minor modification to the example code used to create/render the webchat component.

First I've parameterised the DirectLine client creation. This client is key to posting to the channel once the WebChat component is set up:

var dl = window.WebChat.createDirectLine({ token: '#yourtokenhere#' });

window.WebChat.renderWebChat(
  {
    directLine: dl,
    userID: '#yourid#',
    username: '#yourusername#',
    locale: 'en-US'
  },
    document.getElementById('#yourtargetelement')
);

Using the client I have then posted an event to the channel using the postActivity method:

dl.postActivity({
  from: { id: '#youruserid#', name: '#yourusername#' },
  type: 'event',
  name: '#youreventname#',
  value: {
    // Put your parameters here
  }
})

On the Composer side I have set up a trigger to activate on a "Custom Event" with the name #youreventname#. I can then parse out the parameters from the value property and set my user state.

I personally found the documentation for the Microsoft Direct Line JS protocol much easier to work with than going directly through the WebChat docs.

Thank you to @billoverton for the inspiration to use a custom event.

If you just want to capture information at the time the user renders the webchat session, you can do this by sending a custom event, which you'll also need to handle in your bot code. This specific code will not work if you are trying to create a single instance of the bot that persists across multiple pages, and you are wanting the page details sent every time, but the same concept should apply. This method sends the details only on the initial connection to the bot.

First you need to send an event from your bot rendering via custom store. Here is how I did it.

    var store = window.WebChat.createStore({}, function(dispatch) { return function(next) { return function(action) {
        if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
            dispatch.dispatch({
                type: 'WEB_CHAT/SEND_EVENT',
                payload: {
                    name: 'webchat/join',
                    value: {
                        browserLanguage: navigator.languages[0],
                        page: window.location.href,
                        language: getCookie("LANGUAGE"),
                        country: getCookie("COUNTRYNAME")
                    }
                }
            });
        }

        return next(action);
        
    }}});

Now your bot also needs to be set up to handle that event. Again, I stored the relevant details in "value" but you can design your object differently if you want. I store this in user state under userData.siteContext and then can use the information throughout the bot application. If you want a unique welcome message based on this information, you'll need to add that inside the if statement as well and add a condition that your welcome message in the onMembersAdded handler fires only for non-direct line channels.

if (context.activity.name && context.activity.name === 'webchat/join') {
    const userData = await this.userDialogStateAccessor.get(context, {});
    userData.siteContext = context.activity.value;

    // siteContext specific welcome message if desired

    await this.userState.saveChanges(context);
    await this.conversationState.saveChanges(context);
}

If you need this information at other times than the original connection, you should be able to create another event from your page and set up an appropriate handler in the bot.

Related