Sviluppare un chatbot con Google Chat – seconda parte

Riprendiamo da quanto già fatto nella prima parte di questo articolo.
Vedremo ora come implementare un semplice Bot. Riassumiamo prima le sue componenti in questo diagramma:

 

 

Nella parte tratteggiata abbiamo racchiuso le componenti che dovremo effettivamente implementare.

 

Apriamo quindi la console di GCP https://console.cloud.google.com/ e creiamo dapprima il nuovo progetto

 

 

 

Abilitiamo quindi le API di chat, navigando su API & Services > Dashboard e clicchiamo su “Enable APIs And Services”.

Digitiamo quindi “chat” nella casella di ricerca e abilitiamo 

“Hangouts Chat API” e “Dialog Flow API”.

 

“Perché le API devono essere abilitate?”

In questo caso il nostro progetto è un client delle api di Google Chat.  In quanto client potrà usufruire del servizio e generare un costo. L’amministratore del progetto deve quindi abilitare solo i servizi strettamente necessari al funzionamento del progetto. Gli sviluppatori che lavorano al progetto potranno quindi utilizzare solamente le API abilitate. 

 

Entriamo quindi nella console di “Hangouts Chat API” e clicchiamo, nel menù a sinistra, su  “Configuration”.

 

Personalizziamo adesso il nostro Bot scegliendo il nome, l’avatar e scrivendo una breve descrizione. 

 

Prima di configurare il nostro Bot dobbiamo decidere quale sará il servizio al quale il Bot si appoggerà per lavorare. Le opzioni messe a disposizione da Google sono quattro:

 

 

 

Prima di addentrarci nei dettagli di ciascuna opzione cerchiamo di capire il significato di questo punto. Dobbiamo fare un passo indietro e chiarire alcuni aspetti.

 

Immaginate di utilizzare una chat con i vostri colleghi in una “room” tematica. In questa stessa stanza è presente anche un Bot che partecipa alla conversazione; uno dei partecipanti umani può quindi rivolgere una domanda al Bot. Nel nostro caso potrà chiedere ad esempio: @MeteoBot che tempo farà domani?

Oppure potremmo avere un bot a cui chiedere a che prezzo viene scambiato oggi un certo asset sul mercato finanziario.

 

Quello che succede dietro le quinte è straordinario e usando uno strumento come Google Chat non dovremo occuparci di niente che non sia la logica del Bot, come vedremo in seguito. Il servizio Google Chat provvederà ad inoltrare la domanda posta al Bot di competenza in uno dei modi elencati di sopra. A seconda del metodo che scegliamo e della natura del Bot questo potrà rispondere in modo sincrono o asincrono. Sembra un dettaglio molto tecnico ma vedremo in seguito che questo aspetto è molto importante.  Per semplicità diciamo che una volta interrogato il servizio del Bot questo potrà rispondere con un “ok ricevuto, ci penso e ti faccio sapere” oppure direttamente con la risposta:  “Domani c’è il sole”.

 

In ogni caso il servizio di chat “stamperà” la risposta del Bot così come avrebbe fatto se fosse stato interrogato un essere umano. 

 

Nel caso di risposta asincrona il Bot continuerà a lavorare e a cercare le informazioni che gli abbiamo richiesto e interverrà nella chat solo una volta trovate.

 

Vediamo punto per punto che cosa significano queste opzioni:

 

Boot URL

Se scegliamo questa opzione dovremo implementare un servizio HTTP che risponda direttamente alle richieste che provengono dalla chat. Questo è il metodo di elezione nel caso si volesse usare uno dei tantissimi Bot disponibili su internet. 

 

App Script Project

Possiamo collegare il nostro bot a un progetto realizzato con App Script, un altro prodotto di Google Workspace per la creazioni di semplici app. Maggiori informazioni su questo prodotto possono essere reperite qui https://www.google.com/script/start/.

 

Cloud Pub/Sub

https://cloud.google.com/pubsub/

Il sistema di messaging della Google Cloud Platform, con questo canale possiamo raggiungere qualsiasi servizio, anche, ad esempio un server o un PC dove installiamo il client di Pub/Sub. Questa opzione potrebbe essere interessante nel caso volessimo ad esempio interrogare un server sullo stato di un processo. Immaginiamo ad esempio di avere un server (in cloud o nella nostra rete o datacenter privato) che gestisce la nostra posta elettronica, si potrà interrogarlo per sapere quante email ha ricevuto e smistato oggi.

 

Dialog Flow

In tutte le opzioni precedenti la responsabilità della gestione del dialogo con l’utente è lasciata al servizio, chi scrive il servizio che fornisce le informazioni dovrà farsi carico di interpretare le richieste dei nostri utenti, capire il contesto, chiedere chiarimenti prima di dare le risposte. Tutte queste cose possono essere gestite brillantemente con Dialog Flow. Vediamo con il nostro esempio come utilizzarlo.

 

Prima di continuare apriamo quindi la console di Dialog Flow https://dialogflow.cloud.google.com/ e creiamo il nostro primo agente.

 

Per creare un agente dobbiamo capire quali sono i suoi elementi base, ovvero

 – Intents

 – Entities

 – Fulfilments

 

L’agente deve essere in grado di gestire un certo numero di ”Intents” ovvero “quello che l’utente vuole che il nostro agente faccia”.

Nel caso del nostro esempio, prendiamo in considerazione l’intento “voglio sapere che tempo farà domani” , ma teniamo presente che un agente di Dialog Flow può gestire anche più intenti, a patto che sia in grado di capire, dalla domanda, quale sia appunto l’intento dell’utente. 

Tutti gli agenti di Dialog Flow nascono con un intento preconfigurato che si chiama “Default Welcome Intent” che si occupa ad esempio dei saluti ed si trova lí perché vogliamo che il nostro Bot sia ben educato.

 

Le “Entities” sono i dati che l’agente deve poter estrarre dalle domande dell’utente, ad esempio nel nostro caso, il luogo e la data per cui vogliamo le previsioni. Dialog Flow è in grado di identificare automaticamente queste informazioni all’interno delle frasi.

 

I “Fulfilments” sono le azioni che l’agente dovrà compiere per esaudire la richiesta dell’utente.

 

Creiamo quindi il nostro “Forecast Intent”.

 

 

Nella sezione “Training phrases” digitiamo alcune frasi di esempio. Vediamo che Dialog Flow evidenzia automaticamente le “Entities” ed è in grado di distinguere automaticamente tra il dove e il quando. 

Le entity “@sys.date-time”  e “@sys.location” sono infatti Entity di sistema, sono quindi già previste in Dialog Flow e per il nostro esempio non dovremo definirne altre.

 

Cosa succede se l’utente chiede ad esempio: “Che tempo fa domani?”

In questo caso il nostro agente non sapra il dove. Ovviamente, conoscendo il contesto, potremmo supporre che l’utente chieda informazioni sul luogo in cui si trova, ma benché questo approccio sia molto intelligente esula al momento dallo scopo del nostro piccolo esempio. In generale, l’agente dovrà a questo punto  porre una domanda all’utente per chiedere per quale luogo egli voglia conoscere le previsioni per domani.

 

Vediamo come fare

 

Definiamo i nostri parametri come “Required” e Dialog Flow ci permetterà direttamente di specificare quale domanda porre all’utente per avere l’informazione mancante.

 

 

 

A questo punto possiamo passare al fulfillment, ovvero prendere queste informazioni e passarle al nostro servizio di previsione preferito.

In questo esempio useremo le API fornite da https://openweathermap.org/

 

Per fare questo avremo bisogno di scrivere un po’ di codice, ma non dovremo preoccuparci di installare niente e neppure decidere dove farlo girare, grazie alla integrazione Dialog Flow con GCP è possibile usare la tecnologia serverless delle Cloud Function direttamente dall’interfaccia di Dialog Flow.

 

Abilitiamo il fulfillment per il nostro Intent, scorrendo verso il basso individuiamo la sezione “Fulfillment” e attiviamo la voce “Enable webhook call for this intent”.

 

 

Passiamo ora alla pagina “Fulfillment” dal menu a sinistra. Da qui abbiamo due possibilitá:

 – Webhook

 – Inline Editor

 

Di nuovo ci viene proposta la possibilità, usando webhook, di inviare la richiesta a un servizio esterno. Nel nostro caso, il servizio “https://openweathermap.org/” non sarebbe in grado di interpretare le informazioni passate dall’agente di dialog flow, per questo motivo, abbiamo bisogno di scrivere un po’ di codice per tradurre i parametri della richiesta dell’agente in qualcosa che la nostra API meteo possa interpretare. 

 

Abilitiamo quindi la sezione “Inline Editor”. Da questa sezione potremmo scrivere del codice che verrà distribuito su una Cloud Function all’interno del progetto Google Cloud Platform associato a Dialog Flow. Si tratta dello stesso editor che troveremo nella console di GCP del progetto e non aggiunge niente ad una distribuzione manuale se non la comodità di poter fare tutto dalla stessa interfaccia web (quella di Dialog Flow appunto).

 

La funzione che andremo a scrivere , sarà una funzione di tipo http il cui nome, e quindi l’endpoint generato, dovrà essere “dialogflowFirebaseFulfillment

Dialog Flow ci propone nell’editor del codice di esempio che possiamo modificare. 

 

Nel corpo della funzione principale troviamo questi due statements:

 

console.log(‘Dialogflow Request headers: ‘ + JSON.stringify(request.headers));

console.log(‘Dialogflow Request body: ‘ + JSON.stringify(request.body));

 

Proviamo allora ad eseguire una chiamata al nostro bot e andiamo a vedere nei log cosa viene passato da Dialog Flow al fulfillment.

Una funzione interessante dell’interfaccia di Dialog Flow è la sezione “Try it now” in altro a destra da dove possiamo testare il nostro Agente. 

 

 

Qui sopra un esempio. Alla nostra domanda “Che tempo fa domani?” l’agente ci chiede “Dove vuoi che controlli le previsioni?”. Vediamo che anche il Contesto viene popolato. Il contesto è un aspetto molto utile perché l’agente possa interloquire con noi, ma esula al momento da questa trattazione.    

In basso vediamo che l’agente ha individuato l’intento giusto ovvero il nostro “Forecast Intent”.

 

Rispondiamo quindi con un luogo, ad esempio “A Firenze” e vediamo se la nostra cloud function viene invocata e con quali parametri.

Per farlo possiamo cliccare su “View execution logs in the Google Cloud Console”. In basso nella finestra del Fulfillment.

 

Analizziamo quindi il payload della chiamata, ovvero le informazioni che l’agente passa alla nostra funzione

 

{

“responseId”: “a78ef52a-5c5a-4d11-8474-9455fca497d0-ce5e18e2”,

“queryResult”: {

“queryText”: “Firenze”,

“parameters”: {

“date-time”: “2020-11-27T12:00:00+01:00”,

“location”: {

“country”: “”,

“city”: “Firenze”,

“admin-area”: “”,

“business-name”: “”,

“street-address”: “”,

“zip-code”: “”,

“shortcut”: “”,

“island”: “”,

“subadmin-area”: “”

}

},

“allRequiredParamsPresent”: true,

 

}

 

Nel payload della richiesta, ci sono quindi i parametri che ci servono per interrogare il nostro servizio meteo. Scriviamo dunque la funzione per passare questi parametri alla API di openweathermap.org/ e formuliamo una risposta per l’agente con il metodo.

 

agent.add(“….”)

 

Useremo per l’esempio la API forecast di Open Weather Map https://openweathermap.org/forecast5#name5

questa richiede, oltra alla api key,  il nome della città, un esempio di richiesta è il seguente

 

GET https://api.openweathermap.org/data/2.5/forecast?q=Firenze&appid={API key}

 

Quindi nel nostro codice, estraiamo dal payload le informazioni che ci servono:

 

const city = request.body.queryResult.parameters.location.city;

const dateRaw = request.body.queryResult.parameters[‘date-time’];

 

Usiamo quindi il parametro city per chiamare la il nostro servizio, e usiamo la risposta del servizio per creare la nostra risposta. In caso di errore, informiamo l’utente che qualcosa non ha funzionato.

 

return axios.get(‘https://api.openweathermap.org/data/2.5/forecast’, {

           params: {

               q: request.body.queryResult.parameters.location.city,

               units: ‘metric’,

               lang: ‘it’,

               APPID: OW_API_KEY

           }

       }).then((apiResponse) => {

            const reply = owResponseToHuman(apiResponse);

            agent.add(reply);   

       }).catch((err) => {

     error(err);

     agent.add(`Mi dispiace, qualcosa è andato storto! ${err.message}`);

     return true;

});

 

Facciamo il deploy della nostra funziona direttamente da Dialog Flow, cliccando sul tasto Deploy e abbiamo finito. Possiamo ora interrogare il nostro Bot da Google Chat!

 

Potete trovare qui il codice usato per le Cloud Function https://github.com/wondersys/wonder-meteo-bot

 

Simone Bracaloni

Senior Software Engineer @ Wondersys