สร้าง Python Chatbot ร่วมกับ Line, Dialogflow, Flask, Heroku - Ep.2

Python Line Chatbot Ep.2 เชื่อมต่อ Line SDK กับ Flask และ Dialogflow พร้อมทดสอบ Bot บน NGROK

สร้าง Python Chatbot ร่วมกับ Line, Dialogflow, Flask,  Heroku - Ep.2

สำหรับ Ep.2 เราจะมาเริ่มพัฒนา Chatbot ของเราให้เจ๋งขึ้นไปอีกขั้น ด้วยการเชื่อมต่อ W****ebhookกับ LINE Bot SDKสำหรับ Python โดยการทำงานคร่าว ๆ ของ webhook นั้นเราจะทำการเชื่อม webhook ของ LINE Messaging API ไปให้กับ Dialogflow แล้วจากนั้น ก็เชื่อม webhook ของ Dialogflow ไปยัง Back-end ที่เราสร้างขึ้นมาเองโดยใช้ Flask web framework ของ Python เป็นตัวรับ request จาก Dialogflow แล้วนำ data ต่าง ๆ ที่ได้มาใช้ไปงานกับ LINE Bot SDK เท่านี้เราก็สามารถเขียน code เชื่อมต่อฐานข้อมูล API และ service อื่น ๆ ได้อย่างอิสระมากขึ้น

บทความแนะนำ

สร้าง Python (Flask) โปรเจคท์และเชื่อมต่อกับ Line Bot SDK

Step 1>>

มาเริ่มต้นกันเลยจาก Ep.1 เราได้ทำการเชื่อมต่อ Dialogflow กับ LINE Messaging API เรียบร้อย โดยเราได้ให้ตัว Dialogflow เป็นตัว Responses หรือตอบกลับเท่านั้น หากเราต้องการทำตัว Responses หรือตอบกลับเอง เราต้องทำการเปิด webhook ให้ Dialogflow ก่อน ขั้นแรกให้เราเตรียมสร้างโปรเจคท์โดยใช้ Flask web framework ของ python เป็นตัวรับ request จาก dialogflow ก่อนศึกษา Flask เพิ่มเติมได้ที่นี่ได้เลยครับ

https://stackpython.co/tutorial/django-flask-medium-stackpython

ให้เราสร้างโปรเจคท์ Python และติดตั้ง library Flask กับ Line Bot SDK ของ Python ให้เรียบร้อยและเตรียม Channel secret / Channel access token ไว้ด้วย (จาก Ep.1) ดู document เพิ่มเติมของ Line Bot SDK ได้ที่

https://github.com/line/line-bot-sdk-python

เริ่มต้นสร้างโปรเจคท์และวางโครงสร้างก่อนโดยการเขียน code ตามนี้ได้เลย

from flask import Flask, request
from linebot import *

app = Flask(__name__)

line_bot_api = LineBotApi('xxxxxx')
handler = WebhookHandler('xxxxxx')

@app.route("/callback", methods=['POST'])
def callback():
    body = request.get_data(as_text=True)
    print(body)
    return 'OK'

if __name__ == "__main__":
    app.run()

ถ้า RUN ได้ตามนี้ก็ถือว่าผ่าน

ใช้งาน NGROK

Step 2>>

จากนั้นการที่เราจะทำให้ localhost ของเราสามารถออนไลน์ได้ เราจำเป็นต้องใช้โปรแกรมช่วยในที่นี้เราจะใช้ NGROK สามารถดาวน์โหลดได้ที่นี่เลย https://ngrok.com/download

ดาวน์โหลดเสร็จแล้วกดเปิดขึ้นมาให้พิมพ์ ngrok http 5000

จะได้หน้าตาประมาณนี้ก็ถือว่าสำเร็จแล้ว

Step 3>>

ให้เราทำการ copy บรรทัด Forwarding เอาไว้

DialogFlow Fulfillment and Webhook

Step 4>>

จากนั้นให้เราไปที่ Dialogflow ของเรา https://dialogflow.cloud.google.com

กดไปที่ Fulfillment และกดเปิด webhook ได้เลย

Step 5>>

ให้เรานำ URL ทีได้จาก Forwarding ใน Ngrok มาใส่ในนี้ได้เลย แล้วให้ใส่ /callback ปิดท้าย แล้วกด SAVE ก็เป็นอันเสร็จ

Intent and Training Phrases

Step 6>>

ต่อไปเราจะมาทดสอบกันให้เราสร้าง intent ขึ้นมา 1 intent โดยในตัวอย่างผมจะตั้งชื่อว่า intent 5 และมีการ Training ไว้ว่า “ทดสอบ”

ให้เลื่อนลงมาในส่วนของ Responses นั้นปกติเราจะใส่คำให้ Dialogflow ตอบกลับไปครั้งนี้เราจะไม่ทำแบบนั้นให้กดไปที่ Fulfillment แล้วกด เปิด Enable webhook call for this intent ตามภาพได้เลย เพื่อเป็นการทำให้ intent นี้เชื่อมต่อกับ webhook ที่เราผูกไว้

เสร็จแล้วกด SAVE จากนั้นไปทดสอบกัน

ทดสอบ Line Bot

จะเห็นว่า Chatbot ของเราจะไม่มีการตอบกลับมา ไม่ต้องตกใจเพราะว่าเราได้ทำการผูก webhook ไปยัง Flask หรือโปรเจคท์ของเรานั่นเอง โดยให้ไปกลับไปดูที่โปรเจคท์ของเรา

จะเห็นว่ามีการส่ง request เข้ามาใน route /callback ของเรา ซึ่งหากขึ้นตามนี้ก็ถือว่าโอเครครับ

Step 8>>

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

@app.route("/callback", methods=['POST'])
def callback():
    body = request.get_data(as_text=True)
    # print(body)
    req = request.get_json(silent=True, force=True)
    intent = req["queryResult"]["intent"]["displayName"]
    text = req['originalDetectIntentRequest']['payload']['data']['message']['text']
    reply_token = req['originalDetectIntentRequest']['payload']['data']['replyToken']
    id = req['originalDetectIntentRequest']['payload']['data']['source']['userId']
    disname = line_bot_api.get_profile(id).display_name
    
    print('id = ' + id)
    print('name = ' + disname)
    print('text = ' + text)
    print('intent = ' + intent)
    print('reply_token = ' + reply_token)

    return 'OK'

reply

token

reply token คือตัวที่จะให้เราสามารถตอบกลับไปยังผู้ใช้งานได้แบบ 1 NO 1 ซึ่งจะเป็นการตอบกลับเมื่อผู้ใช้งานมีการส่งข้อความมายัง Chatbot ของเราเท่านั้นเมื่อเราต้องการตอบกลับไป เราต้องผูก reply token กลับไปด้วยเพื่อให้ Chatbot ของเราสามารถตอบกลับได้อย่างถูกต้องโดย LINE Mressaging API นั้นสามารถส่งข้อความได้ 4 แบบคือ

1. 1 NO 1

คือการส่งข้อความแบบ ถามมา-ตอบกลับ จำเป็นต้องมี reply token ทุกครั้งในการตอบกลับ ซึ่งเป็นการส่งข้อความแบบฟรี

2. Push

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

3. Multicast

จะเหมือนกับ Push ทุกอย่างแต่สามารถส่งได้พร้อมกันหลาย id


4. Broadcast

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

Step 9>>

ต่อไปเราจะมาทำให้ Line Bot SDK ของเราสามารถตอบกลับไปยังผู้ใช้งานได้กัน

เริ่มต้นให้เราสร้างฟังก์ชันขึ้นมาก่อนโดยผมจะสร้างฟังก์ชันชื่อว่า reply และการมีการส่งค่าของ

 intent/text/reply_token/id/disname

เข้าไปเพื่อใช้งาน และให้ทำการเพิ่ม

from linebot.models import *

เข้ามาด้วย จากนั้นในฟังก์ชัน reply ผมก็ทำการเช็คค่า intent ที่ส่งมาว่าชื่อ ‘intent 5’ หรือไม่ ถ้าใช่ก็จะใช้ Line Bot SDK ส่งคำตอบพร้อม reply_token กลับไปว่า ‘ทดสอบสำเร็จ’

from flask import Flask, request
from linebot.models import *
from linebot import *

app = Flask(__name__)

line_bot_api = LineBotApi('xxxxxxxx')
handler = WebhookHandler('xxxxxxxx')

@app.route("/callback", methods=['POST'])
def callback():
    body = request.get_data(as_text=True)
    # print(body)
    req = request.get_json(silent=True, force=True)
    intent = req["queryResult"]["intent"]["displayName"]
    text = req['originalDetectIntentRequest']['payload']['data']['message']['text']
    reply_token = req['originalDetectIntentRequest']['payload']['data']['replyToken']
    id = req['originalDetectIntentRequest']['payload']['data']['source']['userId']
    disname = line_bot_api.get_profile(id).display_name

    print('id = ' + id)
    print('name = ' + disname)
    print('text = ' + text)
    print('intent = ' + intent)
    print('reply_token = ' + reply_token)

    reply(intent,text,reply_token,id,disname)

    return 'OK'


def reply(intent,text,reply_token,id,disname):
    if intent == 'intent 5':
        text_message = TextSendMessage(text='ทดสอบสำเร็จ')
        line_bot_api.reply_message(reply_token,text_message)

if __name__ == "__main__":
    app.run()

มาทดสอบกันเลย

Job Done !!

ทำ Workshop เช็คยอดผู้ติดเชื้อ Covid-19

ทีนี้เราจะลองมาทำ workshop เล็กๆน้อยๆกันเป็น workshop ในการเช็คยอดผู้ติดเชื้อ Covid19

เริ่มต้นเช่นเคยไปที่ https://dialogflow.cloud.google.com/https://dialogflow.cloud.google.com/

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

สร้าง intent ชื่อ covid 19 และ Training ให้เรียบร้อยพร้อมเปิด Fulfillment กด SAVE ให้เรียบร้อย

กลับมาที่ โปรเจคของเราทำการเขียน code เพื่อดึง API จากกรมควบคุมโรค กระทรวงสาธารณสุขได้เลย

จากนั้นทำการ import json และ import requests เข้ามาด้วยเพื่อทำการดึงข้อมูลจาก API กรมควบคุมโรค

และแปลงเป็น JSON

import json
import requests

จากนั้นมาเขียนฟังก์ชันกันเลย

from flask import Flask, request
from linebot.models import *
from linebot import *
import json
import requests

app = Flask(__name__)

line_bot_api = LineBotApi('xxxxxxxx')
handler = WebhookHandler('xxxxxxxx')

@app.route("/callback", methods=['POST'])
def callback():
    body = request.get_data(as_text=True)
    # print(body)
    req = request.get_json(silent=True, force=True)
    intent = req["queryResult"]["intent"]["displayName"] 
    text = req['originalDetectIntentRequest']['payload']['data']['message']['text'] 
    reply_token = req['originalDetectIntentRequest']['payload']['data']['replyToken']
    id = req['originalDetectIntentRequest']['payload']['data']['source']['userId']
    disname = line_bot_api.get_profile(id).display_name

    print('id = ' + id)
    print('name = ' + disname)
    print('text = ' + text)
    print('intent = ' + intent)
    print('reply_token = ' + reply_token)
    
    reply(intent,text,reply_token,id,disname)

    return 'OK'
    
    
def reply(intent,text,reply_token,id,disname):
    if intent == 'covid 19':
        data = requests.get('https://covid19.th-stat.com/api/open/today')
        json_data = json.loads(data.text)
        Confirmed = json_data['Confirmed']  # ติดเชื้อสะสม
        Recovered = json_data['Recovered']  # หายแล้ว
        Hospitalized = json_data['Hospitalized']  # รักษาอยู่ใน รพ.
        Deaths = json_data['Deaths']  # เสียชีวิต
        NewConfirmed = json_data['NewConfirmed']  # บวกเพิ่ม
        text_message = TextSendMessage(
            text='ติดเชื้อสะสม = {} คน(+เพิ่ม{})\nหายแล้ว = {} คน\nรักษาอยู่ใน รพ. = {} คน\nเสียชีวิต = {} คน'.format(
                Confirmed, NewConfirmed, Recovered, Hospitalized, Deaths))

        line_bot_api.reply_message(reply_token, text_message)

if __name__ == "__main__":
    app.run()

มาทำการทดสอบกัน

เรียบร้อย!! เท่านี้เราก็ได้ Chatbot ไว้เช็คยอดผู้ติดเชื้อ Covid 19 แบบง่ายๆ แล้ว และนี้คือตัวอย่างข้อดีของการใช้ Line Bot SDK ทำ Webhook เอง ซึ่งทำให้เรา เพิ่มความสามารถให้กับ Chatbot ได้อย่างมาก ซึ่งแน่นอนว่านอกจาก TEXT Message แล้วยังสามารถตอบกลับผู้ใช้งานในรูปแบบอื่นได้อีกด้วยโดย Line Bot SDK ได้ทำ Objects มาให้เราใช้งานไว้เรียบร้อยเรียบแล้วไม่ว่าจะเป็น

Image


image_message = ImageSendMessage(
    original_content_url='https://example.com/original.jpg',
    preview_image_url='https://example.com/preview.jpg'
)

Video


video_message = VideoSendMessage(
    original_content_url='https://example.com/original.mp4',
    preview_image_url='https://example.com/preview.jpg'
)

Audio


audio_message = AudioSendMessage(
    original_content_url='https://example.com/original.m4a',
    duration=240000
)

Location


location_message = LocationSendMessage(
    title='my location',
    address='Tokyo',
    latitude=35.65910807942215,
    longitude=139.70372892916203
)

และยังมี Template Send Message อีกหลายตัวที่เราจะได้เรียนรู้กันใน EP ถัดๆไป หรือสามารถดู document เพิ่มเติมของ Line Bot SDK ได้ที่ https://github.com/line/line-bot-sdk-python

สำหรับ EP.2 เราก็ขอจบลงเพียงเท่านี้ก่อนไว้พบกัน EP.3 กันต่อซึ่งจะเป็น Ep สุดท้ายกันแล้วสำหรับซีรีย์ Python Line Chatbot โดยจะทำการ Deploy Chatbot App ของเราไปที่ Heroku กันครับ

ถ้าชื่นชอบบทความนี้ ซัพพอร์ตเราได้โดยการกด Response หรือคอมเมนต์ด้านล่างบทความนี้ได้เลยนะครับ ขอบคุณครับ