Webhooks

Para brindarte aún más flexibilidad en la creación de acciones, puedes delegar la lógica a los servicios web HTTPS (entrega). Tus acciones pueden activar webhooks que realizan solicitudes a un extremo HTTPS. Estos son algunos ejemplos de lo que puedes hacer en la entrega:

  • Generar un mensaje dinámico en función de la información proporcionada por el usuario
  • Realizar un pedido en un sistema externo y confirmar el éxito
  • Validar ranuras con datos de backend
Figura 1. Los intents y las escenas de invocación pueden activar webhooks.

Activadores y controladores de webhook

Tus acciones pueden activar un webhook dentro de intents o escenas de invocación, que envía una solicitud a tu extremo de entrega. Tu entrega contiene controladores de webhook que procesan la carga útil de JSON en la solicitud. Puedes activar webhooks en las siguientes situaciones:

  • Después de una coincidencia de intent de invocación
  • Durante la etapa de entrada de una escena
  • Después de que una condición se evalúa como verdadera en la etapa de condición de una escena
  • Durante la etapa de llenado de ranuras de una escena
  • Después de que se produce una coincidencia de intent en la etapa de entrada de una escena

Cuando activas un webhook en tus acciones, el Asistente de Google envía una solicitud con una carga útil de JSON a tu entrega, que contiene el nombre del controlador que se usa para procesar el evento. Tu extremo de entrega puede enrutar el evento al controlador adecuado para llevar a cabo la lógica y mostrar una respuesta correspondiente con una carga útil de JSON.

Cargas útiles

En los siguientes fragmentos, se muestran ejemplos de solicitudes que tus acciones envían a la entrega y una respuesta que tu entrega envía de vuelta. Consulta la documentación de referencia para obtener más información.

Ejemplo de solicitud

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "actions.intent.MAIN",
    "params": {},
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {}
  },
  "session": {
    "id": "example_session_id",
    "params": {},
    "typeOverrides": []
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
    }
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

Ejemplo de respuesta

{
  "session": {
    "id": "example_session_id",
    "params": {}
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "Hello World.",
      "text": ""
    }
  },
  "scene": {
    "name": "SceneName",
    "slots": {},
    "next": {
      "name": "actions.scene.END_CONVERSATION"
    }
  }
}

Interacciones del entorno de ejecución

En las siguientes secciones, se describen las tareas comunes que puedes llevar a cabo en tus controladores de webhook.

Enviar mensajes

Puedes crear mensajes con texto simple, texto enriquecido, tarjetas e incluso mensajes HTML completos respaldados por una app web con Interactive Canvas. La documentación de mensajes contiene información completa sobre cómo crear un mensaje cuando se controla un evento de webhook. En los siguientes fragmentos, se muestra un mensaje de tarjeta:

Node.js

app.handle('rich_response', conv => {
  conv.add('This is a card rich response.');
  conv.add(new Card({
    title: 'Card Title',
    subtitle: 'Card Subtitle',
    text: 'Card Content',
    image: new Image({
      url: 'https://developers.google.com/assistant/assistant_96.png',
      alt: 'Google Assistant logo'
    })
  }));
});

Respuesta JSON

{
  "session": {
    "id": "example_session_id",
    "params": {}
  },
  "prompt": {
    "override": false,
    "content": {
      "card": {
        "title": "Card Title",
        "subtitle": "Card Subtitle",
        "text": "Card Content",
        "image": {
          "alt": "Google Assistant logo",
          "height": 0,
          "url": "https://developers.google.com/assistant/assistant_96.png",
          "width": 0
        }
      }
    },
    "firstSimple": {
      "speech": "This is a card rich response.",
      "text": ""
    }
  }
}

Leer parámetros de intent

Cuando el entorno de ejecución del Asistente asocia un intent, extrae los parámetros definidos. La propiedad original es lo que el usuario proporcionó como entrada, y la propiedad resuelta es lo que el NLU resolvió como entrada en función de la especificación de tipo.

Node.js

conv.intent.params['param_name'].original
conv.intent.params['param_name'].resolved

JSON de la solicitud

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "intent_name",
    "params": {
      "slot_name": {
        "original": "1",
        "resolved": 1
      }
    },
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {},
    "next": {
      "name": "actions.scene.END_CONVERSATION"
    }
  },
  "session": {
    "id": "session_id",
    "params": {},
    "typeOverrides": []
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
    }
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

Leer la configuración regional del usuario

Este valor corresponde a la configuración regional del usuario para el Asistente de Google.

Node.js

conv.user.locale

JSON

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "actions.intent.MAIN",
    "params": {},
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {}
  },
  "session": {
    "id": "session_id",
    "params": {},
    "typeOverrides": []
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
    }
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

Leer y escribir almacenamiento

Consulta la documentación de almacenamiento para obtener información completa sobre cómo usar varias funciones de almacenamiento.

Node.js

//read
conv.session.params.key
conv.user.params.key
conv.home.params.key

// write
conv.session.params.key = value
conv.user.params.key = value
conv.home.params.key = value 

JSON de la solicitud

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "actions.intent.MAIN",
    "params": {},
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {}
  },
  "session": {
    "id": "session_id",
    "params": {
      "key": "value"
    },
    "typeOverrides": [],
    "languageCode": ""
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED",
      "key": "value"
    }
  },
  "home": {
    "params": {
      "key": "value"
    }
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

Respuesta JSON

{
  "session": {
    "id": "session_id",
    "params": {
      "key": "value"
    }
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "Hello world.",
      "text": ""
    }
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED",
      "key": "value"
    }
  },
  "home": {
    "params": {
      "key": "value"
    }
  }
}

Verificar las capacidades del dispositivo

Puedes verificar las capacidades de un dispositivo para ofrecer diferentes experiencias o flujos de conversación.

Node.js

const supportsRichResponse = conv.device.capabilities.includes("RICH_RESPONSE");
const supportsLongFormAudio = conv.device.capabilities.includes("LONG_FORM_AUDIO");
const supportsSpeech = conv.device.capabilities.includes("SPEECH");
const supportsInteractiveCanvas = conv.device.capabilities.includes("INTERACTIVE_CANVAS");

JSON de la solicitud

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "actions.intent.MAIN",
    "params": {},
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {}
  },
  "session": {
    "id": "session_id",
    "params": {},
    "typeOverrides": [],
    "languageCode": ""
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
    }
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO",
      "INTERACTIVE_CANVAS"
    ]
  }
}

Para obtener una lista completa de las capacidades de la superficie, consulta la Capability referencia.

Anulaciones de tipo de entorno de ejecución

Los tipos de entorno de ejecución te permiten modificar las especificaciones de tipo en el entorno de ejecución. Puedes usar esta función para cargar datos de otras fuentes y propagar los valores válidos de un tipo. Por ejemplo, puedes usar anulaciones de tipo de entorno de ejecución para agregar opciones dinámicas a una pregunta de la encuesta o para agregar un elemento diario a un menú.

Para usar tipos de entorno de ejecución, activa un webhook desde tu acción que llame a un controlador en tu entrega. Desde allí, puedes propagar el parámetro session.typeOverrides en una respuesta a tu acción. Los modos disponibles incluyen TYPE_MERGE para conservar las entradas de tipo existentes o TYPE_REPLACE para reemplazar las entradas existentes por las anulaciones.

Node.js

conv.session.typeOverrides = [{
    name: type_name,
    mode: 'TYPE_REPLACE',
    synonym: {
      entries: [
        {
          name: 'ITEM_1',
          synonyms: ['Item 1', 'First item']
        },
        {
          name: 'ITEM_2',
          synonyms: ['Item 2', 'Second item']
       },
       {
          name: 'ITEM_3',
          synonyms: ['Item 3', 'Third item']
        },
        {
          name: 'ITEM_4',
          synonyms: ['Item 4', 'Fourth item']
        },
    ]
  }
}];

Respuesta JSON

{
  "session": {
    "id": "session_id",
    "params": {},
    "typeOverrides": [
      {
        "name": "type_name",
        "synonym": {
          "entries": [
            {
              "name": "ITEM_1",
              "synonyms": [
                "Item 1",
                "First item"
              ]
            },
            {
              "name": "ITEM_2",
              "synonyms": [
                "Item 2",
                "Second item"
              ]
            },
            {
              "name": "ITEM_3",
              "synonyms": [
                "Item 3",
                "Third item"
              ]
            },
            {
              "name": "ITEM_4",
              "synonyms": [
                "Item 4",
                "Fourth item"
              ]
            }
          ]
        },
        "typeOverrideMode": "TYPE_REPLACE"
      }
    ]
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "This is an example prompt.",
      "text": "This is an example prompt."
    }
  }
}

Proporcionar sesgos de voz

El sesgo de voz te permite especificar sugerencias para el NLU para mejorar la coincidencia de intents. Puedes especificar hasta 1,000 entradas.

Node.js

conv.expected.speech = ['value_1', 'value_2']
conv.expected.language = 'locale_string'

Respuesta JSON

{
  "session": {
    "id": "session_id",
    "params": {}
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "This is an example prompt.",
      "text": "This is an example prompt."
    }
  },
  "expected": {
    "speech": "['value_1', 'value_2']",
    "language": "locale_string"
  }
}

Escenas de transición

Además de definir transiciones estáticas en tu proyecto de acciones, puedes hacer que se produzcan transiciones de escena en el entorno de ejecución.

Node.js

app.handle('transition_to_hidden_scene', conv => {
  // Dynamic transition
  conv.scene.next.name = "HiddenScene";
});

Respuesta JSON

{
  "session": {
    "id": "session_id",
    "params": {}
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "This is an example prompt.",
      "text": ""
    }
  },
  "scene": {
    "name": "SceneName",
    "slots": {},
    "next": {
      "name": "HiddenScene"
    }
  }
}

Leer ranuras de escena

Durante el llenado de ranuras, puedes usar la entrega para validar la ranura o verificar el estado del llenado de ranuras (SlotFillingStatus).

Node.js

conv.scene.slotFillingStatus  // FINAL means all slots are filled
conv.scene.slots  // Object that contains all the slots
conv.scene.slots['slot_name'].<property_name> // Accessing a specific slot's properties

Por ejemplo, supongamos que deseas extraer la zona horaria de una respuesta. En este ejemplo, el nombre de la ranura es datetime1. Para obtener la zona horaria, usarías lo siguiente:

conv.scene.slots['datetime1'].value.time_zone.id

JSON de la solicitud

{
  "handler": {
    "name": "handler_name"
  },
  "intent": {
    "name": "",
    "params": {
      "slot_name": {
        "original": "1",
        "resolved": 1
      }
    },
    "query": ""
  },
  "scene": {
    "name": "SceneName",
    "slotFillingStatus": "FINAL",
    "slots": {
      "slot_name": {
        "mode": "REQUIRED",
        "status": "SLOT_UNSPECIFIED",
        "updated": true,
        "value": 1
      }
    },
    "next": {
      "name": "actions.scene.END_CONVERSATION"
    }
  },
  "session": {
    "id": "session_id",
    "params": {
      "slot_name": 1
    },
    "typeOverrides": []
  },
  "user": {
    "locale": "en-US",
    "params": {
      "verificationStatus": "VERIFIED"
    }
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

Invalidar ranuras de escena

Puedes invalidar ranuras y hacer que el usuario proporcione un valor nuevo.

Node.js

conv.scene.slots['slot_name'].status = 'INVALID'

Respuesta JSON

{
  "session": {
    "id": "session_id",
    "params": {
      "slot_name": 1
    }
  },
  "prompt": {
    "override": false,
    "firstSimple": {
      "speech": "This is an example prompt.",
      "text": ""
    }
  },
  "scene": {
    "name": "SceneName",
    "slots": {
      "slot_name": {
        "mode": "REQUIRED",
        "status": "INVALID",
        "updated": true,
        "value": 1
      }
    },
    "next": {
      "name": "actions.scene.END_CONVERSATION"
    }
  }
}

Opciones de desarrollo

Actions Builder proporciona un editor directo llamado editor de Cloud Functions, que te permite compilar e implementar una Cloud Function para Firebase directamente en la consola. También puedes compilar e implementar la entrega en el hosting que elijas y registrar tu extremo de entrega HTTPS como controlador de webhook.

Editor directo

Para desarrollar con el editor de Cloud Functions, haz lo siguiente:

  1. Abre tu proyecto de acciones y ve a la pestaña Desarrollar > Webhook > Cambiar método de entrega. Aparecerá la ventana Métodos de entrega.
  2. Selecciona Inline Cloud Functions y haz clic en Confirm.

Extremo HTTPS externo

En esta sección, se describe cómo configurar Cloud Functions para Firebase como un servicio de entrega para tu acción conversacional. Sin embargo, puedes implementar la entrega en un servicio de hosting de tu elección.

Cómo configurar el entorno

Para configurar tu entorno, sigue estos pasos:

  1. Descarga e instala Node.js.
  2. Configura e inicializa Firebase CLI. Si el siguiente comando falla con un EACCES error, es posible que debas cambiar los permisos de npm.

    npm install -g firebase-tools
    
  3. Autentica la herramienta de Firebase con tu Cuenta de Google:

    firebase login
    
  4. Inicia el directorio del proyecto en el que guardaste tu proyecto de acciones. Se te pedirá que selecciones las funciones de Firebase CLI que deseas configurar para tu proyecto de acciones. Elige Functions y otras funciones que quieras usar, como Firestore, y, luego, presiona Intro para confirmar y continuar:

    $ cd <ACTIONS_PROJECT_DIRECTORY>
    $ firebase init
    
  5. Asocia la herramienta de Firebase con tu proyecto de acciones seleccionándolo con las teclas de flecha para navegar por la lista de proyectos:

  6. Después de elegir el proyecto, la herramienta de Firebase inicia la configuración de Functions y te pregunta qué lenguaje deseas usar. Selecciona con las teclas de flecha y presiona Intro para continuar.

    === Functions Setup
    A functions directory will be created in your project with a Node.js
    package pre-configured. Functions can be deployed with firebase deploy.
    
    ? What language would you like to use to write Cloud Functions? (Use arrow keys)
    > JavaScript
    TypeScript
    
  7. Elige si deseas usar ESLint para detectar posibles errores y aplicar estilo escribiendo Y o N:

    ? Do you want to use ESLint to catch probable bugs and enforce style? (Y/n)
  8. Para obtener las dependencias del proyecto, escribe Y en el mensaje:

    ? Do you want to install dependencies with npm now? (Y/n)

    Una vez que se complete la configuración, verás un resultado similar al siguiente:

    ✔  Firebase initialization complete!
    
  9. Instala la dependencia @assistant/conversation:

    $ cd <ACTIONS_PROJECT_DIRECTORY>/functions
    $ npm install @assistant/conversation --save
    
  10. Obtén las dependencias de la entrega e implementa la función de entrega:

    $ npm install
    $ firebase deploy --only functions
    

    La implementación tarda unos minutos. Una vez completada, verás un resultado similar al siguiente. Necesitarás la URL de la función para ingresar en Dialogflow.

    ✔  Deploy complete!
    Project Console: https://console.firebase.google.com/project/<PROJECT_ID>/overview Function URL (<FUNCTION_NAME>): https://us-central1-<PROJECT_ID>.cloudfunctions.net/<FUNCTION_NAME>
  11. Copia la URL de entrega para usarla en la próxima sección.

Registrar el controlador de webhook

Para registrar tu extremo de Cloud Functions como controlador de webhook, haz lo siguiente:

  1. En la Consola de Actions, haz clic en Desarrollar > Webhook.
  2. Haz clic en Cambiar método de entrega. Aparecerá la ventana Métodos de entrega.
  3. Selecciona Webhook y haz clic en Confirm.
  4. Pega la URL de tu servicio web en el campo Webhook.
  5. Haz clic en Guardar.