自動回覆訊息
順利將 LINE BOT 串接 Webhook 後,就能透過 LINE Message API 開發聊天機器人,這篇教學會介紹回覆訊息的方法,並使用 Colab + bgrok 實做一個會自動回覆客製化訊息、表情貼圖、圖片、影片以及地址的 LINE BOT 聊天機器人,最後再將機器人部署到 Google Cloud Functions。
建議先閱讀:
快速導覽:
什麼是 reply token?
不論 LINE BOT 接收那種類型的訊息,回覆訊息都是使用 reply_message 方法進行回覆,reply_message 方法包含一個 reply token 的參數,表示訊息要回覆到哪裡,一個 reply token 只會在接收到訊息時產生一次,如果回覆過的訊息需要再次回覆,則需要再度接收訊息才能回覆,如果要多次主動推播訊息,則需使用 push message 的方式處理。
回覆文字訊息
使用 reply_message 的「TextSendMessage」方法 ( 需要 import ),能夠回覆文字訊息,相關參數如下:
參數 | 說明 |
---|---|
text | 要回覆的文字 ( 不論放入什麼內容都會被轉換成文字 )。 |
使用下方的程式碼執行後,使用者輸入了什麼訊息,LINE BOT 就會回覆一模一樣的文字訊息。
注意,如果是 ngrok 產生的網址,每次重新執行就要再進入 LINE Developer 更新 Webhook。
from flask import Flask, request
from pyngrok import ngrok # Colab 使用,本機環境不需要
# 載入 LINE Message API 相關函式庫
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage
import json
app = Flask(__name__)
# Colab 使用,本機環境不需要下面三行
port = "5000"
public_url = ngrok.connect(port).public_url
print(f" * ngrok tunnel \"{public_url}\" -> \"http://127.0.0.1:{port}\" ")
@app.route("/", methods=['POST'])
def linebot():
body = request.get_data(as_text=True) # 取得收到的訊息內容
try:
json_data = json.loads(body) # json 格式化訊息內容
access_token = '你的 access token'
secret = '你的 Channel secret'
line_bot_api = LineBotApi(access_token) # 確認 token 是否正確
handler = WebhookHandler(secret) # 確認 secret 是否正確
signature = request.headers['X-Line-Signature'] # 加入回傳的 headers
handler.handle(body, signature) # 綁定訊息回傳的相關資訊
msg = json_data['events'][0]['message']['text'] # 取得 LINE 收到的文字訊息
tk = json_data['events'][0]['replyToken'] # 取得回傳訊息的 Token
line_bot_api.reply_message(tk,TextSendMessage(msg)) # 回傳訊息
print(msg, tk) # 印出內容
except:
print(body) # 如果發生錯誤,印出收到的內容
return 'OK' # 驗證 Webhook 使用,不能省略
if __name__ == "__main__":
app.run()
回覆表情貼圖
使用 reply_message 的「StickerSendMessage」方法 ( 需要 import ),能夠回覆表情貼圖,相關參數如下:
參數 | 說明 |
---|---|
package_id | 表情貼圖所在群組 ID。 |
sticker_id | 表情貼圖 ID。 |
LINE BOT 預設的表情貼圖只有 LINE 官方所提供的貼圖,支援的表情貼圖參考:List of available stickers。
下方的程式碼執行後,當使用者傳送了表情貼圖,LINE BOT 就會回覆一模一樣的表情貼圖 ( 限制為官方預設的表情貼圖 )。
注意,如果是 ngrok 產生的網址,每次重新執行就要再進入 LINE Developer 更新 Webhook。
from flask import Flask, request
from pyngrok import ngrok # Colab 使用,本機環境不需要
# 載入 LINE Message API 相關函式庫
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage, StickerSendMessage
# 注意,有載入 StickerSendMessage 模組
import json
app = Flask(__name__)
# Colab 使用,本機環境不需要下面三行
port = "5000"
public_url = ngrok.connect(port).public_url
print(f" * ngrok tunnel \"{public_url}\" -> \"http://127.0.0.1:{port}\" ")
@app.route("/", methods=['POST'])
def linebot():
body = request.get_data(as_text=True) # 取得收到的訊息內容
try:
json_data = json.loads(body) # json 格式化訊息內容
access_token = '你的 access token'
secret = '你的 channel secret'
line_bot_api = LineBotApi(access_token) # 確認 token 是否正確
handler = WebhookHandler(secret) # 確認 secret 是否正確
signature = request.headers['X-Line-Signature'] # 加入回傳的 headers
handler.handle(body, signature) # 綁定訊息回傳的相關資訊
tk = json_data['events'][0]['replyToken'] # 取得回傳訊息的 Token
stickerId = json_data['events'][0]['message']['stickerId'] # 取得 stickerId
packageId = json_data['events'][0]['message']['packageId'] # 取得 packageId
sticker_message = StickerSendMessage(sticker_id=stickerId, package_id=packageId) # 設定要回傳的表情貼圖
line_bot_api.reply_message(tk, sticker_message) # 回傳訊息
except:
print(body) # 如果發生錯誤,印出收到的內容
return 'OK' # 驗證 Webhook 使用,不能省略
if __name__ == "__main__":
app.run()
回覆圖片或影片訊息
使用 reply_message 的「ImageSendMessage」或「VideoSendMessage」方法 ( 需要 import ),能夠回覆圖片或影片,相關參數如下:
參數 | 說明 |
---|---|
original_content_url | 原始圖片或影片網址。 |
preview_image_url | 縮圖網址。 |
下方的程式碼執行後,當使用者傳送了某個文字,LINE BOT 就會回覆跟這個文字有關的圖片 ( 先建立好圖片網址和文字對照的字典,圖片來源是維基百科 ),如果找不到文字對應的圖片,就會回傳「找不到相關圖片」。
注意,如果是 ngrok + Colab 產生的網址,每次重新執行就要再進入 LINE Developer 更新 Webhook。
from flask import Flask, request
from pyngrok import ngrok # Colab 環境需要,本機環境不需要
# 載入 LINE Message API 相關函式庫
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage, StickerSendMessage, ImageSendMessage
# 注意,有載入 ImageSendMessage 模組
import json
app = Flask(__name__)
# Colab 環境需要下面這三行,本機環境不需要
port = "5000"
public_url = ngrok.connect(port).public_url
print(f" * ngrok tunnel \"{public_url}\" -> \"http://127.0.0.1:{port}\" ")
@app.route("/", methods=['POST'])
def linebot():
body = request.get_data(as_text=True) # 取得收到的訊息內容
try:
json_data = json.loads(body) # json 格式化訊息內容
access_token = '你的 access token'
secret = '你的 channel secret'
line_bot_api = LineBotApi(access_token) # 確認 token 是否正確
handler = WebhookHandler(secret) # 確認 secret 是否正確
signature = request.headers['X-Line-Signature'] # 加入回傳的 headers
handler.handle(body, signature) # 綁定訊息回傳的相關資訊
tk = json_data['events'][0]['replyToken'] # 取得回傳訊息的 Token
msg = json_data['events'][0]['message']['text']
if msg == '皮卡丘':
# 如果有圖片網址,回傳圖片
img_url = 'https://upload.wikimedia.org/wikipedia/en/a/a6/Pok%C3%A9mon_Pikachu_art.png'
img_message = ImageSendMessage(original_content_url=img_url, preview_image_url=img_url)
line_bot_api.reply_message(tk,img_message)
else:
# 如果沒有 msg,回傳文字
text_message = TextSendMessage(text='找不到相關圖片')
line_bot_api.reply_message(tk,text_message)
except:
print(body) # 如果發生錯誤,印出收到的內容
return 'OK' # 驗證 Webhook 使用,不能省略
if __name__ == "__main__":
app.run()
回覆地址訊息
使用 reply_message 的「LocationSendMessage」方法 ( 需要 import ),能夠回覆地址訊息,相關參數如下:
參數 | 說明 |
---|---|
title | 地圖標題。 |
address | 地址標示。 |
latitude | 緯度。 |
longitude | 經度。 |
下方的程式碼執行後,當使用者傳送了某個地點的文字,LINE BOT 就會回覆跟這個地點的地圖 ( 先建立文字和地址、經緯度的對照字典 ),如果找不到文字對應的地址,就會回傳「找不到相關地點」。
注意,如果是 ngrok 產生的網址,每次重新執行就要再進入 LINE Developer 更新 Webhook。
from flask import Flask, request
from pyngrok import ngrok # Colab 環境需要,本機環境不需要
# 載入 LINE Message API 相關函式庫
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage, StickerSendMessage, ImageSendMessage, LocationSendMessage
# 注意,有載入 LocationSendMessage 模組
import json
app = Flask(__name__)
# Colab 環境需要下面這三行,本機環境不需要
port = "5000"
public_url = ngrok.connect(port).public_url
print(f" * ngrok tunnel \"{public_url}\" -> \"http://127.0.0.1:{port}\" ")
@app.route("/", methods=['POST'])
def linebot():
body = request.get_data(as_text=True) # 取得收到的訊息內容
try:
json_data = json.loads(body) # json 格式化訊息內容
access_token = '你的 access token'
secret = '你的 channel secret'
line_bot_api = LineBotApi(access_token) # 確認 token 是否正確
handler = WebhookHandler(secret) # 確認 secret 是否正確
signature = request.headers['X-Line-Signature'] # 加入回傳的 headers
handler.handle(body, signature) # 綁定訊息回傳的相關資訊
tk = json_data['events'][0]['replyToken'] # 取得回傳訊息的 Token
msg = json_data['events'][0]['message']['text']
if msg == '101':
# 如果有地點資訊,回傳地點
location_message = LocationSendMessage(title='台北 101',
address='110台北市信義區信義路五段7號',
latitude='25.034095712145003',
longitude='121.56489941996108')
line_bot_api.reply_message(tk,location_message)
else:
# 如果是 False,回傳文字
text_message = TextSendMessage(text='找不到相關地點')
line_bot_api.reply_message(tk,text_message)
except:
print(body) # 如果發生錯誤,印出收到的內容
return 'OK' # 驗證 Webhook 使用,不能省略
if __name__ == "__main__":
app.run()
部署程式到 Google Cloud Functions
因為使用 ngrok + Colab 的 Python 程式,只會運作幾個小時就停止,甚至再次執行時需要重新安裝相關函式庫,所以只能作為「開發中」使用,如果要真正建構 LINE BOT 的 Python 程式,除了可以使用類似 Heroku 之類的雲端伺服器,也可以直接使用 Google Cloud Functions 部署程式。
登入 Google 帳號,啟用 Google Cloud 和 Cloud Functions 後,建立一支 Cloud Functions 的程式,環境設定為 Python 3.7~3.9,進入點設定為 linebot。
編輯 requirements.txt,在 Cloud Functions 安裝 line-bot-sdk 函式庫。
編輯 main.py 主程式檔案,撰寫下方 Python 程式碼,綜合上方所有的範例,程式碼執行後會自動回覆使用者的訊息、表情貼圖、圖片與地點資訊。
import json
from linebot import LineBotApi, WebhookHandler
# 載入對應的函式庫
from linebot.models import TextSendMessage, StickerSendMessage, ImageSendMessage, LocationSendMessage
def linebot(request):
try:
body = request.get_data(as_text=True)
json_data = json.loads(body) # json 格式化收到的訊息
line_bot_api = LineBotApi('你的 Channel access token') # 輸入 你的 Channel access token
handler = WebhookHandler('你的 Channel secret') # 輸入 你的 Channel secret
signature = request.headers['X-Line-Signature']
handler.handle(body, signature)
tk = json_data['events'][0]['replyToken'] # 取得 reply token
tp = json_data['events'][0]['message']['type'] # 取得 message 的類型
if tp == 'text':
# 如果是文字類型的訊息
msg = reply_msg(json_data['events'][0]['message']['text']) # 取出文字並對應到 reply_msg 的函式
if msg[0] == 'text':
# 如果要回傳的訊息是 text,使用 TextSendMessage 方法
line_bot_api.reply_message(tk,TextSendMessage(text=msg[1]))
if msg[0] == 'location':
# 如果要回傳的訊息是 location,使用 LocationSendMessage 方法
line_bot_api.reply_message(tk,LocationSendMessage(title=msg[1]['title'],
address=msg[1]['address'],
latitude=msg[1]['latitude'],
longitude=msg[1]['longitude']))
if msg[0] == 'image':
# 如果要回傳的訊息是 image,使用 ImageSendMessage 方法
line_bot_api.reply_message(tk,ImageSendMessage(original_content_url=msg[1],
preview_image_url=msg[1]))
if tp == 'sticker':
# 如果收到的訊息是表情貼圖
stickerId = json_data['events'][0]['message']['stickerId'] # 取得 stickerId
packageId = json_data['events'][0]['message']['packageId'] # 取得 packageId
# 使用 StickerSendMessage 方法回傳同樣的表情貼圖
line_bot_api.reply_message(tk,StickerSendMessage(sticker_id=stickerId, package_id=packageId))
if tp == 'location':
# 如果是收到的訊息是地點資訊
line_bot_api.reply_message(tk,TextSendMessage(text='好地點!'))
if tp == 'image':
# 如果是收到的訊息是圖片
line_bot_api.reply_message(tk,TextSendMessage(text='好圖給讚!'))
if tp == 'audio':
# 如果是收到的訊息是聲音
line_bot_api.reply_message(tk,TextSendMessage(text='聲音讚喔~'))
if tp == 'video':
# 如果是收到的訊息是影片
line_bot_api.reply_message(tk,TextSendMessage(text='影片內容真是不錯!'))
except:
print('error', body)
return 'OK'
# 定義回覆訊息的函式
def reply_msg(text):
# 客製化回覆文字
msg_dict = {
'hi':'Hi! 你好呀~',
'hello':'Hello World!!!!',
'你好':'你好呦~',
'help':'有什麼要幫忙的嗎?'
}
# 如果出現特定地點,提供地點資訊
local_dict = {
'總統府':{
'title':'總統府',
'address':'100台北市中正區重慶南路一段122號',
'latitude':'25.040319874750914',
'longitude':'121.51162883484746'
}
}
# 如果出現特定圖片文字,提供圖片網址
img_dict = {
'皮卡丘':'https://upload.wikimedia.org/wikipedia/en/a/a6/Pok%C3%A9mon_Pikachu_art.png',
'傑尼龜':'https://upload.wikimedia.org/wikipedia/en/5/59/Pok%C3%A9mon_Squirtle_art.png'
}
# 預設回覆的文字就是收到的訊息
reply_msg_content = ['text',text]
if text in msg_dict:
reply_msg_content = ['text',msg_dict[text.lower()]]
if text in local_dict:
reply_msg_content = ['location',local_dict[text.lower()]]
if text in img_dict:
reply_msg_content = ['image',img_dict[text.lower()]]
return reply_msg_content
編輯完成後,部署程式,出現綠色打勾圖示表示部署完成。
程式部署後,選擇「觸發條件」頁籤,複製觸發的網址,更新 LINE Developer 的 Webhook。
驗證 Webhook 沒問題後,就可以在 LINE 與自己開發的 LINE BOT 聊天了。
小結
了解 LINE Message API 回覆訊息的原理後,就能輕鬆做出一個會自動回覆訊息的 LINE BOT,不過回覆訊息的機制是「一來一往」,只有在發送訊息後取得 reply token 才能回覆訊息,如果要主動推播訊息,則需要使用 push messsage 的方式才能實現。
延伸閱讀
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~