มาใช้ Git จัดการ Intents บน Dialogflow ด้วยกัลล ..

Chanintorn Asavavichairoj
4 min readJul 28, 2019

ทุกๆท่านคงคิดไม่ต่างจากผมเท่าไร .. การสร้างแชตบอทจริงๆแล้วก้อไม่ได้แตกต่างไปจากการทำ Software อื่นๆจริงไหมครับ ไม่ว่าจะเป็น Website หรือ Mobile App ตัว Chatbot เองก้อเป็นเพียงอีก Channel หนึ่งในยุคสมัยนี้ที่คนส่วนใหญ่เริ่มหันมาใช้กันเท่านั้นเอง ซึ่งในการทำ Software ทั่วไปพวกเราก้อคงต้องมี Production สำหรับใช้จริง และ Non-Production เพื่อให้พวกเราเหล่า Developer มีพื้นที่ในการเล่น การทดสอบ การแก้ไขบั๊ก(ถ้ามี) โดย Non-Production เราจะมีมากมีน้อยก้อขึ้นอยู่กับความใหญ่ความซับซ้อนของระบบที่เราพัฒนากัน สำหรับผมและทีมที่ผมทำงานกันอยู่พวกเรามี Non-Production กันมากถึง 5 Environments บ้าบอออออ .. เรื่องอื่นๆเราก้อพอมีท่าจัดการกันได้เพราะมันหนีไม่พอกับการทำ Software อื่นๆทั่วๆไป แต่ทีนี้ลองมานึกถึงตัว Dialogflow ที่เราใช้กับ Chatbot กันสิครับว่าเราจะ Manage ข้อมูลหรือ Content กันยังไง ??? เราจะ Mock เราจะ Stub ไปทุก Environments เลยหรอก้อไม่น่าจะดีใช่ไหมฮ่ะ แล้วทำไงกันดี ???

ความปวดหัวก้อเกิดขึ้นเมื่อท่านมีหลาย Environment!

นับเป็นความเจ็บปวดนึงเมื่อเวลาเราเพิ่ม Content หรือ Intents ใหม่ๆเพื่อ Support Features ที่เรากำลัง Develop อยู่ใน Environment อื่นๆ ที่ยังไม่ต้องการขึ้นบน Production ในขณะเดียวกันบน Production เวลาเจอ Fallback Intents หรือเพิ่ม Gimmick ให้ Chatbot เราก้อมีสอน Dialogflow ไปด้วยกัน โอ้วววบร๊ะจ้าวววว.. แล้วเราจะรวมกันยังไงหน๋อ ทำมือเลยหรอ บร้าหน่าา มันถึกไปป่าววว

นับเป็นโชคดีอยู่บ้างที่ Dialogflow มีการเตรียมช่องทางให้เรา Import/Export ข้อมูลที่เรา Config ไว้บน Agent หนึ่งๆทั้งหมด ที่สามารถทำได้บน Web ได้

เราสามารถที่จะ Export ทั้งหมดออกมาเป็น ZIP ไฟล์, Restore (ลบทิ้งทั้งหมดเอาแต่ที่เราส่งเข้าไปใหม่), และ Import (ไม่ลบทิ้งแต่เป็นการเพิ่มเข้าไป หากชื่อซ้ำกันจะถูก Replace) ได้ ซึ่งก้อช่วยเราได้อยู่แต่นี่มันคือมืออีกแล้วนะฮ่ะ เราอยู่ในโลกดิจิตอลแล้วเราควรจะต้องทำให้มัน Automate ได้หน่อยสิ ว่าแล้วไปคุ้ยดูกันดีกว่าว่ามีไรให้เราใช้ได้บ้าง

ได้เห็นแล้วน้ำตาก้อเริ่มไหล .. คุณพี่เค้าเตรียมมาให้พวกเราเป็นอย่างดี เพียงแต่เราคงต้องมาออกแรงกันหน่อยละครับทีนี้ เริ่มจากไปลองใช้ API กันเลย

มาลองดูดข้อมูลและยัดกลับเข้าไปใน Dialogflow กัน

ก่อนอื่นเลยเครื่องที่เราจะดูดและยัดกลับเข้าไป(ไม่ว่าจะเป็นเครื่องเราเองหรือจะเอาไปทำใน Jenkins Slave ตัวนึงก้อได้นะครับ) จะต้องลง gcloud cli กันก่อนน สำหรับใครใช้ macOS ก้อลงสบายๆผ่าน brew โล้ดฮ่ะ (linux/windows ไปหากันเองเน้ออ)

brew cask install google-cloud-sdk

ทีนี้เพื่อความรวดเร็วผมจะขอพาไป Download Service Account Key File บน GCP Console มาใช้งานกันเลยนะครับ (จริงๆใช้ gcloud cli ทำก้อได้นะครับ) ให้เข้าไปใน Service accounts ของ Dialogflow Integrations ที่ Dialogflow สร้างมาไว้ให้เรา จากนั้นก้อ Create Key แบบ JSON เก็บมาใช้งานได้เลยครับ

เมื่อเราได้ Key File ที่เป็น JSON เรียบร้อย เนื่องจากว่าเราต้องใช้ gcloud เพื่อขอ Token มาใช้งานเราต้อง Export environment variable เอาไว้ใช้ gcloud cli รู้ที่อยู่ของ Key File ด้วยครับ

export GOOGLE_APPLICATION_CREDENTIALS="/<PATH>/<FILE_NAME>.json"

เสร็จแล้วเราก้อเริ่ม ดูดดดดดด .. ข้อมูลด้วย API projects.agent.export

curl -X POST https://dialogflow.googleapis.com/v2/projects/<PROJECT-ID>/agent:export \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
--compressed \
--data-binary '{}' \
| grep agentContent | sed -e 's/.*"agentContent": "\([^"]*\)".*/\1/' \
| base64 --decode > agent-exported.zip

สิ่งที่ Dialogflow ส่งมาให้เราเป็น Base64 ของ ZIP binary ครับ ใน Command ผมแปลงให้เรียบร้อยแล้ว ท่านๆก้อจะได้ ZIP ในทันทีและสามารถคายออกมาดูได้ครับ

ทดสอบยัดกลับเข้าไปด้วย API projects.agent.import ก้อลักษณะเดียวกัน คือแพคของไว้เป็น ZIP แล้วแปลงเป็น Base64 ของ ZIP binary แล้วส่งกับเข้าไปตามนี้ครับ

curl -X POST https://dialogflow.googleapis.com/v2/projects/<PROJECT-ID>/agent:import \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
--compressed \
--data-binary "{
'agentContent': '$(cat agent-exported.zip | base64 -w 0)'
}"

Update นึดนึงครับ เนื่องจากไฟล์ Dialogflow ของผมค่อนข้างใหญ่มากๆแล้ว! หากไฟล์ที่ import เข้าไปมีความยาวมากๆ command curl อาจจะบ่นออกมาได้ให้ใช้คำสั่งแบบนี้แทนครับ

curl -X POST https://dialogflow.googleapis.com/v2/projects/<PROJECT-ID>/agent:import \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
--compressed -d @- <<CURL_DATA
{"agentContent": "$(cat agent-exported.zip | base64 -w 0)}
CURL_DATA

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

โครงสร้างของ Project หลัง Export มาจาก Dialogflow

หากเรา Export กันออกมาแล้วเรามาดูกันหน่อยเถอะครับว่าน่าตาจิ้มลิ้มเพียงใด เราจะพบว่าทุกอย่างเป็น “JSON” โอ้วววว มายยย ก๊อดดด รักเลยยย ถ้าเป็น binary มานี้เราจะทำไรแทบไม่ได้เลย แต่มันเป็น JSON นี่สิครับ ทำให้เราทราบถึงโครงสร้างการเก็บข้อมูลของ Intents หรือ Entites ต่างๆ ที่เราได้ใส่ไว้ใน Dialogflow ได้เป็นอย่างดี

  • agent.json จะเก็บค่า Settings ของ agent ใน Dialogflow ของเราไว้ทั้งหมดที่นี่ ไม่ว่าจะเป็น Fulfillment endpoint ก้อจะสิงสถิตอยู่ ณ ที่นี่
  • package.json ไม่แน่ใจเหมือนกัน เข้าใจว่าเป็นตัวบอก version ของ schema ที่เรา export ออกมา
  • entities ภายใต้ directory นี้จะเก็บข้อมูลของ entities โดยในหนึ่ง entity จะเก็บสองไฟล์คือ
    - <entity-name>.json เป็นไฟล์หลักของ Entity หนึ่งๆ
    - <entity-name>_entries_<lang>.json ใช้เก็บ Data set ของ Entity นั้นๆไว้
  • intents ภายใต้ directory นี้จะเก็บข้อมูลของ intents ทั้งหมด รวมไปถึง Default ที่ Dialogflow สร้างมาให้ด้วย ซึ่งจะประกอบไปด้วยไฟล์ต่างๆตามนี้
    - <intent-name>.json เป็นไฟล์หลักของ Intent นั้นๆ รวมไปถึงเก็บข้อมูลที่เรา Custom Responses ไว้ให้ด้วย
    - <intent-name>_usersays_<lang>.json เก็บ Training Phases ที่เราได้สอนไว้ใน Dialogflow แยกตามภาษาด้วยนะครับ

จากโครงสร้างของ Dialogflow ที่เรา Export ออกมาได้มีเพียงแค่ไฟล์ agent.json เท่านั้นที่มีความเฉพาะตัวยึดติดกับ Dialogflow agent หนึ่งๆเท่านั้น เราจึงละไฟล์นี้เอาไว้ อย่าไปแก้ไขหล่ะครับ และหากท่านใดมี Intents ที่สะสมไว้เยอะแล้ว Backup กันก่อนนะฮ่ะพี่น้องเผื่อความสบายใจ

เราจะเห็นว่า Dialogflow เก็บข้อมูลที่เราได้เคยสอนมันไปไว้เก็บไว้หมดเลย แม้ว่า Export ออกมาแล้วก้อได้มาครบถ้วนและที่สำคัญมันเป็น JSON ครับ ซึ่งเราสามารถเพิ่มเติมมันได้ แก้ไขมันได้ ตราบใดที่ Spec มันถูกต้องใช่ไหมครับ ด้วยเหตุนี้เองผมจึงคิดว่าเราสามารถที่จะใช้ Git เพื่อ Merge สิ่งของต่างๆที่เราทำมาบน Environments อื่นๆ รวมไปถึง Merge back กลับที่เราสอนบน Production กลับไปได้ด้วย ซึ่ง Git เองก้อเก่งไม่ว่าจะเป็นเรื่องการทำ Versioning, การ Merge Sourcecode, หรือการแก้ไขปัญหา Conflict อยู่แล้ว เรามาดูกันต่อดีกว่าครับว่าเราจะเริ่มใช้ Git Manage Intents บน Dialogflow กันได้อย่างไรบ้าง

เริ่มประยุทธ์ เอ้ยยย .. ประยุกต์ใช้ Git / GitFlow มาใช้ Manage Dialogflow

จั่วหัวมาแปลกๆแบบนี้ไม่ต้องตกใจกันก่อนนะฮ่ะ เรามามั่วๆด้วยกันนี่แหละ .. โดยหลังจากที่เราดูดข้อมูลบน Dialogflow บน Production ของเรามาได้แล้วเราก้อเอามาเข้า Git เลยครับเพื่อเป็น Branch Master ตั้งต้นของเรา โดยใช้ Command ของ Git ที่เรารู้จักกันดีนี่แหละครับ ..

git init
git add .
git commit -m ‘<Commit Message>

ทีนี้แล้วแต่ความชอบในการ Manage Git กันเลยนะครับ ปกติแล้วผมเป็นคนที่ชอบใช้แบบ Trunk Base(Single branch) มากกว่า แต่พอเอามาใช้ในการ Manage ข้อมูลบน Dialogflow ผมว่าตัว GitFlow ค่อนข้างมีความลงตัวมากกว่า เพราะถ้าหากเรามองว่า Environmets ต่างๆเป็น Features branch แล้วเราสามารถที่จะ Merge Features branch เข้า Master ได้ และในทางกลับกันหากเรามีการเพิ่มข้อมูลบน Production เราสามารถมองมันเป็น Hotfix เพื่อ Merge กลับเข้า Master, Develop และ Fetures branch ต่างๆได้อย่างสะดวกสบาย ผมยอมรับว่าตัว GitFlow เค้าคิดมาดีแล้วในเรื่องพวกนี้

ทีนี้ผมจะพาไปดูความดีงามเมื่อเราใช้ Git มา Manage ข้อมูลของ Dialogflow ให้ดูกันครับ

จะเห็นว่าเมื่อเราแก้ไขอะไรไปและจับ Export ไปลง Git แล้วเราจะเห็น Diff ของมันทั้งหมด อย่างเช่นตัวอย่างนี้ผมได้ลองเปลี่ยนชื่อ Parameters ใหม่บน Dialogflow จาก number เป็น amount และ currency-name เป็น name ซึ่งพอผมมาดู Change ที่ Diff ไปพบว่า Git ก้อสามารถรู้ได้ว่าผมแก้ไขอะไรลงไป รักที่สุด!

เมื่อทุกอย่างมาอยู่ใน Git ได้ก้อสบายแฮ่เหล่าพวกเราชาวกรรมกรซอฟต์แวร์เลยใช่ไหมฮ่ะ

จริงๆแล้วยังมีอีกวิธีที่สะดวกแต่ยังคงต้องใช้มืออยู่บ้าง คือการ COPY Intents บน Dialogflow ได้โดยตรงเลย แต่ผมคิดว่าหากเรามี Intents ที่ค่อนข้างเยอะแล้ว การที่มาใช้ Git จะสามารถทำให้เรา Visualize ได้ดีย่ิงขึ้นทำให้เห็นซอกหลืบไหนที่มีการเปลี่ยนแปลงจริงๆแม้ว่าเป็นจุดเล็กๆน้อยๆก้อตาม ทำให้เราไม่พลาดที่จะสิ่งเล็กๆน้อยๆที่เราอาจจะลืมได้

วิธีการเลือกที่จะ COPY จาก Dialogflow โดยใช้มือโดยตรง

หวังว่าไอเดียต่างๆเหล่านี้คงเป็นไอเดียนึงที่ทำให้ทุกคนได้มีความสุขมากขึ้นกับการทำแชตบอทนะครับ เราไม่ต้องมาปวดหัวกับการ Manage Intents ที่อยู่ต่าง Environments ว่าอันนี้ใส่ไปหรือยัง อันนี้ลืมหรือเปล่า รวมไปถึงเราสามารถทำ Versioning ในการ Tracking ได้ด้วยว่าเวอร์ชั่นปัจจุบันของเรามันประกอบไปด้วยอะไรบ้าง ย้อนหน้า ถอยหลังได้สบายๆด้วยพลังของ Git

และยิ่งไปกว่านั้นหากผมมีเวลาผมจะพาไปทำ Automate เพื่อการ Manage ข้อมูล Dialogflow ทั้งสายบน Jenkins เพื่อใช้ในการ Promote จาก Envionments ต่างๆไปจนถึง Production ด้วยคลิกเดียวกันต่อไปนะครับ แล้วเจอกันในบทความต่อๆไปครับ สวัสดี :)

--

--