Creare un Bot per Messenger in Node.js

C

Scriviamo un bot

In questi ultimi periodi ormai non si fa altro che parlare di intelligenza artificiale. Film e serie TV più o meno realistiche (alcune molto meno) che spopolano come non mai, scarabocchi con su scritto “machine learning” e “intelligenza artificiale” che si trovano anche nei bagni degli autogrill e una quantità indescrivibile di applicazioni (bot compresi) creati per facilitare e/o automatizzare determinate funzioni.
A seconda di come vengono scritti e di quali tecnologie si utilizzano, anche i chat-bot (da qui in poi scriverò soltanto “bot”) possono essere più “intelligenti” o meno, ma saranno sempre dotati di un’intelligenza artificiale basilare (basandomi su questa definizione di IA).
Scopriamo quindi in questo articolo come crearne uno per Messenger (la chat di Facebook) in Node.js.

Tutto il codice mostrato in quest’articolo sarà disponibile nel mio profilo Github: nodejs-facebook-bot.
Se in qualche modo vi ho aiutati o il codice vi è stato utile, vi chiedo di mettere una stellina!

  1. Bot, questi sconosciuti
  2. Usiamo librerie o no?
  3. Configurare una facebook app
  4. Ngrok
  5. Scriviamo il nostro bot
  6. Capiamo il codice
  7. Parliamo con il nostro bot

 

bot, questi sconosciuti

Nonostante il titolo chiaramente ironico, presumo che tutti voi conoscano i bot e moltissimi di voi li avranno anche usati su qualche piattaforma (telegram, facebook, slack ecc.).
Voglio però dargli una definizione più o meno fissata per ragionarci insieme e affrontare la questione da un determinato punto di vista che ci fornirà da introduzione per l’implementazione del codice.

Specificato un protocollo di comunicazione, un bot è un programma che a determinate richieste, produce determinate risposte.

Non è importante come o quando queste richieste arrivano, ma specificato un protocollo, le si ricevono e si danno indietro delle risposte… vi è familiare questo concetto con qualcos’altro che alcuni di voi già sono abituati a sviluppare?
Stiamo parlando sostanzialmente di un web server.

Usiamo librerie o no?

Sapendo quindi che la nostra applicazione non è nient’altro che un web server, le strade su cui lo sviluppo può proseguire sono due:

  1. Ci si crea a mano con express (o altri framework) un server che si interfacci con le API di Facebook.
  2. Si utilizza una libreria che fa già quanto scritto al punto 1 e che va configurata e implementata con la logica che vogliamo inserire.

A questo punto tocchiamo un argomento molto spesso dibattuto: conviene scrivere autonomamente codice o utilizzare librerie già pronte?
Dal mio punto di vista, e per esperienza personale, posso dirvi che:

Scrivere del codice autonomamente che fungerà da base per tutto il codice che verrà scritto dopo (che è il codice per cui realmente stiamo lavorando) non è una grande idea, neanche se siete i più bravi programmatori del mondo e se lo siete, non c’è bisogno che vi dia questo consiglio perché lo state già seguendo.*

Del tipo: voglio creare un videogioco e mi creo anche il motore grafico, voglio creare una web app e mi creo un framework per la gestione della UI. Questi sono tutti esempi sbagliati per almeno una dozzina di motivi, uno tra tutti è che “n” teste non saranno mai meglio di “n mila teste”. Considerate un progetto su Github con più di 4000 star, il codice che vedete li dentro è:

  • Controllato e ricontrollato da migliaia di utenti che si pongono i problemi più disparati e si impegnano per risolverli.
  • Testato in quanto quel codice è già presente in altri progetti (a volte anche molto grandi).

E via discorrendo.

* Un piccolo appunto: questa regola ha ovviamente delle eccezioni. Direi che vale per il 99% dei casi, ma in alcuni ambiti e in alcuni casi ci sono dei buoni motivi per cui è giusto scrivere del codice a mano ed evitare librerie esterne.

Configurare una facebook app

Questi step sono necessari per ottenere una chiave API da poter utilizzare per metterci in comunicazione con i server di Facebook. Considerate che per creare un bot c’è bisogno di creare anche una pagina alla quale il bot si collegherà. Cominciamo:

  1. Aprite la pagina delle vostre facebook app
    Facebook apps
    Facebook apps
  2. Cliccate su “Aggiungi una nuova app”
  3. Inserite i vostri dati nei campi “Nome visualizzato” e “Indirizzo e-mail di contatto”
    Creazione dell'app
    Creazione dell’app
  4. Entrerete in una schermata dove potrete aggiungere i prodotti di facebook alla tua app. Per il nostro bot necessitiamo soltanto di “Messenger”, clicchiamo quindi sul bottone “Configura”
  5. Nel campo “Generazione di token” clicchiamo su “Crea una nuova pagina”
    Generazione token
    Generazione token
  6. Una volta fatto, sempre sotto il campo “Generazione token“, colleghiamo la nostra applicazione alla pagina che abbiamo creato (confermando i permessi) e vedremo che Facebook ci fornirà un token d’accesso alla pagina, mettetelo da parte.
    Page Token
    Page Token
  7. Cliccate sulla dicitura “Dashboard” nel menu di sinistra e prendete nota della chiave segreta (bisogna cliccare su mostra e inserire la password). Ora sempre dal menu di sinistra, cliccate su “Messenger” per tornare dov’eravate prima.
    App Secret
    App Secret
  8. Nella scheda sottostante “Webhooks“, clicchiamo su “Configura webhooks” e sotto “Campi relativi all’iscrizione” spuntiamo le seguenti voci: message_deliveries, messaging_optins, messaging_postbacks, messages.
    Events subscribe
    Events subscribe

    Sostanzialmente stiamo definendo per quali eventi vogliamo che i server di facebook ci notifichino. Per una lista e conseguenti spiegazioni esaustive sui singoli, ricorriamo alla documentazione ufficiale di Facebook.

  9. Nel campo “Token di verifica“, inseriamo una stringa (suggerisco: VERIFY_TOKEN come vedete dall’immagine in sopra) che servirà per certificare la proprietà dell’applicazione il cui URL di deploy sarà inserito nel campo “URL di callback” una volta che questo sarà configurato (nel prossimo paragrafo).
    Vi consiglio quindi di lasciare la pagina web aperta perché passeremo i prossimi 15 minuti a configurare l’URL e a scrivere una parte iniziale del codice.

NGrok

Facebook, per mettersi in contatto con la nostra applicazione, utilizza un sistema basato su “webhooks“.
Esistono generalmente due modi fondamentali per sviluppare bot su delle piattaforme (Facebook, Telegram ecc.)*:

  1. Aspettare che la piattaforma notifichi dei cambiamenti alla nostra applicazione dopo avergli fornito l’URL su cui quest’ultima risiede e farla reagire di conseguenza.
  2. Costruire la nostra applicazione in modo da chiamare i server della piattaforma ad intervalli regolari per verificare se ci sono novità a cui reagire

La prima tecnica dev’essere chiaramente prevista dai server della piattaforma su cui stiamo sviluppando il nostro bot ed è la più efficiente per ambedue le parti (noi che non dobbiamo effettuare richieste ogni “n secondi” e loro che avranno meno carico sui server) ed è generalmente definita nelle documentazioni come “webhook”.
La seconda invece è quella che possiamo definire come la più base in termini di implementazione ed esosa in termini di risorse. La si trova nelle documentazioni definita generalmente come “long polling”.

Facebook, come avrete capito dalle impostazioni che stiamo settando, utilizza delle webhooks. Come faremo quindi a ottenere un URL della nostra applicazione per far si che Facebook possa avvisarci al verificarsi di eventi (ad esempio un utente che invia un messaggio al nostro bot) se faremo girare la nostra app in localhost?
Ciò che possiamo fare è creare un tunnel tra un dominio aperto e disponibile in rete verso la nostra macchina e che renda quindi pubblica la nostra app.
L’utility che fa tutto questo è ngrok.

Scaricatelo dal link che ho appena inserito e avviatelo da terminale dando questo comando:

./ngrok http 3200

Ciò che farà sarà rendere raggiungibile da chiunque nella rete (compresi i server di Facebook) il nostro caro “localhost” alla porta 3200 attraverso un dominio temporaneo fornito da ngrok. La risposta al comando sarà una cosa del genere:

ngrok
ngrok

Ora, prima di copiare l’URL che trovate di seguito al secondo forwarding (l’https) e darlo in pasto al form della configurazione del nostro bot, dobbiamo comunicargli in qualche modo che siamo proprio noi ad essere i proprietari dell’applicazione che sta girando a quel dominio. Lo facciamo nel paragrafo a seguire.

* Ovviamente tecniche del genere non vengono impiegate esclusivamente nello sviluppo di bot, ma trovano ampio spazio d’utilizzo in diversi ambiti.

scriviamo il nostro bot

Iniziamo quindi a mettere le mani in pasta. Prendiamo il nostro bel terminale e inizializziamo un progetto con npm:

mkdir nodejs-facebook-bot
cd nodejs-facebook-bot
npm init

Configurate il package.json come più preferite. Dopodiché installiamo la libreria che ci permetterà di interfacciarci molto velocemente con le API di facebook come dicevamo poco sopra. Questa è la repo della libreria, scarichiamola:

npm install messenger-bot

E avviamo il nostro editor/IDE di preferenza per scrivere del codice javascript da eseguire (useremo una versione leggermente modificata del codice di esempio che fornisce la repo della libreria):

const http = require('http')
const Bot = require('messenger-bot')

let bot = new Bot({
  token: 'PAGE_TOKEN',
  verify: 'VERIFY_TOKEN',
  app_secret: 'APP_SECRET'
})

bot.on('error', (err) => {
  console.log(err.message)
})

bot.on('message', (payload, reply) => {
  let text = payload.message.text

  bot.getProfile(payload.sender.id, (err, profile) => {
    if (err) throw err

    reply({ text }, (err) => {
      if (err) throw err

      console.log(`Echoed back to ${profile.first_name} ${profile.last_name}: ${text}`)
    })
  })
})

http.createServer(bot.middleware()).listen(3200)
console.log('Echo bot server running at port 3200.')

Come dovreste aver capito, VERIFY_TOKEN non deve essere toccato, mentre PAGE_TOKEN e APP_SECRET dovete sostituirli secondo i dati salvati precedentemente.*
Avviamo quindi lo script:

node index.js

E lasciando aperto ngrok, finalmente possiamo incollare nel campo URL della finestra di configurazione delle webhooks, quanto ci ha fornito nel secondo forwarding ngrok e clicchiamo su Salva.
Se avrete seguito tutto correttamente vi troverete di fronte a una cosa del genere:

Webhook configurati con successo
Webhook configurati con successo

Non ci resta che selezionare la nostra pagina di nuovo alla sinistra di: “Select a page to subscribe your webhook…

* In un ambiente di produzione, i token e altre informazioni sensibili non vengono mai salvate direttamente nel codice sorgente (che tra l’altro, se fosse codice facente parte di un’app aperta al pubblico su Github, chiunque potrebbe usare le nostre API_KEY), piuttosto vengono utilizzate delle variabili d’ambiente che vedremo come settare nel prossimo articolo che sarà dedicato al deploy di un’app Node.js su heroku.

Capiamo il codice

Nel paragrafo precedente, per una migliore separazione dei contenuti, ci siamo ridotti a copiare e incollare un pezzetto di codice. Capiamo ora cosa succede lì dentro.

const http = require('http')
const Bot = require('messenger-bot')

let bot = new Bot({
  token: 'PAGE_TOKEN',
  verify: 'VERIFY_TOKEN',
  app_secret: 'APP_SECRET'
})

Righe:

  • 1, 2: importiamo il modulo http e la libreria per gestire le API di Facebook. 
  • 4 -> 8: istanziamo un oggetto della classe esportata dalla libreria inserendo i dati per la configurazione.
bot.on('error', (err) => {
  console.log(err.message)
})

bot.on('message', (payload, reply) => {
  let text = payload.message.text

  bot.getProfile(payload.sender.id, (err, profile) => {
    if (err) throw err

    reply({ text }, (err) => {
      if (err) throw err

      console.log(`Echoed back to ${profile.first_name} ${profile.last_name}: ${text}`)
    })
  })
})

Righe:

  • 1 -> 3: agganciamo un handler all’evento “error” con il metodo “on” e stampiamo a schermo l’errore.
  • 5 -> 16: agganciamo un handler all’evento “message” e utilizziamo i due parametri “payload” e “reply” per reperire una moltitudine di informazioni a riguardo dell’evento di ricezione di un messaggio.
  • Riga 5: prendiamo il testo del messaggio che un utente ha inviato al nostro bot (attraverso la proprietà message.text dell’oggetto payload)
  • Riga 7: chiamiamo la funzione “getProfile” inclusa nell’oggetto precedentemente istanziato per riprendere informazioni sul profilo che ha inviato il messaggio al bot (prendiamo l’id di quel profilo attraverso payload.sender.id) e associamo un callback di ritorno.
  • 8 -> 12: gestiamo eventuali errori e richiamiamo la funzione reply tornata dall’handler dell’evento “message” per rispondere a quel determinato utente. Come parametro, la funzione reply, prende un oggetto con una proprietà “text” con associato il testo della risposta. Lì, utilizzando l’object destructuring, riusciamo a risparmiare qualche carattere e migliorare la visibilità per rinviare lo stesso messaggio che l’utente ci ha inviato.
    Infine stampiamo a schermo un messaggio consuntivo che notifica che si è risposto ad un utente specificando nome, cognome e testo inviato utilizzando i template literals (anche qui) per risparmiare codice e migliorarne la visibilità.

Ovviamente sono davvero tante le funzioni che Facebook ha messo a disposizione per i Bot e se quest’articolo serviva per mettervi in piedi e farvi cominciare lo sviluppo di un vostro bot, di sicuro ora è compito vostro cercare come fare per arricchirlo di funzionalità.
Prendete come riferimento la documentazione ufficiale e quella della libreria usata in questo tutorial.

Parliamo con il nostro bot

Ora rechiamoci nella home della nostra pagina, “Informazioni” a sinistra e troverete un pulsante “Invia un messaggio“. Vedrete che:

  1. La pagina risponderà con lo stesso testo che avete inviato.
  2. Lo script stamperà sul terminale della vostra macchina qualcosa come: “Echoed back to…”.
  3. Ngrok loggherà una richiesta POST eseguita dai server di Facebook.
Test bot
Test bot

Alla prossima 😉

A proposito di me

Giacomo Cerquone

Appassionato di informatica sin da piccolo, cinefilo accanito, amante di tè e dei posti freddi. Focalizzato in full-stack JavaScript developing, contributor di diversi progetti open source e amante delle tecnologie bleeding edge nell'ambito della programmazione.

Di Giacomo Cerquone

Gli articoli più letti

Articoli recenti

Commenti recenti