שירות webhook

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

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

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

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

אימות

חשוב לאבטח את שירות ה-webhook, כדי שרק אתם או סוכן Dialogflow שלכם יוכלו לשלוח בקשות. ‫Dialogflow תומך במנגנוני האימות הבאים:

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

בקשת webhook

כשמזוהה כוונה שהוגדרה לביצוע,‏ 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 ב-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. בתפריט הצדדי הימני, לוחצים על השלמת הזמנות.
  4. מעבירים את המתג בשדה Webhook למצב Enabled (מופעל).
  5. ממלאים את הפרטים של שירות ה-webhook בטופס. אם ה-webhook לא דורש אימות, משאירים את שדות האימות ריקים.
  6. לוחצים על שמירה בתחתית הדף.

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

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

כדי להפעיל את התכונה 'ביצוע הזמנה' עבור כוונת משתמש באמצעות המסוף:

  1. בתפריט הצדדי הימני, בוחרים באפשרות כוונות.
  2. בוחרים כוונה.
  3. גוללים למטה לקטע Fulfillment (מימוש).
  4. מפעילים את האפשרות הפעלת קריאה ל-webhook עבור הכוונה הזו.
  5. לוחצים על Save.

כדי להפעיל את התכונה 'ביצוע הזמנה' עבור כוונת משתמש באמצעות ה-API, אפשר לעיין בהפניית הכוונות. מגדירים את השדה webhookState לערך WEBHOOK_STATE_ENABLED.

שגיאות ב-webhook

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

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

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

  • הזמן הקצוב לכתיבת תשובה הסתיים.
  • התקבל קוד סטטוס שגיאה.
  • התגובה לא תקינה.
  • שירות ה-Webhook לא זמין.

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

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

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

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

כדי להקטין את הסיכוי לשיחות כפולות:

  • הגדרת ספי תפוגה ארוכים יותר של Webhook.
  • תמיכה באידמפוטנטיות בלוגיקה של ה-webhook או ביטול כפילויות.

שימוש ב-Cloud Functions

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

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

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

  1. חשבון השירות של סוכן השירות של Dialogflow עם הכתובת הבאה צריך להיות קיים בפרויקט של הסוכן:
    service-agent-project-number@gcp-sa-dialogflow.iam.gserviceaccount.com
    חשבון השירות המיוחד הזה והמפתח המשויך אליו נוצרים בדרך כלל באופן אוטומטי כשיוצרים את הסוכן הראשון לפרויקט. אם הסוכן שלכם נוצר לפני 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.iam.gserviceaccount.com

דוגמאות

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

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