Crie o fulfillment com a biblioteca de cliente Node.js para Actions on Google (Dialogflow)

A biblioteca de cliente Node.js do Actions on Google é a maneira recomendada para acessar e interagir com a plataforma Actions on Google se você estiver criando um webhook de fulfillment em JavaScript.

Introdução

A biblioteca de cliente Node.js é uma biblioteca de fulfillment do Actions on Google que oferece estes recursos:

  • Compatível com todos os recursos do Actions on Google, incluindo respostas de texto e multimídia avançadas, login na conta, armazenamento de dados, transações e muito mais.
  • Fornece uma camada de abstração idiomática no JavaScript que une a API de webhook HTTP/JSON de conversa.
  • Processa os detalhes de baixo nível da comunicação entre o fulfillment e a plataforma Actions on Google.
  • Podem ser instaladas usando ferramentas de gerenciamento de pacotes conhecidas, como npm ou yarn.
  • Permite implantar facilmente o webhook de fulfillment em plataformas de computação sem servidor, como Cloud Functions para Firebase ou AWS Lambda. Também é possível hospedar o webhook de fulfillment em um provedor de serviços de nuvem ou em um ambiente auto-hospedado e autogerenciado.
  • é compatível com o Node.js v6.0.0 e versões mais recentes;

É possível usar a biblioteca de cliente em conjunto com a integração do Dialogflow para o Actions on Google ou com o SDK do Actions.

Para ver exemplos de código completos para usar a biblioteca de cliente, acesse a página de amostras.

Ver a Referência da API

A referência da API está hospedada na página do GitHub Biblioteca de cliente Node.js do Actions on Google.

Você também pode gerar uma cópia local da referência executando o seguinte comando no diretório em que fez o download do código da biblioteca de cliente:

yarn docs

Os documentos gerados vão estar disponíveis na pasta docs do diretório em que você fez o download do código da biblioteca de cliente.

Entenda como funciona

Antes de usar a biblioteca de cliente, é útil entender como o webhook de fulfillment usa a biblioteca de cliente para processar solicitações de usuários que o Actions on Google envia para o fulfillment.

Ao criar um webhook de fulfillment em JavaScript, é possível implantar e hospedar seu código em um ambiente de computação sem servidor, como o Cloud Functions para Firebase do Google ou o AWS Lambda. Também é possível hospedar o código sem trabalho extra usando o framework Express da Web (link em inglês).

No ambiente de execução, o webhook de fulfillment pode chamar funções na biblioteca de cliente para processar solicitações de usuários e enviar respostas de volta ao Actions on Google para renderização na saída do usuário.

As principais tarefas que o webhook de fulfillment processa com a biblioteca de cliente são resumidas abaixo:

Figura 1. Arquitetura de alto nível da biblioteca de cliente do Node.js
  1. Recebimento de solicitações do usuário: quando um usuário faz uma consulta no Google Assistente, a plataforma Actions on Google envia uma solicitação HTTP para o webhook de fulfillment. A solicitação inclui um payload JSON que contém a intent e outros dados, como o texto bruto da entrada do usuário e os recursos de superfície do dispositivo do usuário. Para mais exemplos do conteúdo de payload JSON, consulte os guias do formato do webhook do Dialogflow e do formato do webhook de conversa (em inglês).
  2. Detecção de formato de chamada de framework: para frameworks com suporte, a biblioteca de cliente detecta automaticamente o formato de chamada do framework (por exemplo, se a solicitação veio do framework da Web Express ou do AWS Lambda) e sabe lidar com a comunicação com a plataforma Actions on Google.
  3. Processamento do gerenciador de serviço: a biblioteca de cliente representa a API de webhook HTTP/JSON de conversa para o Dialogflow e o SDK do Actions como uma função de serviço. O webhook de fulfillment usa o serviço apropriado para criar uma instância de app global. A instância app atua como um gerenciador de solicitações HTTP e entende o protocolo específico do serviço.
  4. Processamento de conversas:a biblioteca de cliente representa as informações por conversa como um objeto Conversation anexado à instância app. O webhook de fulfillment pode usar o objeto Conversation para recuperar dados ou informações de estado armazenados entre conversas, enviar respostas aos usuários ou fechar o microfone.
  5. Processamento de middleware: a biblioteca de cliente permite criar o próprio middleware de serviços de conversa, que consiste em uma ou mais funções definidas que a biblioteca de cliente executa automaticamente antes de chamar o gerenciador de intents. O webhook de fulfillment pode usar o middleware para adicionar propriedades ou classes auxiliares ao objeto Conversation.
  6. Processamento do gerenciador de intents: a biblioteca de cliente permite definir gerenciadores para intents que o webhook de fulfillment entende. No caso do Dialogflow, a biblioteca de cliente encaminha a solicitação para o gerenciador de intents correto, mapeando para a string exata do nome da intent definido no console do Dialogflow. Para o SDK do Actions, ele é roteado com base na propriedade intent enviada do Actions on Google.
  7. Envio de respostas aos usuários: para criar respostas, o webhook de fulfillment chama a função Conversation#ask(). A função ask() pode ser chamada várias vezes para criar a resposta de forma incremental. A biblioteca de cliente serializa a resposta em uma solicitação HTTP com um payload JSON e a envia para o Actions on Google. A função close() tem um comportamento semelhante a ask(), mas fecha a conversa.

Configurar o ambiente de desenvolvimento local

Antes de implementar o webhook de fulfillment, instale a biblioteca de cliente.

Instale a biblioteca de cliente

A maneira mais fácil de instalar a biblioteca de cliente no ambiente de desenvolvimento local é usar um gerenciador de pacotes, como npm ou yarn.

Para instalar, execute um destes comandos no terminal:

  • Se estiver usando npm: npm install actions-on-google
  • Se estiver usando lã: yarn add actions-on-google

Configurar as pastas do projeto

Dependendo de onde você planeja implantar o webhook de fulfillment (Cloud Functions do Google para Firebase, AWS Lambda ou auto-hospedado Express), pode ser necessário criar uma estrutura de pastas de projeto específica para salvar os arquivos.

Por exemplo, se você estiver usando o Cloud Functions para Firebase, é possível configurar as pastas do projeto necessárias seguindo as etapas descritas em Configurar o Node.js e a CLI do Firebase e Inicializar o Firebase para o Cloud Functions. No Cloud Functions para Firebase, você normalmente grava o webhook de fulfillment no arquivo /functions/index.js.

Criar uma instância de app

O Actions on Google usa formatos de mensagens específicos para trocar solicitações e respostas com o webhook de fulfillment, dependendo se você está criando uma ação de conversação usando o Dialogflow ou o SDK do Actions ou uma ação de casa inteligente.

Para representar esses diferentes protocolos de solicitação e resposta, a biblioteca de cliente oferece três funções de serviço:

O protocolo de webhook de conversa é usado pelos serviços de conversa (Dialogflow e SDK do Actions), mas cada serviço agrupa as mensagens de maneira diferente.

Você usa um serviço para criar uma instância de app. A instância de app encapsula o estado global e a lógica de fulfillment do webhook e processa a comunicação entre o Actions on Google e o fulfillment usando o protocolo específico do serviço.

É possível configurar as propriedades da instância app e chamar os métodos dela para direcionar o comportamento do webhook de fulfillment. Também é possível conectar facilmente a instância app a um ambiente de computação sem servidor, como o Cloud Functions para Firebase, que aceita funções JavaScript como gerenciadores para solicitações HTTP.

Para criar uma instância app no webhook de fulfillment, siga estas etapas:

  1. Chame a função require() para importar o módulo "actions-on-google" e carregar o serviço desejado. Por exemplo, o snippet a seguir mostra como carregar o serviço dialogflow e alguns elementos usados para criar respostas e atribuí-lo a uma constante chamada dialogflow:

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

    Aqui, actions-on-google se refere a uma dependência especificada em um arquivo package.json na pasta do projeto. Consulte este arquivo package.json de exemplo (links em inglês).

    Ao acessar uma instância app, você tem a opção de especificar classes que representam respostas avançadas, intents auxiliares e outras funcionalidades do Actions on Google que você quer usar. Para conferir a lista completa de classes válidas que você pode carregar, consulte a documentação de referência dos módulos de resposta de conversa e intent de auxiliar.

  2. Crie uma instância de app chamando o serviço que você carregou. Por exemplo:

    const app = dialogflow();

  3. Para configurar a instância app na inicialização, forneça um objeto options como o primeiro argumento ao chamar o serviço. Consulte DialogflowOptions para ver mais detalhes. Por exemplo, o snippet a seguir mostra como registrar o payload JSON bruto da solicitação ou resposta do usuário definindo a sinalização { debug: true }:

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

Definir manipuladores para eventos

Para processar eventos relacionados ao Actions on Google criados pela biblioteca de cliente durante o ciclo de vida da interação do usuário com a ação, você usará a biblioteca de cliente para criar gerenciadores para processar as solicitações do usuário e enviar respostas.

Você pode criar funções que funcionam como manipuladores para esses tipos principais de eventos que a biblioteca de cliente reconhece:

  • Eventos de intent:as intents são identificadores exclusivos que o Actions on Google envia para o fulfillment sempre que um usuário solicita alguma funcionalidade específica. Se você estiver usando o Dialogflow, isso corresponde à correspondência entre uma consulta de usuário e uma intent no agente do Dialogflow.
  • Eventos de erro: quando ocorre um erro de JavaScript ou de biblioteca de cliente, é possível usar a função catch da instância app para processar a exceção de erro adequadamente. Implemente uma única função catch para lidar com todos os erros importantes para o fulfillment.
  • Eventos substitutos:um evento substituto ocorre quando o usuário envia uma consulta que o Actions on Google não consegue reconhecer. Você pode usar a função fallback da instância app para registrar um gerenciador substituto genérico que será acionado se nenhum gerenciador de intent corresponder à solicitação de atendimento recebida. Implemente uma única função fallback para processar todos os eventos substitutos. Se você estiver usando o Dialogflow, ele poderá acionar uma intent de fallback específica quando nenhuma outra intent for correspondida. Crie um gerenciador de intent correspondente para essa intent substituta.

Sempre que o usuário envia uma solicitação para a ação, a instância app cria um objeto Conversation que representa essa sessão de conversa. Esse objeto é acessado por meio do nome da variável conv transmitido na função do gerenciador da intent como o primeiro argumento da função. Normalmente, o objeto conv é usado nos gerenciadores para enviar uma resposta ao usuário.

As consultas do usuário também podem incluir parâmetros que a ação pode extrair e usar para refinar respostas.

  • Se você estiver usando o SDK do Actions, defina parâmetros no pacote de ações. Para ver um exemplo de como extrair parâmetros de intents, consulte o exemplo de código Eliza (link em inglês).
  • Se você estiver usando o Dialogflow, poderá acessar os valores de parâmetros por meio da variável params. Para ver exemplos de como processar intents com parâmetros no Dialogflow, consulte Parâmetros e contextos de acesso.

Definir gerenciadores para intents

Para definir o gerenciador de uma intent, chame a função intent() da instância app. Por exemplo, se você estiver usando o Dialogflow, essa será a função DialogflowApp#intent(). Nos argumentos, especifique o nome da intent e forneça uma função de gerenciador.

Se você estiver usando o Dialogflow, não precisará definir gerenciadores para cada intent no agente. Em vez disso, aproveite o gerenciador de respostas integrado do Dialogflow para processar automaticamente as intents sem implementar as próprias funções de gerenciador. Por exemplo, a intent de boas-vindas padrão pode ser delegada ao Dialogflow dessa maneira.

O exemplo a seguir mostra gerenciadores de intents para as intents "greeting" e "bye". As funções de gerenciador anônimos recebem um argumento conv e enviam uma resposta de string simples ao usuário por meio da função conv.ask():

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

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

Observe que a função close() é semelhante a ask(), exceto pelo fato de fechar o microfone e a conversa terminar.

Para saber mais sobre como criar gerenciadores de intents, consulte Criar gerenciadores de intents.

Definir manipuladores para eventos de erro

Para definir os gerenciadores de erros, chame a função catch() da instância app. Por exemplo, se você estiver usando o Dialogflow, essa será a função DialogflowApp#catch().

O exemplo a seguir mostra um gerenciador de erros de captura simples que envia o erro para a saída do console e retorna uma resposta de string simples para solicitar o usuário por meio da função conv.ask():

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

Definir manipuladores para eventos substitutos

Para definir um gerenciador substituto genérico quando nenhuma intent corresponder à solicitação de entrada de fulfillment, chame a função fallback() da instância app. Por exemplo, se você estiver usando o Dialogflow, essa será a função DialogflowApp#fallback().

O exemplo a seguir mostra um gerenciador substituto simples que envia de volta uma resposta de string simples para solicitar o usuário usando a função conv.ask():

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

Criar o gerenciador de intents

Esta seção aborda alguns casos de uso comuns para implementar gerenciadores de intent com a biblioteca de cliente. Para ver como a biblioteca de cliente corresponde à intent, consulte a seção "Processamento do gerenciador de intents" em Entender como funciona.

Acessar parâmetros e contextos

Se você estiver usando o Dialogflow, poderá definir parâmetros e contextos no agente do Dialogflow para manter as informações de estado e controlar o fluxo da conversa.

Os parâmetros são úteis para capturar palavras, frases ou valores importantes nas consultas do usuário. O Dialogflow extrai os parâmetros correspondentes das consultas do usuário no ambiente de execução, e é possível processar esses valores de parâmetros no webhook de fulfillment para determinar como responder aos usuários.

Sempre que o usuário envia uma solicitação para sua ação, a instância DialogflowApp cria um objeto parameters que representa os valores de parâmetro que o Dialogflow extraiu dessa solicitação. Esse objeto é acessado pelo nome da variável params.

O snippet a seguir mostra como acessar a propriedade name do objeto params quando o usuário envia uma solicitação:

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

Veja um snippet alternativo que faz a mesma coisa. As chaves ({}) realizam a desestruturação de JavaScript para usar a propriedade name do objeto parameters como uma variável local:

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

No snippet a seguir, o nome do parâmetro é full-name, mas está desestruturado e atribuído a uma variável local chamada name:

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

Os contextos são um recurso avançado do Dialogflow. É possível usar contextos para gerenciar o estado, o fluxo e a ramificação da conversa. A biblioteca de cliente fornece acesso a um contexto usando o objeto DialogflowConversation#contexts. O snippet a seguir mostra como definir um contexto de maneira programática no webhook de fulfillment e recuperar o objeto de contexto:

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('...');
});

Acessar resultados da intent auxiliar

Por conveniência, a biblioteca de cliente fornece classes de intent auxiliar que unem tipos comuns de dados do usuário solicitados com frequência pelas Ações. Elas incluem classes que representam os resultados das várias intents de auxiliar do Actions on Google. Use intents auxiliares quando quiser que o Google Assistente processe partes da conversa em que o usuário precisa fornecer uma entrada para continuar a conversa.

Exemplo: resultados do assistente de confirmação

A intent auxiliar de confirmação permite solicitar uma confirmação de sim/não do usuário e receber a resposta resultante. O snippet a seguir mostra como o webhook pode personalizar a resposta com base nos resultados retornados pela intent auxiliar de confirmação. Para ver um exemplo mais completo, consulte a documentação de referência da 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.`);
  }
});

O snippet a seguir mostra como o webhook de fulfillment pode personalizar a resposta com base na entrada do usuário em um carrossel. O componente de carrossel permite que a ação apresente uma seleção de opções para os usuários escolherem. Para ver um exemplo mais completo, consulte a documentação de referência da 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!`);
  }
});

Configurar objetos de resposta de conversa

A biblioteca de cliente oferece classes de resposta de conversa que representam respostas avançadas ou elementos multimídia que sua ação pode enviar. Normalmente, você envia essas respostas ou elementos quando os usuários não precisam fornecer nenhuma entrada para continuar a conversa.

Exemplo: imagem

O snippet a seguir mostra como o webhook de fulfillment pode enviar um Image em uma resposta que será anexada automaticamente a uma resposta BasicCard pela biblioteca:

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',
  }));
});

Fazer chamadas de função assíncronas

A biblioteca de cliente Node.js do Actions on Google foi projetada para programação assíncrona. O gerenciador de intents pode retornar uma promessa que será resolvida quando o webhook de fulfillment terminar de gerar uma resposta.

O snippet a seguir mostra como fazer uma chamada de função assíncrona para retornar um objeto de promessa e responder com uma mensagem caso seu webhook de fulfillment receba a intent de "saudação". Nesse snippet, a promessa garante que o webhook de fulfillment retorne uma resposta de conversa somente depois que a promessa para a chamada de API externa for resolvida.

Neste exemplo, estamos usando uma API falsa para acessar os dados meteorológicos.

/**
 * 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}.`);
  });
});

O snippet de código simplificado a seguir tem o mesmo efeito, mas usa o recurso async await introduzido na ECMA 2017 (Node.js versão 8). Para usar esse código com o Cloud Functions para Firebase, verifique se você está usando a versão correta do firebase-tools e a configuração correta.

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

Armazenar dados de conversação

A biblioteca de cliente permite que o webhook de fulfillment salve dados em conversas para uso futuro. Os principais objetos que podem ser usados para o armazenamento de dados incluem:

O snippet a seguir mostra como o webhook de fulfillment pode armazenar dados em uma propriedade arbitrária que você definiu (someProperty) e anexá-la ao objeto Conversation#user.storage. Para ver um exemplo mais completo, consulte a documentação de referência da classe Conversation#user.storage.

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

Você pode usar o objeto Conversation#user para coletar informações sobre o usuário, incluindo um identificador de string e informações pessoais. Alguns campos, como conv.user.name.display e conv.user.email, exigem a solicitação de conv.ask(new Permission) para NOME e conv.ask(new SignIn) para o Login do Google, respectivamente.

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!`);
  }
});

Como escalonar com middleware

É possível estender a biblioteca de cliente com um middleware.

A camada de middleware consiste em uma ou mais funções definidas por você, que a biblioteca de cliente executa automaticamente antes de chamar o gerenciador de intents. O uso de uma camada de middleware permite modificar a instância do Conversation e adicionar outras funcionalidades.

Os serviços do SDK do Actions e do Dialogflow expõem uma função app.middleware() que permite adicionar propriedades ou classes auxiliares à instância Conversation.

O snippet a seguir mostra um exemplo de como você pode usar um 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();
});

Exporte o app

Para expor o webhook de fulfillment para um framework da Web ou uma plataforma de computação sem servidor, é necessário exportar o objeto app como um webhook acessível publicamente. A biblioteca de cliente oferece suporte à implantação em vários ambientes prontos para uso.

Os snippets a seguir mostram como exportar app em diferentes ambientes de execução:

Exemplo: Cloud Functions para Firebase

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

Exemplo: editor in-line do Dialogflow

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

// ... app code here

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

Exemplo: servidor Express auto-hospedado (simples)

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

// ... app code here

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

Exemplo: servidor Express auto-hospedado (várias rotas)

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);

Exemplo: gateway da API AWS Lambda

// ... app code here

exports.fulfillment = app;