Thursday, 13 June, 2019 UTC


It’s amazing how in recent years, Natural Language Processing (NLP) has transformed how we build conversational interfaces. Notably, more businesses are building chatbots that interact with their customers in real time. In my previous tutorial, I wrote about building a chatbot using Dialogflow. In this tutorial, we’re going to build a chatbot using Twilio Autopilot and Whatsapp. Our chatbot will allow users to book an appointment and have a Google calendar event created.
This tutorial requires basic knowledge of Autopilot. If you need to read up, please do so from this guide.
Tutorial Requirements
  • PHP 7 development environment
  • Global installation of Composer
  • Global installation of ngrok
  • Twilio Account
  • Google Account
  • WhatsApp Account
Create a Google Project
To start off, we need to create a Google Project and enable the Google Calendar API. From your project dashboard, click on the Credentials tab. Click the create credentials dropdown button and then click service account key. Provide a service account name, select the owner role, and leave the JSON radio button checked. When you click Create a JSON file will be downloaded. Leave it in the download folder for now, we will use it later.
Note: We need a service account because we will be performing server-to-server interactions. More information on this can be found in the documentation.
Now click the Create credentials dropdown button again. Select API key. An API key will be generated and we will get it later. That’s all we need to do on our Google project console.
Set Up Our Development Environment
From the terminal, in your preferred location, create a new project directory. I’ve called mine Twilio-Autopilot. In the directory, add two files to it:
  • webhook.php
  • .env
We will use webhook.php to listen to a POST request from Autopilot (more on this to follow). The .env file is used to store sensitive credentials.
In the .env file add the following environment variables:
We have two environment variables. The value for the GOOGLE_API_KEY is the API key we created in our Google Project. The second environment variable makes reference to a file in our project’s root directory called credentials.json. Since that doesn’t exist yet, let’s go ahead and create it. Copy the file that was downloaded when we created a service account key on Google to the root directory of our project. Make sure you rename it credentials.json.
Note: credentials.json is a sensitive file and shouldn’t be pushed to a public repository.

Installing Dependencies

For our project we will need two dependencies:
  • PHP Dotenv, which makes it possible for us to load environment variables from the .env file.
  • Google API Client for PHP, which enables us to work with Google APIs. For this tutorial we will use the Google Calendar API.
From the terminal, in the project directory, run the command:
$ composer require vlucas/phpdotenv google/apiclient 
Your folder structure should now look like this:

Start ngrok

We will need our webhook.php file to be accessible through a public URL. To do this we will use ngrok. From your terminal run the command:
$ php -S localhost:3000 
On a new terminal window, run the command:
$ ./ngrok http 3000 
You should see a similar output on your terminal. We will use the forwarding URL later on.
Set Up Autopilot Assistant
From your Twilio account, head over to the Autopilot console and create a new assistant. I’ve named mine appointment-booking.

Twilio Sandbox for WhatsApp

Since we will be using WhatsApp as our Autopilot channel, we need to set up our WhatsApp sandbox. On the left, click channels and select WhatsApp.
You should see the page below. Follow the instructions given to set up your sandbox.
Upon completion, in the Autopilot section, you will see a notification at the top similar to this:
Click “build model” and give it a version v0.1. Once the build is complete, go to WhatsApp and type the word “Hi”. Did you get a response like this one?
The above response was generated by the default Task, “hello_world”.
Tasks are the building blocks for assistants which allow you to use the Autopilot Actions API to define capabilities and build out your assistant’s script.
Let’s go ahead and modify the hello_world task. In the Autopilot section, click on Tasks and on the right side of the hello_world task, click Program. Replace the content with the snippet below:
{  "actions": [  {  "say": "Hey there! My name is X, I'm Charles' Scheduling assistant... Would you like to schedule and appointment?"  },  {  "listen": true  }  ] } 
We have added a new action called “listen”. This tells Autopilot to keep the conversation open. It would otherwise end the conversation.
Save your changes then go back to the previous page. This time click Train. Here we write training phrases that will trigger the hello_world Task. You can add any phrase you’d like. Here are some phrases I added:
Now, that we’ve made changes, we can go ahead and test it out. Before we do so, we need to create a new model. After the new model is built, type any of the training phrases you entered above. You should now see our new message.
Great! This is exciting. Let’s go ahead and create two more tasks. One that is triggered when the user indicates interest in booking an appointment and another when they don’t.
I have named the first task “yes_response”. You can give it a different name if you like. In it let’s copy the following snippet:
{  "actions": [  {  "collect": {  "name": "user_details",  "questions": [  {  "question": "What is your first name?",  "name": "user_first_name",  "type": "Twilio.FIRST_NAME"  },  {  "question": "What is your last name?",  "name": "user_last_name",  "type": "Twilio.LAST_NAME"  },  {  "question": "What's your email?",  "name": "user_email",  "type": "Twilio.EMAIL"  },  {  "question": "On what date would you like to book your appointment?",  "name": "appointment_date",  "type": "Twilio.DATE"  },  {  "question": "At what time?",  "name": "appointment_time",  "type": "Twilio.TIME"  },  {  "question": "What is the purpose of you appointment? e.g check up",  "name": "appointment_purpose"  }  ],  "on_complete": {  "redirect": ""  }  }  }  ] } 
Note: Make sure to replace the redirect URL with your ngrok forwarding URL.
The above snippet asks the user for some details and collects them. Some questions have the type specified. Those are built-in field types and they help enforce the kind of response to expect from the user.
The on_complete action can either redirect the collected data to another task or to a given URL. In our case we are redirecting to our webhook URL.
We need to add some training phrases for this task. Here are some of the phrases I added:
The next task handles a negative response. I have called mine no_response. Let’s copy the following snippet to program it:
{  "actions": [  {  "say": "Okay. Have a great day!"  }  ] } 
This is a simple action that sends a message to the user and ends the conversation. Remember to add training phrases. I have added these:
Time to test our newly added tasks. Go ahead and build a new model then test out the conversational experience on WhatsApp. Here are screenshots of my responses:
This is going great. Now we need to update our webhook to handle the incoming request from Autopilot.
Set Up Webhook

Google Calendar Client

Before we can work on the webhook, we need to set up the Google Calendar Client. Using the Google Calendar API quickstart guide, we can create a Google Calendar Client. Create a file and name it GoogleCalendarClient.php and copy the following code:
<?php  require __DIR__ . '/vendor/autoload.php';  $dotenv = Dotenv\Dotenv::create(__DIR__);  $dotenv->load();   /** * Class GoogleCalendarClient makes API calls to Google API */ class GoogleCalendarClient {  protected $service;   /**  * GoogleCalendarClient constructor  */  public function __construct()  {  $apiKey = getenv( 'GOOGLE_API_KEY' );   $client = new Google_Client();  $client->setAccessType( 'offline' );  $client->useApplicationDefaultCredentials();  $client->setDeveloperKey( $apiKey );  $client->setScopes( [ '' ] );   $this->service = new Google_Service_Calendar( $client );  }   /**  * Creates an event  *  * @param array $eventDetails event details e.g summary, start, end, attendees, e.t.c  *  * @return array $user of a user  */  public function createEvent( $eventDetails )  {  $event = new Google_Service_Calendar_Event( $eventDetails );   $optionalArguments = [ 'sendNotifications' => true ];  $calendarId = 'primary';  $event = $this->service->events  ->insert( $calendarId, $event, $optionalArguments );   return $event;  } } 
This class uses the API key in our .env file as well as the credentials.json file to authenticate our requests. The createEvent() method creates an event based on the arguments passed to it.


Copy the following code in the webhook.php file:
<?php  include_once( 'GoogleCalendarClient.php' );  if ( $_SERVER[ 'REQUEST_METHOD' ] === 'POST' ) {   $userDetails = $_REQUEST[ 'Memory' ];   $userDetails = json_decode( $userDetails );   $userDetails = $userDetails->twilio->collected_data->user_details->answers;   $firstName = $userDetails->user_first_name->answer;   $appointmentDate = $userDetails->appointment_date->answer;   $appointmentTime = $userDetails->appointment_time->answer;   $appointmentStartAndEndTime = formatAppointmentTime( $appointmentDate, $appointmentTime );   $eventDetails = array(  'summary' => $firstName.'\'s Appointment with Charles',  'location' => 'Plaza, Rabai Rd, Nairobi, Kenya',  'description' => $userDetails->appointment_purpose->answer,  'start' => array(  'dateTime' => $appointmentStartAndEndTime[0],  'timeZone' => 'Africa/Nairobi',  ),  'end' => array(  'dateTime' => $appointmentStartAndEndTime[1],  'timeZone' => 'Africa/Nairobi',  ),  'attendees' => array(  array( 'email' => '[email protected]' ),  array( 'email' => $userDetails->user_email->answer ),  ),  'reminders' => array(  'useDefault' => FALSE,  'overrides' => array(  array( 'method' => 'email', 'minutes' => 24 * 60 ),  array( 'method' => 'popup', 'minutes' => 10 ),  ),  ),  );   $client = new GoogleCalendarClient();   $client->createEvent( $eventDetails );   $message = "Thanks $firstName, your appointment has been booked for $appointmentDate at $appointmentTime";   $response = array(  'actions' => array (  array(  'say' => $message  )  )  );   echo json_encode( $response ); }  /** * Formats the date to the format 2015-05-28T09:00:00 * and adds 30 minutes to the start time. This works * with the assumption that an appointment is 30 minutes. * * @param String $date * @param String $time * * @return Array */ function formatAppointmentTime($date, $time) {   $appointmentTime = array();   $start = date( 'Y-m-d H:i:s', strtotime( $date.$time ) );   $end = date( 'Y-m-d H:i:s', strtotime( $start . '+30 minutes' ) );   $start = str_replace( ' ', 'T', $start );   $end = str_replace( ' ', 'T', $end );   array_push( $appointmentTime, $start, $end );   return $appointmentTime; } 
This file makes use of the Google Calendar Client. It receives a request from Autopilot, formats the data, creates a new event and sends a response to the user.
Now that we have everything put in place, it’s time to test! On WhatsApp, complete the conversational experience. You should now have a result like this below:
If you entered a valid Gmail address, you should also have a calendar event on your Google calendar:
Congratulations! You have just created a chatbot using Autopilot and Whatsapp. We have only scratched the surface here. You can go ahead and make your conversational experience more exciting. For example, our application allows us to book appointments at any time and doesn’t handle a situation where there is no free slot.
I look forward to seeing what you build. You can reach me on:
Twitter: @charlieoduk
Github: charlieoduk