In the previous chapter, you learned how to deal with data and how to allow the user to pass in specific pieces of data. However, this can get quite tricky, when we expect a limited number of answers. For example, if the car rental service only operates in four countries, we shouldn't let the user guess which countries are available. Instead, we should use conversational UI to guide the user through the process.
With Conversational UI we not only provide a list of available values, but we can also provide additional information that goes with each item. When listing the available cars, we can also provide the price at the same time.
In this chapter, you will enhance the existing questions steps for Country, City and Car with Conversational UI to improve the booking process.
The simplest of Conversational UI elements is the Quick Reply component.
It displays available answers as a set of buttons. It allows the user to click on one of the buttons, or type the answer.
Add Quick Reply to the Country step, like this:
display
=> start typing di and select display
type
=> start typing ty and select `typequick-reply
=> start typing qui and select quick-reply
You should get something like this:
"display": {
"type": "quick-reply"
}
Note: always use code snippets, they will save you a lot of keystrokes
The whole step should look like this:
{
"type": "question",
"entity": "country",
"entity-type": "Country",
"messages": [
"Which country are you traveling to?"
],
"display": {
"type": "quick-reply"
}
},
The Chatbot will use all the entries allocated to "entity-type": "Country"
, and display each item as a button.
Note: Quick Reply is great when we are dealing with a small list of items. For anything larger than 10 items it is best to display as a list picker (see Single Select below).
Save the cognitive flow, and ask the bot to "rent a car".
Now the Country step should look like this:
The next Conversational UI component is Single Select.
Single Select displays a list of available items in a modal window.
Add Single Select to the City step, like this:
display
=> start typing di and select display
type
=> start typing ty and select `typesingle-select
=> start typing sin and select single-select
title
=> start typing ti and select title
then add Find a city
textbutton-text
=> start typing bu and select button-text
then add Select this city
textYou should get something like this:
"display": {
"type": "single-select",
"title": "Find a city",
"button-text": "Select this city"
},
title
- is used for the text of the button that opens the listbutton-text
- is used for the text of the button that confirms the items selectionThe whole City step should look like this:
{
"type": "question",
"entity": "city",
"entity-type": "City",
"messages": [
"In which city are you looking for a car?"
],
"display": {
"type": "single-select",
"title": "Find a city",
"button-text": "Select this city"
}
},
Save the cognitive flow, and ask the bot to "rent a car in France".
Now the City step should look like this:
Displaying items as in a list is very simple, however, the current workflow has a small flaw. The current list allows the user to select a city from any country, which doesn't make sense if they chose France as the country.
The solution to this is quite simple. Instead of getting the data directly from the Entity, you can make a query and display only the returned items.
To make the Single Select return specific items, you need to add two pieces of configuration to the "display"
object:
data-source
- consists of a REST command to query the datatemplate
- instructs the chatbot on how to display the itemsStep 1 - add data-source
In the configuration of the City Entity you used this endpoint - https://api.demo.nativechat.com/v1/car-rental/offices
- to get all office locations. In order to filter the list by country, you can provide a query object requesting a specific country, like this:
https://api.demo.nativechat.com/v1/car-rental/offices?country=France
To make it more dynamic, you can use the Mustache syntax, and replace France
with {{country}}
, like this:
https://api.demo.nativechat.com/v1/car-rental/offices?country={{country}}
Add the "data-source"
object to the "display"
object, so your final object looks like this:
"data-source": {
"endpoint": "https://api.demo.nativechat.com/v1/car-rental/offices?country={{country}}",
"method": "GET",
"headers": {
"Authorization": "Basic ZGVtby11c2VyOmRlbW8tcGFzc3dvcmQ="
}
}
Step 2 - add template
Next, in order for the chatbot to understand how to display the results of the query, you need to add a template
object to the display
object.
"template": {
"title": "{{name}}",
"subtitle": "{{country}}"
}
A template is made of:
title
- field to display, but also the value returned from the selectionsubtitle
- the text displayed under the itemvalue
- the value that should be returned for the selected itemimage
- the field to use for an imagetitle
vs value
.**It is important to understand that the value returned from the selection must be matched to the items defined in the Entity (in the training tab). So, if you change the title to be:
"title": "Office in {{name}}"
Then selecting Office in Berlin will fail, as the City Entity doesn't contain such record.
In this case, you need to use the value
, which should provide the property that the chatbot could match to, like this:
"template": {
"title": "Office in {{name}}",
"subtitle": "{{country}}",
"value": "{{name}}"
}
To make the list fancier you can add an image with a flag. Although the records don't return a URL for an image, you can use https://api.demo.nativechat.com/v1/resources/country-flag/france.
Bear in mind that the country should be in lower case only. So, we can just use the Mustache syntax along with the $lowercase
formatter, like this:
"template": {
"title": "Office in {{name}}",
"subtitle": "{{country}}",
"value": "{{name}}",
"image": "https://api.demo.nativechat.com/v1/resources/country-flag/{{$lowercase country}}"
}
The whole City step should look like this:
{
"type": "question",
"entity": "city",
"entity-type": "City",
"messages": [
"In which city are you looking for a car?"
],
"display": {
"type": "single-select",
"title": "Find a city",
"button-text": "Select this city",
"data-source": {
"endpoint": "https://api.demo.nativechat.com/v1/car-rental/offices?country={{country}}",
"method": "GET",
"headers": {
"Authorization": "Basic ZGVtby11c2VyOmRlbW8tcGFzc3dvcmQ="
}
},
"template": {
"title": "{{name}}",
"subtitle": "{{country}}",
"value": "{{name}}",
"image": "https://api.demo.nativechat.com/v1/resources/country-flag/{{$lowercase country}}"
}
}
},
The Data Source always expects an array.
However, some services return results as a JSON object. For example, you could get a response like this:
{
code: 200,
result: {
cities: [ 'Berlin', 'Paris', 'Rome', 'Warsaw']
}
}
The data that we need is under result.cities
. In this case, you can use a selector
property and provide a JSONPath to the array.
So, the solution to the above example would be:
"data-source": {
"endpoint": "https://another.api.com/cities",
"method": "GET",
"selector": "$.result.cities[:]"
},
Save the cognitive flow, and ask the bot to "rent a car" and then select a country.
Remember you can always type "restart" in your test console to start over with a new chatbot.
Now the conversation should look like this:
The next of the Conversational UI reply templates (and perhaps the most elegant one) is the Carousel, which allows you to display items in a fancy carousel. This component is best used when you have a few options supported with nice images.
In the previous chapter, in the homework section, you were asked to add a Car Entity and a Question for a Car.
Now, you will add a Carousel Component to the Car step.
The configuration is identical to that of a Single Select Component. The only difference is the Display type:
"display": {
"type": "carousel",
...
}
Can you update the step so that it:
"endpoint": "https://api.demo.nativechat.com/v1/car-rental/cars"
name
as the title,price
as a subtitleimageUrl
as an imageHint: You can use a $currency
formatter to display the price in a nice format. For example:
{{$currency price 'USD'}}
.
You can read more about formatters in the documentation.
Here is how the full step should look like:
{
"type": "question",
"entity": "car",
"entity-type": "Car",
"messages": [
"What car would you like?"
],
"display": {
"type": "carousel",
"title": "Find a car",
"button-text": "Select this car",
"data-source": {
"endpoint": "https://api.demo.nativechat.com/v1/car-rental/cars",
"method": "GET",
"headers": {
"Authorization": "Basic ZGVtby11c2VyOmRlbW8tcGFzc3dvcmQ="
}
},
"template": {
"title": "{{name}}",
"subtitle": "{{$currency price 'USD'}}",
"image": "{{imageUrl}}"
}
}
}
Save the cognitive flow, and ask the bot to "rent a car" and go through the whole flow.
The conversation should look like this:
NativeChat also offers location and date pickers to help users provide a location or a date in an interactive manner. The pickers not only make it easier, but they also make sure that the data is provided in the right format.
Note, the pickers extend the functionality of a question
step.
The date picker allows the user to select a date on an interactive calendar, which returns the date in a specific date format.
To complete the booking process you also need to ask the customer for the pick-up and drop-off dates.
To do that you need to add two question steps.
Add these steps before the Country step, so that the chatbot would start by asking for the dates.
By now, you should be well versed with adding question steps. Try to implement these steps without copy & pasting the solution.
For the first question step, set:
startDate
,Date
When would you like to pick up the car?
Then add a display configuration like this one:
"display": {
"type": "date-picker",
"title": "Find pick-up date",
"button-text": "Select"
}
title
- the button text that opens the calendarbutton-text
- the button text that confirms the calendar choiceAdd the second question step after the first one, set:
endDate
When would you like to drop off the car?
Find drop-off date
The two steps should look like this:
{
"type": "question",
"entity": "startDate",
"entity-type": "Date",
"messages": [
"When would you like to pick up the car?"
],
"display": {
"type": "date-picker",
"title": "Find pick-up date",
"button-text": "Select"
}
},
{
"type": "question",
"entity": "endDate",
"entity-type": "Date",
"messages": [
"When would you like to drop off the car?"
],
"display": {
"type": "date-picker",
"title": "Find drop-off date",
"button-text": "Select"
}
},
Whenever you change the order of conversation, it is worth making sure that you don't break the expected flow.
Since the country is not the first entity that the chatbot should ask about, you should update the condition for the initial message, so that it doesn't show when the startDate
is provided.
The first message step should look like this now:
{
"type": "message",
"messages": [
"Great, let me help you find a car for you."
],
"conditions": [
"{{$not ($has startDate)}}"
]
},
Now you should be able to test the new flow of the rent-car
conversation.
Try the following conversations:
Remember, you can send the restart command, each time you want to try a different conversation.
Pickers only
Mixed
Start with the Intro conversation
The Location Picker is a really useful widget that allows users to select a specific location on a map. The Location Picker returns a Location
object, which contains latitude
and longitude
properties.
The location picker is very easy to configure. You just need a question step with the "entity-type": "Location"
, and a display
object of "type": "location-picker"
, like this:
{
"type": "question",
"entity": "location",
"entity-type": "Location",
"messages": [
"Where is it?"
],
"display": {
"type": "location-picker",
"title": "Pick a location",
"button-text": "The car is here"
}
},
The car rental company offers a special service, where the customers can drop off their car anywhere in the city. The chatbot needs a new conversation that handles this specific scenario.
Add a new conversation called drop-off-location
, which should be triggered with one of these expressions:
The drop-off-location
conversation should work in two steps:
Step 1
In the first step, ask the user about the location of the car:
Then add a location picker, which should show when the user clicks on Pick a location and saves when the user clicks on The car is here.
Step 2
In the second step, just print the following message in 3 lines:
Solution
Here is the full code for the drop-off-location
conversation:
"drop-off-location": {
"type": "goal",
"steps": [
{
"type": "question",
"entity": "location",
"entity-type": "Location",
"messages": [
"Where did you leave the car?",
"Where can we find the car?",
"Can you show us on the location of the car on the map?"
],
"display": {
"type": "location-picker",
"title": "Pick a location",
"button-text": "The car is here"
}
},
{
"type": "message",
"messages": [
[
"Thank you.",
"We will pick up the car from: {{$json location}}",
"Have a nice day"
]
]
}
]
},
Get started today