Crea entregas con la biblioteca cliente de Node.js de Actions on Google (Dialogflow)

La biblioteca cliente de Node.js de Actions on Google es la forma recomendada de acceder a la plataforma de Actions on Google y de interactuar con ella si creas un webhook de entrega en JavaScript.

Introducción

La biblioteca cliente de Node.js es una biblioteca de entregas para Actions on Google que proporciona las siguientes funciones:

  • Admite todas las funciones de Actions on Google, incluidos texto y respuestas multimedia enriquecidas, acceso a la cuenta, almacenamiento de datos, transacciones y más.
  • Proporciona una capa idiomática de abstracción en JavaScript que une la API de webhook de HTTP/JSON de conversación.
  • Controla los detalles de bajo nivel de la comunicación entre tu entrega y la plataforma de Actions on Google.
  • Se pueden instalar con herramientas de administración de paquetes conocidas, como npm o yarn.
  • Te permite implementar con facilidad tu webhook de entrega en plataformas de procesamiento sin servidores, como Cloud Functions para Firebase o AWS Lambda. También puedes alojar tu webhook de entrega en un proveedor de servicios en la nube o en un entorno autoalojado y autoadministrado.
  • Es compatible con Node.js v6.0.0 y versiones posteriores.

Puedes usar la biblioteca cliente junto con la integración de Dialogflow para Actions on Google o con el SDK de Actions.

Si deseas ver muestras de código completas para usar la biblioteca cliente, visita la página de muestras.

Consulta la referencia de la API

La referencia de la API se aloja en la página de GitHub de la biblioteca cliente de Actions on Google para Node.js.

También puedes generar una copia local de la referencia ejecutando el siguiente comando desde el directorio en el que descargaste el código de la biblioteca cliente:

yarn docs

Los documentos generados estarán disponibles en la carpeta docs del directorio en el que descargaste el código de la biblioteca cliente.

Comprende el funcionamiento

Antes de usar la biblioteca cliente, es útil comprender cómo tu webhook de entregas usa la biblioteca cliente para procesar las solicitudes de usuario que Actions on Google envía a tu entrega.

Cuando creas un webhook de entrega en JavaScript, puedes implementar y alojar tu código en un entorno de computación sin servidores, como Cloud Functions para Firebase de Google o AWS Lambda. También puedes alojar el código sin trabajo adicional con el framework web Express.

Dentro del entorno de ejecución, el webhook de entrega puede llamar a funciones en la biblioteca cliente para procesar las solicitudes de los usuarios y enviar respuestas a Actions on Google para renderizarlas en resultados del usuario.

A continuación, se resumen brevemente las tareas clave que controla el webhook de entrega con la ayuda de la biblioteca cliente:

Figura 1. Arquitectura de alto nivel de la biblioteca cliente de Node.js
  1. Recibir solicitudes de usuarios: Cuando un usuario realiza una consulta al Asistente de Google, la plataforma de Actions on Google envía una solicitud HTTP a tu webhook de entrega; la solicitud incluye una carga útil de JSON que contiene el intent y otros datos, como el texto sin procesar de la entrada del usuario y las capacidades de superficie del dispositivo del usuario. Para obtener más ejemplos del contenido de la carga útil de JSON, consulta las guías sobre el formato de webhook de Dialogflow y las guías sobre el formato de webhook de conversación.
  2. Detección del formato de llamada del framework: Para los frameworks compatibles, la biblioteca cliente detecta de forma automática el formato de llamada del framework (por ejemplo, si la solicitud provino del framework web Express o de AWS Lambda) y sabe cómo manejar sin problemas la comunicación con la plataforma Actions on Google.
  3. Procesamiento del controlador de servicio: La biblioteca cliente representa la API de webhook de HTTP/JSON de la conversación para Dialogflow y el SDK de Actions como una función del servicio. Tu webhook de entrega usa el servicio adecuado para crear una instancia app global. La instancia app actúa como un controlador de las solicitudes HTTP y comprende el protocolo específico del servicio.
  4. Procesamiento de conversaciones: La biblioteca cliente representa la información por conversación como un objeto Conversation que se adjunta a la instancia app. Tu webhook de entrega puede usar el objeto Conversation para recuperar datos almacenados entre conversaciones o información de estado, enviar respuestas a los usuarios o cerrar el micrófono.
  5. Procesamiento de middleware: La biblioteca cliente te permite crear tu propio middleware de servicios de conversación, que consiste en una o más funciones que defines para que la biblioteca cliente se ejecute automáticamente antes de llamar al controlador de intents. Tu webhook de entrega puede usar tu middleware para agregar propiedades o clases auxiliares al objeto Conversation.
  6. Procesamiento del controlador de intents: La biblioteca cliente te permite definir controladores para intents que comprenda tu webhook de entregas. Para Dialogflow, la biblioteca cliente enruta la solicitud al controlador de intent correcto mediante la asignación a la string exacta del nombre del intent definido en la consola de Dialogflow. En el caso del SDK de Actions, se enruta según la propiedad intent enviada desde Actions on Google.
  7. Envía respuestas a los usuarios: Para crear respuestas, tu webhook de entrega llama a la función Conversation#ask(). Se puede llamar a la función ask() varias veces para compilar la respuesta de forma incremental. La biblioteca cliente serializa la respuesta en una solicitud HTTP con una carga útil de JSON y la envía a Actions on Google. La función close() tiene un comportamiento similar a ask(), pero cierra la conversación.

Configura el entorno de desarrollo local

Antes de implementar el webhook de entrega, asegúrate de instalar la biblioteca cliente.

Instala la biblioteca cliente

La manera más fácil de instalar la biblioteca cliente en tu entorno de desarrollo local es usar un administrador de paquetes, como npm o yarn.

Para instalarlo, ejecuta uno de estos comandos desde la terminal:

  • Si usas npm: npm install actions-on-google
  • Si usas estambre: yarn add actions-on-google

Cómo configurar las carpetas de tu proyecto

Según dónde planees implementar el webhook de entrega (Cloud Functions para Firebase, AWS Lambda o Express autoalojado de Google), es posible que debas crear una estructura de carpeta de proyecto específica para guardar tus archivos.

Por ejemplo, si usas Cloud Functions para Firebase, puedes configurar las carpetas requeridas del proyecto mediante los pasos que se describen en Configura Node.js y Firebase CLI , y Inicializa Firebase para Cloud Functions. En el caso de Cloud Functions para Firebase, por lo general, debes escribir el webhook de entrega en el archivo /functions/index.js.

Cómo compilar una instancia de app

Actions on Google usa formatos de mensajería específicos para intercambiar solicitudes y respuestas con tu webhook de entregas, según si compilas una acción de conversación con Dialogflow o el SDK de Actions, o bien si compilas una Acción de casa inteligente.

Para representar estos protocolos diferentes de solicitud y respuesta, la biblioteca cliente proporciona tres funciones de servicio:

Ambos servicios de conversación (Dialogflow y SDK de Actions) usan el protocolo de webhook de conversación, pero cada servicio une los mensajes de manera diferente.

Usas un servicio para crear una instancia de app. La instancia app encapsula el estado global y la lógica de entrega de tu webhook, y controla la comunicación entre Actions on Google y tu entrega mediante el protocolo específico del servicio.

Puedes configurar las propiedades de la instancia app y llamar a sus métodos para dirigir el comportamiento del webhook de entrega. También puedes conectar fácilmente la instancia app a un entorno de computación sin servidores, como Cloud Functions para Firebase, que acepta funciones de JavaScript como controladores de solicitudes HTTP.

Para compilar una instancia de app en tu webhook de entrega, sigue estos pasos:

  1. Llama a la función require() para importar el módulo “actions-on-google” y cargar el servicio que deseas. Por ejemplo, en el siguiente fragmento, se muestra cómo cargar el servicio dialogflow y algunos elementos usados para compilar respuestas, y asignarlo a una constante llamada dialogflow:

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

    Aquí, actions-on-google hace referencia a una dependencia que se especifica en un archivo package.json de la carpeta de tu proyecto (puedes consultar este archivo package.json de ejemplo para ver un ejemplo).

    Cuando obtienes una instancia de app, puedes especificar de forma opcional las clases que representan respuestas enriquecidas, intents auxiliares y otras funciones de Actions on Google que deseas usar. Para obtener la lista completa de clases válidas que puedes cargar, consulta la documentación de referencia de los módulos de respuesta a conversación y intent auxiliar.

  2. Llama al servicio que cargaste para crear una instancia de app. Por ejemplo:

    const app = dialogflow();

  3. Para configurar la instancia app en la inicialización, puedes proporcionar un objeto options como primer argumento cuando llames al servicio. (Consulta DialogflowOptions para obtener más detalles). Por ejemplo, en el siguiente fragmento, se muestra cómo registrar la carga útil de JSON sin procesar de la solicitud o la respuesta del usuario mediante la configuración de la marca { debug: true }:

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

Configura controladores para eventos

Para procesar eventos relacionados con Actions on Google que crea la biblioteca cliente durante el ciclo de vida de la interacción del usuario con tu acción, usarás la biblioteca cliente para compilar controladores para procesar las solicitudes de los usuarios y enviar respuestas.

Puedes crear funciones que actúen como controladores para los principales tipos de eventos que la biblioteca cliente reconoce:

  • Eventos de intent: Los intents son identificadores únicos que Actions on Google envía a tu entrega cada vez que un usuario solicita alguna funcionalidad específica. Si usas Dialogflow, esto corresponde a la coincidencia de una consulta de usuario con un intent en tu agente de Dialogflow.
  • Eventos de error: Cuando se produce un error de JavaScript o de la biblioteca cliente, puedes usar la función catch de la instancia app para procesar correctamente la excepción del error. Debes implementar una sola función catch para controlar todos los errores que le interesan a tu entrega.
  • Eventos de resguardo: Un evento de resguardo ocurre cuando el usuario envía una consulta que Actions on Google no puede reconocer. Puedes usar la función fallback de la instancia app para registrar un controlador de resguardo genérico que se activará si no se encontró ningún controlador de intents que coincida con la solicitud de entrega entrante. Debes implementar una sola función fallback para controlar todos los eventos de resguardo. Si usas Dialogflow, Dialogflow puede activar un intent de resguardo específico cuando no hay otra coincidencia con otro intent. Debes crear un controlador de intents correspondiente para ese intent de resguardo.

Cada vez que el usuario envía una solicitud a tu acción, la instancia de app crea un objeto Conversation que representa esa sesión de conversación. Se accede a este objeto a través del nombre de la variable conv que se pasa en la función del controlador del intent como el primer argumento de la función. Por lo general, usarás el objeto conv en tus controladores para enviar una respuesta al usuario.

Las consultas de los usuarios también pueden incluir parámetros que tu acción puede extraer y usar para definir mejor las respuestas.

  • Si usas el SDK de Actions, defines los parámetros en el Paquete de acción. Para ver un ejemplo de cómo puedes extraer parámetros de intents, consulta la muestra de código de Eliza.
  • Si usas Dialogflow, puedes acceder a los valores de los parámetros a través de la variable params. Para ver ejemplos de manejo de intents con parámetros en Dialogflow, consulta Accede a parámetros y contextos.

Cómo configurar controladores para intents

Si deseas configurar el controlador para un intent, llama a la función intent() de tu instancia app. Por ejemplo, si usas Dialogflow, esta es la función DialogflowApp#intent(). En los argumentos, especifica el nombre del intent y proporciona una función del controlador.

Si usas Dialogflow, no necesitas configurar controladores para cada intent en tu agente. En su lugar, puedes aprovechar el controlador de respuestas integrado de Dialogflow para controlar automáticamente los intents sin implementar tus propias funciones de controlador. Por ejemplo, el intent de bienvenida predeterminado se puede delegar a Dialogflow de esta manera.

En el siguiente ejemplo, se muestran los controladores de intents para los intents "greeting" y "bye". Sus funciones de controlador anónimos toman un argumento conv y envían una respuesta de string simple al usuario a través de la función conv.ask():

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

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

Ten en cuenta que la función close() es similar a ask(), excepto que cierra el micrófono y finaliza la conversación.

Si quieres obtener más información a fin de compilar controladores para intents, consulta Cómo compilar tu controlador de intents.

Configura controladores para eventos de error

A fin de configurar los controladores para errores, llama a la función catch() de tu instancia app. (Por ejemplo, si usas Dialogflow, esta es la función DialogflowApp#catch()).

En el siguiente ejemplo, se muestra un controlador de error de captura simple que envía el error al resultado de la consola y devuelve una respuesta de string simple para solicitar al usuario a través de la función conv.ask():

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

Configura controladores para eventos de resguardo

Si deseas configurar un controlador de resguardo genérico cuando no hay coincidencias de intents para la solicitud entrante de entrega, llama a la función fallback() de tu instancia de app. (Por ejemplo, si usas Dialogflow, esta es la función DialogflowApp#fallback()).

En el siguiente ejemplo, se muestra un controlador de resguardo simple que envía una respuesta de string simple para pedirle al usuario mediante la función conv.ask():

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

Cómo compilar tu controlador de intents

En esta sección, se abordan algunos casos de uso comunes en los que se implementan controladores de intents con la biblioteca cliente. Para ver cómo la biblioteca cliente coincide con el intent, consulta la sección "Procesamiento del controlador de intents" en Comprende cómo funciona.

Parámetros de acceso y contextos

Si usas Dialogflow, puedes definir parámetros y contextos en tu agente de Dialogflow para mantener la información de estado y controlar el flujo de la conversación.

Los parámetros son útiles para capturar palabras, frases o valores importantes en las consultas de los usuarios. Dialogflow extrae los parámetros correspondientes de las consultas de los usuarios en el entorno de ejecución, y puedes procesar estos valores de parámetros en tu webhook de entregas para determinar cómo responder a los usuarios.

Cada vez que el usuario envía una solicitud a tu acción, la instancia DialogflowApp crea un objeto parameters que representa los valores del parámetro que Dialogflow extrajo de esa solicitud. Se accede a este objeto a través del nombre de la variable params.

En el siguiente fragmento, se muestra cómo puedes acceder a la propiedad name desde el objeto params cuando el usuario envía una solicitud:

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

Este es un fragmento alternativo que hace lo mismo. Las llaves ({}) realizan la desestructuración de JavaScript para tomar la propiedad name del objeto parameters y usarla como una variable local:

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

En el siguiente fragmento, el nombre del parámetro es full-name, pero está desestructurado y se asigna a una variable local llamada name:

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

Los contextos son una función avanzada de Dialogflow. Puedes usar contextos para administrar el estado, el flujo y la rama de la conversación. La biblioteca cliente proporciona acceso a un contexto a través del objeto DialogflowConversation#contexts. En el siguiente fragmento, se muestra cómo puedes configurar un contexto de manera programática en tu webhook de entrega y cómo recuperar el 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('...');
});

Cómo acceder a los resultados de intents auxiliares

Para mayor comodidad, la biblioteca cliente proporciona clases de intents auxiliares que unen tipos comunes de datos del usuario que las Acciones solicitan con frecuencia. Entre ellas, se incluyen clases que representan los resultados de los distintos intents auxiliares de Actions on Google. Puedes usar intents auxiliares cuando quieras que Asistente de Google maneje partes de la conversación en las que el usuario debe proporcionar una entrada para continuar la conversación.

Ejemplo: Resultados del asistente de confirmación

El intent auxiliar de confirmación te permite solicitar una confirmación de sí o no del usuario y obtener la respuesta resultante. En el siguiente fragmento, se muestra cómo el webhook puede personalizar su respuesta en función de los resultados que muestra el intent auxiliar de confirmación. Para ver un ejemplo más completo, consulta la documentación de referencia de la clase 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.`);
  }
});

En el siguiente fragmento, se muestra cómo tu webhook de entrega puede personalizar su respuesta según la entrada del usuario para un carrusel. El componente de carrusel permite que tu acción presente una selección de opciones para que los usuarios elijan. Para obtener un ejemplo más completo, consulta la documentación de referencia de la clase 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 objetos de respuesta de conversación

La biblioteca cliente proporciona clases de respuesta en conversaciones que representan respuestas enriquecidas o elementos multimedia que tu acción puede enviar. Por lo general, envías estas respuestas o elementos cuando los usuarios no necesitan dar ninguna entrada para continuar la conversación.

Ejemplo: Imagen

En el siguiente fragmento, se muestra cómo tu webhook de entrega puede enviar un Image en una respuesta que la biblioteca adjuntará automáticamente a una respuesta BasicCard:

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

Realiza llamadas a funciones asíncronas

La biblioteca cliente de Node.js de Actions on Google está diseñada para la programación asíncrona. Tu controlador de intents puede mostrar una promesa que se resuelve cuando tu webhook de entrega termina de generar una respuesta.

En el siguiente fragmento, se muestra cómo puedes realizar una llamada a función asíncrona para mostrar un objeto de promesa y, luego, responder con un mensaje si tu webhook de entregas recibe el intent de saludo. En este fragmento, la promesa garantiza que tu webhook de entrega muestre una respuesta de conversación solo después de que se haya resuelto la promesa para la llamada a la API externa.

En este ejemplo, usamos una API falsa para obtener los datos del clima.

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

El siguiente fragmento de código optimizado tiene el mismo efecto, pero usa la función await async que se introdujo en ECMA 2017 (Node.js versión 8). Si quieres usar este código con Cloud Functions para Firebase, asegúrate de usar la versión correcta de firebase-tools y de tener la configuración correspondiente.

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

Almacena datos de conversaciones

La biblioteca cliente permite que tu webhook de entrega guarde datos en conversaciones para usarlos en el futuro. Entre los objetos clave que puedes usar para el almacenamiento de datos, se incluyen los siguientes:

En el siguiente fragmento, se muestra cómo tu webhook de entrega puede almacenar datos en una propiedad arbitraria que definiste (someProperty) y adjuntarlos al objeto Conversation#user.storage. Para obtener un ejemplo más completo, consulta la documentación de referencia de la clase Conversation#user.storage.

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

Puedes usar el objeto Conversation#user para obtener información sobre el usuario, incluido un identificador de cadena y también información personal. Algunos campos, como conv.user.name.display y conv.user.email, requieren solicitar conv.ask(new Permission) para NOMBRE y conv.ask(new SignIn) para el Acceso con 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!`);
  }
});

Cómo escalar con middleware

Puedes extender la biblioteca cliente a través de middleware.

La capa de middleware consta de una o más funciones que defines y que la biblioteca cliente ejecuta automáticamente antes de llamar al controlador de intents. El uso de una capa de middleware te permite modificar la instancia de Conversation y agregar funcionalidades adicionales.

Los servicios del SDK de Dialogflow y Actions exponen una función app.middleware() que te permite agregar propiedades o clases auxiliares a la instancia de Conversation.

En el siguiente fragmento, se muestra un ejemplo de cómo podrías usar el 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 su aplicación

Si quieres exponer tu webhook de entrega para un framework web o una plataforma de computación sin servidores, debes exportar el objeto app como un webhook de acceso público. La biblioteca cliente admite la implementación en varios entornos de manera predeterminada.

En los siguientes fragmentos, se muestra cómo puedes exportar app en diferentes entornos de ejecución:

Ejemplo: Cloud Functions para Firebase

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

Ejemplo: Editor directo de Dialogflow

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

// ... app code here

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

Ejemplo: Servidor Express autoalojado (simple)

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

// ... app code here

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

Ejemplo: Servidor Express autoalojado (varias rutas)

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

Ejemplo: Puerta de enlace de la API de AWS Lambda

// ... app code here

exports.fulfillment = app;