There are many many chatbot creation tools out there. To paraphrase Dr. Seuss, some are good and some are sad and some are very, very bad. I know, I’ve reviewed a bunch of them.
But what if you want to write one yourself, from scratch, without using any fancy tools? Is that even possible? And can you make something useful? The answer is yes, because I’ve done it, and I’m going to show you how.
All the code is available here on Github. We will be creating a bot for Facebook Messenger, and we will use Google App Engine to host our bot, which will be written in Python.
But wait, why would you want to do this? Using a graphical user interface to make your bot is much easier. Well, here are a few reasons:
- It’s free. App Engine’s free tier is so generous it’s unlikely you will exceed it unless you have many thousands of bot users — in which case, you’ll be laughing.
- To learn. See what it really takes to build a chatbot.
- Go beyond what the chatbot creation tools can do. Feeling ambitious? Make something totally original, or make your own chatbot platform.
Choosing a chatbot channel
You can build a bot for many different channels. Some of the most popular are Facebook Messenger, Kik, Slack, Twitter, and Telegram. If you need to support several platforms, you’ll be better off using a bot framework. This way you won’t have to write the code to integrate with all the platforms you want to support.
In this article we’re going to build a chatbot for Facebook Messenger. Why? Well, firstly, it’s the most popular platform for chatbots. Nearly all the tools for building chatbots target Messenger, and quite a few of them only support Messenger. And with good reason: it had 1.2 billion monthly active users in 2017. That’s a lot of potential chatbot users.
There’s another reason we want to target Messenger: quick replies. These are buttons that your chatbot can offer users as a shortcut so they don’t have to type. Not only do they make your bot much more engaging (who likes typing on a mobile phone?), but they also make your job as a chatbot developer a whole lot easier.
If you offer users buttons, they’ll press those buttons. This means you don’t have to worry about parsing arbitrary queries from users who want to know whether it’s going to rain tomorrow or where they can get pizza. Guiding users is good for them and us.
What’s a bot to do?
Your bot needs a purpose. It can’t do everything. My friend Naré Vardanyan and I designed a bot to help people navigate the turbid waters of visa applications to the UK. We’ll be using a simplified version of that bot as an example in this article.
Tree Traversal Magic
We’ll be using a bot design method based around trees. Each node of the tree represents a possible conversation state. Each child of a node corresponds to a possible user message that we understand as being relevant from this particular state.
This is a simplified version of our visa advice bot, in tree form. It’s in YAML (Yet Another Markup Language) format, which makes it easy to read. The root node specifies the first message the bot sends to the user, in this case, asking the user “What is the purpose of your visit?” The child nodes (specified under “answers”) contain the possible answers we will accept, namely “travel,” “study,” “business/work,” and so on.
To create our bot, we need to set up a bunch of things in Facebook. The official instructions are here, but in summary, you will need:
- A Facebook page — each bot needs a different Facebook page.
- A developer account to allow you to create apps.
- A Facebook app to get a secret access token which will be needed later.
Facebook bots work with webhooks, which are just URLs that Facebook Messenger uses to interact with your bot.
To create our webhook, we’ll use Google App Engine. The advantage of this is that it’s free for low volumes, and automatically scales as you get more traffic. For this article, I’ve used Python, but there are lots of other languages you can use. You will need to download the Python SDK and create a Google Cloud Project if you don’t already have one.
Creating our webhook
The first thing our webhook needs to do is to allow Facebook to verify that we are really the correct webhook. We do that by handling a GET request which contains a “verify token.” This is a secret random string that we’ve shared with Facebook. This part of our code is based on the excellent Facebook Messenger Bot repository.
Here we first initialize a class to handle requests within the webapp2 framework. We first log a message to say that the bot is being initialized, then construct the class
TreeBot that will handle all the bot logic, discussed below.
Next we check for “subscribe” requests from Facebook and check that the verify token sent in the request is the same as the secret one we shared with Facebook.
Handling messages from users
Next we need to interpret messages from users, which are sent by Facebook to our webhook using POST requests.
Here we first parse the JSON data from Facebook and log it to help with debugging. We then iterate over the messaging events in the data. First we extract the sender ID, which we’ll need to send replies back to the user. There are two types of events, messages (which the user has typed) and “postback” events, which are sent when a user clicks a quick reply button.
For the first of these, we need to ignore “echo” events. We then extract the message text and send it to our bot logic to handle. We do the same with the postback events, extracting the payload, which in our case is just the text of the button.
Sending messages to users
When we constructed our
TreeBot class, we passed a function
send_message that allows the bot logic to send return messages to the user. Here it is:
The recipient ID will be the sender ID we extracted earlier. Along with that we have the message text, and some quick reply buttons for the user to press. We first make sure that the request headers specify our content as JSON, and then construct our postback buttons part of the message. We specify the recipient ID and message text and convert to JSON. We make our request to the Facebook Graph API, passing in the secret access token that Facebook gave us when we created our app.
Running the bot server
The last piece of code in this file just constructs the main class and runs it:
Now we come to the interesting bit: how does the bot know what to say? The brains of the bot are in the file
The class is initialized with three parameters:
- a callback function (that was defined above) to send messages back to users
- a data access object for storing information about users
- the tree that contains the logic of what should be said when. This is parsed from the YAML we showed above.
First, we record that we received the user’s message, and then retrieve all of the user’s past actions from the data access object. We then replay the user’s actions to figure out where they are currently in the tree.
We initialize the response to a default message that will be returned when the user says something we don’t understand. In our case, this is “I’m sorry, I didn’t understand, shall we start again?” There are also some default possible answers, which are “yes” and “no”. We also keep a record of whether we think we are restarting the conversation from scratch.
We then start iterating over the user’s history. For each message, we check whether it was sent by us, or whether we received it from the user. If it was received, we check for a match with the current options in the tree. This uses the following function:
This checks the content of the user’s message to see if it occurs as a substring of one of the current options in the tree. If there is exactly a single match, we return that match, otherwise either the user’s response is ambiguous or there is no match at all.
Next we check whether we have sent anything at all to the user before. If not, we set our response to be the first response in the tree, and set the possible answers to the first set from the tree.
Then we check whether we found a match for the user’s message. If we did, we update the tree to be the appropriate child branch, and extract the correct response and possible answers from the tree.
We then check if we have suggested restarting and if the user has confirmed they do want to restart the conversation. In that case, we reset the tree back to its initial state and use the first response as we did before.
For each message in the history that was sent by the bot, we update the tree accordingly. Or if we sent the default message, record that we may restart the conversation.
Finally, after traversing all the history, we log our response, send the message back to the user, and record the message we sent in our data access object.
The last piece of the puzzle
The only piece of code left to discuss is the data access object that stores all user interactions. We made the design decision to store all user actions and replay them as we did above because it allowed us to easily change the logic of the bot and still be able to deduce an appropriate state for the bot and the user. If we had chosen instead to label each node of the tree and store that label, then any change to the tree would render old conversations invalid.
So our data access object needs to be able to do two things: store a new user event, and retrieve all the events for a particular user.
Our data access object makes use of Google Datastore, which is very easy to use from App Engine, and has a generous free usage tier. The Python API makes using Datastore very easy. First we create a model class,
UserEvent which specifies the fields and their types. In our case, the user ID, direction of the message and the message itself are strings, and finally the date of the event has a date-time type.
To create and store a new user event, we simply construct this class, set the properties, and then call
put() on the object.
To retrieve the events for user, we call the
query() function on the class, passing in the user ID. We then sort the events by date, and return a list of direction-message pairs.
That’s all the bits of our bot! Now to deploy it and connect it up to Messenger.
To deploy your app to App Engine, use the
gcloud command that came with the App Engine SDK:
gcloud app deploy --project [YOUR_PROJECT_ID]
Once deployed, the URL of your webhook is
Update your Facebook app with this webhook URL (follow the instructions here) and you should be good to go!
The world is your chatbot oyster
You can make many kinds of chatbot using these techniques. I once had fun making a Choose Your Own Adventure style bot, but I’m sure you’ll be able to come up with much more inventive things. Oh, and if you want to try out the visa bot, you can try it here (although this version is a little more sophisticated).
And, if you don’t fancy all this hard work, you could always try one of the many chatbot creation tools.