ทำแชทบอท ด่วนจี๋ ไปรษณีย์จ๋า กับ Sunday Codelabs 3 กับ LINE Developers Thailand

Event Aug 10, 2021

หลังจากที่พลาด Sunday Codelabs สองครั้งแรกเพราะชนกับค่าย TMRW Creators Camp 2021 ที่จัดเวลาเดียวกันพอดี รอบนี้ว่างแล้วไม่พลาดแน่นอน

ก่อนอื่นเราได้ทำการเตรียมพร้อมทั้งหมด โดยได้ไปดู codelab มาก่อนล่วงหน้า ว่าต้องเตรียมอะไรบ้าง เวลาทำจะได้ลื่นๆ แต่คุณกอล์ฟพิมพ์ไวมาก แอบตามไม่ทันเลยค่ะ 555555555555 ก็เลยแนะนะว่า อ่านมาก่อนก็ดีน้าา เพราะตอน Flex Message ใครมันจะก้อปทันกัน 555

Building Package Tracking Chatbot with ThailandPost API
LINE Bot + ThaiPost Rest API (Include Source Code)
บทความนี้จะมาแบ่งปันเรื่องการดึงข้อมูลติดตามสถานะการส่งพัสดุของไปรษณีย์ไทยผ่าน Rest API นะครับ

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

.

"ด่วนจี๋ ไปรษณีย์จ๋า" คือบังเอิญกดทีวีแล้วไปเจอการ์ตูนช่องนึงฉาย แล้วตัวละครพูดคำนี้พอดีเลย555555

ไลฟ์มีการเตรียมคนดูก่อนถึงเวลา พอถึงเวลาปุ๊ป พี่ตี๋พี่แทนมาเลยจ้า และสักพักได้เปิดตัวคนมา coding โชว์พวกเราในวันนี้ เขาคือคุณกอล์ฟ LINE API Expert หรือเรียกย่อๆว่า LAE คนล่าสุดของไทย ที่ได้ตำแหน่งนี้ก่อนโควิด ข้อดีคือจะได้เล่นของใหม่ๆก่อนใคร ในตอนนี้คือ LINE Mini App และถ้าโควิดหมดไปก็จะได้ไปงานที่ญี่ปุ่นด้วยเนอะ

ในวันนี้ เราจะได้ LINE Chatbot ที่สามารถตรวจสอบ tracking จากไปรษณีย์ไทย ว่าตอนนี้ของอยู่ที่ไหนแล้ว และสามารถดู status แต่ละตัวได้ และดูชื่อผู้รับลงไปได้ ซึ่งเพิ่มเข้ามาจาก codelab จ้า

เริ่มต้นที่สร้าง LINE OA ขึ้นมา เริ่มตั้งแต่สร้าง provider จากนั้นมา new channel ถ้าเลือก categories ไม่ถูกเลือกหมวดการศึกษาได้ ซึ่งขั้นตอนนี้ไวมาก จากนั้นได้ LINE Chatbot มา 1 ตัว

ต่อมาปิด auto reply message โดยไป disable ทิ้งไป

และเราเพิ่มเพื่อนกับบอทไว้ก่อนเลย เดี๋ยวเรา coding แล้วมาทดสอบกัน

จากนั้นมาเตรียมของทำโปรแกรมให้บอทกัน โดยเราสร้างโปรเจกใน Firebase โดยคุณกอล์ฟใช้ชื่อว่า ThailandPostTrack ปรากฏว่าชื่อไม่ซํ้าจ้า เยี่ยมเลย

บอทตัวนี้เราเรียก API นอก Google เนอะ อ่ะมีทั้ง LINE แล้วก็ API ของไปรษณีย์ไทย จึงต้อง update project เป็น Blaze Plan เสียก่อน ก็คือผูกบัตรเครดิตก่อน

แต่ถ้าไม่มีบัตรเครดิตหล่ะ? เราสามารถใช้ Firebase Emulator Suite ได้นะทุกคน โดยเราทำบล็อกแยกก่อนหน้านี้ไปนิดนึง แต่ในวันนี้มี tips and trick เยอะ เยอะเกินกว่าบล็อกนี้ที่เขียนไว้ด้วยอ่ะ

วิธีทำ LINE Chatbot สำหรับ developer มือใหม่ ไม่ง้อ DialogFlow
หลายๆคนอาจจะเพิ่งลองทำ LINE chatbot แล้วประสบปัญหาทำใน DialogFlow แต่ใช้ไม่ได้เพราะไม่มีบัตรเครดิต ถ้าอยากลองเขียนต้องทำยังไงบ้างนะ?

ต่อมาติดตั้งอะไรต่างๆกันเถอะ เริ่มที่ติดตั้ง firebase เลย

sudo npm install -g firebase-tools

ที่ต้อง sudo เพราะว่าเผื่อต้องขอสิทธิ์อะไรงี้ ต่อมา check Firebase version เพื่อ make sure ว่าติดตั้งไปเมื่อกี้เรียบร้อยแล้วนะ

firebase --version

จากนั้นทำการ login กันเลย และเราต้องตรวจสอบว่า account ตรงกับที่เราสร้าง Firebase project เมื่อกี้ไหมนะ

firebase login

สร้าง folder ของโปรเจก ซึ่งในที่นี้จะชื่อว่า thailandposttrack ตามชื่อใน Firebase เนอะ

mkdir thailandposttrack

แล้วก็ทำการ init project โดยเลือกใช้ตัว Function และ Emulator เพราะเราใช้ Firebase Emulator Suite ในการทดสอบใน local ก่อนจ้า เอ้ออ เพิ่งรู้ว่าทำในนี้ได้เลยง่ายๆ ไม่ต้องทำ firebase.json เอง

โดยเราจะ run Firebase Emulator Suite กับ Clouds Function for Firebase แล้วตั้ง port ที่เราจะใช้คือ 5001 ใช้ Emulator UI เพื่อ check log ต่างๆ

เรื่องภาษา จริงๆคุณกอล์ฟแนะนำว่าใช้ typescript เพราะปลอดภัยกว่า แต่ในตอนนี้ใช้ javasscript ไปก่อนเนอะ

เมื่อกระบวนการเหล่านี้เรียบร้อยแล้ว เราจะทำการทดสอบโดยการลอง run ใน function ที่เป็นไฟล์เปล่าก่อน คือ เอา comment code ใน index.js ออกนั่นแหละ จากนั้นลองใช้ Firebase Emulator Suite กันเล้ยย

firebase emulators:start

คั่นด้วยคำถามพี่ตี๋ codelab ไหนในนี้ อันไหนเป็นอันล่าสุด ทุกคนโดนแกงกันหมดนึกว่าอันที่ทำอยู่นี้ แต่จริงๆเป็นอันนี้จ้า Handle Non-Text Event with Dialogflow

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

เมื่อเรารัน Firebase Emulator Suite เราจะพบว่า มันจะ default ที่ us-central1 ให้เลย ซึ่งไกลจากบ้านเรามาก ดังน้านน เราเข้าไป check ที่ website นี้ดูก่อนจ้าว่า server ของ Google มีที่ไหนบ้าง และที่ไหนใกล้เราสุด ซึ่งใกล้สุดคือสิงคโปร asia-southeast1 แต่ด้วยความที่ตัว server ของ LINE น่าจะอยู่ที่ญี่ปุ่น ก็เลยเลือก asia-northeast1 ที่โตเกียวนั่นเอง

https://gcping.com/

ดังนั้นเปลี่ยน region ในโค้ดของเรา และทำการ start emulator ใหม่ด้วยน้าา

ต่อมาใช้เจ้า เอ็น-จี-ค๊อก ngrok เพื่อทำการมุดท่อนั่นเอง เข้าไปที่ website แล้วทำการ download และ install ได้เลยย และเราสามารถเปลี่ยน region ใน ngrok ได้ด้วยนะ คือปกติอ่ะ จะไปที่ United States (us) เราสามารถเปลี่ยนไปที่อื่นได้ด้วย เช่นในที่นี้ไปญี่ปุ่น ก็พิมพ์ command line ว่า

ngrok http 5001 -region=jp

เราก็ไปญี่ปุ่นทิพย์แล้ว (เอ๊ะ ใช่เหรอ)

สามารถดู log ได้ว่า bot ทำงานได้จริงไหม และสิ่งที่เราต้องการใช้จาก request ที่เราได้จากข้อความที่ user พิมพ์ ก็จะมี type, message และ replyToken

ต่อมาไปสร้าง account ในเว็บไปรษณีย์ไทย

https://track.thailandpost.co.th/login

จากนั้นก็ไปเอา token มาซึ่ง UI แย่มาก ต้องกดปุ่มและยืนยันก่อนถึงจะได้ เราจะมีโควต้าใช้ได้วันละ 1000 requests นะ

แล้วสร้าง class ใหม่ ชื่อว่า thailandpost.js โดยตัว API ของทางไปรษณีย์ไทยที่ใช้นั้น จะเป็นดังนี้

  • getToken คือการนำ token API ของเรา ทำการ authen เพื่อให้ได้ authen token ออกมา ซึ่งเวลาเราใส่ token ใน header จะเป็น Bearer แล้วตามด้วย token แต่อันนี้เป็นคำว่า Token แทนง่ะ
  • GetItems เป็นการตรวจสอบสถานะของเลขพัสดุนั้นๆ จะใช้ token ที่ได้จาก getToken มาใช้งานนะ

ส่วน RequestItems จะได้ไฟล์ให้ download กลับมาจ้า

ดังนั้นเราจึงสร้างไฟล์ thailandpost.js เพื่อใช้งาน API ต่างๆ ดังนี้

ต่อมาสร้าง Flex Message เพื่อนำมาใช้งานแสดงผลสถานะการส่งพัสดุ ใช้ Flex Message Simulator ในการออกแบบ สุดท้ายก็จะได้ json เอามาใช้ต่อเนอะ แต่อันนี้เป็นหน้าเว็บเนอะ และบังคับ login ด้วย LINE Account นิดนึง

https://developers.line.biz/flex-simulator/?status=success

ขั้นตอนนี้เนี่ยย เอาจริงๆ ข้ามไปเยอะมากเลย เพราะว่าคุณกอล์ฟทำรอไว้ก่อนแล้วไง แต่จะมีเพิ่มมาจาก codelab ตรงเรื่องของชื่อผู้ส่งนั่นเอง สร้างไฟล์ชื่อว่า msgTemplate.js ทั้งหมดจะเป็นแบบนี้

  • ถ้า user กรอกเลขพัสดุแล้วไม่มีข้อมูล จะให้ส่ง text message ไป จะอยู่ใน trackNotFound
  • มีการตัด body มาเป็น trackBody ออกจากตัว body หลัก แล้วจะถูกใส่ในแต่ละ column ใน trackHeader จ้า
  • ตรงชื่อผู้รับ กลับไปดู document ของ API ไปรษณีย์ไทย จะมี status ต่างๆ โดย status item 501 คือ นำจ่ายสำเร็จ นั่นเอง จึงนำ detail.receiver_name มาแสดงได้จ้า
"text": (detail.status === "501") ? `ผู้รับ คุณ${detail.receiver_name}` : " "
  • และมีการใส่สีแต่ละ status item ไว้ด้วย โดย status item 501 คือ นำจ่ายสำเร็จ จะแสดงพื้นหลังเป็นสีเขียว, status item 201 คือ อยู่ระหว่างการขนส่ง จะแสดงพื้นหลังเป็นสีเหลือง และอื่นๆเป็นสีเทา
"backgroundColor": (detail.status === "501") ? "#6BFF6B" : (detail.status === "201") ? "#FCFEC9" : "#EEEEEE"

เมื่อเราได้ message ที่จะส่งเรียบร้อยแล้ว ทำการปั้น body เพื่อทำการส่งข้อความไปให้ user โดยสร้างไฟล์ lineHelper.js ขึ้นมาเพื่อทำสิ่งนี้

เราสามารถดูรายละเอียดการทำ Reply Messages ได้ใน document ของ LINE ได้เลย ซึ่งคุณกอล์ฟก็สอนวิธีอ่านเจ้า curl ต่างๆเนอะ

https://developers.line.biz/en/docs/messaging-api/sending-messages/#methods-of-sending-message
  • curl -v -X POST https://api.line.me/v2/bot/message/reply \ อันนี้จะเห็นได้ว่า เราต้องส่ง method POST ไปที่ https://api.line.me/v2/bot/message/reply
  • -H ก็คือ header โดยเราจะใส่ไป 2 สิ่ง คือ 'Content-Type: application/json' และ 'Authorization: Bearer {channel access token}'
  • -d คือ data parameter ในที่นี้คือ ส่งเป็น response body เข้าไปด้วย มีหลักๆ 2 อย่างคือ replyToken ที่เอามาจากตอนที่เราได้รับข้อความจาก user และ message อันนี้คือข้อความที่เราจะส่งให้ user นั่นเอง

และกลับมาที่ index.js จริงๆเราแอบเล่าข้ามไป เพราะเดี๋ยวจะอธิบายตรงนี้แหละว่าโค้ดมีอะไรบ้าง

  • request.body.events[0] อันนี้ get event ออกมาก่อน โดยเราจะใช้ 3 ตัว คือ replyToken, message, type
  • if (type === "message" && message.type === "text") เราต้อง check ก่อนว่ามันเป็น message ที่เป็น text จริงๆ ไม่งั้นถ้า user ส่งสติ๊กเกอร์หรืออื่นๆมา มันจะพังเพราะ get text ออกมาไม่ได้เน้อ
  • const barCode = message.text; เอา text ที่ได้ออกมาใช้ โดยอันนี้จะเอามา check สถานะของพัสดุนี้
  • มี async ข้างนอก ก็ต้องมี await ด้านใน คือรอให้เรียก API เสร็จก่อน const trackResult = await thailandpost.getItems(barCode); ถึงจะทำงานได้
  • const items = trackResult["response"]["items"][barCode]; เราเอา response.items.barCode ที่ได้จาก API มาใช้งานต่อในการส่ง message ไปหา user
  • let payload = null; ประกาศตัวแปร payload ไว้ เพื่อเอาไปส่ง message นี่แหละ
  • ถ้า items.length <= 0 ก็ให้ส่ง msgTemplate.trackNotFound() กลับไป
  • ถ้ามีของให้ทำการวนลูปเพื่อสร้าง Flex Message จ้า
let body = [];
items.forEach((row) => {
    body.push(msgTemplate.trackBody(row))
});
payload = msgTemplate.trackHeader(barCode, body)
  • await lineApp.reply(replyToken, payload); ได้ของแล้ว ทำการส่งออกไปให้ user เลยจ้า
  • response.send("Hello from Firebase!").end() สุดท้ายทำการส่ง response ไปยัง Cloud Functions for Firebase แหละ ใช้ end() เพื่อความปลอดภัย

สุดท้าย ก่อน deploy หรือเอาโค้ดขึ้น github เราจะต้องทำการซ่อน key โดยใช้ Environment Configuration ก่อนเนอะ เพื่อความปลอดภัย โดยพิมพ์คำสั่งประมาณนี้

firebase functions:config:set thailandpost.tokenkey="YOUR_TOKEN_NA"

อันนี้แอบมีความลุ้นๆนิดนึง เพราะพี่ๆจำ command ไม่ได้แหละ แหะๆ

เวลาเราจะดู token ทั้งหมดก็สามารถพิมพ์ command นี้ได้จ้า

firebase functions:config:get 
Environment configuration | Firebase

จากนั้นทำการ deploy ขึ้นไป ถ้าเราทำ Environment Configuration เราจะต้อง deploy อีก 1 รอบน้าา

firebase deploy --only functions

การ deploy ในตอนนี้จะนานกว่าปกตินิดนึง เพราะฝั่ง Google Clouds เอา code ไป pack เป็น server container เพื่อนำไป build เป็น 1 instant นั่นเอง และมีการ spin up / down ตามเวลาที่คนเล่นน้อย เล่นเยอะ

แต่การใช้ Environment Configuration ก็จะติดปัญหา คือ พอ deploy ไปปุ๊ป พอเราจะเพิ่ม feature หรือปรับแก้อะไรเพิ่มใน local พบว่ามัน error หล่ะสิ ทำยังไงดีนะ หาวิธีก็ไม่ได้ แต่ในไลฟ์นี้ มีคำตอบ

ให้พิมพ์ command ไปดังนี้ เพื่อนำ config ต่างๆ ลงมาเก็บไว้ใน local นั่นเอง

cd functions
firebase functions:config:get > .runtimeconfig.json

ทีนี้ก็ใช้ได้แล้วหล่ะนะ

หลังจากนั้นก็ปั่นบอทใน local ส่งชิงหน้ากากผ้า ไม่รู้จะได้ไหม ฮืออออ เจอว่าเรา deploy ไปแล้วบอทไม่ตอบ เพราะ ลืม npm install ก่อน ฮืออออ และใช้ชื่อว่า webhook ตามเขางาย แต่พอตอบได้คือแอบรอนานเพราะไกลไปหน่อย 555

สรุป Tips & Trick ที่ได้

  • เราสามารถเพิ่ม Emulator ได้ในตอน firebase init ได้เลย
  • ดู region Google server ที่ใกล้ที่สุดได้ที่เว็บนี้เลย gcping
  • สามารถเปลี่ยนที่มุดใน ngrok ได้ด้วยคำสั่ง ngrok http 5001 -region=jp
  • การประกาศตัวแปรใน javascript จะมี 2 แบบหลักๆ คือ let ใช้ประกาศตัวแปรที่สามารถเปลี่ยนค่าได้ และ const เป็นตัวแปรที่เราไม่ต้องการให้มันเปลี่ยนค่าได้นั่นเอง
  • เราสามารถใช้ Environment Configuration ใน local ได้แล้วนะ เพียงแค่พิมพ์คำสั่ง firebase functions:config:get > .runtimeconfig.json โดย .runtimeconfig.json จะต้องอยู่ใน folder ที่ชื่อว่า functions นะ ไม่งั้นมันก็โวยวายว่าหาไม่เจอเน้ออ

สุดท้ายหล่ะจ้า

แถมคลิป TikTok นิดนึง ไถๆมาแล้วไปเจออันนี้ คือพ่อค้าแม่ค้าออนไลน์ติดปัญหาคือร้านขายดีมากๆ แต่กรอกเลข tracking จากบิลยากเว่อร์ เพราะส่งออร์เดอร์แต่ละทีบิลอย่างยาวถูกม่ะ ทางเว็บไปรษณีย์ไทยเลยมี feature ให้ user กรอกเลขบิลแล้วจะได้เลข tracking ของทั้งหมดที่ส่งไปให้ลูกค้า ซึ่งก็สมัครสมาชิกก่อนเหมือนตอนเราใช้ API เขานั่นแหละ เผื่อใครอยากเอาไปต่อยอดได้จ้า โย่วว

@amuse.stuff

พูดเลยว่าโง่มานาน เค้าทำแบบนี้ได้ด้วยยย ชั้นนี่อยากจะเป็นบ้า กรอกจนมือหงิกแล้ว ตอนนี้สบายมากเลยค่า555555555 ##voiceeffects ##amusestuff

♬ WHAT WOULD YOU DO? (feat. Pink Sweat$) - HONNE

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

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

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

Posted by MikkiPastel on Sunday, 10 December 2017

และช่องทางใหม่ใน Twiter จ้า

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.