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

วันพฤหัสบดีที่ 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 มากขึ้นนะครับ 😉


วันอังคารที่ 4 กันยายน พ.ศ. 2561

วิธีขอ Permission เข้าถึงชื่อและสถานที่ของผู้ใช้งานใน Actions on Google


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

          จากเงื่อนไขดังกล่าว เราต้องเขียนโค้ดขอสิทธิ์การเข้าถึงข้อมูลของผู้ใช้งานก่อน ซึ่งทาง Assistant ก็ได้เตรียมข้อความมาตราฐานในการแจ้งกับผู้ใช้งานไว้แล้ว โดยสิทธิ์การเข้าถึงข้อมูลของผู้ใช้งานที่เราสามารถขอได้ ได้แก่
  • NAME: ขอสิทธิ์การเข้าถึงชื่อและนามสกุลของผู้ใช้งาน
  • DEVICE_PRECISE_LOCATION: ขอสิทธิ์การเข้าถึงตำแหน่งที่อยู่ของผู้ใช้งาน โดยจะคืนค่ามาเป็นละติจูดและลองติจูดของตำแหน่งที่ผู้ใช้งานอยู่
  • DEVICE_COARSE_LOCATION: ขอสิทธิ์การเข้าถึงที่อยู่ของผู้ใช้งาน รหัสไปรษณีย์ เมือง และรหัสประเทศ ใช้ได้เฉพาะจากอุปกรณ์ Google Home เท่านั้น
ซึ่งในบทความนี้เราจะมาสร้าง Actions ที่มีลำดับการทำงานดังต่อไปนี้
  • Action: สวัสดีค่ะ นี่เป็น Action สำหรับขอสิทธิ์การเข้าถึงข้อมูล
  • User: สวัสดี
  • Action: จะต้องใช้ชื่อและตำแหน่งปัจจุบันของคุณจาก Google {ข้อความเพิ่มเติมจากในโค้ด} ตกลงมั้ยคะ
  • User: โอเค
  • Action: ขอบคุณค่ะ คุณ{ชื่อ} พิกัดที่คุณอยู่คือ ({ละติจูด}, {ลองติจูด}) ขอให้มีความสุขนะคะ

สร้าง Action


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


          หลังจากทำการสร้างโปรเจค Actions เสร็จแล้ว ให้คลิกเมนู Actions ที่อยู่ในแถบเมนูซ้ายมือ


          คลิกปุ่ม ADD YOUR FIRST ACTION เพื่อเริ่มสร้าง Actions กันเลย


          ป๊อปอัพจะแสดงขึ้นมาให้เลือก Actions ที่เพื่อน ๆ ต้องการจะสร้าง ให้เลือก Custom intent แล้วคลิกปุ่ม BUILD จากนั้นระบบก็จะเปิดหน้าเว็บของ Dialogflow Console ขึ้นมาให้โดยอัตโนมัติ


          เลือกภาษาและเวลาที่จะให้ Actions รองรับการใช้งาน จากนั้นก็คลิกปุ่ม CREATE ได้เลย

สร้าง Intent



          เมื่อระบบสร้าง Actions ขึ้นมาแล้ว เราจะไปอยู่ที่เมนู Intents โดยอัตโนมัติ ซึ่งใน Actions นี้มี intent ที่เราจะใช้ทั้งหมด 3 ตัว นั่นคือ
  • Default Welcome Intent: intent นี้เป็น static intent ธรรมดา ๆ ที่ใช้ทักทายหลังจากผู้ใช้งานได้ทำการเรียก Actions ขึ้นมา โดยจะพูดทักทายผู้ใช้งานว่า "สวัสดีค่ะ นี่เป็น Actions สำหรับขอสิทธิ์การเข้าถึงข้อมูล"
  • request_permission: intent สำหรับร้องขอสิทธิ์การเข้าถึงข้อมูลของผู้ใช้
  • handle_permission: intent ที่จะถูกเรียกใช้งานหลังจากผู้ใช้ตอบคำขอสิทธิ์ ถ้าผู้ใช้ให้สิทธิ์การเข้าถึงข้อมูลก็จะพูดชื่อ พิกัดละติจูดและลองติจูดของผู้ใช้งาน จากนั้นก็จะจบการสนทนา
          เริ่มแรกให้เราจัดการในส่วนทักทายก่อน คลิกไปที่ Default Welcome Intent


          ส่วนของ Responses ให้จัดการลบข้อความอื่น ๆ ออกแล้วใส่คำว่า "สวัสดีค่ะ นี่เป็น Actions สำหรับขอสิทธิ์การเข้าถึงข้อมูล" ลงไปแทน จากนั้นก็คลิกปุ่ม SAVE เพื่อบันทึกการเปลี่ยนแปลง

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


          ในส่วนของ Training phrases ให้พิมพ์คำว่า "สวัสดี" ลงไป ตรงนี้จะเป็นการตั้งค่าให้ Dialogflow ตรวจจับคำพูด เมื่อผู้ใช้งานพูดคำที่เราระบุไว้ใน Training phrases (ในกรณีนี้ก็คือคำว่า "สวัสดี" นั่นเอง) ก็จะเป็นการเรียกใช้งาน intent นี้


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

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


          ในส่วนของ Events ให้พิมพ์ actions_intent_PERMISSION ลงไป เพื่อให้ intent นี้ถูกเรียกใช้งานเมื่อเกิด event ผู้ใช้งานตอบคำขอเข้าถึงข้อมูลของ Action


          ในส่วนของ Fulfillment ที่อยู่ข้างล่างก็ให้คลิกเบา ๆ เพื่อเปิดการเรียกใช้งาน webhook ซะ แล้วคลิกปุ่ม SAVE

เขียนโค้ด


          หลังจากที่เราสร้าง intent ที่ต้องใช้ครบตามที่ต้องการแล้ว ขั้นตอนถัดไปก็จะเป็นการเขียนโค้ดให้ Actions ทำงาน ในส่วนนี้ผมจะเขียนโค้ดที่ Inline Editor เนื่องจากโค้ดไม่ยาว และไม่ได้มีการทำงานซับซ้อนอะไร .....คลิกที่เมนู Fulfillment ที่อยู่ในเมนูด้านซ้ายมือ


          คลิกเปิดการใช้งาน Inline Editor พื้นที่สำหรับเขียนโค้ดข้างล่างก็จะพร้อมใช้งาน จากนั้นก็ก๊อปปี้โค้ดด้านล่างไปใส่ทับโค้ดเก่า

'use strict';

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

// กำหนดให้ intent 'request_permission' ทำการร้องขอสิทธิ์เข้าถึงข้อมูลของผู้ใช้งาน
app.intent('request_permission', (conv) => {
    const options = {
      // ข้อความเพิ่มเติมที่จะแจ้งผู้ใช้งาน
      context: 'เพื่อทำการทดสอบ Action',
      // ข้อมูลที่ต้องการจะขอ
      permissions: ['NAME', 'DEVICE_PRECISE_LOCATION'],
    };
    conv.ask(new Permission(options));
      
});

// กำหนดให้ intent 'handle_permission' ตอบกลับเมื่อผู้ใช้งานให้/ไม่ให้สิทธิ์เข้าถึงข้อมูล
app.intent('handle_permission', (conv, params, confirmationGranted) => {
    const {name} = conv.user;
    const {coordinates} = conv.device.location;
    
    if (confirmationGranted) {
      if (name && coordinates) {
        conv.close(`ขอบคุณค่ะ คุณ${name.display} พิกัดที่คุณอยู่คือ (${coordinates.latitude}, ${coordinates.longitude}) ขอให้มีความสุขนะคะ`);
      } else {
        conv.close(`ไม่พบชื่อหรือพิกัดของคุณ กรุณาตั้งชื่อหรือเปิด GPS ก่อน`);
      }
    } else {
      conv.close(`เสียใจจัง ชั้นไม่สามารถเข้าถึงข้อมูลของคุณได้ เอาไว้ค่อยกลับมาใช้บริการใหม่นะคะ บ๊ายบายค่ะ`);
    }
});

// Set ให้ DialogflowApp object จัดการ HTTPS POST request.
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
          คลิกปุ่ม DEPLOY เพื่อใช้งานโค้ดปัจจุบัน ซึ่ง Dialogflow จะใช้เวลาในการ deploy สักครู่ ระหว่างที่รอระบบ deploy อยู่ เรามาทบทวนการทำงานของ Actions นี้กันเถอะ เริ่มจากเมื่อผู้ใช้เรียกใช้งาน Actions แล้ว
  • Action จะทักทายผู้ใช้งานว่า "สวัสดีค่ะ นี่เป็น Action สำหรับขอสิทธิ์การเข้าถึงข้อมูล"
  • เมื่อ User ทักทายตอบกลับว่า "สวัสดี" Action ก็จะขอสิทธิ์การเข้าถึงข้อมูลด้วยการถามว่า "จะต้องใช้ชื่อและตำแหน่งปัจจุบันของคุณจาก Google {ข้อความเพิ่มเติมจากในโค้ด} ตกลงมั้ยคะ" แต่ถ้า User พูดคำอื่น Action ก็จะงง ๆ ไม่เข้าใจที่ User พูด (เนื่องจากไปตกที่ Default Fallback Intent ก็จะใช้ข้อความ Response ใน intent นั้น ๆ)
  • ในกรณีที่ Action ร้องขอสิทธิ์ แล้ว User ตอบกลับว่า "โอเค" Action ก็จะพูดกลับว่า "ขอบคุณค่ะ คุณ{ชื่อ} พิกัดที่คุณอยู่คือ ({ละติจูด}, {ลองติจูด}) ขอให้มีความสุขนะคะ" แต่กรณีที่ User ตอบปฏิเสธการเข้าถึงข้อมูล Action ก็จะตอบว่า "เสียใจจัง ชั้นไม่สามารถเข้าถึงข้อมูลของคุณได้ เอาไว้ค่อยกลับมาใช้บริการใหม่นะคะ บ๊ายบายค่ะ" แล้วก็จบการสนทนาไป
          หลังจาก deploy เสร็จแล้ว ก็ให้กลับไปหน้า Actions Console คลิกที่เมนู Simulator ถึงตรงนี้เราจะยังทดสอบ Actions ไม่ได้ เนื่องจากเราตั้งค่าให้ Actions ทำงานกับภาษาไทย แต่ใน Simulator ยังเป็นภาษาอังกฤษอยู่ เพราะฉะนั้นเราก็เปลี่ยนภาษาของ Simulator ซะก็สิ้นเรื่อง


          แก้ไขภาษาและตำแหน่งที่อยู่ให้เป็นไทยก่อน เมื่อคลิกปุ่ม START TESTING เพื่อเริ่มทำการทดสอบก็จะมีป๊อปอัพ Start testing your Actions ขึ้นมาให้เราเลือกเวอร์ชันที่จะทดสอบ แต่เนื่องจากตอนนี้มีอยู่เวอร์ชันเดียว งั้นก็ไม่ต้องไปสนใจ คลิกปุ่ม DONE ไปเลย


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


วันพุธที่ 11 กรกฎาคม พ.ศ. 2561

สร้าง Actions on Google ให้เชื่อมต่อกับ API เพื่อเพิ่มความสามารถในการโต้ตอบ


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

สร้างบทสนทนาตอบกลับ


          ก่อนจะเชื่อมต่อ API เรามาแก้ไขรายละเอียดอะไรบางอย่างในตอนท้ายของบทความที่แล้วกันดีกว่า เข้าไปที่ Dialogflow Console กันเล้ยยยยย


          เข้าไปที่เมนู Intents แล้วคลิกที่ Welcome Response Intent ในส่วนของ Text response ให้แก้ไขข้อความเป็น "ดีใจที่ได้ยินเช่นนั้นค่ะ ว่าแต่วันนี้คุณใส่เสื้อสีอะไรเหรอคะ" แล้วคลิกปุ่ม SAVE


          คลิกปุ่ม + ข้าง ๆ เมนู Intents เพื่อสร้าง Intent ขึ้นมาใหม่ และกรอกชื่อว่า Your Color Intent โดยจะมีส่วนที่เราต้องกรอกรายละเอียดเพิ่ออีก 3 ส่วน ได้แก่ Training phrases, Action and parameters และ Fulfillment


          ในส่วน Training phrases ให้ใส่คำว่า "สีแดง", "แดง", "สีแดงครับ", "เสื้อสีแดง" และ"เสื้อสีแดงครับ" ซึ่งเพื่อน ๆ จะสังเกตเห็นว่าตอนที่ใส่คำทีละคำ จะมีไฮไลท์สีเหลืองขึ้นที่คำว่า "สีแดง" ให้โดยอัตโนมัติ และจะมีการใส่ค่า Entity ในส่วนของ Action and parameters ให้เอง..... Entity คืออะไรน่ะเหรอ? Entity ก็คือประเภทของสิ่งต่าง ๆ ซึ่ง Dialogflow จะใช้เพื่อดึงค่าตัวแปรออกมาจากข้อความของผู้ใช้


          ในส่วนของ Fulfillment คลิกเปิดให้ intent นี้มีการเรียกใช้งาน webhook ซึ่งเป็นที่เก็บโค้ดสำหรับประมวลผลและสร้างข้อความโต้ตอบแบบไดนามิก โดยเพื่อน ๆ สามารถสร้าง webhook ได้ 2 วิธี
  1. สร้างภายใน Dialogflow ผ่านเมนู Inline Editor
  2. สร้างที่ Server ภายนอก จากนั้นนำ url มาใส่ให้ Dialogflow
          เมื่อเปิดการเรียกใช้งาน webhook เรียบร้อยแล้วให้คลิกปุ่ม SAVE ซึ่งในขั้นตอนต่อไป เราจะมาทำการสร้าง webhook และเขียนโค้ดเพื่อประมวลผลข้อความของผู้ใช้ ซึ่งผมจะอธิบายวิธีการสร้าง webhook โดยแบ่งออกเป็น 2 วิธี ได้แก่ สร้าง Webhook บน Inline Editor และ สร้าง Webhook บน Cloud Functions for Firebase

สร้าง Webhook บน Inline Editor


          วิธีนี้จะเป็นการสร้าง webhook ภายใน Dialogflow ซึ่งถือเป็นวิธีสร้าง webhook ที่ง่าย เนื่องจากเราไม่จำเป็นต้องติดตั้งอะไรลงบนเครื่องของเรา โดยวิธีสร้างให้คลิกที่เมนู Fulfillment ที่อยู่ในเมนูด้านซ้ายมือ


          คลิกเปิดการใช้งาน Inline Editor จากนั้นก็ก๊อปปี้โค้ดด้านล่างไปใส่

'use strict';

// Import the Dialogflow module from the Actions on Google client library.
const {dialogflow} = require('actions-on-google');
// Import the firebase-functions package for deployment.
const functions = require('firebase-functions');
// Instantiate the Dialogflow client.
const app = dialogflow({debug: true});


app.intent('Your Color Intent', conv => {
    const userColor = conv.parameters.color;
    // ตอบแล้วยังไม่จบการสนทนา
    //conv.ask('เลขนำโชคสำหรับ' + userColor+'คือ '+userColor.length);
    // ตอบแล้วจบการสนทนาทันที
    conv.close('เลขนำโชคสำหรับ' + userColor+'คือ '+userColor.length);
});

// Set the DialogflowApp object to handle the HTTPS POST request.
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
          ถ้าใช้ conv.ask() บทสนทนาจะยังไม่จบ แต่ถ้าใช้ conv.close() บทสนทนาจะจบทันที จากนั้นให้คลิกปุ่ม DEPLOY เพื่อใช้งานโค้ดปัจจุบัน และจะใช้เวลาในการ deploy สักครู่ ระหว่างรอ Dialogflow ทำการ deploy เรามาทำความเข้าใจโค้ดกันสักนิด

          โค้ดที่ใช้ใน webhook จะเขียนด้วยภาษา Javascript และเรียกใช้งาน Actions on Google Node.js client library เพื่อตอบกลับ HTTP requests ที่ Google Assistant ส่งมาที่ webhook ซึ่ง conv.parameters จะเก็บตัวแปรที่มาจาก Entity โดย color มาจากชื่อ Parameter Name ที่ประกาศไว้ใน Entity

          Inline editor ของ Dialogflow จะ deploy โค้ดของ webhook บน Cloud Functions for Firebase ซึ่งเป็น cloud service ของ Google


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

สร้าง Webhook บน Cloud Functions for Firebase


          วิธีนี้จะเป็นการเขียนโค้ดลงในเครื่องของเรา จากนั้นก็จะ deploy ขึ้นไปบน Cloud Functions for Firebase ซึ่งวิธีนี้จะต้องใช้ Node Package Manager หรือ npm ที่เป็นตัวจัดการแพ็คเกจเสริมต่าง ๆ ในการติดตั้งแพ็คเกจ firebase-tools โดยเจ้าตัว npm นี้จะถูกติดตั้งมาพร้อมกับ Node.js เพราะงั้นอันดับแรกเราก็มาติดตั้ง Node.js กันก่อน

วิธีติดตั้ง Node.js


          ให้เข้าไปที่ Nodejs.org แล้วเลือกตัวติดตั้งตามที่เพื่อน ๆ ต้องการ


          เมื่อโหลดตัวติดตั้งเสร็จแล้วก็อย่ารอช้า กดติดตั้งโลด หลังจากติดตั้งเสร็จก็ให้เปิด Command Prompt (สำหรับ Window) หรือ Terminal (สำหรับ Mac) ขึ้นมาแล้วพิมพ์คำสั่ง

node -v
          ถ้าหาก Command Prompt (หรือ Terminal) แสดงเลขเวอร์ชันของ Node.js ขึ้นมา ก็แปลว่าเราได้ติดตั้ง Node.js เสร็จเรียบร้อยแล้ว อันดับถัดไปเราจะต้องติดตั้ง Firebase Command Line Interface (CLI) ให้พิมพ์คำสั่ง

npm -g install firebase-tools
          เราสามารถเช็คว่าติดตั้ง Firebase CLI สำเร็จหรือไม่ ได้โดยการพิมพ์คำสั่ง

firebase --version
          อันดับถัดไปให้ทำการ Login Firebase CLI โดยการพิมพ์

firebase login


          Command Prompt (หรือ Terminal) จะเปิดเว็บบราวน์เซอร์ขึ้นมา ให้เพื่อน ๆ login Account ของ Google


          เมื่อ login แล้ว ก็จะเจอหน้า Firebase CLI ขอสิทธิ์การเข้าถึง Google Account ให้คลิกปุ่ม ALLOW



          เสร็จเรียบร้อยแล้วก็ปิดเว็บบราวน์เซอร์ได้เลย จากนั้นให้สร้างโฟลเดอร์ที่จะเก็บโปรเจค แล้วย้ายเข้าไปยังโฟลเดอร์นั้น

mkdir test-action
cd test-action
          จากนั้นก็ทำการ init ตัว Cloud Functions for Firebase ด้วยคำสั่ง

firebase init functions

          Command Prompt (หรือ Terminal) จะแสดงตัวเลือกให้เลือกโปรเจคที่เราต้องการจะใช้งาน (ตามตัวอย่างผมจะเลือกโปรเจค test-action) จากนั้นก็กดปุ่ม enter แล้ว Firebase CLI จะแสดงคำถามขึ้นมาให้เลือกอีก 3 คำถาม ได้แก่
  • โปรเจคจะใช้ภาษา Javascript หรือ TypeScript (ตามตัวอย่างผมใช้ JavaScript)
  • โปรเจคจะใช้ ESLint เพื่อตรวจสอบ bug และ code style หรือไม่ (ตามตัวอย่างผมเลือก Yes)
  • ต้องการให้ติดตั้ง dependencies ทันทีเลยหรือไม่ (ตอบ Y ไปเล้ยยยยย)
          เมื่อเลือกคำตอบครบเรียบร้อยแล้วก็รอให้ Firebase CLI ทำการ Initial โปรเจคขึ้นมา .....หลังจาก Initial เสร็จแล้ว ไฟล์ที่เราต้องใช้งานคือไฟล์ index.js ที่อยู่ในโฟลเดอร์ functions แต่ก่อนจะเปิดไฟล์ index.js ให้เข้าไปยังโฟลเดอร์ functions แล้วทำการติดตั้ง Actions on Google Node.js client library ด้วยคำสั่ง

cd functions
npm install actions-on-google
          ต่อไปให้เปิดไฟล์ firebase.json ขึ้นมา ลบคำสั่งที่อยู่ในนั้นทั้งหมด แล้วก๊อปปี้คำสั่งข้างล่างลงไปแทน

{
  "functions": {
    "predeploy": [
    ]
  }
}
          อันดับถัดไปให้เปิดไฟล์ index.js ขึ้นมา แล้วก๊อปปี้โค้ดข้างล่างไปวางไว้ในไฟล์ index.js

'use strict';

// Import the Dialogflow module from the Actions on Google client library.
const {dialogflow} = require('actions-on-google');
// Import the firebase-functions package for deployment.
const functions = require('firebase-functions');
// Instantiate the Dialogflow client.
const app = dialogflow({debug: true});


app.intent('Your Color Intent', conv => {
    const userColor = conv.parameters.color;
    // ตอบแล้วยังไม่จบการสนทนา
    //conv.ask('เลขนำโชควันนี้สำหรับ' + userColor+'คือ '+userColor.length);
    // ตอบแล้วจบการสนทนาทันที
    conv.close('เลขนำโชควันนี้สำหรับ' + userColor+'คือ '+userColor.length);
});

// Set the DialogflowApp object to handle the HTTPS POST request.
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
          เสร็จแล้วก็ใช้คำสั่ง deploy เพื่อส่งโค้ดที่เพิ่งเขียนขึ้นไป deploy บน Cloud Functions for Firebase ด้วยคำสั่ง

firebase deploy
          รอสักครู่จน Command Prompt (หรือ Terminal) แสดงข้อความว่า "Deploy complete!" จากนั้นให้เราเข้าไปยังเมนู Fulfillment ของ Dialogflow Console เพื่อตั้งค่า webhook ใหม่


          คลิกเปิดการใช้งานในส่วน Webhook ซึ่งจะมีป๊อปอัพขึ้นมาถามยืนยันว่า "ถ้าเปิดการใช้งานในส่วนนี้ จะปิดการใช้งานของ Inline Editor" ให้คลิกปุ่ม YES ไปได้เลย จะสังเกตได้ว่า Dialogflow มีการใส่ค่าในช่อง URL มาให้โดยอัตโนมัติ ซึ่งเป็นผลจากการเลือกโปรเจคในตอนที่ Initial โปรเจค (โปรเจค test-action) เพียงเท่านี้ก็เสร็จสิ้นการ deploy โค้ดตัวใหม่เรียบร้อยแล้ว ไปทดสอบกันโล้ด


          พอกลับไปทดสอบการทำงานใน Actions Console จะเห็นได้ว่า Actions มีการทำงานแบบเดียวกับตอนที่ใช้ webhook บน Inline Editor แต่ต่างกันเล็กน้อยที่ประโยคตอบกลับ (ตรง "เลขนำโชควันนี้สำหรับ.....") ซึ่งข้อดีของการสร้าง Webhook บน Cloud Functions for Firebase นั่นก็คือ เราสามารถใช้งาน JavaScript Library ตัวอื่นเสริมได้ด้วย ซึ่งจะเพิ่มประสิทธิภาพในการเขียนโค้ดนั่นเอง

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