Desenvolvimento de chatbot para o Facebook Messenger no node.js

O material, cuja tradução apresentamos hoje à sua atenção, é dedicado ao desenvolvimento de um bot de bate-papo para o Facebook Messenger. Um bot chamado Aww Bot, que se comunica com os usuários, envia fotos de gatos e cachorros fofos.



Introdução


Vamos começar criando uma página no Facebook preenchendo os campos obrigatórios. Esta página é para o bot. Além disso, criaremos um aplicativo do Facebook, após o qual, na página Adicionar um produto, conectaremos o produto Messenger ao aplicativo. Em seguida, nos encontraremos na página de configurações do messenger. Aqui você precisa encontrar a seção Geração de token - selecione a página do bot na lista Página. Depois disso, seremos questionados sobre permissões e um token de acesso será criado. O bot usará esse token para fazer chamadas para a API do Facebook Messenger, o que permitirá que ele se comunique com os usuários.

Configuração do servidor da Web


Usaremos node.js e express.js para criar um servidor HTTP. Execute o seguinte comando:

npm install express body-parser request config --save 

Adicione o seguinte código ao index.js que permite criar um servidor HTTP simples:

 'use strict'; let express = require('express'),   bodyParser = require('body-parser'),   app = express(); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.listen(8989, () => console.log('Example app listening on port 8989!')); app.get('/', (req, res) => res.send('Hello World!')); 

Agora, se você iniciar o servidor e continuar usando o navegador em http://127.0.0.1:8989 , verá uma página com a resposta do servidor - Hello World! .

HTTPS e o ambiente de desenvolvimento local


Antes de passar para a tecnologia Webhook, precisamos configurar o HTTPS para o ambiente de desenvolvimento. O messenger não aceitará o endereço Webhook usado para enviar notificações ao nosso servidor se você usar um certificado SSL autoassinado. Um certificado gratuito está disponível no Let's Encrypt . Aqui, no entanto, você pode obter um certificado apenas para um domínio e não para um endereço IP. Usaremos o serviço ngrok , que permitirá organizar o acesso ao servidor local por meio de uma URL pública que usa HTTPS.

Configuração do Ngrok


ngrok fácil. Você só precisa baixar o arquivo compactado do site do projeto, descompactá-lo e executar o seguinte comando:

 ./ngrok http 80 

Lembre-se de redirecionar a porta 80 para 8989 nas configurações de WAN do seu roteador. Como resultado, o ngrok criará endereços HTTP e HTTPS públicos para o servidor local.

Trabalhando com notificações do Webhook


O messenger usa a tecnologia Webhook para autenticação e para enviar notificações sobre eventos ao seu aplicativo. Do ponto de vista da programação, tudo isso se resume às funções usuais de retorno de chamada para processar solicitações HTTP que receberão dados sobre eventos, como mensagens recebidas pelo chatbot. Para analisar solicitações GET e POST, usaremos o módulo body-parser .

Adicione a seguinte rota ao aplicativo. É necessário para processar solicitações de verificação do Webhook.

 //   GET-  webhook app.get('/webhook', (req, res) => {   //  .    ,       let VERIFY_TOKEN = "SOMETHING_RANDOM";   //      let mode = req.query['hub.mode'];   let token = req.query['hub.verify_token'];   let challenge = req.query['hub.challenge'];   // ,     mode  token   if (mode && token) {       //   mode  token       if (mode === 'subscribe' && token === VERIFY_TOKEN) {           //   challenge             console.log('WEBHOOK_VERIFIED');           res.status(200).send(challenge);       } else {           //   '403 Forbidden'                res.sendStatus(403);       }   } }); 

Agora você precisa abrir as configurações do messenger, encontrar a seção Webhooks lá e configurar a integração do aplicativo com as notificações do Webhook. Na página de configurações, no campo URL de retorno de chamada, insira nosso URL HTTPS recebido do ngrok. O token de verificação (aquele que está presente no código e representa uma sequência aleatória que criamos) deve ser colocado no campo Verify Token. Depois disso, você poderá verificar e salvar as configurações clicando no botão Verificar e Salvar se o seu URL para processar notificações do Webhook estiver disponível e o token de verificação corresponder ao do código.


Configure o token e o URL para o aplicativo receber notificações do Webhook

Após salvar, selecione sua página na lista suspensa e assine os eventos da página.

Agora crie uma rota POST para manipular eventos POST do messenger. Adicione o seguinte código ao aplicativo.

 //     webhook app.post('/webhook', (req, res) => {   let body = req.body;   if (body.object === 'page') {       // ,               body.entry.forEach(function(entry) {           //  entry.messaging  ,            //     ,    0           let webhook_event = entry.messaging[0];           console.log(webhook_event);           //  PSID            let sender_psid = webhook_event.sender.id;           console.log('Sender PSID: ' + sender_psid);           //  ,  , message   postback,           //     -           if (webhook_event.message) {               console.log(webhook_event.message)           } else if (webhook_event.postback) {               console.log(webhook_event.postback)           }       });       //  '200 OK'            res.status(200).send('EVENT_RECEIVED');   } else {       //  '404 Not Found',      ,           res.sendStatus(404);   } }); 

Configuramos o aplicativo para que ele lide com dois tipos de eventos - message e postback . Para verificar o funcionamento do mecanismo de notificação do Webhook, abra o messenger e envie uma mensagem para a página bot. Se tudo funcionar como deveria, o PSID do remetente, as informações do evento e o conteúdo da mensagem serão registrados. Agora vamos escrever funções de manipulador para os eventos de seu interesse.

 //   message const handleMessage = (sender_psid, received_message) => {   let response;   if (received_message.text) {   } } //   postback const handlePostback = (sender_psid, received_postback) => {   let response;   //    postback   let payload = received_postback.payload;   if(payload === 'GET_STARTED'){   } } 

O método handleMessage() é responsável pelo processamento de mensagens recebidas e o método handlePostback() é handlePostback() pelo processamento de eventos de postback recebidos. Atualize seu código existente adicionando chamadas a estes métodos:

 //   //     - if (webhook_event.message) {   handleMessage(sender_psid, webhook_event.message); } else if (webhook_event.postback) {   handlePostback(sender_psid, webhook_event.postback); } 

Agora, quando recebermos postback message ou postback , os dados serão transmitidos para os manipuladores correspondentes, juntamente com o PSID do remetente.

Configurando a tela de boas-vindas e os eventos de postagem para iniciar um diálogo com o bot


Quando um novo usuário inicia uma conversa com o bot, o botão Introdução é exibido na janela de bate-papo. Você pode configurar seu próprio evento de postagem para esta situação. Por exemplo, defina uma mensagem para um usuário que descreva o bot e como se comunicar com ele. Para configurar sua própria saudação, execute este comando curl no terminal:

 curl -X POST -H "Content-Type: application/json" -d '{ "greeting": [   {     "locale":"default",     "text":"Hello {{user_first_name}}! Are you ready to see the cutests cats and dogs"   } ] }' "https://graph.facebook.com/v2.6/me/messenger_profile?access_token=YOUR_PAGE_ACCESS_TOKEN" 

Montamos o Aww Bot para exibir uma mensagem perguntando ao usuário se ele está pronto para ver os cães e gatos mais fofos. Para configurar o evento de postagem, execute este comando no terminal:

 curl -X POST -H "Content-Type: application/json" -d '{ "get_started": {"payload": "GET_STARTED"} }' "https://graph.facebook.com/v2.6/me/messenger_profile?access_token=YOUR_PAGE_ACCESS_TOKEN" 

Aqui está a aparência da sessão de bate-papo com o bot.


Tela de introdução

Configuração do aplicativo


Usaremos o módulo de configuração npm para armazenar o token de acesso à página em um arquivo de configuração separado. Crie o diretório config em nosso projeto e o arquivo default.json nele. Nesse arquivo, você precisa adicionar o token de acesso à página e registrar esse arquivo em .gitignore .

 { "facebook": {   "page": {     "access_token": "PAGE_ACCESS_TOKEN"   } } } 

callSendAPI() o token de acesso à página no método callSendAPI() usando o comando config.get('facebook.page.access_token') .

Manipulando um Evento Inicial


Aqui está o código de manipulação de eventos de início.

 const handlePostback = (sender_psid, received_postback) => {   let response;   //   postback-   let payload = received_postback.payload;   if(payload === 'GET_STARTED'){       response = askTemplate('Are you a Cat or Dog Person?');       callSendAPI(sender_psid, response);   } } 

Vamos criar o método askTemplate() , que retornará um objeto de resposta preparado corretamente para a API do messenger. O método callSendAPI() enviará uma mensagem ao usuário. Adicione os seguintes métodos ao aplicativo:

 const askTemplate = (text) => {   return {       "attachment":{           "type":"template",           "payload":{               "template_type":"button",               "text": text,               "buttons":[                   {                       "type":"postback",                       "title":"Cats",                       "payload":"CAT_PICS"                   },                   {                       "type":"postback",                       "title":"Dogs",                       "payload":"DOG_PICS"                   }               ]           }       }   } } //     API Send const callSendAPI = (sender_psid, response, cb = null) => {   //      let request_body = {       "recipient": {           "id": sender_psid       },       "message": response   };   //  HTTP-  Messenger Platform   request({       "uri": "https://graph.facebook.com/v2.6/me/messages",       "qs": { "access_token": config.get('facebook.page.access_token') },       "method": "POST",       "json": request_body   }, (err, res, body) => {       if (!err) {           if(cb){               cb();           }       } else {           console.error("Unable to send message:" + err);       }   }); } 

Enviamos ao usuário uma mensagem contendo dois botões e texto. Quando o usuário seleciona o que ele precisa clicando no botão apropriado, uma solicitação será enviada ao nosso endereço Webhook com os dados do evento de postback e nós a processaremos.


O usuário é solicitado a selecionar o tipo de imagem que lhe interessa.

Manipulação de eventos de postagem personalizados


Atualize o código da função do manipulador de eventos de postagem:

 const handlePostback = (sender_psid, received_postback) => {   let response;   //   postback-   let payload = received_postback.payload;   //  ,       if (payload === 'CAT_PICS') {       response = imageTemplate('cats', sender_psid);       callSendAPI(sender_psid, response, function(){           callSendAPI(sender_psid, askTemplate('Show me more'));       });   } else if (payload === 'DOG_PICS') {       response = imageTemplate('dogs', sender_psid);       callSendAPI(sender_psid, response, function(){           callSendAPI(sender_psid, askTemplate('Show me more'));       });   } else if(payload === 'GET_STARTED'){       response = askTemplate('Are you a Cat or Dog Person?');       callSendAPI(sender_psid, response);   }   //   } 

Quando o usuário clica no botão Cats , uma solicitação com um evento de postback com dados CAT_PICS será CAT_PICS ao nosso endereço usado para processar as notificações do Webhook. A escolha da opção Dogs enviará um evento de postback com dados DOG_PICS . Adicionamos outro método ao sistema, imageTemplate() , que retorna uma mensagem contendo um link para a imagem de um gato ou cachorro.

Crie uma API simples que retorne links de imagem


Escreveremos uma API simples para retornar links para imagens de gatos ou cães que serão usados ​​em mensagens enviadas pelo bot aos usuários. Crie um arquivo pics.js e adicione o seguinte código:

 module.exports = {   cats : [       'https://i.imgur.com/Qbg7CeM.jpg',       'https://i.imgur.com/nUzkpJY.jpg',       'https://i.imgur.com/NpDcKph.jpg',       'https://i.imgur.com/oJtSDaO.jpg',       'https://i.redd.it/82ajpsrd17111.jpg',       'https://i.redd.it/00km1d2rt0111.jpg',       'https://i.redd.it/rdbavhp0y7111.jpg',       'https://i.redd.it/5hn3mg0n98111.jpg',       'https://i.redd.it/d23pb8mta6111.jpg',       'https://i.redd.it/d2gyrwgy7oz01.jpg',       'https://i.redd.it/z4sgl84q72z01.jpg',       'https://i.redd.it/wvykzo8n1cy01.jpg'   ],   dogs : [       'https://i.redd.it/6tjihi2qe7111.jpg',       'https://i.imgur.com/etRCs56.jpg',       'https://i.redd.it/nibw50f8y4111.jpg',       'https://i.redd.it/izcvnvj1o7111.jpg',       'https://i.redd.it/eqs1g9dldz011.jpg',       'https://i.redd.it/civ9dnu9u1111.jpg',       'https://i.redd.it/kk03qwclkp011.jpg',       'https://i.redd.it/2694pupjne011.jpg',       'https://i.redd.it/qk49ls5y6oy01.jpg',       'https://i.imgur.com/oM3mKgB.jpg',       'https://i.redd.it/8kx2riaulux01.jpg'   ] }; 

Agora conecte-o no aplicativo.

 images = require('./pics'); 

Adicione o seguinte método ao código usado para compor uma mensagem contendo um link para a imagem.

 const = imageTemplate(type, sender_id) => {   return {       "attachment":{           "type":"image",           "payload":{               "url": getImage(type, sender_id),               "is_reusable":true           }       }   } } 

No processo de interação do usuário com o bot, as imagens são extraídas seqüencialmente da matriz e enviadas como respostas do bot ao usuário. Depois de enviar a última imagem, retornamos ao topo da lista.

Adicionamos o código a seguir ao projeto, projetado para armazenar e processar dados sobre usuários que se comunicam com o bot.

 let users = {}; const = getImage(type, sender_id) => {   //       -     if(users[sender_id] === undefined){       users = Object.assign({           [sender_id] : {               'cats_count' : 0,               'dogs_count' : 0           }       }, users);   }   let count = images[type].length, //            user = users[sender_id], // ,         user_type_count = user[type+'_count'];   //          let updated_user = {       [sender_id] : Object.assign(user, {           [type+'_count'] : count === user_type_count + 1 ? 0 : user_type_count + 1       })   };   //      users = Object.assign(users, updated_user);   console.log(users);   return images[type][user_type_count]; } 

Armazenamos o PSID de cada usuário que se comunica com o bot como uma chave no objeto de users . Se ainda não houver um registro do usuário, crie um novo registro. Atualizaremos as informações do número da imagem sempre que um usuário solicitar uma foto de um gato ou cachorro. Em seguida, retornamos o caminho absoluto para a imagem que será usada no modelo de mensagem. Em seguida, enviamos uma mensagem com a imagem na forma de uma resposta ao evento de postback gerado quando o usuário seleciona o tipo de imagem que lhe interessa.

 //  ,    postback- if (payload === 'CAT_PICS') {   response = imageTemplate('cats', sender_psid);   callSendAPI(sender_psid, response, function(){       callSendAPI(sender_psid, askTemplate('Show me more'));   }); } else if (payload === 'DOG_PICS') {   response = imageTemplate('dogs', sender_psid);   callSendAPI(sender_psid, response, function(){       callSendAPI(sender_psid, askTemplate('Show me more'));   }); } else if(payload === 'GET_STARTED'){   response = askTemplate('Are you a Cat or Dog Person?');   callSendAPI(sender_psid, response); } 

Além disso, após enviar a imagem, passamos uma função de retorno de chamada para o método callSendAPI() para enviar ao usuário uma nova pergunta sobre em quais imagens ele está interessado. Se for bem-sucedido, chamamos essa função. Esse esquema de trabalho, levando em consideração a natureza assíncrona das funções de retorno de chamada, permite que o usuário receba uma mensagem com uma pergunta sobre a próxima imagem depois que uma mensagem lhe foi enviada com a imagem solicitada anteriormente.


Comunicação com o bot

Sumário


Aqui está o repositório para este projeto. Lá, no arquivo readme.md , você encontra instruções para instalar e configurar o bot. Para que outras pessoas conversem com seu bot, seu aplicativo do Facebook deve ser aprovado. Até esse ponto, apenas administradores e testadores do seu aplicativo poderão conversar com o bot. Aqui está um vídeo demonstrando o processo de comunicação com o bot.

Caros leitores! Você está planejando criar bots para o Facebook Messenger?

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


All Articles