Creating a Bot on FB Messenger with rich UI using Hu:toma AI and Node.JS

Updated 5 months ago by Matthew Clementson

Bots built on Hu:toma AI can be integrated anywhere using our API. However, we support integrations to Facebook Messenger natively and in just a couple of clicks.

Some of the advantages of deploying a bot to Facebook Messenger is that you are able to take advantage of the rich content that is supported.

  • Quick Replies
  • Button Templates
  • List Templates
  • Image & Video content

The purpose of this walkthrough guide is to take you through the process of building a bot that leverages all of the above features using the Hu:toma AI Bot Studio. We'll be showing the process we went through to build our own bot "Hu" which can be found attached to our own FB page.

We'll be using Node.JS and Google Cloud Platform to host our code but you could use any other hosting provider or language.

In order to complete this walkthrough you will need:

  • A Hu:toma AI account
  • A Google Cloud Platform account

In order to support Facebook Messenger's UI we must call out to a Webhook that is hosted externally and will send back a response. To trigger a call to this Webhook an intent must be triggered.

1. Create a webhook

Log into Google Cloud Platform. Create a new account if you don't have one already. Google Cloud Functions is a paid service but the first two million calls are free so you will probably not need to worry about billing just yet.

GCP Webhook

Click "Create function".

GCP Function
  • Name the function
  • Change the trigger type to http
  • Pick a stage bucket. If you have no buckets then create a new one.
  • Change the name of the function to execute to match your webhook function. In the example below the function is named webhook

Paste the following code into the source window.

exports.webhook = function webhook(req, res) {
          
            var variables = {}
            var intentName = 'intentName' in req.body ? req.body.intentName : ''
          
            if ('variablesMap' in req.body) {
              for (key in req.body.variablesMap) {
                variables[key] = req.body.variablesMap[key].value
              }
            }
          
            var response = {
              'text': 'triggered intent: ' + intentName
            }
          
            res.status(200).send(response);
          }
          

Click the Create button to create this cloud function. Once that's done, click on the function again and click on the testing tab to try it out. Paste the following JSON into the triggering event window:

{ "intentName": "random-intent-name" }
          

And test the function.

GCP Function

2. Create an intent

You're now ready to use this webhook inside a bot. From the Hu:toma console, view or create a bot. Once you have clicked "Create New Bot", navigate past the Skills page by clicking "Save and go to Bot" you should navigate to the Intents tab on the left hand side of the page.

Go to the intents tab and add a new intent. Call it "get_started". Add a few phrases in the User Expressions section to trigger the intent. Things like:

  • get started
  • start
  • hello

Now add a response that says "No webhook". This is what the bot will say if the webhook fails to trigger for any reason.

Hutoma Intent

Paste the Google Cloud Function link into the webhook field and save the intent. You will have to click the button to restart training in this bot - wait for this to complete.

You should now be able to trigger the intent and get a response from the webhook. Try saying "start" in the chat window. The response should be "triggered intent: get_started".

3. Integrate with Facebook

There are a few ways users can interact with a bot you have created. The easiest and quickest one is via Facebook integration, meaning that you can connect the bot to a Facebook Page and users can chat to the bot on Messenger or in a browser as if it was a normal Facebook user.

You will need:

  1. A working bot
  2. A Facebook account with admin access to ...
  3. A Facebook page

Go back to Hu:toma console and click on the bot that you would like to integrate. Click on 'integration' in the left hand menu.

Click on the "Connect to Facebook" button. If you are not logged into Facebook then you will have to login now.

Once logged, review the permissions that are required and complete the connect sequence, after which you will return to the Hu:toma console.

Hutoma Integrations

The bot is now connected to Facebook. You should see a list of Facebook pages that you can integrate this bot with. Select one of the pages and click on it.

Hutoma Integrations

Integration is now complete.

Now head over to the Facebook page and talk to the bot to see if it responds.

If you say "start" you should get the same response of "triggered intent: get_started" that is coming from your webhook.

Hutoma Messenger

But there is really no need for the user to type "start" to start a conversation. Facebook allows us to display a "Get Started" button that will do that automatically.

There are two text fields in the integration page. The first is a greeting to display to the user and the second is the text to paste to the bot when the user presses the "Get Started" button.

Add a greeting: Something like "Talk. The machine is listening."?

Fill in the "Get Started" field: You can use "start" or "get started" here to trigger the intent that we created in the last step.

Save your customisations and try the bot now.

Hutoma Messenger

The "Get Started" button should be visible now. Note that this will only happen if this is the first time the user is talking to this bot. If you spoke to the bot in the previous step then you may have to delete the conversation and try to talk to the bot again.

Press the "Get Started" button and you will get a reply from your webhook.

Hutoma Messenger

4. Give the user some options

Let's add some content to the get-started intent.

This is the first interaction that a user would have with our bot, so let's present the user with a message and a little menu.

The menu will allow the user to choose either "Latest News" or "Join the Community".

First we need to create a custom entity. Create an entity and call it "start_menu".

Hutoma Entities

Add two values: "News" and "Join".

Save the entity and return to the "get_started" intent page. Now add an entity to this intent and select the entity type that you have just created.

Set the number of prompts to 1 and make sure that the required box is checked and click on the prompts button.

Add a prompt that says something like "Welcome to this test bot. Would you like to see the latest news or join the community?"

Set the variable label to "start" and save the intent. You will have to retrain the bot for these changes to take effect.

Once that is done try talking to the bot again on Facebook Messenger.

Remember to delete the conversation first so that you will start from scratch with a Get Started button.

Messenger

Hold down on the chat name until an options list appears then select "Delete Conversation."

And now you should be able to re-add the conversation from the beginning.

Messenger

If you click on any one of these buttons the intent will trigger as usual but the variable "start" will be set to the value that the user selected.

To see these values, change the webhook code to spit the intent and variables back to us:

exports.webhook = function webhook(req, res) {
          
            var variables = {}
            var intentName = 'intentName' in req.body ? req.body.intentName : ''
          
            var text  = 'triggered intent: ' + intentName
          
            if ('variablesMap' in req.body) {
              for (key in req.body.variablesMap) {
                variables[key] = req.body.variablesMap[key].value
                text += ", " + key + ": " + variables[key]
              }
            }
          
            var response = {
              'text': text
            }
          
            res.status(200).send(response);
          }
          
Messenger

5. Create some content

One advantage of integrating with Facebook is that our bot can use it to respond to users with rich content rather than just text - that means pictures, video clips, lists, buttons and more. These need to be generated in your webhook code and sent back as a response to a triggered intent.

So far we have been sending text-only responses by responding to webhook calls in this format:

{ "text": "your response here" }
          

You cannot send rich-content alone - it must always be accompanied by plain-text, to be displayed in case the user is not talking to your bot on Facebook.

Here's an example of a response that displays an image on Facebook:

{
             "text":"non-Facebook users will see this text",
             "facebook":{
                "attachment":{
                   "type":"image",
                   "payload":{
                      "url":"http://www.example.com/Facebook/users/get/this/picture.jpg"
                   }
                }
             }
          }
          

See documentation for creating rich content here:

Let's upgrade our webhook to respond with a list template.

We'll need a few functions to create individual pieces of the structure:

function createLinkButton(title, url) {
              return {
                  'title': title,
                  'type': 'web_url',
                  'url': url
              }
          }
          
          function createTemplateItem(title, subtitle, imageUrl, defaultAction, buttons) {
              return {
                  'image_url': imageUrl,
                  'subtitle': subtitle,
                  'title': title,
                  'default_action': defaultAction,
                  'buttons': buttons
              }
          }
          
          function createListTemplate(template_item_list) {
              return {
                  'type': 'template',
                  'payload': {
                      'elements': template_item_list,
                      'template_type': 'list'
                  }
              }
          }
          
          function createButtonTemplate(header_text, button_list) {
              return {
                  'type': 'template',
                  'payload': {
                      'text': header_text,
                      'buttons': button_list,
                      'template_type': 'button'
                  }
              }
          }
          
          and a function to put the content together:
          function createLatestNews() {
              var response = {}
              response.text = "Latest News"
              response.facebook = {
                  "attachment": createListTemplate(
                      [
                          createTemplateItem(
                              'Take a look at our Blog',
                              'Read Hu:toma news hot off the press',
                              'https://storage.googleapis.com/hutoma-bots-resources/hutomabot/icons/hutoma_blog.png',
                              createLinkButton('Blog',
                                  'https://blog.hutoma.ai/'),
                              []
                          ),
          
                          createTemplateItem(
                              'Hu:toma wins Chatbot Summit in Berlin',
                              '',
                              'https://storage.googleapis.com/hutoma-bots-resources/hutomabot/icons/hutoma_logo.png',
                              createLinkButton('News',
                                  'https://blog.hutoma.ai/winning-in-the-chatbot-space-what-weve-learnt-38b78e437c9b'),
                              []
                          ),
          
                      ]
                  )
              }
              return response
          }
          
          
          All that is left is to extend our webhook function to respond with the Latest News template when the user triggers the intent with the 'start' variable set to 'News'.
exports.webhook = function webhook(req, res) {
          
              // name of the intent that triggered this webhook
              var intentName = 'intentName' in req.body ? req.body.intentName : ''
          
              // get all the intent variables in a dictionary with labels as keys
              var variables = {}
              if ('variablesMap' in req.body) {
                  for (key in req.body.variablesMap) {
                      variables[key] = req.body.variablesMap[key].value
                  }
              }
          
              // get the value of the 'start' variable
              var action = 'start' in variables ? variables['start'] : ''
          
              // the default response if we don't recognise the webhook
              var response = {
                  'text': ' unrecognised intent: ' + intentName
              }
          
              if (intentName == 'get_started') {
                  switch(action) {
                      case "News":
                          response = createLatestNews()
                          break
                      default:
                          var response = {
                              'text': 'unrecognised action: ' + action
                          }
                  }
              }
          
              res.status(200).send(response);
          }
          

Here is what it looks like if the user taps Get Started and then selects News from the two options presented.

Messenger

6. Add some more buttons

That's the News option covered but we still don't have anything to say if the user taps the Join button. Let's use a button template to create a couple of buttons that can link to web content.

Add this function to the webhook source:

function createJoinButtons() {
              var response = {}
              response.text = "Join us on Slack or Facebook"
              response.facebook = {
                  "attachment": createButtonTemplate("Join our community",
                      [
                          createLinkButton('Join Slack Community',
                              'https://join.slack.com/t/hutomadotai/shared_invite/MjE0MTU0NTkyNTYzLTE1MDAzODA2OTItMmMxN2ZhZTZlMQ'),
                          createLinkButton('Join Facebook Group',
                              'https://www.facebook.com/groups/botdesigners/'),
          
                      ]
                  )
              }
              return response
          }
          

Now we need the main webhook function to react to the user pressing the Join button. Find the main switch that reacts to an action and add the following code a new case statement just above the default: statement:

            case "Join":
                          response = createJoinButtons()
                          break
          

Save the code and go to the testing tab. Paste the following test JSON into the testing tab:

{
             "intentName":"get_started",
             "variablesMap":{
                "start":{
                   "value":"Join"
                }
             }
          }
          
Testing Join buttons

Now try it out on Facebook Messenger.

Join buttons in Messenger

If you try out our bot, Hu on Messenger you will see there are many more quick reply options after the "get started" intent, why not try recreating these yourself? They follow the same format as the ones we have shown in this tutorial.

You can check out all template types here


How did we do?