📜 ⬆️ ⬇️

Chat bot development for Facebook Messenger

Currently, there is, indeed, a boom chat messengers. One after another platform for instant messaging announce the launch of a platform for the development of bots.
Not an exception and Facebook. On April 12, at the F8 conference, Facebook introduced a platform for developing bots for its instant messenger.
In this article I want to share the experience of developing a chat bot for Facebook in PHP.

general information


Chat bots on Facebook are based on private messages with a public page on behalf of the user.
Therefore, to create a bot, you will need to create the application itself to access the API, and a public page with which users will communicate.

Creating a page


I will not elaborate on this point.
Just create a public page, call it the way we want to see in our bot messenger, and load the icon.

Register and configure the application


We proceed to register your application in the developer account.
Follow the link developers.facebook.com/apps
Click on adding a new application, choose another setting manually:
')


Next, fill out the form:



After creating the application, in the left menu, select the Messenger tab and click on it.
Click "Start."
First of all, select the page created for the bot, and copy the token. We save it somewhere, it is useful to us further.



Next we will configure the webhook to handle incoming messages.
At this step, you need to upload the following script to the server where the bot will be located:

<?php $verify_token = ""; // Verify token if (!empty($_REQUEST['hub_mode']) && $_REQUEST['hub_mode'] == 'subscribe' && $_REQUEST['hub_verify_token'] == $verify_token) { echo $_REQUEST['hub_challenge']; } 

You need to add some text to the $ verify_token variable.
The script is uploaded to the server. Suppose our script is available at: domain.com/fbbot

Go back to the Messenger tab in the FB application settings.
We are looking for the “Webhooks” block and the “Setup Webhooks” button. Click on it.

In the field "Return URL" we indicate the address of our bot - domain.com/fbbot
SSL - certificate is required. A self-signed certificate will not work.

In the field “Confirm token” we specify the text that was specified in the $ verify_token variable in the script.
In the field "Subscription fields" choose which notifications we want to receive on our webhook:

We select the necessary ones and click the button “Confirm and save”.

We connect application and page


We type in the console:

 curl -ik -X POST "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=-token-" 

-token- replace the token of your page.

Message Types in FB Messenger


Messages can be either plain text or Structured Text, which in turn can be:

Buttons (button)


This type is designed to send messages that require user response.
They look like this:


The buttons can be of two types:
  1. Sending the answer to the bot
  2. Going to an Internet address

Important point: in one such message there can be a maximum of 3 buttons, when you try to send a message with a large number of buttons - it simply will not reach the recipient.

Elements (generic)


This type is intended for sending cards of goods or other elements having a similar structure.
Each element can have: Title, subtitle, description, image and buttons.


In a single message can contain up to 10 elements. If there is more than one item, horizontal scrolling appears.
Important point: in one such message there can be a maximum of 3 buttons, when you try to send a message with a large number of buttons - it simply will not reach the recipient.

Invoice for payment (receipt)


Purpose is clear from the title.
Facebook decided to make a full-fledged store out of its messenger.
The invoice for payment may contain information about the goods, cost, payment, shipping address, discounts.


Important point: the account number must be unique.

Write the code


At the time of writing the bot, GitHub was not yet implementing the API for PHP, so I had to write the PHP SDK myself.

Install the PHP SDK to work with the FB Messenger API using composer:
 composer require "pimax/fb-messenger-php" "dev-master" 

Create an index.php file:
 <?php $verify_token = ""; // Verify token $token = ""; // Page token if (file_exists(__DIR__.'/config.php')) { $config = include __DIR__.'/config.php'; $verify_token = $config['verify_token']; $token = $config['token']; } require_once(dirname(__FILE__) . '/vendor/autoload.php'); use pimax\FbBotApp; use pimax\Messages\Message; use pimax\Messages\MessageButton; use pimax\Messages\StructuredMessage; use pimax\Messages\MessageElement; use pimax\Messages\MessageReceiptElement; use pimax\Messages\Address; use pimax\Messages\Summary; use pimax\Messages\Adjustment; $bot = new FbBotApp($token); if (!empty($_REQUEST['hub_mode']) && $_REQUEST['hub_mode'] == 'subscribe' && $_REQUEST['hub_verify_token'] == $verify_token) { // Webhook setup request echo $_REQUEST['hub_challenge']; } else { $data = json_decode(file_get_contents("php://input"), true); if (!empty($data['entry'][0]['messaging'])) { foreach ($data['entry'][0]['messaging'] as $message) { //   //       // ... } } } 

We try to send a message to the user in response when we receive any message from him.
To do this, in the block receiving the message, add:
 $bot->send(new Message($message['sender']['id'], 'Hi there!')); 


We are checking. We find in the messenger of our bot and try to send him any message.
In response, we should receive from him "Hi there!".
Important: Until the application has passed moderation, the bot will work only for the author of the application.

If everything works as it should, go ahead.

Add to the block receiving the message:
 //       if (!empty($message['delivery'])) { continue; } $command = ""; //    ,    if (!empty($message['message'])) { $command = $message['message']['text']; //     ,    } else if (!empty($message['postback'])) { $command = $message['postback']['payload']; } //   switch ($command) { // When bot receive "text" case 'text': $bot->send(new Message($message['sender']['id'], 'This is a simple text message.')); break; // When bot receive "button" case 'button': $bot->send(new StructuredMessage($message['sender']['id'], StructuredMessage::TYPE_BUTTON, [ 'text' => 'Choose category', 'buttons' => [ new MessageButton(MessageButton::TYPE_POSTBACK, 'First button'), new MessageButton(MessageButton::TYPE_POSTBACK, 'Second button'), new MessageButton(MessageButton::TYPE_POSTBACK, 'Third button') ] ] )); break; // When bot receive "generic" case 'generic': $bot->send(new StructuredMessage($message['sender']['id'], StructuredMessage::TYPE_GENERIC, [ 'elements' => [ new MessageElement("First item", "Item description", "", [ new MessageButton(MessageButton::TYPE_POSTBACK, 'First button'), new MessageButton(MessageButton::TYPE_WEB, 'Web link', 'http://facebook.com') ]), new MessageElement("Second item", "Item description", "", [ new MessageButton(MessageButton::TYPE_POSTBACK, 'First button'), new MessageButton(MessageButton::TYPE_POSTBACK, 'Second button') ]), new MessageElement("Third item", "Item description", "", [ new MessageButton(MessageButton::TYPE_POSTBACK, 'First button'), new MessageButton(MessageButton::TYPE_POSTBACK, 'Second button') ]) ] ] )); break; // When bot receive "receipt" case 'receipt': $bot->send(new StructuredMessage($message['sender']['id'], StructuredMessage::TYPE_RECEIPT, [ 'recipient_name' => 'Fox Brown', 'order_number' => rand(10000, 99999), 'currency' => 'USD', 'payment_method' => 'VISA', 'order_url' => 'http://facebook.com', 'timestamp' => time(), 'elements' => [ new MessageReceiptElement("First item", "Item description", "", 1, 300, "USD"), new MessageReceiptElement("Second item", "Item description", "", 2, 200, "USD"), new MessageReceiptElement("Third item", "Item description", "", 3, 1800, "USD"), ], 'address' => new Address([ 'country' => 'US', 'state' => 'CA', 'postal_code' => 94025, 'city' => 'Menlo Park', 'street_1' => '1 Hacker Way', 'street_2' => '' ]), 'summary' => new Summary([ 'subtotal' => 2300, 'shipping_cost' => 150, 'total_tax' => 50, 'total_cost' => 2500, ]), 'adjustments' => [ new Adjustment([ 'name' => 'New Customer Discount', 'amount' => 20 ]), new Adjustment([ 'name' => '$10 Off Coupon', 'amount' => 10 ]) ] ] )); break; // Other message received default: $bot->send(new Message($message['sender']['id'], 'Sorry. I don't understand you.')); } 

We try to send the bot messages:

If everything is done according to the instructions, then you should receive all types of messages in the messenger.

A real example of Bota for Job4Joy freelance exchange


So, our goal is to implement a bot, which, at our request, will issue new projects in the appropriate category.
Data will be received via RSS using picoFeed - github.com/fguillot/picoFeed

We carry out:
 composer require fguillot/picofeed @stable composer require "pimax/fb-messenger-php" "dev-master" 

Create an index.php file with the following content (comments are given in the code):
 <?php $verify_token = ""; // Verify token $token = ""; // Page token $config = []; // config if (file_exists(__DIR__.'/config.php')) { $config = include __DIR__.'/config.php'; $verify_token = $config['verify_token']; $token = $config['token']; } require_once(dirname(__FILE__) . '/vendor/autoload.php'); use PicoFeed\Reader\Reader; use pimax\FbBotApp; use pimax\Messages\Message; use pimax\Messages\MessageButton; use pimax\Messages\StructuredMessage; use pimax\Messages\MessageElement; $bot = new FbBotApp($token); if (!empty($_REQUEST['hub_mode']) && $_REQUEST['hub_mode'] == 'subscribe' && $_REQUEST['hub_verify_token'] == $verify_token) { // Webhook setup request echo $_REQUEST['hub_challenge']; } else { $data = json_decode(file_get_contents("php://input"), true); if (!empty($data['entry'][0]['messaging'])) { foreach ($data['entry'][0]['messaging'] as $message) { if (!empty($data['entry'][0])) { if (!empty($data['entry'][0]['messaging'])) { foreach ($data['entry'][0]['messaging'] as $message) { if (!empty($message['delivery'])) { continue; } $command = ""; if (!empty($message['message'])) { $command = $message['message']['text']; } else if (!empty($message['postback'])) { $command = $message['postback']['payload']; } if (!empty($config['feeds'][$command])) { getFeed($config['feeds'][$command], $bot, $message); } else { sendHelpMessage($bot, $message); } } } } } } } /** * Send Help Message * * @param $bot Bot instance * @param array $message Received message * @return bool */ function sendHelpMessage($bot, $message) { $bot->send(new StructuredMessage($message['sender']['id'], StructuredMessage::TYPE_BUTTON, [ 'text' => 'Choose category', 'buttons' => [ new MessageButton(MessageButton::TYPE_POSTBACK, 'All jobs'), new MessageButton(MessageButton::TYPE_POSTBACK, 'Web Development'), new MessageButton(MessageButton::TYPE_POSTBACK, 'Software Development & IT') ] ] )); $bot->send(new StructuredMessage($message['sender']['id'], StructuredMessage::TYPE_BUTTON, [ 'text' => ' ', 'buttons' => [ new MessageButton(MessageButton::TYPE_POSTBACK, 'Design & Multimedia'), new MessageButton(MessageButton::TYPE_POSTBACK, 'Mobile Application'), new MessageButton(MessageButton::TYPE_POSTBACK, 'Host & Server Management') ] ] )); $bot->send(new StructuredMessage($message['sender']['id'], StructuredMessage::TYPE_BUTTON, [ 'text' => ' ', 'buttons' => [ new MessageButton(MessageButton::TYPE_POSTBACK, 'Writing'), new MessageButton(MessageButton::TYPE_POSTBACK, 'Mobile Application'), new MessageButton(MessageButton::TYPE_POSTBACK, 'Marketing') ] ] )); $bot->send(new StructuredMessage($message['sender']['id'], StructuredMessage::TYPE_BUTTON, [ 'text' => ' ', 'buttons' => [ new MessageButton(MessageButton::TYPE_POSTBACK, 'Business Services'), new MessageButton(MessageButton::TYPE_POSTBACK, 'Translation & Languages') ] ] )); return true; } /** * Get Feed Data * * @param $url Feed url * @param $bot Bot instance * @param $message Received message * @return bool */ function getFeed($url, $bot, $message) { try { $reader = new Reader; $resource = $reader->download($url); $parser = $reader->getParser( $resource->getUrl(), $resource->getContent(), $resource->getEncoding() ); $feed = $parser->execute(); $items = array_reverse($feed->getItems()); if (count($items)) { foreach ($items as $itm) { $url = $itm->getUrl(); $message_text = substr(strip_tags($itm->getContent()), 0, 80); $bot->send(new StructuredMessage($message['sender']['id'], StructuredMessage::TYPE_GENERIC, [ 'elements' => [ new MessageElement($itm->getTitle(), $message_text, '', [ new MessageButton(MessageButton::TYPE_WEB, 'Read more', $url) ]), ] ] )); } } else { $bot->send(new Message($message['sender']['id'], 'Not found a new projects in this section.')); } } catch (Exception $e) { writeToLog($e->getMessage(), 'Exception'); } return true; } /** * Log * * @param mixed $data Data * @param string $title Title * @return bool */ function writeToLog($data, $title = '') { $log = "\n------------------------\n"; $log .= date("Ymd G:i:s") . "\n"; $log .= (strlen($title) > 0 ? $title : 'DEBUG') . "\n"; $log .= print_r($data, 1); $log .= "\n------------------------\n"; file_put_contents(__DIR__ . '/imbot.log', $log, FILE_APPEND); return true; } 


And the config.php file is as follows:
 <?php return [ 'token' => '', //   'verify_token' => '', //   'feeds' => [ 'All jobs' => 'https://job4joy.com/marketplace/rss/', 'Web Development' => 'https://job4joy.com/marketplace/rss/?id=3', 'Software Development & IT' => 'https://job4joy.com/marketplace/rss/?id=5', 'Design & Multimedia' => 'https://job4joy.com/marketplace/rss/?id=2', 'Mobile Application' => 'https://job4joy.com/marketplace/rss/?id=7', 'Host & Server Management' => 'https://job4joy.com/marketplace/rss/?id=6', 'Writing' => 'https://job4joy.com/marketplace/rss/?id=8', 'Customer Service' => 'https://job4joy.com/marketplace/rss/?id=10', 'Marketing' => 'https://job4joy.com/marketplace/rss/?id=11', 'Business Services' => 'https://job4joy.com/marketplace/rss/?id=12', 'Translation & Languages' => 'https://job4joy.com/marketplace/rss/?id=14', ] ]; 


Publication in the directory for all


While the bot is available only to the owner of the account. For a bot to be accessible to everyone, you need On the App Review page, publish the application:



After that, you need to request moderation messenger. To do this, go to the tab - Messenger.
In the “App Review for Messenger” block, click the “Request Permissions” button.
In the window that appears, select "pages_messaging" and click "Add items".

Now it remains only to wait for moderation.

At the time of this writing, the moderation of our first bot has not been completed, although more than two working days have passed since the application was submitted.

Conclusion


In this article, we looked at the basic aspects of creating a chat bot for Facebook.
If the topic turns out to be popular, then I will be ready to talk about the experience of developing bots for other popular messengers.

useful links


  1. Getting Started with FB Chatbots - developers.facebook.com/docs/messenger-platform/quickstart
  2. Web hook Reference - developers.facebook.com/docs/messenger-platform/webhook-reference
  3. FB Messenger PHP API - github.com/pimax/fb-messenger-php
  4. PHP API usage examples - github.com/pimax/fb-messenger-php-example
  5. Job4Joy FB Bot - github.com/pimax/job4joy_fb

Source: https://habr.com/ru/post/281559/


All Articles