เว็บฮุค

คุณสามารถมอบสิทธิ์ตรรกะ ให้กับบริการเว็บ HTTPS (การดำเนินการตามคำสั่ง) เพื่อให้มีความยืดหยุ่นในการสร้าง Actions มากยิ่งขึ้น การดำเนินการของคุณสามารถทริกเกอร์เว็บฮุคที่ ส่งคำขอไปยังปลายทาง HTTPS ได้ ตัวอย่างสิ่งที่คุณทำได้ในการ จัดการคำสั่งซื้อมีดังนี้

  • สร้างพรอมต์แบบไดนามิกตามข้อมูลที่ผู้ใช้ระบุ
  • การสั่งซื้อในระบบภายนอกและการยืนยันว่าสำเร็จ
  • การตรวจสอบความถูกต้องของช่องด้วยข้อมูลแบ็กเอนด์
รูปที่ 1 Intent การเรียกใช้และฉากสามารถทริกเกอร์ Webhook ได้

ทริกเกอร์และตัวแฮนเดิลของเว็บฮุค

การดำเนินการของคุณสามารถทริกเกอร์เว็บฮุคภายใน Intent หรือฉากการเรียกใช้ ซึ่งจะส่งคำขอไปยังปลายทางการดำเนินการตามคำสั่ง การดำเนินการตามคำสั่งมีตัวแฮนเดิลเว็บฮุค ที่ประมวลผลเพย์โหลด JSON ในคำขอ คุณเรียกใช้เว็บฮุกได้ในกรณีต่อไปนี้

  • หลังจากที่ Intent เรียกใช้ตรงกัน
  • ในระหว่างที่ฉากเข้าสู่พื้นที่งาน
  • หลังจากที่เงื่อนไขประเมินเป็นจริงในขั้นตอนเงื่อนไขของฉาก
  • ในระหว่างขั้นตอนการป้อนข้อมูลในช่องของฉาก
  • หลังจากที่การจับคู่ความตั้งใจเกิดขึ้นในขั้นตอนการป้อนข้อมูลของฉาก

เมื่อคุณทริกเกอร์เว็บฮุคใน Actions ของคุณ Google Assistant จะส่งคำขอ พร้อมเพย์โหลด JSON ไปยัง Fulfillment ซึ่งมี ชื่อของแฮนเดิลที่จะใช้ประมวลผลเหตุการณ์ ปลายทางการดำเนินการตามคำสั่งสามารถ กำหนดเส้นทางเหตุการณ์ไปยังแฮนเดิลที่เหมาะสมเพื่อดำเนินการตามตรรกะและส่งคืนการตอบกลับที่สอดคล้องกันพร้อมเพย์โหลด JSON

เพย์โหลด

ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่างคำขอที่ Actions ของคุณส่งไปยัง การดำเนินการตามคำสั่ง และการตอบกลับที่การดำเนินการตามคำสั่งส่งกลับมา ดูข้อมูลเพิ่มเติมในเอกสารอ้างอิง

ตัวอย่างคำขอ

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

ส่งพรอมต์

คุณสร้างพรอมต์ได้ด้วยข้อความธรรมดา Rich Text การ์ด และแม้แต่พรอมต์ HTML แบบเต็มที่ขับเคลื่อนโดยเว็บแอปที่มี Interactive Canvas เอกสารประกอบพรอมต์มีข้อมูลที่ครบถ้วนเกี่ยวกับวิธีสร้างพรอมต์เมื่อจัดการเหตุการณ์ 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": ""
    }
  }
}

อ่านพารามิเตอร์เจตนา

เมื่อรันไทม์ของ 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 จาก Action ที่เรียกใช้แฮนเดิลใน Fulfillment จากนั้นคุณจะป้อนพารามิเตอร์ session.typeOverrides ในการตอบกลับไปยัง Action ได้ โหมดที่ใช้ได้ ได้แก่ 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 Function สำหรับ Firebase ใช้งานได้ในคอนโซลโดยตรง นอกจากนี้ คุณยังสร้างและทำให้ใช้งานได้การประมวลผลตามคำสั่งไปยังโฮสติ้งที่คุณเลือก และจดทะเบียนปลายทางการประมวลผลตามคำสั่ง HTTPS เป็นตัวแฮนเดิลเว็บฮุคได้ด้วย

ตัวแก้ไขอินไลน์

วิธีพัฒนาด้วยโปรแกรมแก้ไข Cloud Functions

  1. สร้างไฟล์ sdk/webhooks/ActionsOnGoogleFulfillment.yaml, และกำหนดตัวแฮนเดิลสำหรับ Action และฟังก์ชันระบบคลาวด์แบบอินไลน์ที่ใช้ สำหรับการดำเนินการตามคำสั่ง
    handlers:
    - name: questionOnEnterFunc
    - name: fruitSlotValidationFunc
    inlineCloudFunction:
      executeFunction: ActionsOnGoogleFulfillment
        
  2. สร้างโฟลเดอร์ sdk/webhooks/ActionsOnGoogleFulfillment และเพิ่มไฟล์ index.js ที่ใช้ตัวแฮนเดิล ที่กำหนดไว้ก่อนหน้านี้ และไฟล์ 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 เป็นบริการ Fulfillment สำหรับการกระทำแบบสนทนา อย่างไรก็ตาม คุณสามารถติดตั้งใช้งาน การจัดการคำสั่งซื้อกับบริการโฮสติ้งที่คุณเลือกได้

ตั้งค่าสภาพแวดล้อม

เราขอแนะนำให้ใช้โครงสร้างโปรเจ็กต์ต่อไปนี้เมื่อใช้ Cloud Functions สำหรับ Firebase เป็นบริการ Fulfillment

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

หากต้องการตั้งค่าสภาพแวดล้อม ให้ทำตามขั้นตอนต่อไปนี้

  1. ดาวน์โหลดและติดตั้ง Node.js
  2. ตั้งค่าและเริ่มต้น Firebase CLI หากเรียกใช้คำสั่งต่อไปนี้ไม่สำเร็จโดยมีข้อผิดพลาด EACCES คุณอาจต้องเปลี่ยนสิทธิ์ npm

    npm install -g firebase-tools
    
  3. ตรวจสอบสิทธิ์เครื่องมือ Firebase ด้วยบัญชี Google โดยทำดังนี้

    firebase login
    
  4. เริ่มไดเรกทอรีโปรเจ็กต์ที่คุณบันทึกโปรเจ็กต์ Actions ระบบจะขอให้คุณเลือกฟีเจอร์ Firebase CLI ที่ต้องการตั้งค่าสำหรับโปรเจ็กต์ Actions เลือก 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. ติดตั้งทรัพยากร Dependency @assistant/conversation

    $ cd <ACTIONS_PROJECT_DIRECTORY>/functions
    $ npm install @assistant/conversation --save
    
  10. รับทรัพยากร Dependency ของการดำเนินการตามคำสั่งและทำให้ฟังก์ชันการดำเนินการตามคำสั่งใช้งานได้

    $ npm install
    $ firebase deploy --only functions
    

    การติดตั้งใช้งานจะใช้เวลาไม่กี่นาที เมื่อเสร็จแล้ว คุณจะเห็นเอาต์พุตที่คล้ายกับ เอาต์พุตต่อไปนี้ คุณจะต้องมี URL ของฟังก์ชันเพื่อป้อนใน Dialogflow

    ✔  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 การดำเนินการตามคำสั่งเพื่อใช้ในส่วนถัดไป

ลงทะเบียนตัวแฮนเดิลเว็บฮุค

  1. สร้างไฟล์ sdk/webhooks/ActionsOnGoogleFulfillment.yaml และกำหนด ตัวแฮนเดิลสำหรับ Action และ URL สำหรับคำขอ Webhook
    httpsEndpoint:
      baseUrl: https://my.web.hook/ActionsOnGoogleFulfillment
      endpointApiVersion: 2
    handlers:
    - name: questionOnEnterFunc
    - name: fruitSlotValidationFunc