Creazione del fulfillment con la libreria client Actions on Google Node.js (Dialogflow)

La libreria client Actions on Google Node.js è il modo consigliato per accedere e interagire con la piattaforma Actions on Google se stai creando un webhook di fulfillment in JavaScript.

Introduzione

La libreria client Node.js è una libreria di distribuzione per Actions on Google che offre le seguenti funzionalità:

  • Supporta tutte le funzionalità di Actions on Google, inclusi testo e risposte multimediali, accesso all'account, archiviazione dati, transazioni e altro ancora.
  • Fornisce un livello di astrazione idiomatico in JavaScript che esegue il wrapping dell'API webhook HTTP/JSON conversazione.
  • Gestisce i dettagli di basso livello della comunicazione tra il fulfillment e la piattaforma Actions on Google.
  • Può essere installato utilizzando strumenti di gestione dei pacchetti familiari, come npm o yarn.
  • Consente di eseguire facilmente il deployment del webhook di fulfillment su piattaforme di serverless computing come Cloud Functions for Firebase o AWS Lambda. Puoi anche ospitare il webhook di fulfillment in un provider di servizi cloud o in un ambiente self-hosted e autogestito.
  • È compatibile con Node.js 6.0.0 e versioni successive.

Puoi utilizzare la libreria client in combinazione con l'integrazione Dialogflow per Actions on Google o con l'SDK Actions.

Per visualizzare esempi di codice completi per l'utilizzo della libreria client, puoi visitare la pagina degli esempi.

Visualizza il riferimento API

Il riferimento API è ospitato nella pagina di GitHub della libreria client Node.js di Actions on Google.

Puoi anche generare una copia locale del riferimento eseguendo questo comando dalla directory in cui hai scaricato il codice della libreria client:

yarn docs

I documenti generati saranno disponibili nella cartella docs della directory in cui hai scaricato il codice della libreria client.

Scopri come funziona

Prima di utilizzare la libreria client, è utile capire in che modo il webhook di fulfillment utilizza la libreria client per elaborare le richieste degli utenti che Actions on Google invia al tuo fulfillment.

Quando crei un webhook di fulfillment in JavaScript, puoi eseguire il deployment e ospitare il codice in un ambiente di serverless computing come Cloud Functions for Firebase di Google o AWS Lambda. Puoi anche ospitare il codice autonomamente senza attività aggiuntive utilizzando il framework web Express.

Nell'ambiente di runtime, il webhook di fulfillment può chiamare le funzioni nella libreria client per elaborare le richieste degli utenti e inviare le risposte ad Actions on Google per il rendering nell'output utente.

Di seguito sono riepilogate brevemente le attività principali che il webhook di fulfillment gestisce con l'aiuto della libreria client:

Figura 1. Architettura di alto livello della libreria client Node.js
  1. Ricezione delle richieste degli utenti: quando un utente esegue una query all'Assistente Google, la piattaforma Actions on Google invia una richiesta HTTP al webhook di fulfillment; la richiesta include un payload JSON che contiene l'intent e altri dati, come il testo non elaborato dell'input utente e le funzionalità di visualizzazione del dispositivo dell'utente. Per altri esempi di contenuti del payload JSON, consulta le guide relative al formato webhook di Dialogflow e al formato di webhook per conversazione.
  2. Rilevamento del formato di chiamata del framework: per i framework supportati, la libreria client rileva automaticamente il formato di chiamata del framework (ad esempio, se la richiesta proviene dal framework web Express o da AWS Lambda) e sa come gestire senza problemi la comunicazione con la piattaforma Actions on Google.
  3. Elaborazione del gestore di servizi: la libreria client rappresenta l'API webhook HTTP/JSON della conversazione per Dialogflow e l'SDK Actions come funzione di servizio. Il webhook di fulfillment utilizza il servizio appropriato per creare un'istanza app globale. L'istanza app agisce da gestore per le richieste HTTP e comprende il protocollo specifico del servizio.
  4. Elaborazione della conversazione: la libreria client rappresenta le informazioni per conversazione come un oggetto Conversation associato all'istanza app. Il webhook di fulfillment può utilizzare l'oggetto Conversation per recuperare dati o informazioni sullo stato archiviati in più conversazioni, inviare risposte agli utenti o chiudere il microfono.
  5. Elaborazione del middleware: la libreria client consente di creare il tuo middleware dei servizi di conversazione, composto da una o più funzioni definite automaticamente dalla libreria client prima di chiamare il gestore di intent. Il webhook di fulfillment può utilizzare il middleware per aggiungere proprietà o classi helper all'oggetto Conversation.
  6. Elaborazione del gestore di intent: la libreria client consente di definire i gestori per gli intent riconosciuti dal webhook di fulfillment. Per Dialogflow, la libreria client instrada la richiesta al gestore di intent corretto eseguendo la mappatura alla stringa esatta del nome dell'intent definito nella console Dialogflow. Per l'SDK Actions, il routing viene eseguito in base alla proprietà intent inviata da Actions on Google.
  7. Invio di risposte agli utenti: per creare le risposte, il webhook di fulfillment chiama la funzione Conversation#ask(). La funzione ask() può essere chiamata più volte per creare la risposta in modo incrementale. La libreria client serializza la risposta in una richiesta HTTP con un payload JSON e la invia ad Actions on Google. La funzione close() ha un comportamento simile a ask(), ma chiude la conversazione.

Configura l'ambiente di sviluppo locale

Prima di implementare il webhook di fulfillment, assicurati di installare la libreria client.

Installa la libreria client

Il modo più semplice per installare la libreria client nell'ambiente di sviluppo locale consiste nell'utilizzare un gestore di pacchetti, come npm o yarn.

Per eseguire l'installazione, esegui uno di questi comandi dal terminale:

  • Se utilizzi npm: npm install actions-on-google
  • Se si utilizza il filato: yarn add actions-on-google

Configura le cartelle di progetto

A seconda di dove prevedi di eseguire il deployment del webhook di fulfillment (Cloud Functions for Firebase di Google, AWS Lambda o Express in self-hosted), potrebbe essere necessario creare una struttura di cartelle di progetto specifica per salvare i file.

Ad esempio, se utilizzi Cloud Functions for Firebase, puoi configurare le cartelle di progetto necessarie eseguendo i passaggi descritti in Configurare Node.js e l'interfaccia a riga di comando di Firebase e Inizializzare Firebase per Cloud Functions. Per Cloud Functions for Firebase, in genere scrivi il webhook di fulfillment nel file /functions/index.js.

Crea un'istanza dell'app

Actions on Google utilizza formati di messaggistica specifici per lo scambio di richieste e risposte con il webhook di fulfillment, a seconda che tu stia creando un'azione conversazionale utilizzando Dialogflow o l'SDK Actions oppure creando un'azione per la smart home.

Per rappresentare questi diversi protocolli di richiesta e risposta, la libreria client fornisce tre funzioni di servizio:

Il protocollo webhook di conversazione viene utilizzato da entrambi i servizi di conversazione (Dialogflow e SDK Actions), ma ogni servizio esegue il wrapping dei messaggi in modo diverso.

Utilizza un servizio per creare un'istanza app. L'istanza app incapsula lo stato globale e la logica di fulfillment per il webhook e gestisce la comunicazione tra Actions on Google e il fulfillment utilizzando il protocollo specifico per il servizio.

Puoi configurare le proprietà dell'istanza app e chiamare i relativi metodi per indirizzare il comportamento del webhook di fulfillment. Puoi anche collegare facilmente l'istanza app a un ambiente di serverless computing come Cloud Functions for Firebase, che accetta le funzioni JavaScript come gestori delle richieste HTTP.

Per creare un'istanza app nel webhook di fulfillment:

  1. Richiama la funzione require() per importare il modulo "actions-on-google" e caricare il servizio che ti interessa. Ad esempio, lo snippet seguente mostra come caricare il servizio dialogflow e alcuni elementi utilizzati per creare le risposte e assegnarlo a una costante denominata dialogflow:

    // Import the service function and various response classes
    const {
      dialogflow,
      actionssdk,
      Image,
      Table,
      Carousel,
    } = require('actions-on-google');

    In questo caso, actions-on-google fa riferimento a una dipendenza specificata in un file package.json nella cartella del progetto (per un esempio, fai riferimento a questo file package.json di esempio).

    Quando ottieni un'istanza app, puoi specificare facoltativamente classi che rappresentano risposte avanzate, intent helper e altre funzionalità di Actions on Google che vuoi utilizzare. Per l'elenco completo delle classi valide che puoi caricare, consulta la documentazione di riferimento per i moduli di risposta alla conversazione e intent helper.

  2. Crea un'istanza app chiamando il servizio che hai caricato. Ad esempio:

    const app = dialogflow();

  3. Per configurare l'istanza app all'inizializzazione, puoi fornire un oggetto options come primo argomento quando chiami il servizio. (Per ulteriori dettagli, visita la pagina DialogflowOptions). Ad esempio, lo snippet seguente mostra come registrare il payload JSON non elaborato dalla richiesta o dalla risposta dell'utente impostando il flag { debug: true }:

const app = dialogflow({
  debug: true
});

Imposta gestori per gli eventi

Per elaborare gli eventi relativi alle azioni su Google creati dalla libreria client durante il ciclo di vita dell'interazione dell'utente con l'Azione, utilizzerai la libreria client per creare gestori al fine di elaborare le richieste degli utenti e inviare le risposte.

Puoi creare funzioni che fungono da gestori per i seguenti tipi principali di eventi riconosciuti dalla libreria client:

  • Eventi di intent: gli intent sono identificatori univoci che Actions on Google invia al tuo fulfillment ogni volta che un utente richiede una funzionalità specifica. Se utilizzi Dialogflow, questo corrisponde a una query utente che corrisponde a un intent nell'agente Dialogflow.
  • Eventi di errore: quando si verifica un errore JavaScript o della libreria client, puoi utilizzare la funzione catch dell'istanza app per elaborare l'eccezione di errore in modo appropriato. Devi implementare una singola funzione catch per gestire tutti gli errori che interessano il tuo fulfillment.
  • Eventi di riserva: si verifica un evento di riserva quando l'utente invia una query che Actions on Google non è in grado di riconoscere. Puoi utilizzare la funzione fallback dell'istanza app per registrare un gestore di fallback generico che verrà attivato se non viene abbinato alcun gestore di intent per la richiesta di evasione degli ordini in entrata. Devi implementare una singola funzione fallback per gestire tutti gli eventi di fallback. Se utilizzi Dialogflow, quest'ultimo può attivare un intent di riserva specifico quando non viene abbinato nessun altro intent. Devi creare un gestore di intent corrispondente per l'intent di riserva.

Ogni volta che l'utente invia una richiesta all'Azione, l'istanza app crea un oggetto Conversation che rappresenta la sessione di conversazione. Questo oggetto è accessibile tramite il nome della variabile conv passato nella funzione di gestore di intent come primo argomento della funzione. In genere, utilizzerai l'oggetto conv nei gestori per inviare una risposta all'utente.

Le query degli utenti possono anche includere parametri che l'Azione può estrarre e utilizzare per perfezionare le risposte.

  • Se utilizzi l'SDK Actions, definisci i parametri nel pacchetto Action. Per un esempio di come estrarre i parametri dagli intent, vedi l'esempio di codice Eliza.
  • Se utilizzi Dialogflow, puoi accedere ai valori dei parametri tramite la variabile params. Per esempi sulla gestione di intent con parametri in Dialogflow, vedi Accedere a parametri e contesti.

Imposta gestori per gli intent

Per impostare il gestore per un intent, chiama la funzione intent() dell'istanza app. Ad esempio, se utilizzi Dialogflow, questa è la funzione DialogflowApp#intent(). Negli argomenti, specifica il nome dell'intent e fornisci una funzione gestore.

Se utilizzi Dialogflow, non è necessario impostare gestori per ogni intent nell'agente. Puoi invece sfruttare il gestore delle risposte integrato di Dialogflow per gestire automaticamente gli intent senza implementare le tue funzioni di gestore. Ad esempio, l'intent di benvenuto predefinito può essere delegato a Dialogflow in questo modo.

L'esempio seguente mostra i gestori di intent per gli intent "greeting" e "bye". Le funzioni di gestore anonimo prendono un argomento conv e inviano una semplice risposta stringa all'utente tramite la funzione conv.ask():

app.intent('Default Welcome Intent', (conv) => {
  conv.ask('How are you?');
});

app.intent('bye', (conv) => {
  conv.close('See you later!');
});

Tieni presente che la funzione close() è simile alla funzione ask(), ma chiude il microfono e la conversazione è terminata.

Per scoprire di più su come creare gestori per gli intent, consulta Creare un gestore di intent.

Imposta gestori per gli eventi di errore

Per impostare i gestori per gli errori, chiama la funzione catch() dell'istanza app. Ad esempio, se utilizzi Dialogflow, questa è la funzione DialogflowApp#catch().

L'esempio seguente mostra un semplice gestore di errori catch che invia l'errore all'output della console e invia una semplice risposta stringa per richiedere all'utente tramite la funzione conv.ask():

app.catch((conv, error) => {
  console.error(error);
  conv.ask('I encountered a glitch. Can you say that again?');
});

Imposta gestori per gli eventi di fallback

Per impostare un gestore di riserva generico quando non esiste alcuna corrispondenza di intent per la richiesta in arrivo per il fulfillment, chiama la funzione fallback() della tua istanza app. Ad esempio, se utilizzi Dialogflow, questa è la funzione DialogflowApp#fallback().

L'esempio seguente mostra un semplice gestore di riserva che invia una semplice risposta stringa per richiedere all'utente tramite la funzione conv.ask():

app.fallback((conv) => {
  conv.ask(`I couldn't understand. Can you say that again?`);
});

Creare il gestore di intent

Questa sezione illustra alcuni casi d'uso comuni in cui implementi gestori di intent con la libreria client. Per vedere in che modo la libreria client corrisponde all'intent, consulta la sezione "Elaborazione del gestore di intent" in Comprendere il funzionamento.

Parametri di accesso e contesti

Se utilizzi Dialogflow, puoi definire parametri e contesti nell'agente Dialogflow per mantenere le informazioni sullo stato e controllare il flusso della conversazione.

I parametri sono utili per acquisire parole, frasi o valori importanti nelle query degli utenti. Dialogflow estrae i parametri corrispondenti dalle query degli utenti in fase di runtime e puoi elaborare questi valori parametro nel webhook di fulfillment per determinare come rispondere agli utenti.

Ogni volta che l'utente invia una richiesta all'azione, l'istanza DialogflowApp crea un oggetto parameters che rappresenta i valori parametro che Dialogflow ha estratto dalla richiesta. Questo oggetto è accessibile tramite il nome della variabile params.

Lo snippet seguente mostra come accedere alla proprietà name dall'oggetto params quando l'utente invia una richiesta:

app.intent('Default Welcome Intent', (conv, params) => {
  conv.ask(`How are you, ${params.name}?`);
});

Di seguito è riportato uno snippet alternativo che ha lo stesso comportamento. Le parentesi graffe ({}) eseguono la distruzione JavaScript per prendere la proprietà name dall'oggetto parameters e utilizzarla come variabile locale:

app.intent('Default Welcome Intent', (conv, {name}) => {
  conv.ask(`How are you, ${name}?`);
});

Nello snippet seguente, il nome del parametro è full-name ma è destrutturato e assegnato a una variabile locale denominata name:

app.intent('Default Welcome Intent', (conv, {'full-name': name}) => {
  conv.ask(`How are you, ${name}?`);
});

I contesti sono una funzionalità avanzata di Dialogflow. Puoi utilizzare i contesti per gestire lo stato, il flusso e il branching della conversazione. La libreria client fornisce l'accesso a un contesto tramite l'oggetto DialogflowConversation#contexts. Lo snippet seguente mostra come impostare un contesto in modo programmatico nel webhook di fulfillment e come recuperare l'oggetto di contesto:

app.intent('intent1', (conv) => {
  const lifespan = 5;
  const contextParameters = {
    color: 'red',
  };
  conv.contexts.set('context1', lifespan, contextParameters);
  // ...
  conv.ask('...');
});

app.intent('intent2', (conv) => {
  const context1 = conv.contexts.get('context1');
  const contextParameters = context1.parameters;
  // ...
  conv.ask('...');
});

app.intent('intent3', (conv) => {
  conv.contexts.delete('context1');
  // ...
  conv.ask('...');
});

Accedi ai risultati dell'intent helper

Per praticità, la libreria client fornisce classi di intent helper che aggregano tipi comuni di dati utente richiesti di frequente dalle Azioni. tra cui classi che rappresentano i risultati dei vari intent helper di Actions on Google. Puoi utilizzare intent helper quando vuoi che l'Assistente Google gestisca parti della conversazione in cui l'utente deve fornire input per continuare la conversazione.

Esempio: risultati dell'helper per la conferma

L'intent helper conferma ti consente di chiedere una conferma sì/no da parte dell'utente e ottenere la risposta risultante. Lo snippet seguente mostra in che modo il webhook può personalizzare la risposta in base ai risultati restituiti dall'intent helper di conferma. Per un esempio più completo, consulta la documentazione di riferimento della classe Confirmation.

// Create Dialogflow intent with `actions_intent_CONFIRMATION` event
app.intent('get_confirmation', (conv, input, confirmation) => {
  if (confirmation) {
    conv.close(`Great! I'm glad you want to do it!`);
  } else {
    conv.close(`That's okay. Let's not do it now.`);
  }
});

Lo snippet seguente mostra in che modo il webhook di fulfillment può personalizzare la propria risposta in base all'input dell'utente per un carosello. Il componente Carousel consente all'Azione di presentare una selezione di opzioni. Per un esempio più completo, consulta la documentazione di riferimento della classe Carousel.

app.intent('carousel', (conv) => {
  conv.ask('Which of these looks good?');
  conv.ask(new Carousel({
    items: {
      car: {
        title: 'Car',
        description: 'A four wheel vehicle',
        synonyms: ['automobile', 'vehicle'],
      },
      plane: {
        title: 'Plane',
        description: 'A flying machine',
        synonyms: ['aeroplane', 'jet'],
      }
    }
  }));
});

// Create Dialogflow intent with `actions_intent_OPTION` event
app.intent('get_carousel_option', (conv, input, option) => {
  if (option === 'one') {
    conv.close(`Number one is a great choice!`);
  } else {
    conv.close(`Number ${option} is a great choice!`);
  }
});

Configura oggetti risposta conversazione

La libreria client fornisce classi di risposta alle conversazioni che rappresentano risposte avanzate o elementi multimediali che l'Azione può inviare. In genere, invii queste risposte o questi elementi quando gli utenti non devono dare alcun input per continuare la conversazione.

Esempio: immagine

Lo snippet seguente mostra in che modo il webhook di fulfillment può inviare un elemento Image in una risposta che verrà allegata automaticamente a una risposta BasicCard dalla libreria:

app.intent('Default Welcome Intent', (conv) => {
  conv.ask('Hi, how is it going?');
  conv.ask(`Here's a picture of a cat`);
  conv.ask(new Image({
    url: '/web/fundamentals/accessibility/semantics-builtin/imgs/160204193356-01-cat-500.jpg',
    alt: 'A cat',
  }));
});

Effettuare chiamate di funzioni asincrone

La libreria client Node.js di Actions on Google è progettata per la programmazione asincrona. Il gestore di intent può restituire una promessa che si risolve quando il webhook di fulfillment genera una risposta.

Lo snippet seguente mostra come effettuare una chiamata di funzione asincrona per restituire un oggetto promessa e quindi rispondere con un messaggio se il webhook di fulfillment riceve l'intent di saluto. In questo snippet, la promessa garantisce che il webhook di fulfillment restituisca una risposta conversazionale solo dopo la risoluzione della promessa relativa alla chiamata API esterna.

In questo esempio, utilizziamo un'API falsa per recuperare i dati meteo.

/**
 * Make an external API call to get weather data.
 * @return {Promise<string>}
 */
const forecast = () => {
  // ...
};

app.intent('Default Welcome Intent', (conv) => {
  return forecast().then((weather) => {
    conv.ask('How are you?');
    conv.ask(`Today's weather is ${weather}.`);
  });
});

Il seguente snippet di codice semplificato ha lo stesso effetto, ma utilizza la funzionalità async await introdotta in ECMA 2017 (Node.js versione 8). Per utilizzare questo codice con Cloud Functions for Firebase, assicurati di utilizzare la versione corretta di firebase-tools e di avere la configurazione corretta.

app.intent('Default Welcome Intent', async (conv) => {
  const weather = await forecast();
  conv.ask('How are you?');
  conv.ask(`Today's weather is ${weather}.`);
});

Archivia dati conversazionali

La libreria client consente al webhook di fulfillment di salvare i dati nelle conversazioni per utilizzarli in futuro. Gli oggetti chiave che puoi utilizzare per l'archiviazione dei dati includono:

Lo snippet seguente mostra in che modo il webhook di fulfillment può archiviare i dati in una proprietà arbitraria che hai definito (someProperty) e collegarli all'oggetto Conversation#user.storage. Per un esempio più completo, consulta la documentazione di riferimento della classe Conversation#user.storage.

app.intent('Default Welcome Intent', (conv) => {
  conv.user.storage.someProperty = 'someValue';
  conv.ask('...');
});

Puoi utilizzare l'oggetto Conversation#user per ottenere informazioni sull'utente, inclusi un identificatore di stringa e informazioni personali. Determinati campi, come conv.user.name.display e conv.user.email, richiedono, rispettivamente, la richiesta di conv.ask(new Permission) per NAME e conv.ask(new SignIn) per Accedi con Google.

const {Permission} = require('actions-on-google');
app.intent('Default Welcome Intent', (conv) => {
  if (conv.user.last.seen) {
    conv.ask('Welcome back! How are you?');
  } else {
    conv.ask('Nice to meet you! How are you doing?');
  }
});

app.intent('permission', (conv) => {
  conv.ask(new Permission({
    context: 'To greet you personally',
    permissions: 'NAME',
  }));
});

// Create Dialogflow intent with `actions_intent_PERMISSION` event
app.intent('get_permission', (conv, input, granted) => {
  if (granted) {
    conv.close(`Hi ${conv.user.name.display}!`);
  } else {
    // User did not grant permission
    conv.close(`Hello!`);
  }
});

Scalabilità con il middleware

Puoi estendere la libreria client tramite il middleware.

Il livello middleware è costituito da una o più funzioni definite da te, che la libreria client esegue automaticamente prima di chiamare il gestore di intent. L'utilizzo di un livello middleware consente di modificare l'istanza Conversation e aggiungere funzionalità aggiuntive.

I servizi Dialogflow e Actions SDK espongono una funzione app.middleware() che ti consente di aggiungere proprietà o classi helper all'istanza Conversation.

Lo snippet seguente mostra un esempio di come utilizzare il middleware:

class Helper {
  constructor(conv) {
    this.conv = conv;
  }

  func1() {
    this.conv.ask(`What's up?`);
  }
}

app.middleware((conv) => {
  conv.helper = new Helper(conv);
});

app.intent('Default Welcome Intent', (conv) => {
  conv.helper.func1();
});

Esporta l'app

Per esporre il webhook di fulfillment per un framework web o una piattaforma di serverless computing, devi esportare l'oggetto app come webhook accessibile pubblicamente. La libreria client supporta subito il deployment in diversi ambienti.

I seguenti snippet mostrano come esportare app in diversi runtime:

Esempio: Cloud Functions for Firebase

const functions = require('firebase-functions');
// ... app code here
exports.fulfillment = functions.https.onRequest(app);

Esempio: editor incorporato Dialogflow

const functions = require('firebase-functions');

// ... app code here

// Exported function name must be 'dialogflowFirebaseFulfillment'
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);

Esempio: server Express self-hosted (semplice)

const express = require('express');
const bodyParser = require('body-parser');  

// ... app code here

express().use(bodyParser.json(), app).listen(3000);

Esempio: server Express self-hosted (più percorsi)

const express = require('express');
const bodyParser = require('body-parser');

// ... app code here

const expressApp = express().use(bodyParser.json());

expressApp.post('/fulfillment', app);

expressApp.listen(3000);

Esempio: gateway API AWS Lambda

// ... app code here

exports.fulfillment = app;