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

כדי ליהנות מגמישות רבה יותר ביצירת Actions, אפשר להאציל לוגיקה לשירותי אינטרנט מסוג HTTPS (מילוי). הפעולות יכולות להקפיץ webhooks ששולחים בקשות לנקודת קצה (endpoint) מסוג HTTPS. דוגמאות לפעולות שאפשר לבצע במילוי הבקשה:

  • יצירת הנחיה דינמית על סמך מידע שהמשתמש סיפק.
  • ביצוע הזמנה במערכת חיצונית ואישור הצלחה.
  • אימות יחידות קיבולת (Slot) עם נתוני קצה עורפי.
איור 1. אובייקטים מסוג Intent וסצנות של קריאה יכולים להפעיל webhooks.

טריגרים ורכיבי handler של תגובה לפעולה מאתר אחר (webhook)

הפעולות יכולות להפעיל תגובה לפעולה מאתר אחר (webhook) בתוך אובייקטים מסוג Intent או סצנות של הפעלה, ששולחת בקשה לנקודת הקצה של מילוי הבקשה. מילוי הבקשה מכיל רכיבי handler של תגובה לפעולה מאתר אחר (webhook) שמעבדים את המטען הייעודי (payload) של JSON בבקשה. אפשר להפעיל webhooks במצבים הבאים:

  • אחרי התאמת ה-Intent להפעלה
  • בזמן שסצנה בכניסה לבמה
  • אחרי שתנאי מסוים מקבל את הערך True בשלב התנאי של הסצנה
  • במהלך שלב השלמה של סצינה
  • אחרי שהתאמת Intent מתרחשת בשלב הקלט של הסצנה

כשמפעילים תגובה לפעולה מאתר אחר (webhook) ב-Actions, Google Assistant שולחת בקשה עם מטען ייעודי (payload) של JSON למילוי הבקשה, שכוללת את השם של ה-handler שישמש אתכם לעיבוד האירוע. נקודת הקצה של מילוי הבקשה יכולה לנתב את האירוע ל-handler המתאים כדי לבצע לוגיקה ולהחזיר תגובה תואמת עם מטען ייעודי (payload) של JSON.

מטענים ייעודיים (payloads)

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

בקשה לדוגמה

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

תשובה לדוגמה

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

אינטראקציות בזמן ריצה

בקטעים הבאים מתוארות משימות נפוצות שאפשר לבצע ברכיבי ה-handler של התגובה לפעולה מאתר אחר (webhook).

שליחת הנחיות

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

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 של התשובה

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

קריאת פרמטרים של Intent

כשזמן הריצה של Assistant תואם ל-Intent, הוא מחלץ את כל הפרמטרים שהוגדרו. הנכס המקורי הוא הערך שהמשתמש סיפק כקלט, והמאפיין שנפתר הוא הנכס שה-NLU עבד עליו את הקלט על סמך פירוט הסוג.

Node.js

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

בקשת 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"
    ]
  }
}

קריאת הלוקאל של המשתמש

הערך הזה תואם להגדרת הלוקאל של המשתמש ב-Google Assistant.

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

אחסון לקריאה ולכתיבה

במסמכי העזרה בנושא אחסון מוסבר איך משתמשים בתכונות האחסון השונות.

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 

בקשת 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 של התשובה

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

בדיקת היכולות של המכשיר

אפשר לבדוק את היכולות של המכשיר כדי לספק חוויות שונות או ליצור תהליכי שיחה שונים.

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

בקשת 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"
    ]
  }
}

לקבלת רשימה מלאה של היכולות הזמינות של הפלטפורמות, קראו את המאמר Capability.

שינויים של סוג זמן הריצה

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

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

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 של התשובה

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

לספק הטיית דיבור

הטיית הדיבור מאפשרת לציין רמזים ל-NLU כדי לשפר את התאמת הכוונות. אפשר לציין עד 1,000 רשומות.

Node.js

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

קובץ JSON של התשובה

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

סצנות מעבר

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

Node.js

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

קובץ JSON של התשובה

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

קריאה של מיקומי סצנות

במהלך המילוי של יחידות הקיבולת, אתם יכולים להשתמש במילוי הבקשה כדי לאמת את יחידת הקיבולת (Slot) או לבדוק את הסטטוס של מילוי יחידות הקיבולת (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

לדוגמה, נניח שאתם רוצים לחלץ את אזור הזמן מתגובה. בדוגמה הזו, השם של יחידת הקיבולת (Slot) הוא datetime1. כדי למצוא את אזור הזמן, משתמשים ב:

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

בקשת 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"
    ]
  }
}

ביטול התוקף של מיקומי סצנות

אפשר לבטל את התוקף של יחידות הקיבולת (Slot) ולבקש מהמשתמש לספק ערך חדש.

Node.js

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

קובץ JSON של התשובה

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

אפשרויות פיתוח

הכלי Actions Builder מספק עורך מוטבע שנקרא Cloud Functions editor, שמאפשר ליצור ולפרוס פונקציה ב-Cloud Functions for Firebase ישירות במסוף. אתם יכולים גם ליצור ולפרוס את מילוי הבקשה באירוח שבחרתם, ולרשום את נקודת הקצה של מילוי הבקשה ב-HTTPS בתור ה-handler של תגובה לפעולה מאתר אחר (webhook).

עורך מוטבע

כדי לפתח באמצעות עורך Cloud Functions:

  1. פותחים את פרויקט הפעולות ועוברים אל הכרטיסייה 'פיתוח' > Webhook > שינוי שיטת האספקה. יופיע החלון שיטות למילוי הזמנות.
  2. בוחרים באפשרות Inline Cloud Functions ולוחצים על Confirm.

נקודת קצה (endpoint) חיצונית מסוג HTTPS

בקטע הזה מוסבר איך להגדיר את Cloud Functions for Firebase כשירות מילוי הזמנות של פעולות השיחה. עם זאת, אתם יכולים לפרוס את מילוי ההזמנות בשירות אירוח לבחירתכם.

הגדרת סביבה

כדי להגדיר את הסביבה, בצעו את השלבים הבאים:

  1. מורידים ומתקינים את Node.js.
  2. מגדירים ומפעילים את ה-CLI של Firebase. אם הפקודה הבאה נכשלת עם שגיאת EACCES, יכול להיות שתצטרכו לשנות את ההרשאות של ה-npm.

    npm install -g firebase-tools
    
  3. מאמתים את כלי Firebase עם חשבון Google:

    firebase login
    
  4. מתחילים את ספריית הפרויקט שבה שמרתם את פרויקט הפעולות. תתבקשו לבחור את התכונות של ה-CLI של Firebase שתרצו להגדיר בפרויקט Actions. בוחרים את Functions ותכונות אחרות שאולי רוצים להשתמש בהן, כמו Firestore, ומקישים על Enter כדי לאשר ולהמשיך:

    $ cd <ACTIONS_PROJECT_DIRECTORY>
    $ firebase init
    
  5. משייכים את הכלי Firebase לפרויקט הפעולות על ידי בחירה בו באמצעות מקשי החיצים:

  6. אחרי שבוחרים את הפרויקט, הכלי של Firebase מפעיל את ההגדרה של הפונקציות ושואלים אתכם באיזו שפה להשתמש. בוחרים באמצעות מקשי החיצים ומקישים על Enter כדי להמשיך.

    === 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. בוחרים אם להשתמש ב-ESLint כדי לאתר באגים אפשריים ולאכוף סגנון על-ידי הקלדת Y או N:

    ? Do you want to use ESLint to catch probable bugs and enforce style? (Y/n)
  8. כדי לקבל את יחסי התלות של הפרויקט, מקלידים Y בהנחיה:

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

    לאחר השלמת ההגדרה, יוצג פלט הדומה לפלט הבא:

    ✔  Firebase initialization complete!
    
  9. מתקינים את התלות @assistant/conversation:

    $ cd <ACTIONS_PROJECT_DIRECTORY>/functions
    $ npm install @assistant/conversation --save
    
  10. משיגים את יחסי תלות של מילוי הבקשה ופורסים את הפונקציה של מילוי הבקשה:

    $ npm install
    $ firebase deploy --only functions
    

    הפריסה נמשכת כמה דקות. בסיום התהליך, תראו פלט דומה לזה: כדי להזין את כתובת ה-URL של הפונקציה ב-Dialogflow, נדרשת כתובת ה-URL של הפונקציה.

    ✔  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. יש להעתיק את כתובת ה-URL למילוי הבקשה ולהשתמש בה בקטע הבא.

רישום handler של תגובה לפעולה מאתר אחר (webhook)

כדי לרשום את נקודת הקצה של הפונקציה ב-Cloud Functions כ-handler של תגובה לפעולה מאתר אחר (webhook):

  1. במסוף הפעולות, לוחצים על פיתוח > Webhook.
  2. לוחצים על שינוי שיטת מילוי ההזמנה. מופיע החלון Fulfillment method.
  3. בוחרים באפשרות תגובה לפעולה מאתר אחר (webhook) ולוחצים על Confirm (אישור).
  4. מדביקים את כתובת ה-URL של שירות האינטרנט בשדה webhook.
  5. לוחצים על שמירה.