שירות webhook

כדי להשתמש במילוי בקשות במערכת ייצור, צריך להטמיע ולפרוס שירות webhook. כדי לטפל במילוי הבקשה, שירות ה-webhook צריך לקבל בקשות בפורמט JSON ולהחזיר תגובות בפורמט JSON, כמו שמפורט במדריך הזה. תהליך העיבוד המפורט של מילוי בקשות ו-webhooks מתואר במסמך הסקירה הכללית של מילוי בקשות.

דרישות לגבי שירותי webhook

שירות ה-webhook צריך לעמוד בדרישות הבאות:

  • לטפל בבקשות HTTPS. אין תמיכה ב-HTTP. אם אתם מארחים את שירות ה-webhook ב- Google Cloud באמצעות פתרון Compute או מחשוב בלי שרת (serverless computing), עיינו במסמכי התיעוד של המוצר כדי להבין איך להציג באמצעות HTTPS. לאפשרויות אירוח אחרות, ראו קבלת אישור SSL לדומיין.
  • מוודאים שכתובת ה-URL של שירות ה-webhook נגישה לכולם.
  • טיפול בבקשות POST עם גוף WebhookRequest בפורמט JSON.
  • מגיבים לבקשות WebhookRequest באמצעות גוף JSON WebhookResponse.

אימות

X פריט
שם משתמש וסיסמה להתחברות בהגדרות של ה-webhook, אתם יכולים לציין ערכים אופציונליים של שם משתמש וסיסמה להתחברות. אם מספקים את המידע הזה, Dialogflow מוסיף כותרת HTTP של הרשאה לבקשות של ה-webhook. הכותרת הזו היא בפורמט: "authorization: Basic <base 64 encoding of the string username:password>".
כותרות אימות בהגדרות של ה-webhook, אתם יכולים לציין צמדי מפתח/ערך אופציונליים של כותרת HTTP. אם מציינים כותרות HTTP, ‏Dialogflow מוסיף אותן לבקשות של ה-webhook. בדרך כלל מספקים זוג אחד עם מפתח של authorization.
אימות מובנה של פונקציות Cloud Run אתם יכולים להשתמש באימות המובנה כשאתם משתמשים בפונקציות Cloud Run. כדי להשתמש בסוג האימות הזה, אל תספקו שם משתמש, סיסמה או כותרות הרשאה. אם תספקו את אחד מהשדות האלה, הם לא ישמשו לאימות המובנה.
טוקנים של זהות השירות אפשר להשתמש באסימוני זהות של שירות לצורך אימות. אם לא תספקו שם משתמש וסיסמה להתחברות, או כותרת עם מפתח של authorization, המערכת של Dialogflow תניח באופן אוטומטי שצריך להשתמש באסימוני זהות של השירות ותוסיף כותרת HTTP של הרשאה לבקשות של ה-webhook. הכותרת הזו היא בפורמט: "authorization: Bearer <identity token>".
אימות TLS בו-זמני (mTLS) למידע נוסף, קראו את המאמר אימות TLS בו-זמני (mTLS).

בקשה מ-webhook

כשמתבצעת התאמה ל-intent שמוגדר למילוי בקשה, Dialogflow שולח בקשת webhook מסוג HTTPS POST לשירות ה-webhook שלכם. גוף הבקשה הוא אובייקט JSON עם מידע על הכוונה התואמת.

בנוסף לשאילתה של משתמש הקצה, הרבה שילובים שולחים גם מידע על משתמש הקצה. לדוגמה, מזהה שמזהה את המשתמש באופן ייחודי. אפשר לגשת למידע הזה באמצעות השדה originalDetectIntentRequest בבקשת ה-webhook, שמכיל את המידע שנשלח מפלטפורמת השילוב.

מידע נוסף מופיע במאמרי העזרה של WebhookRequest.

הנה דוגמה לבקשה:

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

תגובה לפעולה מאתר אחר (webhook)

אחרי שה-webhook מקבל בקשה, הוא צריך לשלוח תשובה. גוף התגובה הוא אובייקט JSON שמכיל את הפרטים הבאים:

ההגבלות הבאות חלות על התשובה:

  • צריך להגיב תוך 10 שניות לאפליקציות של Google Assistant או תוך 5 שניות לאפליקציות אחרות, אחרת הזמן הקצוב לתפוגה של הבקשה יסתיים.
  • גודל התגובה צריך להיות עד 64KiB.

מידע נוסף מופיע במאמרי העזרה של WebhookResponse.

תשובה בהודעת טקסט

דוגמה לתגובת טקסט:

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

תשובה בכרטיס

דוגמה לתשובה בכרטיס:

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

תשובה מ-Google Assistant

הדוגמה הבאה היא של תשובה מ-Google Assistant:

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

הקשר

הדוגמה הבאה מגדירה הקשר פלט:

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

אירוע

דוגמה להפעלה של אירוע בהתאמה אישית:

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

ישות הסשן

בדוגמה הבאה מוגדרת ישות סשן:

{
  "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) מותאם אישית

הדוגמה הבאה מספקת מטען ייעודי (payload) מותאם אישית:

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

הפעלה וניהול של מילוי בקשות

כדי להפעיל ולנהל את מילוי הבקשות של הנציג באמצעות המסוף:

  1. נכנסים למסוף Dialogflow ES.
  2. בוחרים סוכן.
  3. בתפריט סרגל הצד, בוחרים באפשרות Fulfillment.
  4. מעבירים את המתג בשדה Webhook למצב מופעל.
  5. ממלאים בטופס את הפרטים של שירות ה-webhook. אם ה-webhook לא דורש אימות, משאירים את שדות האימות ריקים.
  6. לוחצים על Save.

צילום מסך של הפעלת מילוי הבקשה.

כדי להפעיל ולנהל את מילוי הבקשות של הנציג באמצעות ה-API, עיינו במסמכי העזר של הנציג. ה-methods‏ getFulfillment ו-updateFulfillment מאפשרות לנהל את הגדרות המילוי.

כדי להפעיל מילוי בקשה ל-intent באמצעות המסוף:

  1. בתפריט שבסרגל הצד הימני, לוחצים על Intents (כוונות).
  2. בוחרים כוונה.
  3. עוברים לקטע Fulfillment (מילוי בקשות).
  4. מעבירים את המתג Enable webhook call for this intent למצב On.
  5. לוחצים על Save.

כדי להפעיל מילוי בקשות ל-intent באמצעות ה-API, עיינו בחומר העזר בנושא intents והגדירו את השדה webhookState לערך WEBHOOK_STATE_ENABLED.

שגיאות ב-webhook

אם מתרחשת שגיאה בשירות ה-webhook, הוא צריך להחזיר אחד מקודי הסטטוס הבאים של HTTP:

  • 400: בקשה לא תקינה
  • ‫401: אין הרשאה
  • ‫403: הגישה אסורה
  • 404: לא נמצא
  • 500: שגיאת שרת פנימית
  • ‫503: השירות לא זמין

בכל אחד ממצבי השגיאה הבאים, Dialogflow מגיב למשתמש הקצה עם התגובה המובנית שהוגדרה ל-Intent התואם:

  • הזמן הקצוב לתגובה חלף.
  • התקבל קוד סטטוס של שגיאה.
  • התשובה לא תקינה.
  • שירות ה-webhook לא זמין.

בנוסף, אם קריאה ל-API לזיהוי כוונה מפעילה את ההתאמה לכוונה, השדה status בתגובה לזיהוי הכוונה מכיל את פרטי השגיאה של ה-webhook. לדוגמה:

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

ניסיונות חוזרים אוטומטיים

כדי לשפר את העמידות, Dialogflow ES כולל מנגנונים פנימיים שמנסים שוב באופן אוטומטי במקרה של שגיאות מסוימות ב-webhook. המערכת מנסה שוב רק שגיאות לא סופיות, כמו שגיאות של זמן קצוב לתפוגה או שגיאות בחיבור.

כדי לצמצם את הסיכוי לשיחות כפולות:

  • להגדיר סף ארוך יותר לזמן הקצוב לתפוגה של ה-webhook.
  • תמיכה באידמפוטנטיות בלוגיקה של ה-webhook או ביטול כפילויות של בקשות.

שימוש בפונקציות Cloud Run

יש כמה דרכים להשתמש בפונקציות Cloud Run למילוי בקשות. העורך הישיר של Dialogflow משתלב עם פונקציות Cloud Run. כשמשתמשים בעורך בקוד כדי ליצור ולערוך את קוד ה-webhook, ‏ Dialogflow יוצר חיבור מאובטח לפונקציה של Cloud Functions.

אפשר גם להשתמש בפונקציה של Cloud Functions שלא נוצרה באמצעות עריכה ישירה. אם הפונקציה של Cloud Functions נמצאת באותו פרויקט כמו הנציג, הנציג יכול לשלוח קריאה ל-webhook בלי צורך בהגדרה מיוחדת.

עם זאת, צריך להגדיר את השילוב הזה באופן ידני בשני המצבים הבאים:

  1. חשבון השירות Dialogflow Service Agent עם הכתובת הבאה חייב להיות קיים בפרויקט של הנציג:
    service-agent-project-number@gcp-sa-dialogflow.
    חשבון השירות המיוחד הזה והמפתח שמשויך אליו נוצרים בדרך כלל באופן אוטומטי כשיוצרים את הנציג הראשון בפרויקט. אם הנציג נוצר לפני 10 במאי 2021, יכול להיות שתצטרכו להפעיל את היצירה של חשבון השירות המיוחד הזה באמצעות:
    1. יוצרים נציג חדש לפרויקט.
    2. מריצים את הפקודה הבאה:
      gcloud beta services identity create --service=dialogflow.googleapis.com --project=agent-project-id
  2. אם פונקציית ה-webhook נמצאת בפרויקט אחר מזה של הסוכן, צריך לתת את תפקיד ה-IAM Cloud Functions Invoker לחשבון השירות Dialogflow Service Agent בפרויקט של הפונקציה.

טוקנים של זהות השירות

כש-Dialogflow קורא ל-webhook, הוא מספק אסימון זהות של Google עם הבקשה. כל תגובה לפעולה מאתר אחר (webhook) יכולה לאמת את האסימון באמצעות ספריות לקוח של Google או ספריות קוד פתוח כמו github.com/googleapis/google-auth-library-nodejs. לדוגמה, אפשר לאמת את ה-email של טוקן המזהה באופן הבא:

service-agent-project-number@gcp-sa-dialogflow.

דוגמאות

בדוגמאות הבאות אפשר לראות איך מקבלים WebhookRequest ושולחים WebhookResponse. הדוגמאות האלה משתמשות ב-Intent שנוצרו במדריך למתחילים.

Go

כדי לבצע אימות ב-Dialogflow CX, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.

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

כדי לבצע אימות ב-Dialogflow CX, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.


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

כדי לבצע אימות ב-Dialogflow CX, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.

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

כדי לבצע אימות ב-Dialogflow CX, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.

# 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