Serviço de webhook

Para usar o fulfillment em um sistema de produção, você deve implementar e implantar um serviço de webhook. Para processar o fulfillment, seu serviço de webhook precisa aceitar solicitações JSON e retornar respostas JSON conforme especificado neste guia. O fluxo de processamento detalhado do fulfillment e dos webhooks é descrito no documento de visão geral do fulfillment.

Requisitos de serviço do webhook

Os seguintes requisitos devem ser atendidos pelo serviço do webhook:

  • Ele precisa processar solicitações HTTPS. O HTTP não é compatível. Se você hospedar seu serviço de webhook no Google Cloud Platform usando uma solução de computação ou computação sem servidor, consulte a documentação do produto para veiculação com HTTPS. Para conhecer outras opções de hospedagem, consulte Adquira um certificado SSL para seu domínio.
  • Seu URL para solicitações deve ser acessível publicamente.
  • Ele precisa processar solicitações POST com um corpo JSON WebhookRequest.
  • Ele precisa responder a solicitações WebhookRequest com um corpo JSON WebhookResponse.

Autenticação

É importante proteger seu serviço de webhook para que somente você ou seu agente do Dialogflow sejam autorizados a fazer solicitações. O Dialogflow é compatível com os seguintes mecanismos de autenticação:

Termo Definição
Nome de usuário e senha de login Nas configurações do webhook, é possível especificar valores opcionais de nome de usuário e senha de login. Se fornecido, o Dialogflow adiciona um cabeçalho HTTP de autorização às solicitações do webhook. Esse cabeçalho tem o formato: "authorization: Basic <base 64 encoding of the string username:password>".
Cabeçalhos de autenticação Nas configurações do webhook, especifique pares de chave-valor do cabeçalho HTTP opcionais. Se fornecidos, o Dialogflow adiciona esses cabeçalhos HTTP às solicitações de webhook. É comum fornecer um único par com uma chave de authorization.
Autenticação integrada do Cloud Functions Você pode usar a autenticação integrada ao usar o Cloud Functions. Para usar esse tipo de autenticação, não forneça nome de usuário de login, senha de login ou cabeçalhos de autorização. Se você fornecer algum desses campos, eles serão usados para autenticação em vez da autenticação integrada.
Tokens de identidade de serviço Use tokens de identidade de serviço para autenticação. Se você não fornecer o nome de usuário e a senha de login ou um cabeçalho com uma chave authorization, o Dialogflow presume automaticamente que os tokens de identidade do serviço devem ser usados e adiciona um cabeçalho HTTP de autorização às solicitações do webhook. Esse cabeçalho tem o formato: "authorization: Bearer <identity token>".
Autenticação TLS mútua Consulte a documentação Autenticação TLS mútua.

Solicitação de webhook

Quando uma intent configurada para fulfillment é correspondido, o Dialogflow envia uma solicitação de webhook HTTPS POST para seu serviço de webhook. O corpo dessa solicitação é um objeto JSON com informações sobre a intent correspondente.

Além da consulta do usuário final, muitas integrações também enviam algumas informações sobre o usuário final. Por exemplo, um ID para identificar exclusivamente o usuário. Essas informações podem ser acessadas pelo campo originalDetectIntentRequest na solicitação do webhook, que conterá as informações enviadas da plataforma de integração.

Consulte a documentação de referência de WebhookRequest para mais detalhes.

Veja um exemplo de solicitação:

{
  "responseId": "response-id",
  "session": "projects/project-id/agent/sessions/session-id",
  "queryResult": {
    "queryText": "End-user expression",
    "parameters": {
      "param-name": "param-value"
    },
    "allRequiredParamsPresent": true,
    "fulfillmentText": "Response configured for matched intent",
    "fulfillmentMessages": [
      {
        "text": {
          "text": [
            "Response configured for matched intent"
          ]
        }
      }
    ],
    "outputContexts": [
      {
        "name": "projects/project-id/agent/sessions/session-id/contexts/context-name",
        "lifespanCount": 5,
        "parameters": {
          "param-name": "param-value"
        }
      }
    ],
    "intent": {
      "name": "projects/project-id/agent/intents/intent-id",
      "displayName": "matched-intent-name"
    },
    "intentDetectionConfidence": 1,
    "diagnosticInfo": {},
    "languageCode": "en"
  },
  "originalDetectIntentRequest": {}
}

Resposta do webhook

Uma vez que seu webhook recebe uma solicitação de webhook, ela precisa enviar uma resposta a um webhook. O corpo dessa resposta é um objeto JSON com as seguintes informações:

As seguintes limitações se aplicam à sua resposta:

  • A resposta deve ocorrer dentro de 10 segundos para aplicativos do Google Assistente ou 5 segundos para todos os outros aplicativos. Caso contrário, a solicitação atingirá o tempo limite.
  • É necessário que o tamanho da resposta seja menor ou igual a 64 KiB.

Consulte a documentação de referência de WebhookResponse para mais detalhes.

Resposta de texto

Exemplo para uma resposta de texto:

{
  "fulfillmentMessages": [
    {
      "text": {
        "text": [
          "Text response from webhook"
        ]
      }
    }
  ]
}

Resposta do card

Exemplo para uma resposta do card:

{
  "fulfillmentMessages": [
    {
      "card": {
        "title": "card title",
        "subtitle": "card text",
        "imageUri": "https://example.com/images/example.png",
        "buttons": [
          {
            "text": "button text",
            "postback": "https://example.com/path/for/end-user/to/follow"
          }
        ]
      }
    }
  ]
}

Resposta do Google Assistente

Exemplo para uma resposta do Google Assistente:

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "richResponse": {
        "items": [
          {
            "simpleResponse": {
              "textToSpeech": "this is a Google Assistant response"
            }
          }
        ]
      }
    }
  }
}

Contexto

Exemplo que define o contexto de saída:

{
  "fulfillmentMessages": [
    {
      "text": {
        "text": [
          "Text response from webhook"
        ]
      }
    }
  ],
  "outputContexts": [
    {
      "name": "projects/project-id/agent/sessions/session-id/contexts/context-name",
      "lifespanCount": 5,
      "parameters": {
        "param-name": "param-value"
      }
    }
  ]
}

Evento

Exemplo que invoca um evento personalizado:

{
  "followupEventInput": {
    "name": "event-name",
    "languageCode": "en-US",
    "parameters": {
      "param-name": "param-value"
    }
  }
}

Entidade de sessão

Exemplo que define uma entidade de sessão:

{
  "fulfillmentMessages": [
    {
      "text": {
        "text": [
          "Choose apple or orange"
        ]
      }
    }
  ],
  "sessionEntityTypes":[
    {
      "name":"projects/project-id/agent/sessions/session-id/entityTypes/fruit",
      "entities":[
        {
          "value":"APPLE_KEY",
          "synonyms":[
            "apple",
            "green apple",
            "crabapple"
          ]
        },
        {
          "value":"ORANGE_KEY",
          "synonyms":[
            "orange"
          ]
        }
      ],
      "entityOverrideMode":"ENTITY_OVERRIDE_MODE_OVERRIDE"
    }
  ]
}

Payload personalizado

Exemplo que fornece um payload personalizado:

{
  "fulfillmentMessages": [
    {
      "payload": {
        "facebook": { // for Facebook Messenger integration
          "attachment": {
            "type": "",
            "payload": {}
          }
        },
        "slack": { // for Slack integration
          "text": "",
          "attachments": []
        },
        "richContent": [ // for Dialogflow Messenger integration
          [
            {
              "type": "image",
              "rawUrl": "https://example.com/images/logo.png",
              "accessibilityText": "Example logo"
            }
          ]
        ],
        // custom integration payload here
      }
    }
  ]
}

Ativar e gerenciar o fulfillment

Para ativar e gerenciar o preenchimento de seu agente com o console:

  1. Acesse o Console do Dialogflow ES.
  2. Selecione um agente.
  3. Selecione Fulfillment no menu da barra lateral esquerda.
  4. Alterne o campo Webhook para Ativado.
  5. Forneça os detalhes do serviço de webhook no formulário. Se o webhook não exigir autenticação, deixe os campos de autenticação em branco.
  6. Clique em Salvar na parte inferior da página.

Captura de tela da ativação do fulfillment.

Para ativar e gerenciar o fulfillment do agente com a API, consulte a referência do agente. Os métodos getFulfillment e updateFulfillment podem ser usados para gerenciar as configurações de fulfillment.

Para ativar o fulfillment para uma intent com o console:

  1. Selecione Intents no menu da barra lateral à esquerda.
  2. Selecione uma intent.
  3. Role para baixo até a seção Fulfillment.
  4. Alternar Ativar chamada de webhook para este intent para ativada.
  5. Clique em Salvar.

Para ativar o fulfillment para uma intent com a API, consulte a referência de intents. Defina o campo webhookState como WEBHOOK_STATE_ENABLED.

Erros de webhook

Se o serviço do webhook encontrar um erro, ele retornará um dos seguintes códigos de status HTTP:

  • 400 Solicitação inválida
  • 401 Não autorizado
  • 403 Proibido
  • 404 Não encontrado
  • 500 Falha no servidor
  • 503 Serviço não disponível

Em qualquer uma das seguintes situações de erro, o Dialogflow responde ao usuário final com a resposta integrada configurada para a intent correspondente:

  • Tempo limite de resposta excedido.
  • Código de status de erro recebido.
  • A resposta é inválida.
  • O serviço de webhook não está disponível.

Além disso, se a correspondência de intent tiver sido acionada por uma chamada de API de intent de detecção, o campo status na resposta de intent de detecção conterá as informações de erro do webhook. Exemplo:

"status": {
    "code": 206,
    "message": "Webhook call failed. <details of the error...>"
}

Como usar o Cloud Functions

Há algumas maneiras de usar o Cloud Functions para fulfillment. O editor in-line do Dialogflow é integrado ao Cloud Functions. Quando você usa o editor in-line para criar e editar o código do webhook, o Dialogflow estabelece uma conexão segura com a função do Cloud.

Também é possível usar uma função do Cloud que não foi criada pelo editor in-line. talvez você queira usar uma linguagem diferente do Node.js. Se a função do Cloud estiver no mesmo projeto que o agente, ele poderá chamar o webhook sem precisar de configuração especial.

No entanto, há duas situações em que é preciso configurar essa integração manualmente:

  1. A conta de serviço do agente de serviço do Dialogflow com o seguinte endereço precisa existir para seu projeto de agente:
    service-agent-project-number@gcp-sa-dialogflow.iam.gserviceaccount.com
    Essa conta de serviço especial e a chave associada normalmente são criadas automaticamente quando você cria o primeiro agente de um projeto. Se o agente tiver sido criado antes de 10 de maio de 2021, talvez seja necessário acionar a criação dessa conta de serviço especial com o seguinte:
    1. Crie um novo agente para o projeto.
    2. Execute este comando:
      gcloud beta services identity create --service=dialogflow.googleapis.com --project=agent-project-id
  2. Se a função do webhook residir em um projeto diferente do agente, forneça o Papel do IAM Invocador do Cloud Functions à conta de serviço Agente de serviço do Dialogflow no projeto da função.

Tokens de identidade de serviço

Quando o Dialogflow chama um webhook, ele fornece um token de identidade do Google com a solicitação. Qualquer webhook pode, opcionalmente, validar o token usando bibliotecas de cliente do Google ou bibliotecas de código aberto, como em github.com/googleapis/google-auth-library-nodejs (em inglês). Por exemplo, você pode verificar o email do token de ID como:

service-agent-project-number@gcp-sa-dialogflow.iam.gserviceaccount.com

Amostras

Os exemplos a seguir mostram como receber um WebhookRequest e enviar um WebhookResponse. Esses exemplos de intents de referência são criados no quickstart.

Go

Para autenticar no Dialogflow, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
)

type intent struct {
	DisplayName string `json:"displayName"`
}

type queryResult struct {
	Intent intent `json:"intent"`
}

type text struct {
	Text []string `json:"text"`
}

type message struct {
	Text text `json:"text"`
}

// webhookRequest is used to unmarshal a WebhookRequest JSON object. Note that
// not all members need to be defined--just those that you need to process.
// As an alternative, you could use the types provided by
// the Dialogflow protocol buffers:
// https://godoc.org/google.golang.org/genproto/googleapis/cloud/dialogflow/v2#WebhookRequest
type webhookRequest struct {
	Session     string      `json:"session"`
	ResponseID  string      `json:"responseId"`
	QueryResult queryResult `json:"queryResult"`
}

// webhookResponse is used to marshal a WebhookResponse JSON object. Note that
// not all members need to be defined--just those that you need to process.
// As an alternative, you could use the types provided by
// the Dialogflow protocol buffers:
// https://godoc.org/google.golang.org/genproto/googleapis/cloud/dialogflow/v2#WebhookResponse
type webhookResponse struct {
	FulfillmentMessages []message `json:"fulfillmentMessages"`
}

// welcome creates a response for the welcome intent.
func welcome(request webhookRequest) (webhookResponse, error) {
	response := webhookResponse{
		FulfillmentMessages: []message{
			{
				Text: text{
					Text: []string{"Welcome from Dialogflow Go Webhook"},
				},
			},
		},
	}
	return response, nil
}

// getAgentName creates a response for the get-agent-name intent.
func getAgentName(request webhookRequest) (webhookResponse, error) {
	response := webhookResponse{
		FulfillmentMessages: []message{
			{
				Text: text{
					Text: []string{"My name is Dialogflow Go Webhook"},
				},
			},
		},
	}
	return response, nil
}

// handleError handles internal errors.
func handleError(w http.ResponseWriter, err error) {
	w.WriteHeader(http.StatusInternalServerError)
	fmt.Fprintf(w, "ERROR: %v", err)
}

// HandleWebhookRequest handles WebhookRequest and sends the WebhookResponse.
func HandleWebhookRequest(w http.ResponseWriter, r *http.Request) {
	var request webhookRequest
	var response webhookResponse
	var err error

	// Read input JSON
	if err = json.NewDecoder(r.Body).Decode(&request); err != nil {
		handleError(w, err)
		return
	}
	log.Printf("Request: %+v", request)

	// Call intent handler
	switch intent := request.QueryResult.Intent.DisplayName; intent {
	case "Default Welcome Intent":
		response, err = welcome(request)
	case "get-agent-name":
		response, err = getAgentName(request)
	default:
		err = fmt.Errorf("Unknown intent: %s", intent)
	}
	if err != nil {
		handleError(w, err)
		return
	}
	log.Printf("Response: %+v", response)

	// Send response
	if err = json.NewEncoder(w).Encode(&response); err != nil {
		handleError(w, err)
		return
	}
}

Java

Para autenticar no Dialogflow, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.


// TODO: add GSON dependency to Pom file
// (https://mvnrepository.com/artifact/com.google.code.gson/gson/2.8.5)
// TODO: Uncomment the line bellow before running cloud function
// package com.example;

import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.BufferedWriter;

public class Example implements HttpFunction {

  public void service(HttpRequest request, HttpResponse response) throws Exception {
    JsonParser parser = new JsonParser();
    Gson gson = new GsonBuilder().create();

    JsonObject job = gson.fromJson(request.getReader(), JsonObject.class);
    String str =
        job.getAsJsonObject("queryResult")
            .getAsJsonObject("intent")
            .getAsJsonPrimitive("displayName")
            .toString();
    JsonObject o = null;
    String a = '"' + "Default Welcome Intent" + '"';
    String b = '"' + "get-agent-name" + '"';
    String responseText = "";

    if (str.equals(a)) {
      responseText = '"' + "Hello from a Java GCF Webhook" + '"';
    } else if (str.equals(b)) {
      responseText = '"' + "My name is Flowhook" + '"';
    } else {
      responseText = '"' + "Sorry I didn't get that" + '"';
    }

    o =
        parser
            .parse(
                "{\"fulfillmentMessages\": [ { \"text\": { \"text\": [ "
                    + responseText
                    + " ] } } ] }")
            .getAsJsonObject();

    BufferedWriter writer = response.getWriter();
    writer.write(o.toString());
  }
}

Node.js

Para autenticar no Dialogflow, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

const functions = require('@google-cloud/functions-framework');

// TODO: Add handleWebhook to 'Entry point' in the Google Cloud Function
functions.http('handleWebhook', (request, response) => {
  const tag = request.body.queryResult.intent.displayName;

  let jsonResponse = {};
  if (tag === 'Default Welcome Intent') {
    //fulfillment response to be sent to the agent if the request tag is equal to "welcome tag"
    jsonResponse = {
      fulfillment_messages: [
        {
          text: {
            //fulfillment text response to be sent to the agent
            text: ['Hello from a GCF Webhook'],
          },
        },
      ],
    };
  } else if (tag === 'get-name') {
    //fulfillment response to be sent to the agent if the request tag is equal to "welcome tag"
    jsonResponse = {
      fulfillment_messages: [
        {
          text: {
            //fulfillment text response to be sent to the agent
            text: ['My name is Flowhook'],
          },
        },
      ],
    };
  } else {
    jsonResponse = {
      //fulfillment text response to be sent to the agent if there are no defined responses for the specified tag
      fulfillment_messages: [
        {
          text: {
            ////fulfillment text response to be sent to the agent
            text: [
              `There are no fulfillment responses defined for "${tag}"" tag`,
            ],
          },
        },
      ],
    };
  }
  response.send(jsonResponse);
});

Python

Para autenticar no Dialogflow, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

# TODO: change the default Entry Point text to handleWebhook
import functions_framework


@functions_framework.http
def handleWebhook(request):
    req = request.get_json()

    responseText = ""
    intent = req["queryResult"]["intent"]["displayName"]

    if intent == "Default Welcome Intent":
        responseText = "Hello from a GCF Webhook"
    elif intent == "get-agent-name":
        responseText = "My name is Flowhook"
    else:
        responseText = f"There are no fulfillment responses defined for Intent {intent}"

    # You can also use the google.cloud.dialogflowcx_v3.types.WebhookRequest protos instead of manually writing the json object
    res = {"fulfillmentMessages": [{"text": {"text": [responseText]}}]}

    return res