[Progress News] [Progress OpenEdge ABL] Build a Viber Chatbot with NativeChat

Status
Not open for further replies.
S

Sebastian Witalec

Guest
A good chatbot can elegantly handle much of the communication with your users. In this tutorial, we'll build a Viber chatbot with NativeChat.

Over the last decade, the paradigm of communications has changed. We used to talk to each other face to face or on a phone, while lately we tend to communicate more and more through text. Furthermore, we find it more and more comfortable to communicate through channels like SMS, WhatsApp or Viber—each more or less popular depending on where in the world you are. As a result of which, companies need to adapt and provide different ways of communication channels for their customer and employees.

This is where chatbots come in handy. Chatbots can work 24/7, are great at handling repetitive tasks, and can provide a queue-free form of communication. A well-designed chatbot can handle a big portion of the communication with your users while leaving your trained employees to handle more complicated or unique scenarios.

In this article, we will look into building a Viber chatbot with NativeChat.

First, we will go through the required configuration, then we will add handling of straightforward questions and answers, and finally, we will create a step-by-step conversation that will guide a user to complete a bigger task.

Configuration

Overview


To start working with NativeChat and Viber we need to set our development environment in the following steps:

  1. Create a new NativeChat Project
  2. Get Proxy Command
  3. Add NativeChat Proxy Channel to Viber
  4. Run the Proxy Command
Step 1: NativeChat—Create Project


Sign Up

If you don't have a NativeChat account, you should create a free trial account.

Create Project

From the NativeChat console, create a new chatbot project. Choose Blank Bot, set the Name to ACME Ride, and press Create bot button.

Create Project


Step 2: NativeChat—Get Proxy Command


After the project gets created, you will arrive to the Dashboard.

On the right hand side you will find the Test Window, which is where you can test your chatbot as you go.

One of the first things that you will see is a Proxy Command, which we can use to test our chatbot outside of NativeChat, like with Viber, Facebook Messenger and Amazon Alexa.

Take a note of the Proxy Command, you are going to use it in a moment.

Proxy Command


Step 3: Viber—Add NativeChat Proxy Channel


Now, you need to add the NativeChat Proxy Channel in the Viber app. The Proxy Channel takes care of communication between your NativeChat chatbot and Viber.

On your mobile device open the Viber app, navigate to More (1) and start the QR Code Scanner (2).

Viber Add Channel


Then scan the following QR Code.

Note, you can find the QR code at the NativeChat channel for Viber page.

NativeChat QR Code


Tap the Open now button.

Viber NativeChat Page


Tap the Message.

Viber NativeChat Channel


Step 4: Viber—Connect to your Project


Now, that you have the Viber Proxy Channel, you need to connect it to your NativeChat project.

This is done with the Proxy Command that you saw in the step 2.

Copy the Proxy Command and run it in the Viber Proxy Channel.

Send Proxy Command


Note #1, you might need to email yourself the proxy command, so that you could access it on your mobile phone, or you could use Viber for Desktop.
Note #2, you can only have one active project connected with the Proxy Channel, if you run a Proxy Command from another project, then the Proxy Channel will disconnect from the current project and connect with the new one.
First Test


Go to Viber and say "Hi." In response you should get something like this:

First Test


And just like that we managed to configure NativeChat with Viber to let the user communicate with our chatbot via Viber.

The Scenario—Taxi Service


Now, that we have a working configuration, it is time for us to make our chatbot do something useful.

As part of this article, we will build a chatbot for a taxi company. It will allow users to ask some questions about the services offered, and also take them through a conversation to book a taxi ride. To book a taxi ride the chatbot will ask the user a few questions—like pick-up & drop-off locations, date/time and type of service they need—and finally, it will send the booking request to a server.

Add Q&A example


Every chatbot should be capable of answering useful questions. Such as:

Code:
Q: Do you have electric cars?
A: Our company is environmentally conscious. All our cars are either electric or hybrid.

Code:
Q: What type of cars do you offer?
A: We offer: 
Regular (4 passengers, 2 suitcases)
TaxiXL (6 passengers, 4 suitcases)
VIP (3 passengers, 3 suitcases, high comfort)

These are always two step interactions:

  • (1) The user asks a question
  • (2) The chatbot responds with an answer
  • (-) No follow up required

Training a chatbot to answer questions is fairly straight forward. It is all done from the Question answering page.

You can find the Question answering page in two ways:

  • From the Dashboard navigate to Question answering
  • Select the Training tab, then select Question answering

Instructions

Open the Question answering page. First, we need to create a new category to hold all our Questions and Answers. Press the + Add a category button, set the category name to QnA and press the Create category button.

Now, we can add our questions and answer in the QnA category.

Press the + Add a question button and set the following fields to:

  • Question: Do you have electric cars?
  • Group name: electric-cars
  • Answer: Our company is environmentally conscious. All our cars are either electric or hybrid.
Note, the Group name is used as a name for each Question and Answer, which comes useful when we need to check logs to see which QnA was identified by the chatbot.

Then Save changes.

Like this:


Note, that you can provide multiple expressions for the question. This tells the chatbot that there are many ways of invoking this QnA.

Also, you can provide multiple answers. In this case, the chatbot will randomly pick one of the answers and return it to the user. This way the chatbot could answer the same question in many ways.

Then you can add then second question, with the following fields to:

  • Question #1: What services do you offer?
  • Question #2: What cars do you offer?
  • Group name: service-types
  • Answer: We offer: Regular (4 passengers, 2 suitcases) TaxiXL (6 passengers, 4 suitcases) VIP (3 passengers, 3 suitcases, high comfort)

And Save changes.

Test in Viber

Finally, we can test our questions.

In Viber, ask:

  • do you use electric cars?
  • what type of services do you offer?

QnA Test Viber


Test with NativeChat

You can also test your chatbot in the NativeChat portal, with the built-in test window.

Note that the visual part of the chatbot might be slightly different, as this is used for testing web-based chatbots.

Let's give it a go. Go to the test window which is located on the right-hand side, and send messages like:

  • What types of cars do you have?
  • Do you have electric cars?

And the chatbot should respond with a relevant answer.

QnA Test NativeChat


What Can We Send/Receive via Viber


Before we jump into building a step-by-step conversation to allow a user to book a ride, we should go over the possibilities and limitations of a Viber based chatbot.

The user can send via Viber:

  • Text—that one is rather obvious
  • Dates and Time—chatbot can extract date/time from the user input, it can handle many formats like: 20-June-2020, Tomorrow, or in 30 minutes
  • Files—any documents or images, the chatbot can even validate the contents of a picture (i.e. it could check if the picture looks like a receipt)
  • Current Location—the user can send their current location, however this won't work with the live location

The chatbot in return can send:

  • Text
  • Images—as images/as links
  • Files—as links
  • Buttons
  • List Pickers

Viber cannot display conversational UI elements, like:

  • Carousels—instead it display a list picker
  • Date Picker
Add Booking Conversation


Now let's have some fun and build a step-by-step conversation that will help our users book a taxi.

The chatbot should ask the user for:

  • pick-up and drop-off locations
  • day and time of the pick-up
  • a type of car they want
  • how they intend to pay: cash or card—the assumption is that the payment should be made with the driver, and the driver should have a working card terminal for card payments.

And finally, the chatbot should send the booking to the server, and provide the user with a confirmation number.

Create and Configure a New Conversation


Whenever I need to add a new conversation, I like to start by creating a new conversation with a simple message like "Hello from Conversation Name." This way, I can quickly wire up all the important parts and test that the conversation gets triggered as expected. Then once I am happy with that, I can go back to the conversation, and start working on the conversation flow.

Create Conversation

Step-by-step conversations are defined in JSON, which we can work on at the Cognitive Flow page.

The Cognitive Flow page comes with a built-in Monaco Editor, which is just like any other powerful IDE. You get access to built-in code snippets (just start typing conv and the editor will show you a list of options), context-based IntelliSense (press CTRL+Space and you will see a list of relevant properties and code snippets) auto-formatting (each time you save your code, it will fix the formatting and indentation), syntax errors highlights, and most of the features that you would expect from an IDE like Visual Studio Code (highlight a word, press CMD+D or CTRL+D a few times and you can use the multi-edit feature).

The whole JSON structure is divided into three settings:

  • conversations—this is where we define step-by-step conversations
  • settings—global settings for the chatbot
  • commands—used to define the expressions users need to say to move to the next page or restart the conversation

Let's add a new conversation to "conversations", which we will call "book-ride". To do that we need to create a new line after line two (this is where we begin defining the "conversations" property). The easiest way to do that is to go to line two and press CTRL + Enter (on Windows) or CMD + Enter (on macOS).

Then we need to add the code for our new conversation. Start typing conv—this will display a number of code snippets—and select conversation-goal and press enter. This will generate the following code snippet for you:

Code:
"conversation-name": {
  "type": "goal",
  "steps": [
    
  ]
}

Now just change "conversation-name" to "book-ride", and add a comma at the end of this code-snippet. Like this:

Code:
"book-ride": {
  "type": "goal",
  "steps": [
    
  ]
},

Next we need to add a message step that will say "Hello from book-ride." Go inside the steps array and start typing stme and select step-message. Then set the message text to "Hello from book-ride." The beginning of your JSON code should look like this:

Code:
{
  "conversations": {
    "book-ride": {
      "type": "goal",
      "steps": [
        {
          "type": "message",
          "messages": [
            "Hello from book-ride"
          ]
        }
      ]
    },
    "welcome": {
...

How To—Video

Here is how I do that:

New Conversation


Conversation Trigger

Next, we need to instruct the chatbot when to trigger the book-ride conversation. To do that we need to configure Conversation Triggers, which are a set of expressions—like "I need a taxi" or "Book a ride"—that are linked with the book-ride conversation.


  1. Navigate to the Training tab, then to Conversation triggers.


  2. Press the [+ Add new] button


  3. Set Conversation name to book-ride


  4. Add Trigger expressions:
    1. Book ride
    2. Book taxi
    3. Order taxi
    4. Need ride

  5. Save changes

The conversation trigger should look like this:

New Conversation Trigger


Test

Now we can test the chatbot with expressions like:

  • Book a ride
  • I want to order a taxi
  • I need a ride

New Conversation Test


Improve Chatbot Understanding


At this point, the chatbot should be able to react to the above expressions and start the book-ride conversation to help the users book their taxi. The set of triggering expressions is something that should evolve over time.

As your chatbot matures, you need to keep updating them to make sure that your chatbot can handle most of the user's expressions.

It is important to understand what NLP is, how it works, and how to optimise your chatbot training. Understanding these concepts will help your build chatbots with a better understanding of user input. You can get started with the following two articles:

Implement Conversation Flow


Great, now that the chatbot knows when to start the book-ride conversation, it is time for us to tell it how to handle this conversation.

Ask for Pick-Up Location (address-from)


First the chatbot should ask for the pick-up location.

To do that we will need to use a question step, and remember user response as address-from entity.

Entities are like variables. They are placeholders for the chatbot to remember what values have been provided.

Your chatbot will only ask for the entities that it doesn't have the values for.

Go back to the Cognitive flow page and remove the message step from book-ride.

From inside the steps array start typing stq and select step-question. You should get the following code snippet:

Code:
{
  "type": "question",
  "entity": "entity-name",
  "entity-type": "",
  "messages": [
    "How to ask for entity?"
  ]
}

Set the following fields to:

  • entity to address-from—the chatbot will store the response in here
  • entity-type to Text—we tell the chatbot that we expect address-from to be a free text
  • messages to Where do you need the taxi from?—this it the prompt message the chatbot will display to the user

Save the code.

Code

The book-ride conversation should look like this now:

Code:
"book-ride": {
  "type": "goal",
  "steps": [
    {
      "type": "question",
      "entity": "address-from",
      "entity-type": "Text",
      "messages": [
        "Where do you need the taxi from?"
      ]
    }
  ]
},

How To—Video

Here is how I did it step by step:

Address From Step


Test

Now when you test the updated conversation, the chatbot should ask you the address-from question, but it won't say anything once it receives the address. Like this:

Address From Test


Ask for Drop-Off Location (address-to)


Now we need to add another question step to ask for the drop-off location, and we should remember it in an entity called address-to.

To do that, go to the closing curly bracket from the first step, add a comma, and start typing stq and select step-question.

Then set the following properties to:

  • entity to address-to
  • entity-type to Text
  • messages to Where are you going to?

And Save the code.

Code

The book-ride conversation should look like this now:

Code:
"book-ride": {
  "type": "goal",
  "steps": [
    {
      "type": "question",
      "entity": "address-from",
      "entity-type": "Text",
      "messages": [
        "Where do you need the taxi from?"
      ]
    },
    {
      "type": "question",
      "entity": "address-to",
      "entity-type": "Text",
      "messages": [
        "Where are you going to?"
      ]
    }
  ]
},

Test

Now, when we test book-ride, the chatbot will ask you first for the address-from and then for the address-to. Like this:

Address To Test


Ask for the Date and Time for the Pick-Up


Next, we should ask the user when they would like to get the taxi. In order to arrange a pick-up the chatbot needs to ask for both date and time.

Add a new question step to ask for the date, and remember the response in pick-up-date, with the following fields:

  • entity to pick-up-date
  • entity-type to Date
  • messages to When do you need the ride for?

Then add another question step to ask for the time, and remember the response in pick-up-time, using the following fields:

  • entity to pick-up-time
  • entity-type to Time
  • messages to What time?
Note, that this time we are using Date and Time as our Entity Types. Which are designed to handle date and time formats in a way that we speak. So you can provide the date by saying "14-July" or "Tomorrow" or even "Next week Friday," and for time you can say "at 3PM" or "midnight."

And Save the code.

Code

The additional two question steps should look like this:

Code:
    {
      "type": "question",
      "entity": "pick-up-date",
      "entity-type": "Date",
      "messages": [
        "When do you need the ride for?"
      ]
    },
    {
      "type": "question",
      "entity": "pick-up-time",
      "entity-type": "Time",
      "messages": [
        "What time?"
      ]
    }

The Date/Time Flow

The cool thing about using the Date and Time is that the chatbot can extract their values from the middle of a sentence. So when the user says "Pick me up at quarter past," the chatbot will extract the time and format it to 12:15.

Additionally, using the date and time together means that depending on what the user says, the chatbot can handle ask for the pick-up date/time in one or two steps.

For example, if the user says: "I want a taxi for tomorrow"—then the chatbot needs to ask a follow-up question to get the time.

However, when the user says something like: "This Friday at 3pm" or "In half an hour"—then there is no need for the follow-up question, as the chatbot can extract both pick-up-date and pick-up-time in one step.

Test

Now, you should be able to test the updated conversation, and the chatbot should ask you about the date and time for the booking. Like this:

Date Time Test


User Time Zone

Whenever we need to ask the user for time, we should configure our chatbot to use our user's time zone.

This can be done by adding the "use-user-timezone": true to settings. You can find the settings at the bottom of the Cognitive Flow json.

Update the settings to look like this:

Code:
"settings": {
  "invalid-replies": [
    "I am not sure I understood what you said."
  ],
  "general-failure": [
    "We are experiencing technical difficulties at this moment."
  ],
  "previous-conversation-messages": [
    "I am going back to the {{ conversationDisplayName }} now."
  ],
  "use-user-timezone": true
},
Debugging the Flow


Now, that we have a working chatbot with four questions, you are probably wondering how to make sure that we get the right data, and that the chatbot understands what we think it should.

There are two ways we could check what is going on:

  • Test Chatbot Debugging
  • Temporary Message Step

Test Chatbot Debugging

The built-in NativeChat test window has a Debug tab. It allows you to see what the user said and what the chatbot understood.

For example, if you say: "Order a taxi tomorrow at 7am," then switch to the Debug tab and expand on Underestanding—you should see something like this:

Debugging Test Chat


From here we can see:

(1)—the chatbot recognized:

  • conversation
  • pick-up-time — with Time assigned to it
  • pick-up-date — with Date assigned to it

(2)—the Conversation is book-ride with 66% confidence

(3)—the Time is 07:00

(4)—the Date is 2020.06.17

The Debug tab gives a lot of information, which helps us understand what the chatbot understands, and what entities get updated. You should check this page whenever you work with new types of entities.

Video

Here is a short recording of me using the chatbot and checking chatbot's understanding for of each step.

Debugging Test Chat Recording


Temporary Message Step

We could also display the entity values in a message step.

In the Cognitive Flow, when you start typing stme and choose step-message, you should get the following code snippet:

Code:
{
  "type": "message",
  "messages": [
    "Your message"
  ]
}

You can provide your own message in the messages property. So, the above step would say "Your message," each time the chatbot would get to this stage.

If we want to display a value of any entity, we need to use {{}} interpolation. To display pick-up-time, we need to something like this:

Code:
{
  "type": "message",
  "messages": [
    "Pick up Time: {{pick-up-time}}"
  ]
}
Note, that messages is an array, which allows us to provide multiple ways the chatbot can respond. How the chatbot uses each string might surprise you. For example, if we have a messages like:

Code:
"messages": [
"One", "Two", "Three"
]

You might expect that it would say: (One) (Two) (Three). While the chatbot will pick randomly one of the strings and display it to the user. For example you might get: (Two)

In order to make the chatbot display each string, we need to use an array of arrays, like this:

Code:
"messages": [
  [
"One", "Two", "Three"
  ]
]

This way the chatbot will understand that it has to display all of the strings.

Go to the end of the book-ride conversation, add a new message step (you can use stme => stem-message code snippet), and update the messages to look like this:

Code:
{
  "type": "message",
  "messages": [
    [
      "Address From: {{address-from}}",
      "Address To: {{address-to}}",
      "Pick up Date: {{pick-up-date}}",
      "Pick up Time: {{pick-up-time}}"
    ]
  ]
}

Save the code.

Note, that the message step will be displayed every time the chatbot will reach/go past this step. So, if we have another 2-3 steps in this conversation, the chatbot would display the same message each time the user provides new input.

You can learn more about the conversation flow and how to work around it from the tutorial.

Test

Let's test the updated conversation.

Once you reach the end of the conversation you should see something like this:

Debugging Temp Message


Entities


Before we create the next two question steps, we should talk about Entity Types.

Out of the box, NativeChat can handle the following entity-types: Text, Date, Time, Number, File, Location and Confirmation. This means that when a chatbot sees something that looks like a number — for example when the user says: "I need 3 seats"—it can automatically assign it to a Number entity.

To help our chatbot understand our users better, we can create our own Entity Types—that are relevant to our chatbot.

Payment Method

For example, our chatbot should be able to understand that when our users say "Cash" or "Card," they are providing it with the payment method.

To create a new Entity Type:

  • go to the Training tab, then select Entities.
  • press the + Add new button
  • set the name of the entity to PaymentMethod
  • keep the Training data source as Static—since we only have two values that we want to use, we can provide them manually
  • press the Create button

Now, we need to provide the entity values.

  • press the + Add new button—to add the first value
  • set the value to Cash
  • Save changes
  • add another value
  • set the value to Card
  • set the synonym to Credit
  • Save changes

And just like that you've created a new type (PaymentMethod), which the chatbot should be able to recognize—when the user says "Cash" or "Card."

Synonyms allow us to provide other ways to recognise the same entity value.

In our example, saying Card or Credit will both match to Card value.

Test

You can test the new type from the built-in NativeChat test window.

Just switch to the Understanding tab, and type "I have a card and some cash", which should highlight Card and Cast with PaymentMethod next to each of them.

Video

Here is how you can do the whole thing in one go:

Entity Add Payment Method


Service Type

Next, we should add an Entity Type to let the user select a type of service they want.

However, this time instead of typing all the values manually, we will pull all the values from https://demoapis.com/sample/taxi/service-types, which returns the following values:

Code:
[
  {
    "name": "Standard",
    "alt": "Regular",
    "rate": 1.5
  },
  {
    "name": "TaxiXL",
    "alt": "Minivan",
    "rate": 3.2
  },
  {
    "name": "VIP",
    "alt": "Limo",
    "rate": 9.9
  }
]

To do that:

  • go to the Entities page
  • add new entity
  • set the name to ServiceType
  • change the Training data source as Dynamic—as we want to dynamically load all the values
  • set Endpoint URL to https://demoapis.com/sample/taxi/service-types
  • set Value template to {{name}}—this is how we tell NativeChat that it should use the name property for the training
  • set Synonym templates to {{alt}}—this is how we tell NativeChat that it should use the alt property for the synonyms training
  • press the Create button

The Request configuration should look like this:

Entity Add Service Type


The ServiceType should display Entity valuesStandard, TaxiXL, and VIP—and the Metadata for each item, like this:

Entity Service Type Values


Test

Now, you should be able to test ServiceType with Understanding by saying: I am interested in Minivan or VIP. As a result Minivan, and VIP should be matched, while Minivan should be linked to TaxiXL. Like this:

Entity Service Type Test


How to Pay


Great!!! We are only two questions away from booking a taxi for our customers.

Let's start with the easy one, and ask our users how they would like to pay.

Just like in the previous steps, we need to add a new question step, but this time we will use a custom entity type PaymentMethod, and then instruct the chatbot to display the available options.

Create a new question step at the end of the conversation, and set the following properties:

  • entity to payment-method
  • entity-type to PaymentMethod
  • messages to How would you like to pay?

Display Available Payment Methods

Now, to instruct our chatbot to automatically display available payment methods, we need to add the display property with type set to quick-reply.

Go to the closing ] from messages, add a , and start typing di and choose display. Then start typing ty and select type. Finally, start typing qu and choose quick-reply.

Code

The Payment Method question step should look like this:

Code:
{
  "type": "question",
  "entity": "payment-method",
  "entity-type": "PaymentMethod",
  "messages": [
    "How would you like to pay?"
  ],
  "display": {
    "type": "quick-reply"
  }
}

Test

Now, when we test the chatbot again, the chatbot asks the user for the preferred payment method and also displays a button for each available value. Like this:

Payment Method Test


Get Quotes + What Type of Service


For the final question, we should ask our customers to pick the type of service they need.

In order for the customer to make an informed decision, the chatbot should request quotes from the server, and use the carousel display type, to show a list with each available service with the price.

Quotes Service

To get the quotes, we can call demoapis.com/sample/taxi/quotes service, provide from and to query params: https://demoapis.com/sample/taxi/quotes?from=home&to=office, and we should get a response like this:

Code:
// https://demoapis.com/sample/taxi/quotes?from=home&to=office
[
  {
    "name": "Standard",
    "quote": 6.9
  },
  {
    "name": "TaxiXL",
    "quote": 14.72
  },
  {
    "name": "VIP",
    "quote": 45.54
  }
]

Question Step

First, add a new question step with the following fields set to:

  • entity to service-type
  • entity-type to ServiceType
  • messages to What type of service would you like?

Next, we need to add display with the configuration for a Carousel with data coming from a web service, like this:

Code:
"display": {
  "type": "carousel",
  "data-source": {
    "endpoint": "https://demoapis.com/sample/taxi/quotes?from={{$encodeURI address-from}}&to={{&encodeURI address-to}}"
  },
  "template": {
    "title": "{{name}}",
    "subtitle": "{{$currency quote 'EUR'}}"
  },
  "button-text": "Select",
  "title": "Show Services"
}

If you are curious, here is a quick explanation of each property


  • data-source—used to provide the parameters to call our service
    • Note, that we interpolate the value of address-from and address-to
    • Additionally, we use $encodeURI to convert the address text to a URI-safe format

  • template—used to pinpoint the properties used to display each item
    • title—the main text field value
    • subtitle—the supporting text field value

  • title to Show Quotes—the name for a button that will display the list of values


  • button-text to Select—this name for a button used to confirm the selected option

Code

The Service Type question step should look like this:

Code:
{
  "type": "question",
  "entity": "service-type",
  "entity-type": "ServiceType",
  "messages": [
    "What type of service would you like?"
  ],
  "display": {
    "type": "carousel",
    "data-source": {
      "endpoint": "https://demoapis.com/sample/taxi/quotes?from={{$encodeURI address-from}}&to={{&encodeURI address-to}}"
    },
    "template": {
      "title": "{{name}}",
      "subtitle": "{{$currency quote 'EUR'}}"
    },
    "button-text": "Select",
    "title": "Show Services"
  }
},

Save your code and test.

Test

This time, the chatbot asks the user for the type of service, and presents three quotes for each type. Like this:

Ride Type Test


And when you tap on the Show Services button, you will be presented with options like this:

Ride Type Test Options


Web

If you try the same step in the web client, the chatbot will display the carousel like this:

Ride Type Web Carousel


Send Booking Request to the Server


Now that the chatbot collected all the entities from the user, all we have left is to send the request to the backend, book the service, and respond with a booking confirmation.

Book Service

To do that, we need to make a POST request to https://demoapis.com/sample/taxi/book with Body properties:

  • from—to be provided by address-from
  • to—to be provided by address-to
  • type—to be provided by service-type
  • payment—to be provided by payment-method
  • date—to be provided by pick-up-date
  • time—to be provided by pick-up-time

In response, the service will return a JSON object like this:

Code:
{
  "bookingRef": "S01575",
  "from": "home",
  "to": "office",
  "service": "Standard",  
  "quote": 10.5,
  "payment": "Card",
  "date": "19-Jun-2020",
  "time": "09:16 PM"
}

Webhook Step

To make such request, we need to use a Webhook step.

At the end of the conversation, start typing stwe and pick step-webhook. You should be presented with the following code snippet:

Code:
{
  "type": "webhook",
  "data-source": {
    "endpoint": "https://",
    "method": "POST",
    "headers": {
      "header name": "header value"
    },
    "payload": {
      "key": "value"
    }
  }
}

First, let's configure the data-source, to call the book service. Update the following properties:


  • set endpoint to https://demoapis.com/sample/taxi/book


  • remove headers


  • update payload to include all the entities the chatbot collected from the user:

    Code:
    "payload": {
      "from": "{{address-from}}",
      "to": "{{address-to}}",
      "type": "{{service-type}}",
      "payment": "{{payment-method}}",
      "date": "{{pick-up-date}}",
      "time": "{{pick-up-time}}"
    }

Next, we need to provide a response to the user. To do that we need to:


  • capture the result in an entity—after the line with "type": "webhook", add a new line with: "entity": "book-response", this instructs the chatbot to save the result of the POST request in book-response.


  • display a confirmation message— after the closing } for data-source, add a , and then a messages property like this:

    Code:
    "messages": [
      [
      "OK, the {{service-type}} service is booked for you. Your reference number is {{book-response.bookingRef}}",
      "The estimated price of {{$currency book-response.quote 'EUR'}} to be paid directly to the driver by {{payment-method}}.",
      "Your driver will pick you up on {{$date pick-up-date pick-up-time 'DD-MMM [at] h:mm A'}}"
      ]
    ]

Code

The Webhook step should look like this:

Code:
{
  "type": "webhook",
  "entity": "book-response",
  "data-source": {
    "endpoint": "https://demoapis.com/sample/taxi/book",
    "method": "POST",
    "payload": {
      "from": "{{address-from}}",
      "to": "{{address-to}}",
      "type": "{{service-type}}",
      "payment": "{{payment-method}}",
      "date": "{{pick-up-date}}",
      "time": "{{pick-up-time}}"
    }
  },
  "messages": [
    [
      "OK, the {{service-type}} service is booked for you. Your reference number is {{book-response.bookingRef}}",
      "The estimated price of {{$currency book-response.quote 'EUR'}} to be paid directly to the driver by {{payment-method}}.",
      "Your driver will pick you up on {{$date book-response.date book-response.time 'DD-MMM [at] h:mm A'}}"
    ]
  ]
}

Save your code and test.

Test

Finally, when the user provides the chatbot with all the necessary information, the chatbot should book the taxi, and display a confirmation message. Like this:

Booking Confirmation Test


Final Word


And just like that, we were able to build a Viber chatbot.

The chatbot is capable of handling a couple of FAQs and also guide a user through a taxi booking service.

Next Steps

There is a lot more that we could do with this service, like make use of user location to provide a pick-up location, respond with acknowledgements to user input, or implement input validation.

You can learn more about building chatbots from our comprehensive NativeChat Tutorial.

(Bonus)—Geolocation


As reward for making it all the way to the end of this tutorial, I will show you how to make use of the user location to find a nearby address.

This can be done in two steps, which should be added to the beginning of the whole conversation.

Step 1

First, I use the following Question step:

Code:
{
  "type": "question",
  "entity": "location",
  "entity-type": "Location",
  "conditions": [
    "{{$has location}}"
  ]
},

Note, the following:

  • the entity-type is set to Location—this means that when chatbot receives a location object, it will save it in the location entity
  • there is no messages property, as this question step is not meant to be displayed to the user—I mean, we could actively ask the user to provide the location, but we don't have to
  • we use a conditions property that makes sure that this step is never shown to the user

Step 2

The second step is a Webhook step—which will only be triggered when the chatbot receives a location—which uses Google Maps Geolocation service.

Code:
{
  "type": "webhook",
  "entity": "address-from",
  "data-source": {
    "endpoint": "https://maps.googleapis.com/maps/api/geocode/json?latlng={{location.latitude}},{{location.longitude}}&key=YOUR_API_KEY",
    "selector": "$.results[:1].formatted_address"
  },
  "conditions": [
    "{{$has location}}"
  ],
  "messages": [
    "We can send a taxi to {{address-from}}"
  ]
},

Note, the following:

  • the service uses location.latitude and location.longitude received in the previous step
  • the key is not provided. If you want to make this step work, you will need to sign up to Google Maps Geolocation service
  • the selector is used to drill down to the first formatted_address returned from the geolocation service
  • the conditions property ensures that this webhook step will only be triggered when we receive a location
  • the "entity": "address-from" tells the chatbot to save the formatted_address in the address-from entity. It is important that this whole step is placed before the question step that asks the user for the pick-up location. Because if the chatbot already has the address-from then this webhook will not be executed
The Whole Code


Here is the whole code for this chatbot:

Code:
{
  "conversations": {
    "book-ride": {
      "type": "goal",
      "steps": [
        {
          "type": "question",
          "entity": "address-from",
          "entity-type": "Text",
          "messages": [
            "Where do you need the taxi from?"
          ]
        },
        {
          "type": "question",
          "entity": "address-to",
          "entity-type": "Text",
          "messages": [
            "Where are you going to?"
          ]
        },
        {
          "type": "question",
          "entity": "pick-up-date",
          "entity-type": "Date",
          "messages": [
            "When do you need the ride for?"
          ],
          "reactions": {
            "acknowledgements": [
              "Sure, we can arrange something for {{#if ($has pick-up-time)}} {{$date pick-up-date pick-up-time 'DD-MMM [at] h:mm A'}} {{else}} {{$date pick-up-date 'DD-MMM'}} {{/if~}}"
            ]
          }
        },
        {
          "type": "question",
          "entity": "pick-up-time",
          "entity-type": "Time",
          "messages": [
            "What time?"
          ]
        },
        {
          "type": "question",
          "entity": "payment-method",
          "entity-type": "PaymentMethod",
          "messages": [
            "How would you like to pay?"
          ],
          "display": {
            "type": "quick-reply"
          }
        },
        {
          "type": "question",
          "entity": "service-type",
          "entity-type": "ServiceType",
          "messages": [
            "What type of service would you like?"
          ],
          "display": {
            "type": "carousel",
            "data-source": {
              "endpoint": "https://demoapis.com/sample/taxi/quotes?from={{$encodeURI address-from}}&to={{&encodeURI address-to}}"
            },
            "template": {
              "title": "{{name}}",
              "subtitle": "{{$currency quote 'EUR'}}"
            },
            "button-text": "Select",
            "title": "Show Services"
          }
        },
        {
          "type": "webhook",
          "entity": "book-response",
          "data-source": {
            "endpoint": "https://demoapis.com/sample/taxi/book",
            "method": "POST",
            "payload": {
              "from": "{{address-from}}",
              "to": "{{address-to}}",
              "type": "{{service-type}}",
              "payment": "{{payment-method}}",
              "date": "{{pick-up-date}}",
              "time": "{{pick-up-time}}"
            }
          },
          "messages": [
            [
              "OK, the {{service-type}} service is booked for you. Your reference number is {{book-response.bookingRef}}",
              "The estimated price of {{$currency book-response.quote 'EUR'}} to be paid directly to the driver by {{payment-method}}.",
              "Your driver will pick you up on {{$date pick-up-date pick-up-time 'DD-MMM [at] h:mm A'}}"
            ]
          ]
        }
      ]
    },
    "welcome": {
      "type": "support",
      "steps": [
        {
          "type": "message",
          "messages": [
            "This is a welcome conversation for your chatbot."
          ]
        },
        {
          "type": "conversation",
          "conversation": "help",
          "conditions": [
            "{{$not ($has conversation) }}"
          ]
        }
      ]
    },
    "help": {
      "type": "support",
      "steps": [
        {
          "type": "message",
          "messages": [
            [
              "If you get stuck, you can always restart our conversation by typing 'restart'"
            ]
          ]
        }
      ]
    },
    "restart": {
      "type": "support",
      "steps": [
        {
          "type": "message",
          "messages": [
            "Your conversation is restarted."
          ]
        },
        {
          "type": "conversation",
          "conversation": "welcome"
        }
      ]
    }
  },
  "settings": {
    "invalid-replies": [
      "I am not sure I understood what you said."
    ],
    "general-failure": [
      "We are experiencing technical difficulties at this moment."
    ],
    "previous-conversation-messages": [
      "I am going back to the {{ conversationDisplayName }} now."
    ],
    "use-user-timezone": true
  },
  "commands": {
    "NEXT-PAGE": [
      "Next 5"
    ],
    "RESTART": [
      "restart"
    ]
  }
}

Continue reading...
 
Status
Not open for further replies.
Top