แสดงบทความที่มีป้ายกำกับ Chatbot แสดงบทความทั้งหมด
แสดงบทความที่มีป้ายกำกับ Chatbot แสดงบทความทั้งหมด

วันศุกร์ที่ 26 ตุลาคม พ.ศ. 2561

วิธีใช้ Message objects เพิ่มลูกเล่นในการตอบกลับของ Line บน Dialogflow ด้วย Custom payload


          ในบทความก่อนหน้านี้ เราได้ทำการ integrate Line เข้ากับ Dialogflow ไปแล้ว ส่งผลให้ความสะดวกสบายในการคัดกรองข้อความเพิ่มขึ้น แต่กระนั้นก็ยังมีข้อจำกัดอยู่ นั่นคือ Responses ของ Dialogflow ไม่สามารถส่งสติกเกอร์ตอบกลับได้..... "อ้าว! แล้วถ้าเราอยากส่งสติกเกอร์ตอบกลับล่ะ จะทำยังไงดี" .....ไม่เป็นไรทาง Dialogflow มีเปิดช่องทาง Custom payload ให้เราได้ customize ข้อความตอบกลับด้วย JSON เพื่อปรับเปลี่ยนข้อความตอบกลับให้ตรงตาม API ของแต่ละ platform นั่นเอง

          เรามาลองใช้งาน Custom payload กัน ให้เข้าไปที่ https://dialogflow.com/ แล้วเลือก Agent ที่ได้สร้างไว้แล้วในบทความก่อนหน้านี้ จากนั้นก็คลิกไปที่ "Default Welcome Intent" แล้วเลื่อนลงมาในส่วนของ Response


          เจ้า Custom payload จะอยู่ในส่วนของ Responses ให้คลิกปุ่ม ADD RESPONSE แล้วเลือก Custom payload ก็จะมีพื้นที่ว่าง ๆ ขึ้นมา และจาก docs ของ LINE Messaging API รูปแบบของ JSON ที่ใช้ตอบกลับในประเภทข้อความเป็นดังนี้

{     
    "type": "text",     
    "text": "Hello, world" 
}
โดย "type" คือประเภทของการตอบกลับ ใน docs ของ LINE Messaging API จะแบ่งประเภทการตอบกลับออกเป็นประเภทต่าง ๆ ซึ่งจะพูดถึงภายหลังในส่วนของ Message objects และ "text" คือข้อความที่จะตอบกลับ ให้เราใส่ JSON ดังต่อไปนี้ลงไป

{
  "line": {
    "type": "text",
    "text": "สวัสดี นี่คือคำทักทายจาก Dialogflow (Custom payload)"
  }
}
จากการสังเกต จะเห็นว่า JSON ที่เราเพิ่มลงไปในช่อง Custom payload จะอยู่ข้างใน key "line" อีกที เป็นการบอกให้ Dialogflow รู้ว่านี่เป็น response สำหรับ LINE เท่านั้น เมื่อพิมพ์ JSON เสร็จ ให้คลิกปุ่ม SAVE แล้วลองทดสอบด้วยการพิมพ์ว่า "สวัสดี"


ผลลัพธ์ที่ได้ก็จะเป็นข้อความ "สวัสดี นี่คือคำทักทายจาก Dialogflow" และ "สวัสดี นี่คือคำทักทายจาก Dialogflow (Custom payload)" โดยข้อความแรกมาจาก Text response และข้อความที่สองมาจาก Custom payload .....ว่าแต่เมื่อกี้เพื่อน ๆ สังเกตเห็นอะไรกันหรือเปล่าเอ่ย ข้าง ๆ แถบ DEFAULT มีแถบ LINE อยู่


          เมื่อคลิกไปที่แถบ LINE แล้ว ก็จะมีตัวเลือกรูปแบบข้อความตอบกลับให้ 5 ตัวเลือก ได้แก่
  • Text response: เป็นการตอบกลับด้วยข้อความ ซึ่งจะมีช่องให้กรอกข้อความที่จะใช้ในการตอบกลับผู้ใช้ เหมือนกับในแถบ DEFAULT
  • Image: เป็นการตอบกลับด้วยรูป โดยจะมีช่องให้กรอก URL ของไฟล์รูป
  • Card: เป็นการตอบกลับด้วยการ์ด ซึ่งจะมีช่องให้กรอก URL ของไฟล์รูปที่ใช้เป็นรูปของการ์ด, ช่องให้กรอก Card Title, ช่องให้กรอก Card Subtitle, ช่องให้กรอกข้อความของปุ่ม (รายละเอียดอยู่ในส่วนของ Message objects ข้างล่าง)
  • Quick replies: เป็นการตอบกลับด้วยข้อความพร้อมทั้งปุ่ม (รายละเอียดอยู่ในส่วนของ Message objects ข้างล่าง)
  • Custom payload
ซึ่งเป็นการเพิ่มความง่ายในการตอบกลับข้อความของ LINE (มีตัวเลือก Custom payload ให้ด้วย) เพราะมีเป็น Template ให้อยู่แล้ว ทำให้เราไม่ต้องสร้าง JSON ขึ้นมาใหม่


LINE Message objects


          อย่างที่กล่าวไว้เมื่อตอนต้นว่า LINE Message object แบ่งประเภทการตอบกลับออกเป็นประเภทต่าง ๆ แต่ละประเภทก็จะมีจุดประสงค์การใช้ที่แตกต่างกันไป เช่น สติกเกอร์ หรือพิกัดตำแหน่ง เป็นต้น ซึ่งเราสามารถสร้าง Message object ได้จาก JSON รูปแบบต่าง ๆ ตามที่ทาง LINE กำหนดไว้ จากนั้นก็เอาไปใส่ไว้ใน Custom payload ภายใต้ key "line" ตามที่ได้ลองทำเมื่อสักครู่ .....ว่าแล้วเราก็มาดู Message objects แต่ละประเภทกันเลยดีกว่า ซึ่งเราสามารถแบ่งประเภทการตอบกลับออกได้เป็นดังนี้


Text message


          เริ่มจากพื้นฐานสุด ๆ ที่ Text message หรือก็คือการตอบกลับประเภทข้อความ ซึ่งเป็นการตอบกลับด้วยข้อความธรรมดา ๆ โดยจะมีหน้าตา JSON ดังต่อไปนี้

{
  "line": {
    "type": "text",
    "text": "นี่คือข้อความตอบกลับของ Text message"
  }
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ text
  • text: ข้อความที่แสดง สูงสุด 2,000 ตัวอักษร


Image message


          Image message เป็นการตอบกลับด้วยรูป โดยจะใช้ JSON ที่มีรูปแบบดังต่อไปนี้

{
  "line": {
    "type": "image",
    "originalContentUrl": "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjq9glxf1PI7p2RxnPHpL3oUiFgXW8Xhd1saDLw2xLsF3vZunZpGPW-UwPpEffmGhTRWoZ64HHY1VeljF0uDuGn6Lve2ncoTSZY4sl2L0ibbDlpojgUa0llhv7WnrVLkXX6tln7NLg-FkZI/s1600/sao-full.jpg",
    "previewImageUrl": "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvXWIsA2ka3azOhyeXwvizWjyz0sTiYhBuxFuQ451rXCKyX5wbIl47CIOKz8jk8pcKOC8kiriAIHTFo-zKkcO8Ied4vysq9Na00dlWfBksUMFxDdwSsYTrkjXyG-JGp5GcjgLJLjzmFerk/s1600/sao-preview.jpg"
  }
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ image
  • originalContentUrl: Url ของไฟล์รูปภาพต้นฉบับที่มีจำนวนตัวอักษรไม่เกิน 1,000 ตัวอักษร เป็น HTTPS และมีขนาดไม่เกิน 1 MB
  • previewImageUrl: Url ของไฟล์รูปภาพที่ใช้แสดงซึ่งมีจำนวนตัวอักษรไม่เกิน 1,000 ตัวอักษร เป็น HTTPS และมีขนาดไม่เกิน 1 MB


Sticker message


          Sticker message เป็นการตอบกลับด้วยสติกเกอร์อันน่ารักของ LINE แต่มีข้อจำกัดตรงที่สติกเกอร์ที่ใช้ในการตอบกลับนั้นต้องเป็นสติกเกอร์ที่สร้างโดย LINE เท่านั้น ไม่สามารถใช้สติกเกอร์ของ Creator คนอื่น ๆ ได้ โดยมีรูปแบบ JSON ดังต่อไปนี้

{
  "line": {
    "type": "sticker",
    "packageId": "1",
    "stickerId": "1"
  }
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ sticker
  • packageId: รหัสแพ็กเกจของสติกเกอร์ที่ต้องการส่ง ดูได้จากที่นี่
  • stickerId: รหัสของสติกเกอร์ที่ต้องการส่ง ดูได้จากที่นี่


Video message


          Video message เป็นการตอบกลับด้วยคลิปวิดีโอสั้น ๆ มีรูปแบบ JSON ดังต่อไปนี้

{
  "line": {
    "type": "video",
    "originalContentUrl": "https://s3-ap-southeast-1.amazonaws.com/dezpax/b_files/video_example.mp4",
    "previewImageUrl": "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvXWIsA2ka3azOhyeXwvizWjyz0sTiYhBuxFuQ451rXCKyX5wbIl47CIOKz8jk8pcKOC8kiriAIHTFo-zKkcO8Ied4vysq9Na00dlWfBksUMFxDdwSsYTrkjXyG-JGp5GcjgLJLjzmFerk/s1600/sao-preview.jpg"
  }
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ video
  • originalContentUrl: Url ของไฟล์วิดีโอที่มีจำนวนตัวอักษรไม่เกิน 1,000 ตัวอักษร เป็น HTTPS และมีขนาดไม่เกิน 10 MB
  • previewImageUrl: Url ของไฟล์รูปภาพที่ใช้แสดงซึ่งมีจำนวนตัวอักษรไม่เกิน 1,000 ตัวอักษร เป็น HTTPS และมีขนาดไม่เกิน 1 MB


Audio message


          Audio message เป็นการตอบกลับด้วยเสียงสั้น ๆ มีรูปแบบ JSON ดังต่อไปนี้

{
  "line": {
    "type": "audio",
    "originalContentUrl": "https://s3-ap-southeast-1.amazonaws.com/dezpax/b_files/audio_example.m4a",
    "duration": 10000
  }
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ audio
  • originalContentUrl: Url ของไฟล์เสียงที่มีจำนวนตัวอักษรไม่เกิน 1,000 ตัวอักษร เป็น HTTPS และมีขนาดไม่เกิน 10 MB
  • duration: ความยาวของไฟล์เสียง หน่วยเป็น milliseconds ( 1 วินาที = 1,000 milliseconds )


Location message


          Location message เป็นการตอบกลับด้วยพิกัดตำแหน่งที่อยู่ แสดงชื่อสถานที่และที่อยู่ของสถานที่นั้น ๆ เมื่อคลิกก็จะเป็นการเปิดแผนที่ใน LINE ขึ้นมา พร้อมทั้งปักหมุดพิกัดสถานที่นั้นให้โดยอัตโนมัติ มีรูปแบบ JSON ดังต่อไปนี้

{
  "line": {
    "type": "location",
    "title": "เซ็นทรัลพลาซา ลาดพร้าว",
    "address": "1693 ถนนพหลโยธิน แขวงจตุจักร เขตจตุจักร กรุงเทพมหานคร 10900",
    "latitude": 13.8164458,
    "longitude": 100.558962
  }
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ location
  • title: ชื่อสถานที่
  • address: ที่อยู่ของสถานที่นั้น ๆ
  • latitude: ตำแหน่งละติจูดของสถานที่นั้น ๆ
  • longitude: ตำแหน่งลองจิจูดของสถานที่นั้น ๆ


Imagemap message


          Imagemap message เป็นการตอบกลับด้วยรูป ซึ่งเราสามารถฝัง action ลงไปในรูปได้ แต่มีข้อเสียนิดหน่อยตรงที่เราจะต้องออกแบบรูปโดยแบ่งพื้นที่ของแต่ละ action เอาเอง จากรูปตัวอย่างจะเป็นการแบ่งรูปออกเป็นสองฝั่ง เมื่อแตะฝั่งซ้ายจะเปิดหน้าเว็บ ส่วนฝั่งขวาจะเป็นการส่งข้อความว่า "Hello" เข้าไปในห้องพูดคุย โดย JSON ที่ใช้มีรูปแบบดังต่อไปนี้

{
  "line": {
    "type": "imagemap",
    "baseUrl": "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjq9glxf1PI7p2RxnPHpL3oUiFgXW8Xhd1saDLw2xLsF3vZunZpGPW-UwPpEffmGhTRWoZ64HHY1VeljF0uDuGn6Lve2ncoTSZY4sl2L0ibbDlpojgUa0llhv7WnrVLkXX6tln7NLg-FkZI/s1600/",
    "altText": "This is an imagemap",
    "baseSize": {
      "height": 1040,
      "width": 1040
    },
    "actions": [
      {
        "type": "uri",
        "linkUri": "https://www.google.com/",
        "area": {
          "x": 0,
          "y": 0,
          "width": 512,
          "height": 731
        }
      },
      {
        "type": "message",
        "text": "Hello",
        "area": {
          "x": 512,
          "y": 0,
          "width": 512,
          "height": 731
        }
      }
    ]
  }
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ imagemap
  • baseUrl: Url ของไฟล์รูปภาพ ควรทำให้สามารถเข้าถึงภาพ 5 ขนาดได้ (240px, 300px, 460px, 700px, 1040px) โดยใช้รูปแบบ baseUrl/{image width} (เช่น https://1.bp.blogspot.com/-U90M8DyKu7Q/W9EtONMCf6I/AAAAAAAAW_4/7L_jB_Rg9oweu2HKhULNdu9WNefw9zf9wCLcBGAs/s1600/ เป็นต้น) ซึ่ง LINE จะเลือกโหลดขนาดภาพให้เหมาะสมกับอุปกรณ์เอง
  • altText: ข้อความของรูปภาพ จำนวนตัวอักษรสูงสุด 400 ตัวอักษร
  • baseSize: ขนาดของรูปภาพ
    • width: ความกว้างของรูปภาพ ให้เซ็ตเป็น 1040
    • height: ความสูงของรูปภาพ ให้เซ็ตเป็น 1040
  • actions: อาร์เรย์ actions ของ Imagemap โดยเราสามารถใส่ action ได้มากสุด 50 actions
    • type: ประเภทของ action ได้แก่ uri หรือ message ถ้ากำหนดเป็น uri นั่นหมายถึง เมื่อกดที่ action นี้แล้วก็จะทำการเปิดเว็บขึ้นมา และถ้ากำหนดเป็น message นั่นหมายถึง เมื่อกดที่ action นี้แล้วจะทำการส่งข้อความกลับมาให้ bot
    • label: ป้ายกำกับของ action
    • linkUri: Url ของเว็บ ใช้ในกรณีที่กำหนด type = uri
    • text: ข้อความที่จะทำการส่งกลับมาให้ bot ใช้ในกรณีที่กำหนด type = message
    • area: พื้นที่สำหรับ action
      • x: ตำแหน่งแนวนอนนับจากมุมบนซ้ายของพื้นที่
      • y: ตำแหน่งแนวตั้งนับจากมุมบนซ้ายของพื้นที่
      • width: ความกว้างของพื้นที่ action
      • height: ความสูงของพื้นที่ action


Template messages

          Template messages คือ ข้อความที่มีรูปแบบตามที่ LINE กำหนดเอาไว้แล้ว ซึ่งเราสามารถปรับแต่งเพื่อให้ผู้ใช้สามารถโต้ตอบกับ bot ได้ง่ายขึ้น ซึ่ง LINE แบ่งประเภทของเทมเพลตออกเป็นดังนี้


          Buttons template เทมเพลตที่ประกอบไปด้วยรูปภาพ ชื่อ ข้อความ และปุ่มการดำเนินการหลายปุ่ม โดยใช้ JSON ที่มีรูปแบบดังต่อไปนี้

{
  "line": {
    "type": "template",
    "altText": "This is a buttons template",
    "template": {
        "type": "buttons",
        "thumbnailImageUrl": "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjq9glxf1PI7p2RxnPHpL3oUiFgXW8Xhd1saDLw2xLsF3vZunZpGPW-UwPpEffmGhTRWoZ64HHY1VeljF0uDuGn6Lve2ncoTSZY4sl2L0ibbDlpojgUa0llhv7WnrVLkXX6tln7NLg-FkZI/s1600/sao-full.jpg",
        "imageAspectRatio": "rectangle",
        "imageSize": "cover",
        "imageBackgroundColor": "#FFFFFF",
        "title": "แผ่นเกม Sword Art Online",
        "text": "กรุณาเลือก",
        "defaultAction": {
            "type": "uri",
            "label": "View detail",
            "uri": "https://www.google.com"
        },
        "actions": [
            {
              "type": "postback",
              "label": "สั่งซื้อ",
              "data": "action=buy&itemid=123"
            },
            {
              "type": "postback",
              "label": "เพิ่มลงรถเข็น",
              "data": "action=add&itemid=123"
            },
            {
              "type": "uri",
              "label": "อ่านรายละเอียด",
              "uri": "https://www.google.com"
            }
        ]
    }
  }
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ template
  • altText: ข้อความกำกับของ template จำนวนตัวอักษรสูงสุด 400 ตัวอักษร
  • template:
    • type: ประเภทของ template ในที่นี้คือ buttons
    • thumbnailImageUrl: Url ของไฟล์รูปภาพที่มีจำนวนตัวอักษรไม่เกิน 1,000 ตัวอักษร เป็น HTTPS และมีขนาดไม่เกิน 1 MB
    • imageAspectRatio: อัตราส่วนของภาพ มีค่าเป็น rectangle (สี่เหลี่ยมผืนผ้า) หรือ square (สี่เหลี่ยมจตุรัส)
    • imageSize: ขนาดของรูปภาพ มีค่าเป็น cover หรือ contain
    • imageBackgroundColor: สีพื้นหลังของรูปภาพ
    • title: หัวเรื่อง จำนวนตัวอักษรสูงสุด 40 ตัวอักษร
    • text: ข้อความ กรณีที่ไม่มีหัวเรื่องหรือรูปภาพ สามารถใส่ได้สูงสุด 160 ตัวอักษร แต่ถ้ามีหัวเรื่องหรือรูปภาพจะใส่ได้สูงสุด 60 ตัวอักษร
    • defaultAction: action ที่จะทำงานเมื่อรูปภาพถูกกด (อ่านรายละเอียดของ action เพิ่มเติมในส่วนของ Action objects)
    • actions: อาร์เรย์ของ action ที่จะทำงานเมื่อถูกกด ใส่ได้มากสุด 4 actions  (อ่านรายละเอียดของ action เพิ่มเติมในส่วนของ Action objects)
....................


          Confirm template เทมเพลตที่ประกอบไปปุ่มการดำเนินการสองปุ่ม โดยใช้ JSON ที่มีรูปแบบดังต่อไปนี้

{
  "line": {
    "type": "template",
    "altText": "this is a confirm template",
    "template": {
      "type": "confirm",
      "text": "ต้องการที่จะลบข้อมูลหรือไม่?",
      "actions": [
        {
          "type": "message",
          "label": "ใช่",
          "text": "ใช่"
        },
        {
          "type": "message",
          "label": "ไม่",
          "text": "ไม่"
        }
      ]
    }
  }
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ template
  • altText: ข้อความกำกับของ template จำนวนตัวอักษรสูงสุด 400 ตัวอักษร
  • template:
    • type: ประเภทของ template ในที่นี้คือ confirm
    • text: ข้อความ จำนวนตัวอักษรสูงสุด 240 ตัวอักษร
    • actions: อาร์เรย์ของ action ที่จะทำงานเมื่อถูกกด ใส่ได้มากสุด 2 actions (อ่านรายละเอียดของ action เพิ่มเติมในส่วนของ Action objects)
....................


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

{
  "line": {
    "type": "template",
    "altText": "this is a carousel template",
    "template": {
      "type": "carousel",
      "imageAspectRatio": "rectangle",
      "imageSize": "cover",
      "columns": [
        {
          "thumbnailImageUrl": "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjq9glxf1PI7p2RxnPHpL3oUiFgXW8Xhd1saDLw2xLsF3vZunZpGPW-UwPpEffmGhTRWoZ64HHY1VeljF0uDuGn6Lve2ncoTSZY4sl2L0ibbDlpojgUa0llhv7WnrVLkXX6tln7NLg-FkZI/s1600/sao-full.jpg",
          "imageBackgroundColor": "#FFFFFF",
          "title": "แผ่นเกม Sword Art Online",
          "text": "แผ่นเกม Sword Art Online",
          "defaultAction": {
            "type": "uri",
            "label": "รายละเอียด",
            "uri": "https://www.google.com/"
          },
          "actions": [
            {
              "type": "postback",
              "label": "สั่งซื้อ",
              "data": "action=buy&itemid=111"
            },
            {
              "type": "postback",
              "label": "เพิ่มลงรถเข็น",
              "data": "action=add&itemid=111"
            },
            {
              "type": "uri",
              "label": "รายละเอียด",
              "uri": "https://www.google.com/"
            }
          ]
        },
        {
          "thumbnailImageUrl": "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibVSKKr0uN4_y_UPxK7jk3cP6xB9ERt1OZ_efvW7t40lhiV8xsCakvoYcqy1_3aQMNQHy3f1AX7p9KqBMiWHEVK60QJc3nDFe1FkJP8qPSvImtP7Vq0JSAEt_6HZ3a2jVC1ZRLdYUufulM/s1600/sao-os.jpg",
          "imageBackgroundColor": "#FFFFFF",
          "title": "Sword Art Online Ordinal Scale",
          "text": "Sword Art Online Ordinal Scale",
          "defaultAction": {
            "type": "uri",
            "label": "รายละเอียด",
            "uri": "https://www.google.com/"
          },
          "actions": [
            {
              "type": "postback",
              "label": "สั่งซื้อ",
              "data": "action=buy&itemid=111"
            },
            {
              "type": "postback",
              "label": "เพิ่มลงรถเข็น",
              "data": "action=add&itemid=111"
            },
            {
              "type": "uri",
              "label": "รายละเอียด",
              "uri": "https://www.google.com/"
            }
          ]
        }
      ]
    }
  }
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ template
  • altText: ข้อความกำกับของ template จำนวนตัวอักษรสูงสุด 400 ตัวอักษร
  • template:
    • type: ประเภทของ template ในที่นี้คือ carousel
    • imageAspectRatio: อัตราส่วนของภาพ มีค่าเป็น rectangle (สี่เหลี่ยมผืนผ้า) หรือ square (สี่เหลี่ยมจตุรัส)
    • imageSize: ขนาดของรูปภาพ มีค่าเป็น cover หรือ contain
    • columns: อาร์เรย์ของ column ใส่ได้มากสุด 10 column
      • thumbnailImageUrl: Url ของไฟล์รูปภาพที่มีจำนวนตัวอักษรไม่เกิน 1,000 ตัวอักษร เป็น HTTPS และมีขนาดไม่เกิน 1 MB
      • imageBackgroundColor: สีพื้นหลังของรูปภาพ
      • title: หัวเรื่อง จำนวนตัวอักษรสูงสุด 40 ตัวอักษร
      • text: ข้อความ กรณีที่ไม่มีหัวเรื่องหรือรูปภาพ สามารถใส่ได้สูงสุด 160 ตัวอักษร แต่ถ้ามีหัวเรื่องหรือรูปภาพจะใส่ได้สูงสุด 60 ตัวอักษร
      • defaultAction: action ที่จะทำงานเมื่อรูปภาพถูกกด (อ่านรายละเอียดของ action เพิ่มเติมในส่วนของ Action objects)
      • actions: อาร์เรย์ของ action ที่จะทำงานเมื่อถูกกด ใส่ได้มากสุด 4 actions (อ่านรายละเอียดของ action เพิ่มเติมในส่วนของ Action objects)
....................


          Image carousel template เทมเพลตที่มีรูปภาพหลายรูป มีการแสดงผลตามลำดับโดยการเลื่อนไปตามแนวนอน โดยใช้ JSON ที่มีรูปแบบดังต่อไปนี้

{
  "line": {
    "type": "template",
    "altText": "this is a image carousel template",
    "template": {
      "type": "image_carousel",
      "columns": [
        {
          "imageUrl": "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjq9glxf1PI7p2RxnPHpL3oUiFgXW8Xhd1saDLw2xLsF3vZunZpGPW-UwPpEffmGhTRWoZ64HHY1VeljF0uDuGn6Lve2ncoTSZY4sl2L0ibbDlpojgUa0llhv7WnrVLkXX6tln7NLg-FkZI/s1600/sao-full.jpg",
          "action": {
            "type": "postback",
            "label": "สั่งซื้อ",
            "data": "action=buy&itemid=111"
          }
        },
        {
          "imageUrl": "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibVSKKr0uN4_y_UPxK7jk3cP6xB9ERt1OZ_efvW7t40lhiV8xsCakvoYcqy1_3aQMNQHy3f1AX7p9KqBMiWHEVK60QJc3nDFe1FkJP8qPSvImtP7Vq0JSAEt_6HZ3a2jVC1ZRLdYUufulM/s1600/sao-os.jpg",
          "action": {
            "type": "message",
            "label": "ตกลง",
            "text": "ตกลง"
          }
        },
        {
          "imageUrl": "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDnf6GMcW7s9i9uBie9tQZBaepFr6hTOVozf97hmq1w-XC3gEfsZn-EILsLKjpBihd-scR3kdXGJY6iXa2LnTFtXmz5ajoQP_9YtxC1au4aFGmyYGir8b0ZV4B1laG1ZBndVd74BOoDrcf/s1600/saohr-cover-image.jpg",
          "action": {
            "type": "uri",
            "label": "อ่านรายละเอียด",
            "uri": "https://www.google.com/"
          }
        }
      ]
    }
  }
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ template
  • altText: ข้อความกำกับของ template จำนวนตัวอักษรสูงสุด 400 ตัวอักษร
  • template:
    • type: ประเภทของ template ในที่นี้คือ image_carousel
    • columns: อาร์เรย์ของ column ใส่ได้มากสุด 10 column
      • imageUrl: Url ของไฟล์รูปภาพที่มีจำนวนตัวอักษรไม่เกิน 1,000 ตัวอักษร เป็น HTTPS และมีขนาดไม่เกิน 1 MB
      • actions: action ที่จะทำงานเมื่อรูปภาพถูกกด  (อ่านรายละเอียดของ action เพิ่มเติมในส่วนของ Action objects)


Flex message


          Flex Message คือ ข้อความที่เปิดให้นักพัฒนาสามารถออกแบบหน้าตาของข้อความได้อย่างอิสระ แตกต่างจาก Template messages ตรงที่ Template messages จะมีรูปแบบตายตัว ถึงจะมีส่วนที่เราสามารถปรับแต่งได้ แต่โดยรวมก็ยังอยู่ในรูปแบบตามที่ LINE กำหนด เช่น ตำแหน่งของรูปภาพจะต้องอยู่ข้างบนสุด ตามด้วยข้อความ จากนั้นจึงจะเป็นปุ่มที่อยู่อันดับล่างสุด เป็นต้น ซึ่งเราไม่สามารถแก้ไขตำแหน่งเหล่านั้นได้ แต่ Flex Message เปิดให้เราสามารถออกแบบข้อความได้ตามใจชอบ สามารถกำหนดให้ตำแหน่งของรูปอยู่ข้างล่างข้อความได้

          เนื่องจากความอิสระของ Flex Message ทำให้ JSON ค่อนข้างมีความซับซ้อน ซึ่งผมขอแนะนำให้เพื่อน ๆ ไปอ่านรายละเอียด รวมถึงวิธีการสร้าง JSON ของ Flex Message เพิ่มเติมที่บทความ "ฉีกกฎการแสดงผลข้อความแบบเดิมๆใน LINE Messaging API ด้วย Flex Messag" ของคุณ Jirawatee ครับ


Action objects

          ประเภทของ action ที่ bot สามารถใช้งานได้เมื่อผู้ใช้แตะปุ่มหรือรูปภาพในข้อความ เช่น เปิดเว็บ เปิดกล้อง หรือแสดงตำแหน่งบนแผนที่ เป็นต้น โดยแบ่งประเภทของ action ออกได้เป็น


          Postback action เมื่อตัวควบคุมที่เกี่ยวข้องกับ Postback action ถูกแตะก็จะทำการส่งค่ากลับไปยัง webhook ด้วยค่าที่ระบุใน data โดย JSON ของการกระทำนี้จะมีหน้าตาประมาณนี้

{  
   "type":"postback",
   "label":"สั่งซื้อ",
   "data":"action=buy&itemid=123",
   "displayText":"สั่งซื้อ"
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ postback
  • label: ข้อความกำกับของ action
  • data: ค่าที่จะส่งไปยัง webhook จำนวนตัวอักษรไม่เกิน 300 ตัวอักษร
  • displayText: ข้อความที่จะส่งเข้าไปในห้องพูดคุยในฐานะข้อความจากผู้ใช้ จำนวนตัวอักษรไม่เกิน 300 ตัวอักษร
....................

          Message action เมื่อตัวควบคุมที่เกี่ยวข้องกับ Message action ถูกแตะ ข้อความที่ระบุอยู่ใน text จะถูกส่งเข้าไปในห้องพูดคุยในฐานะข้อความจากผู้ใช้ โดย JSON ของการกระทำนี้จะมีหน้าตาเป็นแบบนี้

{  
   "type":"message",
   "label":"สั่งซื้อ",
   "text":"สั่งซื้อ"
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ message
  • label: ข้อความกำกับของ action
  • text: ข้อความที่จะส่งเข้าไปในห้องพูดคุยในฐานะข้อความจากผู้ใช้ จำนวนตัวอักษรไม่เกิน 300 ตัวอักษร
....................

          URI action เมื่อตัวควบคุมที่เกี่ยวข้องกับ URI action ถูกแตะ URI ที่ระบุอยู่ใน uri จะถูกเรียกใช้งาน โดย JSON ของการกระทำนี้จะมีหน้าตาเป็นแบบนี้

{  
   "type":"uri",
   "label":"Google",
   "uri":"https://www.google.com/"
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ uri
  • label: ข้อความกำกับของ action
  • uri: URI ที่จะทำงาน รองรับ http, https, line, และ tel จำนวนตัวอักษรไม่เกิน 1,000 ตัวอักษร
....................

          Datetime picker action เมื่อตัวควบคุมที่เกี่ยวข้องกับ Datetime picker action ถูกแตะ ก็จะแสดงตัวเลือกวัน-เวลาขึ้นมาให้ผู้ใช้เลือก เมื่อเลือกเสร็จแล้วก็จะส่งค่าไปที่ webhook โดย JSON ของการกระทำนี้จะมีหน้าตาเป็นแบบนี้

{  
   "type":"datetimepicker",
   "label":"เลือกวันและเวลา",
   "data":"value=12345",
   "mode":"datetime",
   "initial":"2018-10-26t00:00",
   "max":"2019-12-31t23:59",
   "min":"2017-01-01t00:00"
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ datetimepicker
  • label: ข้อความกำกับของ action
  • data: ค่าที่จะส่งไปยัง webhook จำนวนตัวอักษรไม่เกิน 300 ตัวอักษร
  • mode: โหมดสำหรับตัวเลือก มีทั้งหมด 3 โหมด ได้แก่ date สำหรับเลือกวันที่, time สำหรับเลือกเวลา และ datetime สำหรับเลือกทั้งวันที่และเวลา
  • initial: ค่าเริ่มต้น
  • max: ค่ามากสุดที่สามารถเลือกได้
  • min: ค่าน้อยสุดที่สามารถเลือกได้
ค่าของวันที่จะอยู่ในรูปแบบ "ปี-เดือน-วัน" เช่น 2018-10-26 เป็นต้น
ค่าของเวลาจะอยู่ในรูปแบบ "ชั่วโมง:นาที" เช่น 13:00 เป็นต้น
ค่าของวันเวลาจะอยู่ในรูปแบบ "ปี-เดือน-วันTชั่วโมง:นาที" หรือ "ปี-เดือน-วันtชั่วโมง:นาที" เช่น 2018-10-26T13:00 หรือ 2018-10-26t13:00 เป็นต้น

....................

          Camera action เมื่อตัวควบคุมที่เกี่ยวข้องกับ Camera action ถูกแตะก็จะทำการเปิดหน้าจอกล้องถ่ายรูปของ LINE ขึ้นมา โดย JSON ของการกระทำนี้จะมีหน้าตาประมาณนี้

{  
   "type":"camera",
   "label":"กล้องถ่ายรูป",
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ camera
  • label: ข้อความกำกับของ action จำนวนตัวอักษรไม่เกิน 20 ตัวอักษร
....................

          Camera roll action เมื่อตัวควบคุมที่เกี่ยวข้องกับ Camera roll action ถูกแตะก็จะทำการเปิดหน้าจอเลือกรูปภาพของ LINE ขึ้นมา โดย JSON ของการกระทำนี้จะมีหน้าตาประมาณนี้

{  
   "type":"cameraRoll",
   "label":"เลือกรูป",
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ cameraRoll
  • label: ข้อความกำกับของ action จำนวนตัวอักษรไม่เกิน 20 ตัวอักษร
....................

          Location action เมื่อตัวควบคุมที่เกี่ยวข้องกับ Location action ถูกแตะก็จะทำการเปิดหน้าจอเลือกรูปภาพของ LINE ขึ้นมา โดย JSON ของการกระทำนี้จะมีหน้าตาประมาณนี้

{  
   "type":"location",
   "label":"แผนที่",
}
  • type: เป็นตัวกำหนดประเภทของการตอบกลับ ในที่นี้คือ location
  • label: ข้อความกำกับของ action จำนวนตัวอักษรไม่เกิน 20 ตัวอักษร


          บทความนี้เป็นการแนะนำวิธีใช้ความสามารถในการตอบกลับอันหลากหลายของ LINE bot บน Dialogflow โดยการใช้ Custom payload ช่วยในการดัดแปลงข้อความตอบกลับ ซึ่งจะทำให้ bot ของเรามีความน่าสนใจมากยิ่งขึ้น และถ้าอยากทราบรายละเอียดเชิงลึก เพื่อน ๆ สามารถเข้าไปอ่านเพิ่มเติมได้ที่ docs ของ LINE Messaging API .....ถึงตรงนี้ ผมก็คงต้องขอตัวลาไปก่อน ไว้พบกันใหม่ในบทความถัดไป บ๊ายบาย


วันพฤหัสบดีที่ 20 กันยายน พ.ศ. 2561

สร้าง LINE Chatbot อย่างง่าย ๆ ด้วย Dialogflow


          ในบทความก่อนหน้านี้ (ที่นานมากแล้ว) ผมเขียนถึงวิธีสร้าง LINE Chatbot ด้วย Messaging API ซึ่งเป็นวิธีที่เราต้องจัดการกับข้อความที่ได้รับมาจากผู้ใช้งานทั้งหมดเองเลย มันก็อาจจะลำบากเอาการอยู่ ดังนั้นผมเลยมีอีกวิธีหนึ่งมาช่วยในการสร้าง Chatbot นั่นคือการผนวก Dialogflow ร่วมเข้ามาด้วยนั่นเอง โดย Dialogflow จะช่วยในการทำ Natural Language Understanding (NLU) ในการตรวจจับข้อความของผู้ใช้งาน และสามารถเลือก Intent ที่เข้ากับข้อความนั้น ๆ ได้โดยที่เราไม่ต้องเขียนโปรแกรมเพิ่ม นอกจากนี้เรายังจับเจ้า Dialogflow ไปใช้งานร่วมกับ Chat Platform อื่น ๆ (เช่น LINE, Google Assistant, Facebook Messenger เป็นต้น) เพื่อสร้าง Chatbot ได้อีกด้วย

          การนำ Dialogflow มาทำงานร่วมกับ Line นั้น จำเป็นต้องทำการตั้งค่าให้ทั้งคู่รู้จักและสนิทสนมกันก่อน ซึ่งขั้นตอนมันก็จะวุ่นวายนิดนึง เพราะงั้นผมเลยจะแบ่งบทความนี้ออกเป็น 4 ส่วน ได้แก่
สำหรับเพื่อน ๆ ที่เคยสร้าง LINE Chatbot หรือ Agent ใน Dialogflow จากบทความเก่ามาแล้ว ก็ข้ามไปทำขั้นตอนอื่นได้เลย


สร้าง LINE Chatbot


          อันดับแรกให้เราเข้าไปที่ LINE Developers console เพื่อสร้าง channel หรือช่องทางที่จะเชื่อมต่อโปรแกรมของเราเข้ากับแพลตฟอร์มของ LINE


          ใส่ username และ password บัญชีของ LINE เพื่อ Log in เข้าสู่ระบบ


          ในกรณีที่เข้า LINE Developers console เป็นครั้งแรก ก็จะมีให้กรอกชื่อและ Email ของนักพัฒนาก่อน ใส่ข้อมูลแล้วกดสมัครโล้ด


          คลิกที่ปุ่ม Create New Provider


          ตั้งชื่อ Provider จะใช้เป็นชื่อบริษัทก็ได้ ซึ่งชื่อ Provider จะใช้เป็นชื่อผู้ผลิตบอท จากนั้นก็คลิกปุ่ม Confirm แล้วคลิกปุ่ม Create เพื่อสร้าง Provider


          หลังจากสร้าง Provider เสร็จแล้ว ในหน้าเว็บจะแสดงลิสต์ Provider ทั้งหมดของเรา ให้คลิกที่ชื่อ Provider ที่เพิ่งสร้างเมื่อกี้ตรงแถบเมนูด้านซ้าย


          เมื่อเข้ามาแล้วจะมีบริการให้เราเลือกสร้าง แน่นอนว่าต้องเลือกอันกลาง Message API อยู่แล้ว คลิกปุ่ม Create Channel ได้เลย


          ให้กรอกข้อมูลสำหรับบอท เริ่มจาก App icon ซึ่งก็คือรูปโปรไฟล์ของบอทในไลน์นั่นเอง โดยไฟล์รูปที่ใช้ต้องเป็นไฟล์นามสกุล JPEG/PNG/GIF/BMP และมีขนาดไม่เกิน 3mb


          ถัดไปจะต้องกรอก
  • App name: เป็นชื่อของบอท ซึ่งจำกัดได้ไม่เกิน 20 ตัวอักษร
  • App description: เป็นคำอธิบายของบอทว่าบอทตัวนี้ใช้ทำอะไรได้บ้าง จำกัดไม่เกิน 500 ตัวอักษร


  • Plan: สำหรับนักพัฒนาชาวไทย ตอนนี้ยังมีให้เลือกแค่ Developer Trial ซึ่งสามารถส่งข้อความให้ผู้ใช้งานบอทได้ แต่จะจำกัดให้บอทมีเพื่อนได้แค่ 50 คน
  • Category และ Subcategory: คือประเภทของบอท
  • Email address: email ของนักพัฒนา เอาไว้สำหรับส่งแจ้งเตือนต่าง ๆ
จากนั้นก็คลิกปุ่ม Confirm คลิกยอมรับเงื่อนไขการใช้งาน แล้วคลิกปุ่ม Create เพื่อสร้าง Channel ได้เลย


          เรียบร้อย! เท่านี้ก็จบขั้นตอนการสร้าง LINE Chatbot แล้ว ส่วนวิธีการเพิ่มบอทเป็นเพื่อนก็ง่าย ๆ แค่คลิกเข้าไปยังบอทที่ต้องการ


          เลื่อนลงมาในส่วนของ QR code of your bot เอามือถือมาสแกน QR code แล้วก็กดเพิ่มเพื่อนได้เลย


สร้าง Agent ใน Dialogflow


          ถัดไปจะเป็นการสร้าง Agent ใน Dialogflow ให้เข้าไปที่ https://dialogflow.com/


          คลิกที่ปุ่ม GO TO CONSOLE (มุมบนขวา) จากนั้นก็เข้าสู่ขั้นตอนการ Login หรือลงทะเบียน สำหรับผู้ที่ Login แล้วก็คลิก Create new agent เพื่อสร้าง Agent ใหม่ขึ้นมาเลย


          ให้กรอกข้อมูลของ Agent ที่จะทำการสร้าง
  • Agent name: ชื่อของ Agent
  • Default Language: ภาษาตั้งต้นที่จะให้ Agent รองรับ
  • Default Time Zone: โซนเวลา
จากนั้นให้คลิกปุ่ม CREATE เท่านี้ก็สร้าง Agent เสร็จแล้ว ง่ายม่ะ ฮา


ตั้งการตอบกลับข้อความ ใน Dialogflow


          ขั้นตอนต่อไปจะเป็นการตั้งข้อความตอบกลับ เพื่อให้รู้ว่าเราเชื่อมต่อ LINE Chatbot เข้ากับ Dialogflow ได้แล้ว โดยเราจะสร้างบทสนทนา (.....จะเรียกว่าบทสนทนาได้ป่าวหว่า แค่พูดมาก็ตอบกลับสั้น ๆ) เมื่อผู้ใช้งานพิมพ์คำว่า "สวัสดี" เข้ามาแล้ว บอทก็จะทำการตอบข้อความกลับไปหาผู้ใช้งานอย่างง่าย ๆ ว่า "สวัสดี นี่คือคำทักทายจาก Dialogflow"


          เมื่อสร้าง Agent เสร็จแล้ว ก็จะพบกับ Default Intents ที่ Dialogflow สร้างขึ้นมาให้ 2 ตัว ให้คลิกไปที่ "Default Welcome Intent"


          ตรงส่วน Training phrases เป็นการกำหนดข้อความที่จะเป็นตัวเรียกใช้งาน Intent หรือพูดง่าย ๆ ว่าถ้าผู้ใช้งานส่งข้อความที่อยู่ในส่วนของ Training phrases เข้ามา Intent นั้นก็จะทำงาน


          ให้เลื่อนลงมาในส่วนของ Responses เราสามารถเพิ่ม แก้ไข หรือลบข้อความตอบกลับผู้ใช้งานได้ ในที่นี้ให้ลบข้อความที่มีอยู่แล้วออกให้หมด จากนั้นก็เพิ่มข้อความว่า "สวัสดี นี่คือคำทักทายจาก Dialogflow" แล้วคลิกปุ่ม SAVE (ถ้าต้องการให้บอทตอบกลับข้อความที่หลากหลายมากขึ้นก็ให้เพิ่มข้อความลงไปอีก)

เชื่อมต่อ LINE Chatbot เข้ากับ Dialogflow


          ขั้นตอนนี้จะเป็นการตั้งค่าให้ LINE Chatbot เชื่อมต่อกับ Dialogflow เพื่อให้ทำงานร่วมกัน อันดับแรกเราจะเริ่มจากนำค่าของ LINE Chatbot มาใส่ใน Dialogflow ให้เรียบร้อยก่อน จากนั้นค่อยนำค่าของ Dialogflow ไปใส่ใน LINE Chatbot .....งงม่ะ ถ้างงก็ไม่เป็นไร ค่อย ๆ ทำตามขั้นตอนไปเดี๋ยวก็รู้เรื่อง


          คลิกปุ่ม Integrations ที่แถบเมนูด้านซ้าย


          คลิกเปิดการใช้งานตรง LINE จะมีป๊อปอัพแสดงขึ้นมา


          จะเห็นได้ว่าเราไม่สามารถคลิกปุ่ม START ได้ เนื่องจากยังไม่ได้กรอกข้อมูลสำคัญลงไป ได้แก่ Channel ID, Channel Secret และ Channel Access Token ซึ่งข้อมูลเหล่านี้ เราต้องไปเอามาจาก LINE Chatbot ที่เพิ่งสร้างตอนต้นบทความ ให้กลับไปที่ LINE Developers console แล้วคลิกเข้าไปที่บอท


          เลื่อนลงมาข้างใต้ App description จะเจอ Channel ID กับ Channel Secret ให้ก๊อปปี้ค่าทั้งสองออกมาใส่ในป๊อปอัพของ Dialogflow Console


          ต่อไปก็เลื่อนลงไปอีกจนถึงส่วนของ Messaging settings ก็จะเจอกับ Channel access token ที่เราตามหา แต่เอ๊ะ! ค่าของ Channel access token เป็น - นี่นา แล้วจะทำยังไงดี ไม่เป็นไร ให้คลิกปุ่ม Issue ข้าง ๆ เพื่อทำการสร้าง token ขึ้นมา


เมื่อคลิกแล้วจะขึ้นป๊อปอัพให้เราตั้งเวลาหมดอายุของ token ถ้าเราเลือก 0 ก็จะเป็นการกำหนดให้ token ไม่มีวันหมดอายุ จากนั้นก็คลิกปุ่ม Issue เพื่อทำการสร้าง token ขึ้นมา แล้วก๊อปปี้ค่ากลับไปใส่ในป๊อปอัพของ Dialogflow Console เหมือนเมื่อกี้


          เท่านี้ก็ตั้งค่าในฝั่ง Dialogflow เสร็จแล้ว คลิกปุ่ม START โลด แต่ก่อนจะปิดป๊อปอัพอันนี้ไป ให้คลิกก๊อปปี้ Webhook URL ที่อยู่บรรทัดล่างก่อน

          ขั้นตอนต่อไปให้กลับไปที่ LINE Developers console เพื่อนำ Webhook URL ที่ก๊อปปี้ไว้ไปกรอก ก็จะเสร็จสิ้นการตั้งค่าแล้ว


          ใน LINE Developers console ให้เลื่อนลงมาถึงส่วนของ Messaging settings ก็จะเจอ Use webhooks และ Webhook URL ที่อยู่ข้างล่าง Channel access token

          ให้เราคลิกปุ่ม Edit ตรง Use webhooks คลิก Enabled แล้วคลิกปุ่ม Update จากนั้นค่อยคลิกปุ่ม Edit ตรง Webhook URL เพื่อใส่ URL ที่เราก๊อปปี้มา โดยตัด https:// ออก แล้วคลิกปุ่ม Update


          สุดท้ายก็คลิกปุ่ม Verify เพื่อให้ระบบทำการตรวจสอบ URL ถ้า URL ของเราสามารถใช้งานได้จริง ก็จะขึ้นข้อความว่า Success .....อ้อ เกือบลืมไป เราต้องไปปิดฟีเจอร์ Auto-reply messages ด้วย มิฉะนั้นบอทจะตอบข้อความกลับไปให้ผู้ใช้โดยอัตโนมัติ และจะไม่ส่งข้อความมาที่ Dialogflow ของเรา


          วิธีปิดก็ง่าย ๆ แค่เลื่อนลงมาที่ Using LINE@ features ก็จะเห็น Auto-reply messages ให้คลิกปุ่ม Edit เลือก Disabled แล้วคลิกปุ่ม Update ก็จะเป็นการปิดฟีเจอร์ Auto-reply messages แล้ว ส่วนฟีเจอร์ Greeting messages ที่อยู่ข้างล่างนั้นเป็นฟีเจอร์ที่จะส่งข้อความทักทายผู้ใช้งานเมื่อมีคนกดเพิ่มบอทเป็นเพื่อน โดยข้อความทักทายที่ LINE ตั้งไว้ให้ตั้งแต่ต้นคือ

"ขอบคุณที่เพิ่มฉันเป็นเพื่อน!(happy)

ถ้าคุณคิดว่าคุณไดัรับข้อความเเจ้งเตือนมากเกินไป คุณสามารถปิดการไดัรับข้อความเเจ้งเตือนได้โดยไปยังหน้าต่างตั้งค่าในห้องเเชทนี้เเละปิดการส่งข้อความเเจ้งเตือน(ok)"

และเราสามารถแก้ไขข้อความทักทายได้โดยคลิกที่ Set message


          เมื่อคลิก Set message แล้ว เบราว์เซอร์ก็จะเปิดเว็บ LINE @ Manager ขึ้นมาให้เราแก้ไขข้อความทักทาย ซึ่งสามารถใส่ข้อความทักทายได้ไม่เกิน 500 ตัวอักษร หลังจากนั้นก็คลิกปุ่ม Save เพื่อบันทึกการแก้ไข จากนั้นก็.....เอ๊ะ นั่นอะไร สังเกตเห็นข้อความใต้ชื่อบอทที่อยู่ตรงแถบด้านซ้ายกันหรือเปล่าเอ่ย นั่นก็คือ LINE ID ที่ใช้ในสำหรับเพิ่มเพื่อนนั่นเอง ถ้าใครไม่อยากสแกน QR code เพื่อเพิ่มเพื่อนก็ใช้ LINE ID ตรงนี้แทนก็ได้

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


          หลังจากเพิ่มบอทเป็นเพื่อนแล้ว บอทก็จะส่งคำทักทายมาตามที่ตั้งค่าไว้ พอพิมพ์ข้อความที่กำหนดไว้ใน Training phrases (ในที่นี้คือคำว่า "สวัสดี") "Default Welcome Intent" ก็จะทำงานและตอบข้อความที่กำหนดไว้ใน Responses กลับคืนมา

          เท่านี้ Dialogflow ก็เชื่อมต่อกับ LINE Chatbot เรียบร้อย ทำให้เราสามารถจัดการกับข้อความของผู้ใช้งาน เลือก Intent และข้อความตอบกลับได้ง่ายขึ้น .....เอาล่ะ สำหรับบทความนี้ ผมขอจบไว้เพียงแค่นี้ ไว้พบกันใหม่บทความถัดไปครับผม บ๊ายบาย ✋👦


วันพฤหัสบดีที่ 6 กันยายน พ.ศ. 2561

จัดการ Surface Capabilities ใน Actions on Google


          ปัจจุบันนี้ก็มีอุปกรณ์มากมายที่สามารถใช้งาน Google Assistant ได้ ไม่ว่าจะเป็น Google Home, Smart Display, Smart Watch, โทรศัพท์มือถือ ฯลฯ ซึ่งหมายความว่าอุปกรณ์เหล่านี้ก็สามารถเข้าถึง Actions ที่เราสร้างได้นั่นเอง อุปกรณ์เหล่านี้ต่างก็มีส่วนติดต่อผู้ใช้งานที่แตกต่างกันไป เช่น Google Home ที่มีแต่ลำโพงกับปุ่มอีกนิดหน่อยเป็นส่วนติดต่อผู้ใช้ ก็จะไม่สามารถแสดงผลภาพได้ หรือ Smart Watch ที่แม้จะมีหน้าจอแสดงผล แต่ก็ไม่สามารถเปิดเข้าเว็บไซต์ได้ เป็นต้น

          เจ้าข้อจำกัดที่กล่าวมานี้จะส่งผลต่อประสิทธิภาพในการแสดงข้อมูลที่ Actions นำเสนอ ถ้าเราสร้าง Actions ที่มีความสามารถในการแสดงผลลิงค์ไปยังเว็บไซต์ หรือแสดงตัวเลือกบนหน้าจอ แต่อุปกรณ์ที่เรียกใช้งาน Actions ของเรากลับเป็น Google Home .....อ้าว งานเข้าสิครับ Google Home ไม่สามารถแสดงผลลิงค์ได้ ก็เกิด Error ขึ้นมาแทน และนั่นก็จะเป็นการสร้างความหงุดหงิดให้ผู้ใช้งาน "พังอีกแล้ว แอปอะไรว่ะเนี่ย พังตลอด"

          Surface Capabilities คือวิธีในการจัดการกับการแสดงผลที่จะใช้ภายใน Actions ของเราให้เหมาะสมกับอุปกรณ์ที่เรียกใช้งาน ระบุฟีเจอร์ที่อุปกรณ์จำเป็นต้องมีในการเรียกใช้งาน เพื่อความต่อเนื่องในการใช้งาน Actions ของผู้ใช้ ซึ่งจะแบ่งออกเป็น 2 ส่วน ได้แก่ Surface Capabilities และ Runtime Surface Capabilities

Surface Capabilities


          Surface Capabilities เป็นการระบุฟีเจอร์ที่อุปกรณ์จำเป็นต้องมีลงไปในรายละเอียดของ Actions ส่งผลให้อุปกรณ์ที่มีสเปคไม่ตรงตามที่กำหนดไว้จะไม่สามารถเรียกใช้งาน Actions นั้น ๆ ได้ ส่วนวิธีระบุก็ทำได้ง่าย ๆ โดยอันดับแรกให้ทำการสร้าง Actions ขึ้นมา (วิธีสร้าง Actions บน Google Assistant)


          ตรงแถบเมนูด้านซ้าย ให้เลื่อนลงมาจนถึงส่วน DEPLOY จากนั้นก็คลิกที่เมนู Surface capabilities


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

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

Runtime Surface Capabilities


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

          การเขียนโค้ดจัดการ Runtime Surface Capabilities แบ่งออกได้เป็น 3 วิธี ดังนี้
  • Response branching: ปรับเปลี่ยนการตอบสนองให้แตกต่างกันไปขึ้นอยู่กับอุปกรณ์ของผู้ใช้งาน โดยยังคงโครงสร้างของการสนทนาไว้อยู่
  • Conversation branching: เปลี่ยนการตอบสนองให้แตกต่างกันโดยสิ้นเชิงตามแต่ละอุปกรณ์ของผู้ใช้งาน
  • Multi-surface conversations: ปรับให้การตอบสนองบนอุปกรณ์หนึ่งสามารถย้ายไปแสดงผลและสนทนาต่อบนอุปกรณ์อีกเครื่องหนึ่งได้
          เพื่อให้เพื่อน ๆ เข้าใจมากขึ้น ผมจะทำการสร้าง Actions ขึ้นมาเพื่อแสดงวิธีเขียนโค้ดจัดการ Runtime Surface Capabilities ทั้ง 3 วิธี โดยหลังจากทักทายผู้ใช้เสร็จแล้ว
  • เมื่อผู้ใช้งานพูดว่า "วิธีแรก" Actions จะตอบสนองด้วยวิธี Response branching
  • เมื่อผู้ใช้งานพูดว่า "วิธีสอง" Actions จะตอบสนองด้วยวิธี Conversation branching
  • เมื่อผู้ใช้งานพูดว่า "วิธีสอง" Actions จะตอบสนองด้วยวิธี Multi-surface conversations

.........................

1. Response branching

          เป็นวิธีการเขียนโค้ดเพื่อปรับเปลี่ยนการตอบสนองของ Actions ให้แตกต่างกันไปขึ้นอยู่กับอุปกรณ์ของผู้ใช้งาน โดยที่ยังคงโครงสร้างของการสนทนาไว้เหมือนเดิม หรือพูดให้เข้าใจง่าย ๆ ก็คือ การที่เราใช้ประโยคสนทนาเดียวกันสั่งให้อุปกรณ์ 2 ประเภทใช้งาน Actions เดียวกัน แล้วได้การตอบสนองที่แตกต่างกันนั่นเอง

          ลองจินตนาการถึง Actions พยากรณ์อากาศ ถ้าเราสั่งใช้งาน Actions นี้บนโทรศัพท์มือถือก็จะแสดงรูปสภาพอากาศ แต่ถ้าเราสั่งใช้งานบน Google Home ด้วยคำสั่งเดียวกัน Google Home ก็จะเล่นไฟล์เสียงในการสื่อถึงสภาพอากาศ (เช่น เสียงฝนตก เสียงนกร้อง) แทน

          ในตอนที่ Actions กำลังทำงานอยู่ และ fulfillment ได้รับ request มาจาก Google Assistant เราสามารถเขียนโค้ดตรวจสอบฟีเจอร์ของอุปกรณ์ได้ ซึ่ง Actions library ได้เตรียมชุดคำสั่งสำหรับตรวจสอบเอาไว้ให้แล้ว โดยเราจะเข้าถึงคุณสมบัติของอุปกรณ์ผ่านอินเตอร์เฟซการสนทนา "conv" และเรียกใช้งานฟังก์ชันของ class "surface" ด้วยคำสั่ง  surface.capabilities.has 

const hasScreen = conv.surface.capabilities.has('actions.capability.SCREEN_OUTPUT');
const hasAudio = conv.surface.capabilities.has('actions.capability.AUDIO_OUTPUT');
const hasMediaPlayback = conv.surface.capabilities.has('actions.capability.MEDIA_RESPONSE_AUDIO');
const hasWebBrowser = conv.surface.capabilities.has('actions.capability.WEB_BROWSER');
          ขั้นตอนถัดไป ผมจะนำโค้ดพวกนี้ไปใช้ใน Actions ที่สร้างไว้เมื่อสักครู่ ให้เข้าไปสร้าง Intent ใหม่ใน Dialogflow Console แล้วก็ตั้งชื่อว่า handle_method_one


          ตามที่แผนที่กำหนดไว้ เราจะให้เรียกใช้งาน Intent นี้ในกรณีที่ผู้ใช้งานพูดคำว่า "วิธีแรก" เพราะงั้นให้เราไปตั้งค่าในส่วนของ Training phrases โดยเพิ่มคำว่า "วิธีแรก" ลงไป


          เลื่อนลงมาข้างล่างในส่วนของ Fulfillment คลิกเปิดให้มีการเรียกใช้งาน Webhook เนื่องจากเราจะต้องเขียนโค้ดร้องขอสิทธิ์ที่ Intent นี้ จากนั้นก็คลิกปุ่ม SAVE โลด

          อันดับถัดเป็นโค้ดที่ใช้ควบคุม handle_method_one Intent (โค้ดการทำงานทั้งหมดจะอยู่ข้างล่างของบทความ)

app.intent('handle_method_one', (conv) => {
    var deviceSupport = '';
    
    if( conv.surface.capabilities.has('actions.capability.SCREEN_OUTPUT') ) {
        deviceSupport+= 'หน้าจอแสดงผล .';
    }
    if( conv.surface.capabilities.has('actions.capability.AUDIO_OUTPUT') ) {
        deviceSupport+= 'ลำโพงเสียง .';
    }
    if( conv.surface.capabilities.has('actions.capability.MEDIA_RESPONSE_AUDIO') ) {
        deviceSupport+= 'การเล่นเสียงมีเดีย .';
    }
    if( conv.surface.capabilities.has('actions.capability.WEB_BROWSER') ) {
        deviceSupport+= 'การแสดงเว็บไซต์ .';
    }
    conv.ask('อุปกรณ์นี้รองรับ'+deviceSupport);
      
});
          เมื่อมีการเรียกใช้งาน Intent นี้แล้ว จะทำการเช็คว่าอุปกรณ์ที่ใช้งานอยู่รองรับการตอบกลับแบบไหนบ้าง .....ว่าแล้วเราก็มาลองทดสอบกันเลยดีกว่า


          ในเมนู Simulator ของ Actions Console จะมีตัวเลือกสำหรับการจำลองอุปกรณ์อยู่ โดยเราสามารถจำลองอุปกรณ์ได้ 3 ประเภท ได้แก่ โทรศัพท์มือถือ, ลำโพงอัจฉริยะ และ Smart Display ให้เพื่อน ๆ ลองเลือกจำลองอุปกรณ์แล้วสังเกตการตอบกลับ

รูปซ้าย: ทดสอบด้วยการจำลองอุปกรณ์เป็นโทรศัพท์มือถือ
รูปขวา: ทดสอบด้วยการจำลองอุปกรณ์เป็นลำโพงอัจฉริยะ

          จากการใช้งานในอุปกรณ์ที่แตกต่างกัน เห็นได้ว่าแม้จะใช้บทสนทนาเดียวใน แต่การตอบกลับจะไม่เหมือนกัน ขึ้นอยู่กับอุปกรณ์ที่ใช้งาน Actions ตามตัวอย่าง โทรศัพท์มือถือ (รูปฝั่งซ้าย) จะตอบกลับมาว่า "อุปกรณ์นี้รองรับหน้าจอแสดงผล .ลำโพงเสียง .การเล่นเสียงมีเดีย .การแสดงเว็บไซต์ ." ส่วนลำโพงอัจฉริยะ (รูปฝั่งขวา) จะตอบกลับมาว่า "อุปกรณ์นี้รองรับลำโพงเสียง .การเล่นเสียงมีเดีย ."

.........................

2. Conversation branching

          เป็นวิธีการเขียนโค้ดเปลี่ยนการตอบสนองให้แตกต่างกันโดยสิ้นเชิงตามแต่ละอุปกรณ์ของผู้ใช้งาน หรือพูดง่าย ๆ ก็คือ การที่เราใช้งาน Actions ในอุปกรณ์ต่างประเภทกันแล้ว บทสนทนาระหว่างผู้ใช้และอุปกรณ์ก็จะแตกต่างกันไป นอกจากนี้ข้อความที่ตอบกลับมาก็จะไม่เหมือนกันด้วย

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

          เราสามารถตั้งค่าให้ Intent ถูกเรียกใช้งานเมื่อได้รับ Request จากอุปกรณ์ที่รองรับฟีเจอร์บางอย่างตามที่กำหนดไว้ได้ เช่น กำหนดให้ Intent หนึ่งถูกเรียกใช้งานเมื่อมี Request มาจากอุปกรณ์ที่มีหน้าจอแสดงผล แล้วกำหนดให้ Intent สองถูกเรียกใช้งานเมื่อมี Request มาจากอุปกรณ์ที่มีลำโพง เป็นต้น ซึ่งเราจะระบุประเภทของอุปกรณ์ไว้ในส่วน Contexts ของ Intent โดยมีค่าของ Contexts ที่สามารถกำหนดได้ดังต่อไปนี้
  • actions_capability_audio_output : อุปกรณ์ที่มีลำโพง
  • actions_capability_screen_output : อุปกรณ์ที่มีหน้าจอแสดงผล
  • actions_capability_media_response_audio : อุปกรณ์ที่รองรับการเล่นไฟล์มีเดีย
  • actions_capability_web_browser : อุปกรณ์ที่รองรับเว็บบราวเซอร์
          อันดับถัดไป ให้เราสร้าง Intent ใหม่ 2 Intent ใน Actions โดยตั้งชื่อว่า handle_method_two_with_screen ซึ่งจะถูกเรียกใช้งานเมื่อมี Request มาจากอุปกรณ์ที่มีหน้าจอแสดงผล และตั้งชื่ออีก Intent หนึ่งว่า handle_method_two_with_audio ซึ่งจะถูกเรียกใช้งานเมื่อมี Request มาจากอุปกรณ์ที่มีลำโพง

          เริ่มจากสร้าง Intent ที่ชื่อ handle_method_two_with_screen กันเลยดีกว่า


          ในส่วน Contexts ให้ระบุค่าเป็น  actions_capability_screen_output  เพื่อเป็นการกำหนดให้ Intent นี้ถูกเรียกโดยอุปกรณ์ที่มีหน้าจอ


          กำหนดคำพูดที่เป็น Keyword ในการเรียกใช้งาน Intent นี้ในส่วนของ Training phrases ว่า "วิธีสอง"  (จากรูปตัวอย่างจะเห็นได้ว่า Dialogflow ฉลาดพอที่จะเข้าใจคำว่า "สอง" คือตัวเลข จึงไปกำหนดเป็น Parameter ให้เองโดยอัตโนมัติ แต่เราไม่จำเป็นต้องใช้ Parameter ก็ให้ลบออกไป)


          ลำดับถัดไปให้พิมพ์ข้อความที่จะให้ Intent นี้ตอบกลับ โดยระบุลงไปในส่วนของ Responses ว่า "ตอบกลับจากอุปกรณ์ที่มีหน้าจอ" เพื่อเป็นการพิสูจน์ว่า Intent นี้ถูกเรียกใช้โดยอุปกรณ์ที่มีหน้าจอ จากนั้นก็ให้คลิกปุ่ม SAVE

          เมื่อเราสร้าง Intent ที่ชื่อ handle_method_two_with_screen เสร็จแล้ว ต่อไปก็สร้าง handle_method_two_with_audio ต่อกันเลย


          ในส่วน Contexts ให้ระบุค่าเป็น  actions_capability_audio_output  เพื่อเป็นการกำหนดให้ Intent นี้ถูกเรียกโดยอุปกรณ์ที่มีลำโพง


          กำหนดคำพูดที่เป็น Keyword ในการเรียกใช้งาน Intent นี้ในส่วนของ Training phrases ว่า "วิธีสอง" เหมือนของ handle_method_two_with_screen


          ลำดับถัดไปให้พิมพ์ข้อความที่จะให้ Intent นี้ตอบกลับ โดยระบุลงไปในส่วนของ Responses ว่า "ตอบกลับจากอุปกรณ์ที่มีลำโพง" เพื่อเป็นการพิสูจน์ว่า Intent นี้ถูกเรียกใช้โดยอุปกรณ์ที่มีลำโพง จากนั้นก็ให้คลิกปุ่ม SAVE

          เมื่อสร้าง Intent ครบทั้ง 2 Intent เสร็จแล้ว เราก็ไปทดสอบกันได้เล้ย

รูปซ้าย: ทดสอบด้วยการจำลองอุปกรณ์เป็นโทรศัพท์มือถือ
รูปขวา: ทดสอบด้วยการจำลองอุปกรณ์เป็นลำโพงอัจฉริยะ

          จากการใช้งานในอุปกรณ์ที่แตกต่างกัน จะเห็นได้ว่าการตอบกลับจะไม่เหมือนกัน ตามตัวอย่าง โทรศัพท์มือถือ (รูปฝั่งซ้าย) จะตอบกลับมาว่า "ตอบกลับจากอุปกรณ์ที่มีหน้าจอ" ที่มาจาก handle_method_two_with_screen ส่วนลำโพงอัจฉริยะ (รูปฝั่งขวา) จะตอบกลับมาว่า "ตอบกลับจากอุปกรณ์ที่มีลำโพง" ที่มาจาก handle_method_two_with_audio

.........................

3. Multi-surface Conversations

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

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

          เนื่องจากวิธีนี้จะมีการย้ายบทสนทนาไปยังอุปกรณ์อื่น เพราะฉะนั้นจะต้องมี Intent สองตัว หนึ่งคือ Intent ที่ทำหน้าที่ส่งบทสนทนาไปยังอุปกรณ์อื่น และอีกหนึ่งคือ Intent ที่รับบทสนทนาต่อมาจากอุปกรณ์ต้นทาง

          ขั้นตอนในการย้ายบทสนทนาไปยังอุปกรณ์อื่นนั้น เริ่มจากการ
  1. ตรวจสอบว่าผู้ใช้มีอุปกรณ์ที่พร้อมใช้งานหรือเปล่า ซึ่งมีข้อแม้ว่าเจ้าอุปกรณ์นั้นจะต้องเชื่อมต่อกับบัญชี Google เดียวกันกับอุปกรณ์ต้นทางด้วย โดยวิธีการตรวจสอบให้ใช้คำสั่ง  conv.available.surfaces.capabilities.has() 
  2. ถ้าพบอุปกรณ์ตามที่ต้องการแล้ว ให้ทำการส่ง Request เพื่อขอย้ายบทสนทนาไปยังอุปกรณ์นั้น ด้วยคำสั่ง  NewSurface()  โดยข้อมูลการสนทนาจะถูกโอนไปยังอุปกรณ์ใหม่ทั้งหมด รวมไปถึงค่าที่บันทึกลงในการสนทนาด้วย
  3. จัดการ Request ที่ได้รับมา โดยให้ Intent ที่ดักจับเหตุการณ์ actions_intent_NEW_SURFACE ทำการตรวจสอบว่าการโอนบทสนทนาสำเร็จหรือไม่
          เอาล่ะ ขั้นตอนต่อไปเราก็มาสร้าง Intent ทั้งสอง ซึ่งได้แก่ handle_method_three_request สำหรับสร้าง Request ไปยังอุปกรณ์ใหม่ และ handle_method_three_response สำหรับรับ Request .....เริ่มจากสร้าง handle_method_three_request กันก่อนเลย


          ในส่วนของ Training phrases ให้กำหนดคำพูดที่เป็น Keyword ในการเรียกใช้งาน Intent ว่า "วิธีสาม"  จากนั้นก็ให้ลบ Parameter ออกไป


          ในส่วนของ Fulfillment ก็คลิกเปิดการเรียกใช้งาน Webhook ให้เรียบร้อย จากนั้นก็คลิกปุ่ม SAVE โลด ต่อไปให้คลิกเข้าไปที่ Fulfillment ตรงแถบเมนูด้านซ้าย แล้วเพิ่มโค้ดข้างล่างนี้

app.intent('handle_method_three_request', (conv) => {
    const screenAvailable = conv.available.surfaces.capabilities.has('actions.capability.SCREEN_OUTPUT');
    
    if( screenAvailable ) {
        const context = 'มีภาพอยากจะอวดคุณด้วย.';
        const notification = 'ภาพเด็ดต้องดู!';
        const capabilities = ['actions.capability.SCREEN_OUTPUT'];

        conv.ask(new NewSurface({context, notification, capabilities}));
    } else {
        conv.close('ขอโทษด้วย. ไม่สามารถแสดงรูปได้');
    }

});
          Intent นี้จะเช็คดูว่าเรามีอุปกรณ์อะไรที่มีหน้าจอแสดงผลหรือไม่ ด้วยการใช้คำสั่ง  conv.available.surfaces.capabilities.has()  ที่เราเคยใช้ในช่วงกลาง ๆ ของบทความ ถ้าไม่มีก็จะตอบกลับว่า "ขอโทษด้วย. ไม่สามารถแสดงรูปได้" จากนั้นก็จบการสนทนา แต่ถ้ามีก็จะทำการส่ง Request ไปยังอุปกรณ์นั้นด้วย class  NewSurface  ซึ่งจะรับ Parameter เข้ามาสามค่า ได้แก่
  • Context: ข้อความที่ Actions จะถามผู้ใช้ เพื่อขอสิทธิ์ในการโอนบทสนทนาไปยังอุปกรณ์ใหม่
  • Notification: หัวเรื่องที่จะปรากฏตรงแถบแจ้งเตือนบนอุปกรณ์
  • Capabilities: ประเภทของอุปกรณ์ที่ต้องการจะโอนบทสนทนา ในที่นี้คือ อุปกรณ์ที่มีหน้าจอแสดงผล (actions.capability.SCREEN_OUTPUT)
          เท่านี้ก็สร้าง Intent เสร็จไปตัวนึงแล้ว ต่อไปก็มาสร้าง handle_method_three_response สำหรับจัดการ Request กันเลยดีกว่า


          ให้กำหนด Events เป็น  actions_intent_NEW_SURFACE  เพื่อให้ Intent นี้ดักจับ Event ร้องขอการโอนบทสนทนาจากอุปกรณ์อื่น


          ในส่วนของ Fulfillment ให้คลิกเปิดการเรียกใช้งาน Webhook หลังจากคลิกปุ่ม SAVE แล้วก็ให้คลิกเข้าไปที่ Fulfillment ตรงแถบเมนูด้านซ้าย แล้วเพิ่มโค้ดข้างล่างนี้

app.intent('handle_method_three_response', (conv, input, newSurface) => {
    
    if (newSurface.status === 'OK') {
        conv.close('แบร่! ชั้นโกหกคุณต่างหาก. บ๊ายบาย');
    } else {
        conv.close('เสียใจที่คุณไม่อยากดูภาพของชั้น. ไว้ค่อยคุยกันใหม่ทีหลังละกัน');
    }

});
          Intent นี้จะเช็คดูว่าโอนบทสนทนาได้หรือไม่ ถ้าโอนได้ก็จะพูดว่า "แบร่! ชั้นโกหกคุณต่างหาก. บ๊ายบาย" แต่ถ้าโอนไม่ได้ก็จะพูดว่า "เสียใจที่คุณไม่อยากดูภาพของชั้น. ไว้ค่อยคุยกันใหม่ทีหลังละกัน" แล้วจบการสนทนา .....ชักจะตื่นเต้นแล้ว มาทดสอบกันเลย


          เมื่อ handle_method_three_request เริ่มทำงานก็จะเช็คดูว่าเรามีอุปกรณ์อะไรที่มีหน้าจอแสดงผลหรือไม่ เมื่อพบแล้วก็ทำการขออนุญาตผู้ใช้งานว่า "{ข้อความเพิ่มเติม} ฉันส่งไปที่โทรศัพท์ได้ไหมคะ" ถ้าเราอนุญาต Actions ก็จะตอบกลับมาว่า "ได้สิคะ ดูในนั้นได้เลย เราไปคุยกันที่นั่นนะคะ" แล้วก็โอนบทสนทนาไปยังโทรศัพท์มือถือ ที่โทรศัพท์มือถือก็จะมีข้อความแจ้งเตือนเด้งขึ้นมา พอเรากดที่การแจ้งเตือน ก็จะเป็นการเปิด Google Assistant ในสภาพที่พร้อมจะสนทนาต่อได้เลย
***** อุปกรณ์ที่จะรับบทสนทนาต้องเชื่อมต่อกับบัญชี Google เดียวกันกับอุปกรณ์ที่โอนบทสนทนามาให้ *****

'use strict';

// Import Dialogflow และ NewSurface module จาก Actions on Google library.
const {dialogflow, NewSurface} = require('actions-on-google');
// Import firebase-functions package
const functions = require('firebase-functions');
// Instantiate the Dialogflow client.
const app = dialogflow({debug: true});


app.intent('handle_method_one', (conv) => {
    var deviceSupport = '';
    
    if( conv.surface.capabilities.has('actions.capability.SCREEN_OUTPUT') ) {
        deviceSupport+= 'หน้าจอแสดงผล .';
    }
    if( conv.surface.capabilities.has('actions.capability.AUDIO_OUTPUT') ) {
        deviceSupport+= 'ลำโพงเสียง .';
    }
    if( conv.surface.capabilities.has('actions.capability.MEDIA_RESPONSE_AUDIO') ) {
        deviceSupport+= 'การเล่นเสียงมีเดีย .';
    }
    if( conv.surface.capabilities.has('actions.capability.WEB_BROWSER') ) {
        deviceSupport+= 'การแสดงเว็บไซต์ .';
    }
    conv.ask('อุปกรณ์นี้รองรับ'+deviceSupport);
      
});

app.intent('handle_method_three_request', (conv) => {
    const screenAvailable = conv.available.surfaces.capabilities.has('actions.capability.SCREEN_OUTPUT');
    
    if( screenAvailable ) {
        const context = 'มีภาพอยากจะอวดคุณด้วย.';
        const notification = 'ภาพเด็ดต้องดู!';
        const capabilities = ['actions.capability.SCREEN_OUTPUT'];

        conv.ask(new NewSurface({context, notification, capabilities}));
    } else {
        conv.close('ขอโทษด้วย. ไม่สามารถแสดงรูปได้');
    }

});

app.intent('handle_method_three_response', (conv, input, newSurface) => {
    
    if (newSurface.status === 'OK') {
        conv.close('แบร่! ชั้นโกหกคุณต่างหาก. บ๊ายบาย');
    } else {
        conv.close('เสียใจที่คุณไม่อยากดูภาพของชั้น. ไว้ค่อยคุยกันใหม่ทีหลังละกัน');
    }

});

// Set ให้ DialogflowApp object จัดการ HTTPS POST request.
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
          โค้ดทั้งหมดที่ใช้ในบทความครั้งนี้ หวังว่าเพื่อน ๆ จะเข้าใจวิธีจัดการ Surface Capabilities เพื่อลดการเกิด Error และเพิ่มประสิทธิ์ภาพใน Chatbot มากขึ้นนะครับ 😉