Servizio webhook

Per utilizzare l'evasione degli ordini in un sistema di produzione, devi implementare ed eseguire il deployment di un servizio webhook. Per gestire l'evasione, il servizio webhook deve accettare richieste JSON e restituire risposte JSON come specificato in questa guida. Il flusso di elaborazione dettagliato per fulfillment e webhook è descritto nel documento di panoramica dell'evasione degli ordini.

Requisiti del servizio webhook

Il servizio webhook deve soddisfare i seguenti requisiti:

  • Deve gestire le richieste HTTPS. HTTP non è supportato. Se ospiti il servizio webhook sulla piattaforma Google Cloud utilizzando una soluzione di computing o cloud computing serverless, consulta la documentazione del prodotto per la pubblicazione con HTTPS. Per altre opzioni di hosting, consulta Ottieni un certificato SSL per il tuo dominio.
  • L'URL per le richieste deve essere accessibile pubblicamente.
  • Deve gestire le richieste POST con un corpo JSON WebhookRequest.
  • Deve rispondere alle richieste WebhookRequest con un corpo WebhookResponse in formato JSON.

Autenticazione

È importante proteggere il servizio webhook, in modo che solo tu o il tuo agente Dialogflow siate autorizzati a effettuare richieste. Dialogflow supporta i seguenti meccanismi di autenticazione:

Termine Definizione
Nome utente e password di accesso Per le impostazioni del webhook, puoi specificare valori facoltativi per nome utente e password di accesso. Se fornita, Dialogflow aggiunge un'intestazione HTTP di autorizzazione alle richieste webhook. Questa intestazione è del tipo: "authorization: Basic <base 64 encoding of the string username:password>".
Intestazioni dell'autenticazione Per le impostazioni del webhook, puoi specificare coppie chiave-valore facoltative dell'intestazione HTTP. Se fornite, Dialogflow aggiunge queste intestazioni HTTP alle richieste webhook. È comune fornire una singola coppia con una chiave authorization.
Autenticazione integrata di Cloud Functions Puoi utilizzare l'autenticazione integrata quando utilizzi Cloud Functions. Per utilizzare questo tipo di autenticazione, non fornire il nome utente di accesso, la password di accesso o le intestazioni di autorizzazione. Se fornisci uno di questi campi, questi verranno utilizzati per l'autenticazione anziché per l'autenticazione integrata.
Token di identità del servizio Puoi utilizzare i token di identità del servizio per l'autenticazione. Se non fornisci il nome utente, la password di accesso o un'intestazione con una chiave authorization, Dialogflow presuppone automaticamente che si debbano utilizzare token di identità del servizio e aggiunge un'intestazione HTTP di autorizzazione alle richieste webhook. Questa intestazione è del tipo: "authorization: Bearer <identity token>".
Autenticazione TLS reciproca Consulta la documentazione sull'autenticazione TLS reciproca.

Richiesta webhook

Quando viene trovata una corrispondenza per un'intenzione configurata per l'evasione, Dialogflow invia una richiesta webhook POST HTTPS al tuo servizio webhook. Il corpo di questa richiesta è un oggetto JSON con informazioni sull'intent abbinato.

Oltre alla query dell'utente finale, molte integrazioni inviano anche informazioni sull'utente finale. Ad esempio, un ID per identificare in modo univoco per l'utente. È possibile accedere a queste informazioni tramite il originalDetectIntentRequest nella richiesta webhook, che conterrà le informazioni inviate dal completamente gestita.

Per informazioni dettagliate, consulta la documentazione di riferimento di WebhookRequest.

Ecco una richiesta di esempio:

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

Risposta webhook

Una volta che il tuo webhook riceve una richiesta, deve inviare una risposta. Il corpo di questa risposta è un oggetto JSON con le seguenti informazioni:

Alla risposta si applicano le seguenti limitazioni:

  • La risposta deve verificarsi entro 10 secondi per Assistente Google applicazioni o cinque secondi per tutte le altre applicazioni, altrimenti la richiesta scadrà.
  • La risposta deve essere inferiore o uguale a 64 KiB.

Consulta le WebhookResponse documentazione di riferimento per maggiori dettagli.

Risposta di testo

Esempio per una risposta testuale:

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

Risposta della carta

Esempio di risposta della scheda:

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

Risposta dell'Assistente Google

Esempio per una Risposta dell'Assistente Google:

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

Contesto

Esempio che imposta il contesto di output:

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

Esempio che richiama un evento personalizzato:

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

Entità sessione

Esempio che imposta un session entity:

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

Esempio che fornisce un payload personalizzato:

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

Attiva e gestisci l'evasione degli ordini

Per abilitare e gestire il fulfillment per il tuo agente tramite la console:

  1. Vai alla console di Dialogflow ES.
  2. Seleziona un agente.
  3. Seleziona Fulfillment nel menu della barra laterale a sinistra.
  4. Imposta il campo Webhook su Attivato.
  5. Fornisci i dettagli del servizio webhook nel modulo. Se il webhook non richiede l'autenticazione, lascia vuoti i campi di autenticazione.
  6. Fai clic su Salva nella parte inferiore della pagina.

Screenshot dell&#39;attivazione dell&#39;evasione.

Per attivare e gestire l'evasione per il tuo agente con l'API, consulta la documentazione di riferimento dell'agente. I metodi getFulfillment e updateFulfillment possono essere utilizzati per gestire le impostazioni di evasione.

Per attivare l'evasione di un'intenzione con la console:

  1. Seleziona Intent nel menu della barra laterale a sinistra.
  2. Seleziona un intent.
  3. Scorri verso il basso fino alla sezione Completamento.
  4. Attiva l'opzione Abilita chiamata webhook per questo intent.
  5. Fai clic su Salva.

Per abilitare il completamento di un intent con l'API, vedi il riferimento agli intent. Imposta il campo webhookState su WEBHOOK_STATE_ENABLED.

Errori webhook

Se il servizio webhook rileva un errore, deve restituire uno dei seguenti codici di stato HTTP:

  • 400 Richiesta errata
  • 401 non autorizzato
  • 403 Vietato
  • 404 non trovato
  • 500 Errore del server
  • 503 Servizio non disponibile

In una delle seguenti situazioni di errore, Dialogflow risponde all'utente finale con la risposta integrata configurata per l'intent attualmente associato:

  • Timeout risposta superato.
  • Codice di stato di errore ricevuto.
  • La risposta non è valida.
  • Il servizio webhook non è disponibile.

Inoltre, se la corrispondenza di intenzione è stata attivata da un rilevamento della chiamata all'API, Il campo status nella risposta di rilevamento dell'intent contiene le informazioni sull'errore del webhook. Ad esempio:

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

Nuovi tentativi automatici

Dialogflow ES include meccanismi interni che tentano automaticamente di nuovo in caso di determinati errori webhook per migliorare la robustezza. Solo gli errori non del terminale vengono nuovi tentativi (ad esempio, errori di timeout o di connessione).

Per ridurre la probabilità di chiamate duplicate:

  • Imposta soglie di timeout del webhook più lunghe.
  • Supporta l'idempotenza nella logica webhook o deduplica.

Utilizzo di Cloud Functions

Esistono alcuni modi per utilizzare Cloud Functions per il completamento. Dialogflow editor in linea si integra con Cloud Functions. Quando utilizzi l'editor in linea per creare e modificare il codice webhook, Dialogflow stabilisce una connessione sicura alla tua funzione Cloud.

Hai anche la possibilità di utilizzare una funzione Cloud non creata dall'editor incorporato (ad esempio perché vuoi utilizzare un linguaggio diverso da Node.js). Se la funzione Cloud si trova nello stesso progetto dell'agente, quest'ultimo può chiamare l'webhook senza alcuna configurazione speciale.

Tuttavia, esistono due situazioni in cui devi configurare manualmente questa integrazione:

  1. Per il progetto dell'agente deve esistere l'account di servizio Agente di servizio Dialogflow con il seguente indirizzo:
    service-agent-project-number@gcp-sa-dialogflow.iam.gserviceaccount.com
    Questo account di servizio speciale e la chiave associata di solito viene creato automaticamente quando crei il primo agente per un progetto. Se il tuo agente è stato creato prima del 10 maggio 2021, potresti dover attivare la creazione di questo account di servizio speciale con quanto segue:
    1. Crea un nuovo agente per il progetto.
    2. Esegui questo comando:
      gcloud beta services identity create --service=dialogflow.googleapis.com --project=agent-project-id
  2. Se la funzione webhook si trova in un progetto diverso dall'agente, devi fornire l'invoker di Cloud Functions Ruolo IAM all'account di servizio dell'agente di servizio Dialogflow nel progetto della funzione.

Token di identità del servizio

Quando Dialogflow chiama un webhook, fornisce un token di identità Google con la richiesta. Qualsiasi webhook può, facoltativamente, convalidare il token utilizzando librerie client di Google o librerie open source, github.com/googleapis/google-auth-library-nodejs. Ad esempio, puoi verificare il email del token ID come segue:

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

Esempi

Gli esempi riportati di seguito mostrano come ricevere un messaggio WebhookRequest e inviare un messaggio WebhookResponse. Questi esempi fanno riferimento agli intent creati nella guida rapida.

Go

Per eseguire l'autenticazione in Dialogflow, configura Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

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

Per eseguire l'autenticazione in Dialogflow, configura Credenziali predefinite dell'applicazione. Per ulteriori informazioni, vedi Configura l'autenticazione per un ambiente di sviluppo locale.


// 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

Per eseguire l'autenticazione in Dialogflow, configura Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

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

Per autenticarti a Dialogflow, configura le credenziali predefinite dell'applicazione. Per ulteriori informazioni, vedi Configura l'autenticazione per un ambiente di sviluppo locale.

# 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