Webhooks

Para oferecer ainda mais flexibilidade na criação de ações, você pode delegar a lógica a serviços da Web HTTPS (fulfillment). Suas ações podem acionar webhooks que fazem solicitações para um endpoint HTTPS. Veja alguns exemplos do que é possível fazer no fulfillment:

  • Gerar um comando dinâmico com base nas informações fornecidas pelo usuário.
  • Fazer um pedido em um sistema externo e confirmar o sucesso.
  • Como validar slots com dados de back-end.
Figura 1. Intents e cenas de invocação podem acionar webhooks.

Acionadores e gerenciadores de webhook

Suas ações podem acionar um webhook em intents ou cenas de invocação, que envia uma solicitação para o endpoint de fulfillment. O fulfillment contém gerenciadores de webhook, que processam o payload JSON na solicitação. É possível acionar webhooks nas seguintes situações:

  • Após uma correspondência de intent de invocação
  • Durante a entrada de uma cena
  • Depois que uma condição for avaliada como verdadeira no estágio de condição de um cenário
  • Durante o estágio de preenchimento de slots de uma cena
  • Depois que uma correspondência de intent ocorre no estágio de entrada de uma cena

Quando você aciona um webhook nas ações, o Google Assistente envia uma solicitação com um payload JSON para o fulfillment, que contém o nome do gerenciador a ser usado para processar o evento. O endpoint de fulfillment pode encaminhar o evento ao gerenciador apropriado para executar a lógica e retornar uma resposta correspondente com um payload JSON.

Payloads

Os snippets a seguir mostram exemplos de solicitações que suas ações enviam para o fulfillment e uma resposta que o fulfillment envia de volta. Consulte a documentação de referência para mais informações.

Exemplo de solicitação

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

Exemplo de resposta

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

Interações no momento da execução

As seções a seguir descrevem tarefas comuns que você pode realizar nos gerenciadores de webhook.

Enviar solicitações

Use o Tela interativa para criar comandos com texto simples, rich text, cards e até instruções HTML completas baseadas em um app da Web. A documentação de solicitações tem informações completas sobre como criar um comando ao processar um evento de webhook. Os snippets a seguir mostram uma solicitação de card:

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 resposta

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

Ler parâmetros de intent

Quando o ambiente de execução do Google Assistente corresponde a uma intent, ele extrai todos os parâmetros definidos. A propriedade original foi o que o usuário forneceu como entrada, e a propriedade resolvida é o que o PLN resolveu a entrada com base na especificação do tipo.

Node.js

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

Solicitação JSON

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

Ler localidade do usuário

Esse valor corresponde à configuração de localidade do usuário para o Google Assistente.

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

Armazenamento de leitura e gravação

Consulte a documentação sobre armazenamento para informações completas sobre como usar vários recursos de armazenamento.

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 

Solicitação JSON

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

{
  "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 os recursos do dispositivo

Você pode verificar os recursos de um dispositivo para oferecer diferentes experiências ou fluxos de conversa.

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

Solicitação JSON

{
  "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 ver uma lista completa de recursos de plataforma, consulte a referência Capability.

Substituições de tipo de ambiente de execução

Com os tipos de ambiente de execução, é possível modificar as especificações dele. Use esse recurso para carregar dados de outras fontes e preencher os valores válidos de um tipo. Por exemplo, é possível usar substituições de tipo de ambiente de execução para adicionar opções dinâmicas a uma pergunta de pesquisa ou adicionar um item diário a um menu.

Para usar tipos de ambiente de execução, acione um webhook da ação que chama um gerenciador no fulfillment. Depois, você pode preencher o parâmetro session.typeOverrides em uma resposta à sua ação. Os modos disponíveis incluem TYPE_MERGE para preservar as entradas de tipo existentes ou TYPE_REPLACE para substituir as entradas atuais pelas substituições.

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 resposta

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

Fornecer polarização de fala

O redirecionamento de fala permite especificar dicas para o PLN a fim de melhorar a correspondência de intent. É possível especificar até 1.000 entradas.

Node.js

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

JSON de resposta

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

Cenas de transição

Além de definir transições estáticas no projeto do Actions, você pode fazer com que as transições de cena ocorram durante a execução.

Node.js

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

JSON de resposta

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

Ler slots de cena

Durante o preenchimento de slots, é possível usar o fulfillment para validar o slot ou verificar o status dele (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 exemplo, suponha que você queira extrair o fuso horário de uma resposta. Neste exemplo, o nome do slot é datetime1. Para ver o fuso horário, você usaria:

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

Solicitação JSON

{
  "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 slots de cena

É possível invalidar slots e fazer com que o usuário forneça um novo valor.

Node.js

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

JSON de resposta

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

Opções de desenvolvimento

O Actions Builder fornece um editor in-line chamado editor do Cloud Functions, que permite criar e implantar uma função do Cloud para Firebase diretamente no console. Também é possível criar e implantar o fulfillment na hospedagem de sua escolha e registrar o endpoint de fulfillment HTTPS como gerenciador do webhook.

Editor in-line

Para desenvolver com o editor do Cloud Functions:

  1. Abra o projeto do Actions e acesse a guia Desenvolver > Webhook > Alterar método de fulfillment. A janela Fulfillment Methods será exibida.
  2. Selecione Cloud Functions in-line e clique em Confirmar.

Endpoint HTTPS externo

Nesta seção, descrevemos como configurar o Cloud Functions para Firebase como um serviço de fulfillment para sua ação de conversa. No entanto, é possível implantar o fulfillment em um serviço de hospedagem de sua escolha.

Configurar o ambiente

Para configurar o ambiente, siga estas etapas:

  1. Faça o download e instale o Node.js.
  2. Configure e inicialize a CLI do Firebase. Se o comando a seguir falhar com um erro EACCES, talvez seja necessário alterar as permissões do NPM.

    npm install -g firebase-tools
    
  3. Autentique a ferramenta do Firebase com sua Conta do Google:

    firebase login
    
  4. Inicie o diretório em que você salvou o projeto do Actions. Você precisará selecionar quais recursos da CLI do Firebase quer configurar para o projeto do Actions. Escolha Functions e outros recursos que você queira usar, como o Firestore, e pressione Enter para confirmar e continuar:

    $ cd <ACTIONS_PROJECT_DIRECTORY>
    $ firebase init
    
  5. Associe a ferramenta do Firebase ao seu projeto do Actions selecionando-a usando as teclas de seta para navegar pela lista de projetos:

  6. Depois de escolher o projeto, a ferramenta do Firebase inicia a configuração do Functions e pergunta qual idioma você quer usar. Selecione usando as teclas de seta e pressione Enter 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. Escolha se quer usar o ESLint para detectar prováveis bugs e aplicar o estilo digitando Y ou N:

    ? Do you want to use ESLint to catch probable bugs and enforce style? (Y/n)
  8. Para acessar as dependências do projeto, digite Y no prompt:

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

    Quando a configuração for concluída, você verá uma resposta parecida com a seguinte:

    ✔  Firebase initialization complete!
    
  9. Instale a dependência @assistant/conversation:

    $ cd <ACTIONS_PROJECT_DIRECTORY>/functions
    $ npm install @assistant/conversation --save
    
  10. Consiga as dependências de fulfillment e implante a função de fulfillment:

    $ npm install
    $ firebase deploy --only functions
    

    A implantação leva alguns minutos. Quando terminar, você verá uma saída parecida com a seguinte. Você precisará do URL da função para inserir no 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. Copie o URL de fulfillment para usar na próxima seção.

Registrar gerenciador de webhook

Para registrar o endpoint da função do Cloud como um gerenciador de webhook:

  1. No Console do Actions, clique em Desenvolver > Webhook.
  2. Clique em Alterar método de fulfillment. A janela Fulfillment Methods será exibida.
  3. Selecione Webhook e clique em Confirmar.
  4. Cole o URL do serviço da Web no campo Webhook.
  5. Clique em Salvar.