In an earlier blog post, I ran through how you can mix and match regular dialogs (Waterfalls) with Composer Generated (Adaptive) Dialogs and how this lets you adopt a hybrid approach to developing your chatbots.
I also talked about some of the benefits of this and how you can effectively daisy-chain these dialogue types to form part of the conversational experience you need to build.
The demo in that blog post showed you how the Composer / Adaptive Dialog could read the text from the final activity of the “regular” dialog.
In this blog post, I follow on from that theme.
More specifically, I’ll show you how to share State data between Waterfall dialogs and Composer generated Adaptive Dialogs.
This is a subtle difference from that earlier blog post but MUCH more powerful as it gives your chatbot the capability to access data (at varying scopes) throughout ANY point in the conversation across different types of dialogues.
Why do this? The Business Problem this helped me solve
I recently came out of the other end of months of chatbot development that involved LUIS, Bot Framework Composer, Virtual Assistant, and Skills – all housed within Webchat.
One problem I had was that I needed to find a way of passing data from the Dialogs creating using Composer (which the Bot Framework hydrates as Adaptive Dialogs at run-time) to the traditional Waterfall Dialogs written in C#.
One of my Composer/Adaptive Dialogs invoked a Web API endpoint to extract data from an Azure SQL instance. This data was used to direct the flow of the conversation, the data was also needed by one of the “regular” Waterfall Dialogs to raise an event (in C#) to the Webchat component and perform some client-side wizardry.
This is where being able to share State between Composer / Adaptive and regular Waterfall Dialogs came into play.
Bridge the data gap between Adaptive Dialogs and Traditional Dialogs
By implementing this, I was able to grab the data in the “Composer” section of the conversation, then reference it again later in a Waterfall Dialog using C#. Pretty slick!
An Example Scenario
To show this in action we’ll use a chatbot that builds on my last chatbot blog post. We’ll introduce updates that let the chatbot obtain and process the user’s location.
First, an overview of the main dialogs that form the functionality. The chatbot features the following main dialogues you can see in the diagram below:
This is the entry dialog for the chatbot. It adds all dialogs to stack numbered 1 -4 in the above diagram to a Waterfall Dialog. It consists of the following:
- 2 x Regular Dialogs (UserProfile.cs and LocationDialog.cs)
- 2 x Adaptive Dialogs created using Composer (Main.dialog and ProcessLocation.dialog)
The dialogs are added in the order 1-4 and invoked sequentially.
This dialog is the first to run. It asks the user for their name then greets them.
After greeting them, the chatbot moves onto the next dialog – Main.dialog.
This is a dialog written using Composer. It’s an Adaptive Dialog. You can see the logic for this dialog here:
With the above logic in mind, inputting “jamie” for the name results in the chatbot sending the following messages to the user:
This is the third dialog to run. It’s another Adaptive Dialog that was created in Composer. This dialog prompts the user to enter their postcode. When the user enters their postcode, it gets added to a State Property user.postcode. The user is then thanked for their input. You can see this here:
And an example of the associated interaction:
This is a regular Waterfall Dialog that takes the value user.postcode (from the previous dialog) and uses it to make a call to at 3rd party web service. The web service uses the location to then return some location-specific data related to the postcode. You can see this in action here:
That was a break down of the main dialogs, the inputs they process and the outputs they return. It’s this regular dialog that needs to grab data from the previous Composer / Adaptive Dialog.
Let’s look at the “glue” you need to code to make this happen.
How To share State between Composer Adaptive Dialogs and Waterfalls Dialogs
The main piece of data we’re processing is the user postcode. As we mentioned earlier, this information is captured during the execution of ProcessLocation.dialog which is an Adaptive Dialog. This user input is added to the State variable user.postcode.
The postcode is then used in LocationDialog.cs which sends it onto a web service for further processing which is then returned to the chatbot.
let ProcessLocation.dialog share its data with LocationDialog.cs
Before we do any of that, however, we need to let ProcessLocation.dialog share its data with LocationDialog.cs.
Show me the Glue!
To do this, we have a method in LocationDialog called DisplayLocationFromComposer. You can see an extract of this in the screenshot below:
Let’ pick apart to main code segments.
We invoke stepContext.GetState() to return a reference to the State object. We then use this reference to grab the user state (remember user.postcode is in here?). This is the key part that lets us reference State that was set in a Composer Adaptive Dialog!
We echo some information back to the user then send the postcode onto the web service api.postcodes.io.
After the web service has been consumed, we read the content and send this to the user. The dialog then moves onto the next step (of which there are none) and is complete!
So, there you have it, how to share data between Dialogs created using Bot Framework Composer (Adaptive) and regular Bot Framework Dialogs (Waterfall)!
What we’ve just run through is a powerful concept for lots of different reasons. The main being that it lets you bridge the data gap between the different types of dialog types.
For example, you may have less technical users creating dialogs with Composer, but they are comfortable with using basic variables and loops. This is great but you will no doubt (at some point) need to reference this data in your more complex dialogs that developers are creating in a programming language such as C#
Using this approach lets you do that. During the design phase, each Team can agree upon and work with a common set of variables. Or, if variable manipulation is localized to each dialog, rather than use user scope, you can opt for dialog scope.
You can find out more information about the different types of variable scoping here.
We’ve seen how data can be easily passed between these different types. We’ve also seen how to pass conversational data to 3rd party web services and surface the response in the conversation.
Being able to share state across the Bot Framework stack like this lets you build extendable chatbots, accelerate your development process and make it easy to share data.
- Are you building chatbots?
- Do you have a question or topic you’d like covered?
- Drop a message below or contact me on social!
The full source code for this blog post can be found on the GitHub repo here.