ทำบอทลงทะเบียนง่ายๆ กับ Sunday Codelabs 4 กับ LINE Developers Thailand

Event Aug 20, 2021

จาก Sunday Codelabs 3 คราวที่แล้ว ที่เราได้หน้ากากผ้าไปอ่ะ แหะๆ แปปๆเขาประกาศ Sunday Codelabs 4 อย่างไวกับ speaker ที่มีแฟนคลับอยากฟังเขาเยอะอยู่ คือคุณหนึ่ง LAE นั่นเอง

ก่อนอื่น เราแอบไปเล่น popcat ก่อน แต่ก็เตรียมอ่าน codelab ตามหัวข้อเลย เพื่อเตรียมตัวอ่ะเนอะ ซึ่งเราใช้โปรเจกเดิม แต่เริ่มจะเละเทะหล่ะน้าา

Handle Non-Text Event with Dialogflow
https://codelab.line.me/codelabs/handle-non-text-event-with-dialogflow/index.html

ไลฟ์สามารถดูได้ที่นี่เลยจ้า

ส่วนใหญ่วันนี้เลยนั่งดูนั่งจดชิวๆไปเนอะ

ก่อนอื่นเลย มาโหวตกันเลยจ้า โหวตกันรัวๆเลย คำตอบคือหัวใจด้วย

ในวันนี้เราจะรอพี่ๆตบมุขตลกคาเฟ่ เอ้ยย มาทำ codelab Handle Non-Text Event with Dialogflow กันจ้า

เกิดจากคำถามที่ว่า เราจะส่ง event อื่นๆไปยัง DialogFlow ได้อย่างไร เช่น date picker, location ทำอย่างไรให้ DialogFlow เข้าใจ event อื่นๆได้ด้วย ในที่นี้จะเป็นระบบลงทะเบียนเนอะ

มาทำ Codelab ไปพร้อมๆกันเถอะ

จากนั้นเปิดตัวคนที่จะ live coding ในวันนี้ คุณหนึ่งนั่นเองงงง~~~

ก่อนจะมาทำ codelab กันนั้น มีกติกาการร่วมสนุกประจำสัปดาห์ ในสัปดาห์นี้น้านนน ยังได้หน้ากากผ้าเช่นเคย ซึ่งเราได้ของอาทิตย์ก่อนแล้ว เลยอ่ะให้คนอื่นๆเขาบ้างเนอะ ส่วนโจทย์เพิ่มเติมเดี๋ยวมาเฉลยตอนท้ายอีกทีนึงเนอะ ซึ่งมาเริ่มเขียนบล็อกหลังปิดรับฟอร์มแล้วนั่นเอง เย้ๆๆๆๆๆๆๆ (เพราะไปดูสตรีมเมอร์เล่นเกมส์งับ -___-)

flow การทำงานจะเป็นแบบนี้

ให้ user กรอกชื่อด้วย Message Event ประเภท Text จากนั้นใส่ location ด้วย Message Event ประเภท Location และเลือกวันที่จาก DateTime Picker ด้วย Postback Event

โดยให้ตัว Firebase Cloud Functions เป็น API ตัวนึง และใช้ Cloud Firestore เป็น database จ้า

ต่อมาสร้าง LINE OA ในส่วนนี้ขอข้ามเลยแล้วกัน สิ่งที่เราต้องทำก็คือ เพิ่มบอทเป็นเพื่อนรอไว้, ไปปิด auto reply และไป issue access token รอไว้ก่อนเลย

จากนั้นไปสร้างโปรเจก Firebase กัน โดยเปลี่ยนเป็น Blaze Plan เพราะเชื่อมต่อ API ภายนอก ทั้ง DialogFlow และ LINE ซึ่งต้องมีบัตรเครดิต และจำนวน project ที่ใช้บัตรเกินโควต้า หรือผูกบัตรไม่เกิน 5 project ไม่งั้นมันอัพเดต plan ไม่ได้ เราเคยติด กว่าจะหาเจอว่าลบตรงไหน นานมาก คือไปลบใน console ของฝั่ง Cloud พบว่าผูกกับโปรเจกเปล่าๆในนั้นที่ไม่ได้ใช้ 1 ตัวง่ะ

เมื่อสร้างโปรเจกเสร็จแล้วก็ไป create database ใน Cloud Firestore รอก่อนเลย 1 กรุบ โดยเลือกเป็น production mode น้าาา และเลือก region asia-northeast1 ที่ Tokyo เพราะใกล้กับ server LINE มากที่สุด ดังนั้นมันจะวิ่งแค่ hop ประเทศไทยและประเทศญี่ปุ่นเท่านั้น ไม่งั้นวิ่งไปเมกามันก็หลาย hop อ่ะเนอะ

ที่สำคัญ ตั้ง region แล้ว เปลี่ยนไม่ได้น้าาา

ต่อมาไปสร้าง Agent ใน DialogFlow ซึ่ง Agent ก็จะประมาณ chatbot ตัวนึง ที่ข้างในมีการวิเคราะห์ content ต่างๆด้วย AI ให้เรา

ถ้าเรายังไม่เคยใช้ DialogFlow จะต้อง login ด้วย Google Account ก่อนน้า แบบนี้ๆ

https://dialogflow.cloud.google.com/

เมื่อ login เข้ามาแล้วให้ไปสร้าง Agent เลือกภาษาไทย เลือก project ก็คือเชื่อมกับ project Firebase ที่เราเพิ่งสร้างมะกี้ แล้วก็กด create และรอกินหนมแปปนึง

DialogFlow ที่เราใช้จะเป็นแบบ Essentials เนอะ หรือ ES และอีกแบบคือ Customer Experience หรือ CS นั่นเอง ถามว่าทั้งสองต่างกันอย่างไร? อ่านบล็อกนี้จ้า

ทำความรู้จักกับ Dialogflow CX
Dialogflow ออก Edition ใหม่แล้วนะค้าบบพี่น้อง โดย Edition ใหม่นี้มาในชื่อว่า Dialogflow CX ไม่แน่ใจว่า CX จะย่อมาจากอะไรนะครับ…

Intent ใน DialogFlow คืออะไร? intent แปลว่า ความตั้งใจ เป็นการวิเคราะห์ content ว่า user พิมพ์ message มาว่าอะไร และจะตั้งใจจะสื่อสารอะไรงี้ โดยตัว default มันจะมีให้ 2 ตัวคือ

  • Default Welcome Intent : ประโยคทักทาย
  • Default Fallback Intent : ถ้าไม่ตรงกับ intent ใดๆจะมาที่นี่

ส่วนสำคัญใน Intent ก็คือ Training phrases เราสอนบอทว่า user พิมพ์ message ว่าอะไร เราสามารถใส่ได้ 2000 ประโยค! ต่อ 1 intent และยิ่งเราใส่หลากหลาย บอทเราจะยิ่งเก่งขึ้นโนะ และก็ Responses คือข้อความที่ bot จะตอบกลับไป

สำหรับคนที่ใช้ครั้งแรก ต้องไปกด accept policy & privacy ที่ cloud console ก่อนนะ

Google Cloud Platform
Google Cloud Platform lets you build, deploy and scale applications, websites and services on the same infrastructure as Google.
https://console.cloud.google.com/

ต่อมาเราจะทำการสร้าง Intent แต่ละตัว ด้วยความระวัดระวัง เพราะถ้าผิด บอทเราจะทำงานไม่ได้น้า เราก็แอบทำล่วงหน้าใน codelab แหละ ในนี้ขอสรุปแบบคร่าวๆแล้วกันเนอะ

register อันนี้ใส่ Training phrases เป็นคำว่า "ลงทะเบียน" แล้วก็ "register" เนอะ ส่วน Responses ก็จะเป็น text ธรรมดาอันนึงให้เรากรอกชื่อ ซึ่ง design จริงๆอาจจะกดลงทะเบียนจาก Rich Menu หรือ Flex Message หรือใดๆก็ได้

จากนั้นสร้าง Intent ใหม่ โดยกดตรง Add Follow Up intent ด้านหลัง Register Intent และเลือกเป็น Custom เพราะว่าทำงานต่อจาก Intent ก่อนหน้านั่นเอง

เปลี่ยนชื่อ Intent นี้เป็น register-name ใส่ Training phrases เป็นชื่อคน และเก็บ parameter ชื่อว่า name โดยการเก็บชื่อที่ user พิมพ์มาใส่ตัวแปร ระบุ Entity Type เป็น @sys.any เพื่อความหลากหลาย และกำหนด value เป็น $name แล้วก็ไป highlight ชื่อที่เราพิมพ์มา เพื่อระบุในการ training ส่วน Responses คือเราต้องการให้ user แชร์ location ต่อนั่นเอง

จากนั้นไปทดสอบที่เราทำมาก่อนที่ด้านขวามือ 1 รอบก่อนจ้า

ต่อมาสร้าง Intent ใหม่เพื่อรับ location โดยทำงานต่อจาก intent register - name เมื่อกี้ ให้ชื่อว่า register - location เราจะพิมพ์สอน Dialogflow ตาม pattern ที่เราต้องการไปก่อนใน Training phrases เป็น LAT : 13.00 , LNG : 100.00

จากนั้นสร้าง parameter ตามรูปนี้เลย รับ latitude และ longitude เป็น @sys.number และรับชื่อจาก Intent ก่อนหน้า จึงใส่ # จะประมาณว่าตามด้วย Intent นั้น ตามด้วยชื่อตัวแปรนั่นเอง

และ Intent สุดท้าย register - date เราพิมพ์สอน Dialogflow ตาม pattern ที่เราต้องการน Training phrases เช่นเคย เป็น DATE : 2021-07-01 แล้วสร้าง parameter วันที่ที่เราเลือกชื่อว่า selected_date เป็น @sys.date ส่วนที่เหลือรับจาก intent ก่อนหน้าทั้งสิ้น ซึ่งต้องส่งเป็นรอบๆ ไม่งั้นมันจะหายหมด

ข้อควรระวังคือ ต้องสะกดให้ถูก ไม่งั้นเราจะตามหาบัคยาก

จากนั้นก็ทดสอบให้เราดูอีกรอบนึง พบว่า parameter ตามมาแล้ว และ intent สุดท้าย ไม่ต้องใส่ Responses แต่ให้เปิด Fulfillment นะ

สำหรับ DialogFlow นั้น Intent ใน 1 Agent มีได้มากสุด 2000 Intents เลยทีเดียว

แล้วก็มีเพิ่มที่เป็น custom payload ของ LINE เพื่อ UX ที่ดีย์ขึ้นเนอะ ไปที่ Intent register - name ไปใส่ตรง Reponses จากนั้นกด + ข้าง Default แล้วก็เลือก LINE เนอะ

โดยตัว Text Message ใน LINE หน้าตามันจะเป็นแบบนี้

{
    "type": "text",
    "text": "กรุณาแชร์โลเคชั่นของคุณมาหน่อย"
}

และหน้าตาใน payload จะมีตัว line ครอบมาแบบนี้

{
    "line": {
        "type": "text",
        "text": "กรุณาแชร์โลเคชั่นของคุณมาหน่อย"
    }
}

ใน register เราเพิ่ม Quick Reply เข้าไป โดยจะให้กดจาก Location Action ซึ่งเราสามารถดูตามใน LINE Document ได้เลย ซึ่ง Quick Reply จะใส่เป็น item ไปแบบนี้

https://developers.line.biz/en/reference/messaging-api/#items-object

วิธีการใช้ Quick Reply

Using quick replies
The LINE Developers site is a portal site for developers. It contains documents and tools that will help you use our various developer products. Creating LINE Login and Messaging API applications and services has never been easier!
https://developers.line.biz/en/docs/messaging-api/using-quick-reply/

หน้าตาทั้งหมดในตอนนี้

{
  "line": {
    "type": "text",
    "text": "ขอบคุณ คุณ$name กรุณาแชร์โลเคชั่นของคุณ",
    "quickReply": {
      "items": [
        {
          "action": {
            "type": "location",
            "label": "แชร์โลเคชั่น"
          },
          "type": "action"
        }
      ]
    }
  }
}

และอีกทีคือ register - location ใส่ Quick Reply เป็น Datetime Picker ส่วน data ไม่ได้ใช้ เลยใส่ชื่อตัวแปรไปก่อน

{
  "line": {
    "type": "text",
    "quickReply": {
      "items": [
        {
          "type": "action",
          "action": {
            "type": "datetimepicker",
            "label": "เลือกวันที่",
            "data": "selected_date",
            "mode": "date"
          }
        }
      ]
    },
    "text": "ตำแหน่งของคุณคือ $latitude,$longitude  ขั้นตอนต่อไปกรุณาเลือกวันที่"
  }
}

เมื่อสร้าง intent ทั้งหมดเสร็จแล้ว ทำการเชื่อมต่อ DialogFlow เข้ากับ LINE เนอะ

เราจะต้องลอก Channel ID, Channel Secret และ Channel Access Token จาก LINE OA มาใส่ และเอาตัว webhook ใน DialogFlow ไปใส่ใน LINE OA ของเรา อีกทีนุง

และทางบ้านติดจ้า ติดตอนเพิ่ม response เป็น LINE วิธีแก้คือไป set integration กับ LINE ก่อน แล้วค่อย refresh อีก 1 รอบ

ตอนทดสอบจะมี message ซ้อนมา

ให้ไปปิดตรงนี้ก่อน

เมื่อเราเทส พอส่ง location ไปแล้ว บอทจะนิ่ง เพราะเราไป connect กับ LINE ตรงๆ แต่ DialogFlow ไม่เข้าจายย ดังนั้นตรง location message เราจะต้องทำ proxy server ขึ้นมาก่อน

ชื่อแมวที่บ้านเนอะ555555555555

ไปที่ Visual Studio Code ที่เรารัก (พอๆกับ Android Studio แหละ) ไปที่ Terminal เพื่อติดตั้ง Firebase CLI สำหรับคนที่ไม่เคยติดตั้ง และก็ login ซึ่งต้องตรงกับ project ที่เราสร้าง และ firebase init เลือก Firestore, Function และติด Emulator เผื่อไว้เนอะสำหรับเทส แล้วเลือกทั้งหมดเป็น default

จากนั้น shell ไป folder function cd functions เพื่อติดตั้ง express กับ line-sdk ก่อนเนอะ

npm i express @line/bot-sdk --save

แล้วก็ config environment รอก่อน โดยเก็บ channel access token และ  channel secret ของฝั่ง LINE OA มา และ agent id จาก DialogFlow มา โดยเอาจากใน webhook ซึ่งจะอยู่หลังคำว่า webhook นั่นเอง

firebase functions:config:set line.channel_access_token="xxxxx" line.channel_secret="xxxxx" dialogflow.agent_id="xxxxx"

และดูค่าที่เราเก็บไว้ทั้งหมดด้วย firebase functions:config:get เนอะ

กลับมา coding หล่ะ ก่อนอื่นเราก็ require library ต่างๆเข้ามากันก่อนนะ

const functions = require('firebase-functions');
const line = require('@line/bot-sdk');
const express = require('express');

แล้วก็สร้างตัวแปรเพื่อสร้าง header สำหรับใช้ใน LINE API เนอะ

const config = {
   channelAccessToken: functions.config().line.channel_access_token,
   channelSecret: functions.config().line.channel_secret
}

และประกาศ Express พร้อมด้วยสร้างตัว Express รับ Post request ที่ path /webhook และเพิ่ม middleware ของ LINE เข้าไปได้เลย line.middleware(config) เพื่อ check signature x-line-signature

app.post('/webhook', line.middleware(config), (req, res) => { 
   //TODO
});
https://developers.line.biz/en/reference/messaging-api/#request-headers

และเข้ารหัสด้วย body ของ channel secret เวลารับ request ก็เอา body มาเข้ารหัสกับ secret channel และ validate ว่าตรงกันไหม

จากนั้น export เส้นที่เราเขียนเมื่อกี้ออกมา โดยเชื่อมกับตัว Cloud Function for Firebase พร้อมด้วยใส่ region ซึ่งก็อันเดียวกันกับตอนที่สร้าง Cloud Firestore นั่นเอง

exports.api = functions
   .region('asia-northeast1')
   .https
   .onRequest(app);

โดยตัว event webhook ที่ได้จะเป็น array เนอะ ก็เติมไปในโค้ดแบบนี้

app.post('/webhook', line.middleware(config), (req, res) => { 
   const events = req.body.events
   events.foreach(event =>
       handleEvent(req, event)
   )
});
https://developers.line.biz/en/reference/messaging-api/#webhook-event-objects

และทุกๆ request โยนให้ handleEvent() ทำงาน ดูว่าอันนี้เป็น message อะไร?

ข้างในจะทำการแยก type ว่าเป็น type อะไรบ้าง ซึ่งที่เราสนใจก็จะมี text ซึ่งจะ forward กลับไปให้ DialogFlow ตรงๆเลย และ location อันนี้จะสร้าง text message ใหม่ส่งกลับไปให้ DialogFlow จ้า อันนี้รวบตึงโค้ดทั้งหมดมาเลยเนาะ แน่นอนว่าแตก เดี๋ยวลง gist รงบทั้งหมดอีกรอบ

async function handleEvent(req, event) {
   switch (event.type) {
      case 'message':
          switch(event.message.type) {
              case 'text':
                  return postToDialogflow(req)
              case 'location':
                  const locationText = `LAT: ${event.message.latitude}, LNG: ${event.message.longitude}`
                  const locationMsg = createLineTextEvent(req, event, locationText)
                  return convertToDialogflow(req, locationMsg)
          }
      case 'postback':
          const dateText = `DATE: ${event.postback.params.date}`
          const dateMsg = createLineTextEvent(req, event, dateText)
          return convertToDialogflow(req, dateMsg)
   }
}

ตัว postback ใช้กับ datetime ticker ที่ user เลือกก็จะอยู่ใน postback params โดยเราสามารถเลือกได้ 3 แบบ คือ date, time, datetime

https://developers.line.biz/en/reference/messaging-api/#datetime-picker-action

อันนี้เป็นตัว adapter ซึ่งคุณหนึ่งทำเป็น gist ชื่อไฟล์ว่า dialogflow.js ไว้ให้แล้วจ้า

  • postToDialogflow() ส่งไปให้ DialogFlow โดยตรงเล้ยย
  • convertToDialogflow() แปลงเป็น text message event
  • calculateLineSignature() คำนวณ x-line-signature ให้ใหม่ ไม่งั้น DialogFlow จะ reject เพราะตัว body ถูกเปลี่ยนแปลง เพื่อให้ DialogFlow รับอันนี้ ซึ่งก็มีการ modified payload และ signatur อีกที
  • createLineTextEvent() เปลี่ยน type เป็น message event ที่เป็น text message เลียนแบบ request ที่ได้ เพื่อให้ format ตรงกับฝั่ง DialogFlow

ทำการติดตั้ง library ในไฟล์นี้ ก็จะมี request กับ crypto เห็นคุณกอล์ฟคอมเมนต์ในช่องแชทในไลฟ์ว่าของดี ซึ่งตัว library นี้เขาบอกกันว่าใช้ง่ายนะ

npm i request crypto --save

จากนั้นทำการ deploy กันอีกสัก 1 รอบเนอะ เพื่อเอา webhook ที่เป็น proxy ไปใช้ต่อใน LINE OA ของเราเนอะ

มีการทำ cleaning คือล้างหน้าให้สะอาด ปราศจากเครื่องสำอาง ไม่ช่ายยย คือก่อนหน้านี้มีไฟล์ image ที่ไม่ได้ใช้ ตอนนี้จะทำการลบ image ที่ไม่ได้ใช้ทุกครั้งในการ deploy นั่นเอง

ในช่องแชทมีคำถามด้วยหล่ะ

สอบถามครับ
event type ของ line มีกี่แบบครับ? ช่วยแนะนำวิธีดูใน line document หน่อยครับใน message

ซึ่งมี LINE Certified Coach ที่เป็นสาย API มั้งถ้าจำไม่ผิด ท่านนึง เข้ามาตอบไว้ว่า

event จะมี type อีก 7 อัน จะมี test, image, video, audio, file, location และ sticker

ส่วนอันนี้ Document

Messaging API reference
The LINE Developers site is a portal site for developers. It contains documents and tools that will help you use our various developer products. Creating LINE Login and Messaging API applications and services has never been easier!
https://developers.line.biz/en/reference/messaging-api/#webhook-event-objects

เราสามารถเข้าไปอ่านเรื่อง "15 สัญญาณจาก Webhook Events ที่จะปลุกให้ LINE Bot ของคุณตื่นจากภวังค์" เพิ่มเติมได้ที่บล็อกนี้

15 สัญญาณจาก Webhook Events ที่จะปลุกให้ LINE Bot ของคุณตื่นจากภวังค์
Webhook Events คือ event ต่างๆที่เกิดขึ้นกับ LINE Bot(Event trigger) โดยเมื่อ event เกิดขึ้นแล้วจะมีสัญญาณพร้อมกับข้อมูลในรูปแบบที่เป็น…

กลับมาที่ codelab ของเรา

ทุก request จะถูกเข้าไปใน proxy นี้ก่อนที่จะส่งไปให้ DialogFlow และเปลี่ยน webhook จาก DialogFlow ไปยัง proxy

และอย่าลืมใส่ /webhook ต่อหลังตัว Cloud Function ที่ได้จากการ deploy ด้วยนะ

จากนั้นทีการ demo อีกครั้งนึง คราวนี้รับ date ได้แล้ว แต่ยังขาด fullfillment เพราะเรายังไม่ได้ implement นั่นเอง

โค้ดในขั้นตอนนี้จะเป็นแบบนี้นะ

ต่อมาทำการเชื่อมต่อข้อมูลกับ Cloud Firebase กันต่อเนอะ ดังนั้นจะต้อง require firebase-admin เข้าไปนั่นเอง

const admin = require('firebase-admin');

อย่าลืม initialize นิดนึง

admin.initializeApp({});

แล้วก็สร้าง path ใหม่อีกหนึ่งอัน ชื่อว่า fullfillment ทำหน้าที่รับ request จาก DialogFlow

app.post('/fullfillment', (request, response) => {
    //TODO
})

มีการใช้ middleware แปลง body ให้เป็น json เพื่อให้ตัว Express สามารถเข้าใจได้

app.use(express.json());

เมื่อเราจะใช้ DialogFlow ในโปรเจกนี้ของเรา จะต้องไป require dialogflow-fulfillment เข้ามาในโปรเจก

const { WebhookClient, Payload } = require('dialogflow-fulfillment');

ถ้าใครเคยไปทำ fullfillment ที่ Inline Editor ก็จะเริ่มคุ้นๆหล่ะ ก็คือตัวเดียวกันแหละเนอะ

และทำการ install DialogFlow และควบคู่ด้วย actions-on-google

npm i dialogflow-fulfillment actions-on-google --save

มา implement ใน path fullfillment กันต่อ ตัว agent รับ request และส่ง response ออกไปได้เลย และตัวชื่อ Intent จะต้องตรงกับที่เราตั้งชื่อใน DialogFlow นะ

app.post('/fullfillment', (request, response) => {
    const agent = new WebhookClient({ request, response });
    let intentMap = new Map();
    intentMap.set('Register - date', handleFullfillment);
    agent.handleRequest(intentMap);
});

สร้าง handleFullfillment() เพื่อทำการ implement ในส่วนสร้าง Document โดยใช้ Cloud Firestore โดย key จะเป็น userId ของคนที่พิมพ์หาบอท ซึ่งมาจาก webhook ของ LINE อีกทีนึง ข้างในชื่อตัวแปรจะต้องตรงกับที่เราตั้งไว้ใน DialogFlow นะ ในที่น้ีจะเก็บผ่าน database ตรงๆ และให้ส่งไปบอกว่าเก็บข้อมูลเรียบร้อยแล้ว

ใน codelab จะเห็น selected_date: Date.parse(selected_date)ถ้าเก็บ date ที่เป็น long number ก็ convert ได้นะ อันนี้ก็แล้วแต่เราเลย

function handleFullfillment(agent) {
    const userId = agent.originalRequest.payload.data.source.userId;
    const { name, latitude, longitude, selected_date } = agent.parameters;
    const doc = {
        uid: userId,
        name,
        latitude,
        longitude,
        selected_date
    };
    firebase.firestore().collection('member').doc(userId).set(doc);

    agent.add('บันทึกข้อมูลสำเร็จแล้ว');
}

เมื่อเก็บข้อมูลเรียบร้อยแล้วส่งไปบอก user ได้เลย

การทำงานในส่วนนี้จะมี flow คือ : LINE app -> Proxy Server -> DialogFlow -> Fullfillment

จากนั้น deploy อีก 1 กรุบ สำหรับเส้น fullfillment

และแล้วถึงเวลาตื่นเต้นที่สุด เพราะไม่เคยทำมาก่อน คือการใส่ webhook ที่เราสร้างจาก Cloud Functions ลงใน DialogFlow เว้ยยย เพราะเราทำไม่เป็นไงประเด็น 555

ผลที่ควรจะได้หลัง deploy

ข้อมูลจะถูกเก็บไว้ใน Cloud Firestore แบบนี้

รวบตึงโค้ดสักนิด

แต่พอเป็น text แบบนี้มันก็จะดูแห้งๆไป แน่นอนว่าใน codelab ไม่มี อิอิ ดังนั้นเราจะมาสร้าง Flex Message เมื่อสร้างเสร็จแล้วเอามาแปลงใน EX10 ได้นะ ในที่นี้ให้กด FORMAT AS FLEX MESSAGE นะ

จากนั้นทำการสร้าง payload และส่ง payload ออกไป

const msg = {};
const payload = new Payload(
    agent.LINE, 
    msg, 
    { 
        sendAsMessage: true, 
        rawPayload: false 
     }
);
agent.add(payload);
ข้อควรระวัง custom payload รองรับ DialogFlow version 0.6.1 ขึ้นไป

และในการ implement payload ครั้งนี้ ไม่ต้องมี line {} มาครอบนะ

นอกจาก EX10 จะช่วยแปลง Flex Message จาก LINE Bot Designer หรือ Flex Message Simulator ให้เราสามารถใช้งานต่อได้แล้ว ยังมี feature อื่นๆอีก เช่น

  • Emoji Selector : ช่วย set index ของ emoji ให้ไปอยู่ใน array ที่ถูกต้อง
  • Messages Imagemap : มี resize แล้วให้ url เรากลับไปใช้ด้วย
  • Bulk Processor : ใส่ uid เพื่อช่วยยิงเวลาเปลี่ยน Rich Menu ให้กับ user ที่เป็นเพื่อนใน LINE OA นั้นทุกคน โดยจะทยอยยิงไปแหละ แต่เราทำในนี้ครั้งเดียวพอ
  • Encode & Decode มีทั้ง url และ base64

โจทย์เพิ่มเติมของการบ้านจ้า

  • เมื่อเพิ่มเพื่อนแล้ว จะมีหน้าตาคล้ายๆ Dialog ขึ้นมาให้เราลงทะเบียนเลย
  • หลังจากเลือกวันที่ ให้ user ส่งสติ๊กเกอร์เพื่อแสดงความรู้สึกด้วย
  • สุดท้ายแสดงผลออกมา เป็นการยืนยันการลงทะเบียน
update : เพิ่มไปในนี้เลยแล้วกันเนาะ

มาเริ่มส่วนที่ง่ายที่สุดก่อน คือเพิ่มให้ user แสดงความรู้สึก แล้วสุดท้ายแสดงทั้งหมดออกมาเป็น Flex Message

ก่อนอื่นเลยเรามาแก้ Intent ใน DialogFlow กันก่อน ชื่อว่า Register - date โดยเราจะใช้ custom payload ในการแสดง text ทั้งสองตัว คือ วันที่ที่เราใส่เข้าไป และ ให้ user ส่ง sticker กลับมานั่นเอง เราจึงต้องเพิ่มเป็น 2 blocks นะ แบบนี้

//custom payload 1
{
  "line": {
    "text": "คุณเลือกวันที่ $selected_date",
    "type": "text"
  }
}

//custom payload 2
{
  "line": {
    "text": "ส่งสติ๊กเกอร์บอกความรู้สึกของคุณในตอนนี้",
    "type": "text"
  }
}

Multiple Responses with Dialogflow (aka Api.ai)
I’m trying to create a chatbot which once “greetings” process is done goes on and initiate a new topic without any user query. It has to be something like the following: bot : hello user : hello...

แล้วอย่าลืมไปปิด fullfilment ออกด้วยนะ

จากนั้นสร้าง follow-up intent ใหม่ที่เป็น custom เหมือนเดิม สร้างต่อจาก Register - date ให้ชื่อว่า Register - sticker ก็แล้วกันเนอะ

เราจะทำการส่งทุก parameter จาก intent ก่อนหน้า เข้ามาใน intent นี้ และสร้าง parameter ใหม่ชื่อว่า sticker_keywords เพื่อนำ sticker keyword มาแสดง

แล้วก็ครอบใน Training phrases

แล้วเปิด fulfillment ไว้

ในโค้ดเปลี่ยนชื่อ intent ที่ใช้ fulfillment เป็น Register - sticker

app.use(express.json());
app.post('/fullfillment', (request, response) => {
    const agent = new WebhookClient({ request, response });
    const intentMap = new Map();
    intentMap.set('Register - sticker', handleFullfillment);
    agent.handleRequest(intentMap);
});

ใน handleFullfillment() เราจะเพิ่ม parameter sticker_keywords เพื่อนำไปเก็บไว้ใน Cloud Firestore และนำมาแสดงผลเพิ่มเติมใน Flex Message

และไปเพิ่ม type sticker ใน handleEvent()

โดยตัว sticker เราจะได้เป็น request body มาประมาณนี้ โดยตัว sticker keywords จะเป็น array เราเลยแปลงเป็น String ซะ

https://developers.line.biz/en/reference/messaging-api/#message-event

จากนั้นลอง deploy 1 รอบ มาดูผลลัพธ์กัน

ปล. กว่าจะเสร็จ คือปาไปหลายวันเลยอ่ะ ฮือออออออ

โค้ดในส่วนนี้

สุดท้ายอันเพิ่มเพื่อนแล้วแสดง Flex Message ซึ่งเราจะใช้ event ที่ชื่อว่า Follow event เนอะ

https://developers.line.biz/en/reference/messaging-api/#follow-event

จากนั้นเราก็ทำ Flex Message ขึ้นมาอันนึงเนอะ แล้วก็เมื่อเจอ event นี้แล้ว ให้ส่ง Flex Message ตัวนี้มาเลย แต่ของเรายังติดโค้ดนิดหน่อย ก็จะประมาณนี้เนอะ ใครจะมาช่วยแก้ก็ได้น้าาา เพราะเรามูฟออนไปเรื่องอื่นแล้วง่าาา


สามารถ support ค่ากาแฟเจ้าของบล็อกได้ที่ปุ่มแดงส้มสุดน่ารักที่มุมซ้ายล่าง หรือกดที่นี่ก็ได้จ้า https://ko-fi.com/mikkipastel

กด follow Twitter เพื่อได้รับข่าวสารก่อนใคร เช่น สปอย content ใหม่ หรือสรุป content เร็วๆในนี้จ้า

ติดตามข่าวสารและบทความใหม่ๆได้ที่

อย่าลืมกด like กด share บทความกันด้วยนะคะ :)

Posted by MikkiPastel on Sunday, 10 December 2017

download แอพอ่านบล็อกใหม่ของเราได้ที่นี่

MikkiPastel - Apps on Google Play
First application from “MikkiPastel” on play store beta feature- read blog from https://www.mikkipastel.com by this application- read blog content by chrome custom tab- update or refresh new content by pull to refresh- share content to social network
https://play.google.com/store/apps/details?id=com.mikkipastel.blog

Tags

Minseo Chayabanjonglerd

I am a full-time Android Developer and part-time contributor with developer community and web3 world, who believe people have hard skills and soft skills to up-skill to da moon.