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

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

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

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

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

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

כשמפעילים תגובה לפעולה מאתר אחר (webhook) בפעולות, 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"
    }
  }
}

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

בחלקים הבאים מתוארות משימות נפוצות שניתן לבצע גורמים מטפלים בתגובה לפעולה מאתר אחר (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"
    }
  }
}

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

במהלך מילוי המשבצות, אפשר להשתמש במילוי האוטומטי כדי לאמת את המשבצת הזו או לבדוק את סטטוס מילוי המשבצות (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

לדוגמה, נניח שרוצים לחלץ את אזור הזמן מתשובה. לחשבון בדוגמה הזו, השם של משבצת הזמן הוא 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"
    ]
  }
}

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

אפשר לבטל את התוקף של משבצות השידור ולתת למשתמש ערך חדש.

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, שמאפשר ליצור ולפרוס פונקציה של Cloud Functions ל-Firebase ישירות במסוף. אפשר גם ליצור ולפרוס מילוי הזמנות באירוח לבחירתכם ורושמים את נקודת הקצה למילוי הזמנות ב-HTTPS כ-handler של ה-webhook.

עורך מוטבע

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

  1. יוצרים את הקובץ sdk/webhooks/ActionsOnGoogleFulfillment.yaml, ולהגדיר את ה-handlers של הפעולה ושל הפונקציה בענן המוטבעת שבה נעשה שימוש למילוי הזמנות.
    handlers:
    - name: questionOnEnterFunc
    - name: fruitSlotValidationFunc
    inlineCloudFunction:
      executeFunction: ActionsOnGoogleFulfillment
        
  2. יוצרים את התיקייה sdk/webhooks/ActionsOnGoogleFulfillment, ולהוסיף קובץ index.js שמטמיע את רכיבי ה-handler שהוגדר קודם לכן וקובץ package.json שמגדיר NPM הדרישות לקוד.
    // index.js
    const {conversation} = require('@assistant/conversation');
    const functions = require('firebase-functions');
    
    const app = conversation();
    
    app.handle('questionOnEnterFunc', conv => {
      conv.add('questionOnEnterFunc triggered on webhook');
    });
    
    app.handle('fruitSlotValidationFunc', conv => {
      conv.add('fruitSlotValidationFunc triggered on webhook');
    });
    
    exports.ActionsOnGoogleFulfillment = functions.https.onRequest(app);
        
    // package.json
    {
      "name": "ActionsOnGoogleFulfillment",
      "version": "0.1.0",
      "description": "Actions on Google fulfillment",
      "main": "index.js",
      "dependencies": {
        "@assistant/conversation": "^3.0.0",
        "firebase-admin": "^5.4.3",
        "firebase-functions": "^0.7.1"
      }
    }
        

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

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

הגדרת סביבה

כשמשתמשים בפונקציות של Cloud, מומלץ להשתמש במבנה הבא של הפרויקט, Firebase כשירות מילוי הזמנה:

ProjectFolder        - Root folder for the project
  sdk                - Actions project configuration files
  functions          - Cloud functions for Firebase files

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

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

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

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

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

  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
    

    הפריסה נמשכת כמה דקות. בסיום התהליך, הפלט יהיה דומה הבאות. כדי להזין ב-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 של מילוי ההזמנות שרוצים להשתמש בה בקטע הבא.

רישום webhook handler

  1. יוצרים את הקובץ sdk/webhooks/ActionsOnGoogleFulfillment.yaml ומגדירים של הגורמים המטפלים בפעולה של הפעולה ובכתובת ה-URL של בקשות ה-webhook.
    httpsEndpoint:
      baseUrl: https://my.web.hook/ActionsOnGoogleFulfillment
      endpointApiVersion: 2
    handlers:
    - name: questionOnEnterFunc
    - name: fruitSlotValidationFunc