Webhooks

Para darte aún más flexibilidad en la compilación de Actions, puedes delegar la a servicios web HTTPS (entregas). Tus Acciones pueden activar webhooks que realiza solicitudes a un extremo HTTPS. Algunos ejemplos de lo que puedes hacer en entregas incluyen:

  • Generar una instrucción dinámica basada en la información que proporcionó el usuario
  • Realizar un pedido en un sistema externo y confirmar que se realizó correctamente
  • Validación de ranuras con datos de backend
Figura 1: Las escenas y los intents de invocación pueden activar webhooks.

Activadores y controladores de webhooks

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

  • Después de que coincida un intent de invocación
  • Durante una escena que está en entrar al escenario
  • 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 relleno de ranuras de una escena
  • Después de una coincidencia de intent en la etapa de entrada de una escena

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

Cargas útiles

Los siguientes fragmentos muestran ejemplos de solicitudes a las que envían tus acciones la entrega y una respuesta que esta envíe de vuelta. Consulta la documentación de referencia para obtener más información.

Solicitud de ejemplo

{
  "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 en tiempo de ejecución

En las siguientes secciones, se describen las tareas comunes que puedes realizar en tu controladores de webhook.

Cómo enviar instrucciones

Puedes crear instrucciones con texto simple, texto enriquecido, tarjetas y hasta elementos completos Instrucciones HTML respaldadas por una aplicación web con lienzo interactivo. La documentación sobre mensajes tiene y completa para crear una instrucción cuando se controla un evento de webhook. Los siguientes fragmentos muestran 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'
    })
  }));
});

JSON de la respuesta

{
  "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": ""
    }
  }
}

Cómo leer los parámetros del intent

Cuando el tiempo de ejecución de Asistente coincide con un intent, extrae cualquier intent definido parámetros. La propiedad original era la que el usuario proporcionó como entrada. resuelta es lo que la CLN resolvió la entrada según el tipo especificación.

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 configuración regional del usuario

Este valor corresponde a la configuración regional del usuario para 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"
    ]
  }
}

Almacenamiento de lectura y escritura

Consulta la documentación sobre almacenamiento para obtener información completa sobre cómo usan 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"
    ]
  }
}

JSON de la respuesta

{
  "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"
    }
  }
}

Cómo verificar las capacidades del dispositivo

Puedes comprobar las capacidades de un dispositivo para brindar diferentes experiencias de los 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 superficie, consulta el archivo Capability. referencia.

Anulaciones del tipo de entorno de ejecución

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

Para usar tipos de entorno de ejecución, debes activar un webhook desde tu acción que llame a un en tu entrega. Desde allí, puedes completar session.typeOverrides en una respuesta a tu acción. Disponibles los modos incluyen TYPE_MERGE para preservar las entradas de tipo existentes o TYPE_REPLACE para reemplazar las entradas existentes con 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']
        },
    ]
  }
}];

JSON de la respuesta

{
  "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 personalización del habla

La personalización de voz te permite especificar sugerencias a la CLN para mejorar la coincidencia de intents. Tú puede especificar hasta 1,000 entradas.

Node.js

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

JSON de la respuesta

{
  "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 Actions, puedes para que ocurran transiciones de escena durante el tiempo de ejecución.

Node.js

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

JSON de la respuesta

{
  "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 el espacio o verificar la 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 En este ejemplo, el nombre del espacio es datetime1. Para obtener la zona horaria, deberías usa:

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 espacios de escena

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

Node.js

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

JSON de la respuesta

{
  "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 el de Cloud. También puedes compilar e implementar las entregas en el hosting que elijas y registrar tu extremo de entrega HTTPS como tu controlador de webhook.

Editor directo

Sigue estos pasos para desarrollar con el editor de Cloud Functions:

  1. Crea el archivo sdk/webhooks/ActionsOnGoogleFulfillment.yaml: y definir los controladores para la acción y la Cloud Function intercalada que se usa para la entrega.
    handlers:
    - name: questionOnEnterFunc
    - name: fruitSlotValidationFunc
    inlineCloudFunction:
      executeFunction: ActionsOnGoogleFulfillment
        
  2. Crea la carpeta sdk/webhooks/ActionsOnGoogleFulfillment. y agrega un archivo index.js que implemente los controladores definido previamente y un archivo package.json que define npm los requisitos de tu código.
    // index.js
    const {conversation} = require('@assistant/conversation');
    const functions = require('firebase-functions');
    
    const app = conversation();
    
    app.handle('questionOnEnterFunc', conv => {
      conv.add('questionOnEnterFunc triggered on webhook');
    });
    
    app.handle('fruitSlotValidationFunc', conv => {
      conv.add('fruitSlotValidationFunc triggered on webhook');
    });
    
    exports.ActionsOnGoogleFulfillment = functions.https.onRequest(app);
        
    // package.json
    {
      "name": "ActionsOnGoogleFulfillment",
      "version": "0.1.0",
      "description": "Actions on Google fulfillment",
      "main": "index.js",
      "dependencies": {
        "@assistant/conversation": "^3.0.0",
        "firebase-admin": "^5.4.3",
        "firebase-functions": "^0.7.1"
      }
    }
        

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 de conversación. Sin embargo, puedes implementar entregas a un servicio de hosting que elijas.

Cómo configurar el entorno

Recomendamos la siguiente estructura de proyecto cuando uses Cloud Functions para Firebase como servicio de entrega:

ProjectFolder        - Root folder for the project
  sdk                - Actions project configuration files
  functions          - Cloud functions for Firebase files

Para configurar tu entorno, sigue estos pasos:

  1. Descarga y, luego, instala Node.js.
  2. Configura y, luego, inicializa Firebase CLI. Si el siguiente comando falla con EACCES, 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 donde guardaste tu proyecto de Acciones. Se te pedirá que selecciones las funciones de Firebase CLI para las que quieres configurar tu proyecto de Acciones. Elige Functions y otras funciones que podrían interesarte usar, como Firestore, luego presiona Intro para confirmar y continuar:

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

  6. Después de elegir el proyecto, la herramienta de Firebase inicia las funciones y te preguntará qué idioma quieres 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 el estilo de manera forzosa. Para ello, escribe Y o N:

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

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

    Cuando finalice 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 entrega y, luego, implementa la función de entrega:

    $ npm install
    $ firebase deploy --only functions
    

    La implementación tarda unos minutos. Cuando termines, verás un resultado similar al como se muestra a continuación. Necesitarás la URL de la función para ingresarla 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 siguiente sección.

Registrar controlador de webhook

  1. Crea el archivo sdk/webhooks/ActionsOnGoogleFulfillment.yaml y define los controladores para tu acción y la URL para las solicitudes de webhook.
    httpsEndpoint:
      baseUrl: https://my.web.hook/ActionsOnGoogleFulfillment
      endpointApiVersion: 2
    handlers:
    - name: questionOnEnterFunc
    - name: fruitSlotValidationFunc