iT邦幫忙

2023 iThome 鐵人賽

0
Software Development

跟著 OXXO 一起學 Python系列 第 84

( Day 40.1 ) Python LINE BOT 自動回覆訊息

  • 分享至 

  • xImage
  •  

順利將 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 的方式處理。

LINE BOT 教學 ( Python ) - 自動回覆訊息

回覆文字訊息

使用 reply_message 的「TextSendMessage」方法 ( 需要 import ),能夠回覆文字訊息,相關參數如下:

參數 說明
text 要回覆的文字 ( 不論放入什麼內容都會被轉換成文字 )。

使用下方的程式碼執行後,使用者輸入了什麼訊息,LINE BOT 就會回覆一模一樣的文字訊息。

注意,如果是 ngrok + Colab 產生的網址,每次重新執行就要再進入 LINE Developer 更新 Webhook。

from flask_ngrok import run_with_ngrok   # colab 使用,本機環境請刪除
from flask import Flask, request
from linebot import LineBotApi, WebhookHandler
from linebot.models import TextSendMessage   # 載入 TextSendMessage 模組
import json

app = Flask(__name__)

@app.route("/", methods=['POST'])
def linebot():
    body = request.get_data(as_text=True)
    json_data = json.loads(body)
    print(json_data)
    try:
        line_bot_api = LineBotApi('你的 Channel access token')
        handler = WebhookHandler('你的 LINE Channel secret')
        signature = request.headers['X-Line-Signature']
        handler.handle(body, signature)
        tk = json_data['events'][0]['replyToken']         # 取得 reply token
        msg = json_data['events'][0]['message']['text']   # 取得使用者發送的訊息
        text_message = TextSendMessage(text=msg)          # 設定回傳同樣的訊息
        line_bot_api.reply_message(tk,text_message)       # 回傳訊息
    except:
        print('error')
    return 'OK'

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

LINE BOT 教學 ( Python ) - 自動回覆訊息

回覆表情貼圖

使用 reply_message 的「StickerSendMessage」方法 ( 需要 import ),能夠回覆表情貼圖,相關參數如下:

參數 說明
package_id 表情貼圖所在群組 ID。
sticker_id 表情貼圖 ID。

LINE BOT 預設的表情貼圖只有 LINE 官方所提供的貼圖,支援的表情貼圖參考:List of available stickers

LINE BOT 教學 ( Python ) - 自動回覆訊息

下方的程式碼執行後,當使用者傳送了表情貼圖,LINE BOT 就會回覆一模一樣的表情貼圖 ( 限制為官方預設的表情貼圖 )。

注意,如果是 ngrok + Colab 產生的網址,每次重新執行就要再進入 LINE Developer 更新 Webhook。

from flask_ngrok import run_with_ngrok          # colab 使用,本機環境請刪除
from flask import Flask, request
from linebot import LineBotApi, WebhookHandler
from linebot.models import StickerSendMessage   # 載入 StickerSendMessage 模組
import json

app = Flask(__name__)

@app.route("/", methods=['POST'])
def linebot():
    body = request.get_data(as_text=True)
    json_data = json.loads(body)
    print(json_data)
    try:
        line_bot_api = LineBotApi('你的 Channel access token')
        handler = WebhookHandler('你的 LINE Channel secret')
        signature = request.headers['X-Line-Signature']
        handler.handle(body, signature)
        tk = json_data['events'][0]['replyToken']      # 取得 reply 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('error')
    return 'OK'

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

LINE BOT 教學 ( Python ) - 自動回覆訊息

回覆圖片或影片訊息

使用 reply_message 的「ImageSendMessage」或「VideoSendMessage」方法 ( 需要 import ),能夠回覆圖片或影片,相關參數如下:

參數 說明
original_content_url 原始圖片或影片網址。
preview_image_url 縮圖網址。

下方的程式碼執行後,當使用者傳送了某個文字,LINE BOT 就會回覆跟這個文字有關的圖片 ( 先建立好圖片網址和文字對照的字典,圖片來源是維基百科 ),如果找不到文字對應的圖片,就會回傳「找不到相關圖片」。

注意,如果是 ngrok + Colab 產生的網址,每次重新執行就要再進入 LINE Developer 更新 Webhook。

from flask_ngrok import run_with_ngrok                          # colab 使用,本機環境請刪除
from flask import Flask, request
from linebot import LineBotApi, WebhookHandler
from linebot.models import TextSendMessage, ImageSendMessage    # 載入 TextSendMessage 和 ImageSendMessage 模組
import json

app = Flask(__name__)

@app.route("/", methods=['POST'])
def linebot():
    body = request.get_data(as_text=True)
    json_data = json.loads(body)
    print(json_data)
    try:
        line_bot_api = LineBotApi('你的 Channel access token')
        handler = WebhookHandler('你的 LINE Channel secret')
        signature = request.headers['X-Line-Signature']
        handler.handle(body, signature)
        tk = json_data['events'][0]['replyToken']
        msg = json_data['events'][0]['message']['text']
        img_url = reply_img(msg)   # 取得對應的圖片,如果沒有取得,會是 False
        if img_url:
            # 如果有圖片網址,回傳圖片
            img_message = ImageSendMessage(original_content_url=img_url, preview_image_url=img_url)
            line_bot_api.reply_message(tk,img_message)
        else:
            # 如果是 False,回傳文字
            text_message = TextSendMessage(text='找不到相關圖片')
            line_bot_api.reply_message(tk,text_message)
    except:
        print('error')
    return 'OK'
# 建立回覆圖片的函式
def reply_img(text):
    # 文字對應圖片網址的字典
    img = {
        '皮卡丘':'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'
    }
    if text in img:
      return img[text]
    else:
      # 如果找不到對應的圖片,回傳 False
      return False

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

LINE BOT 教學 ( Python ) - 自動回覆訊息

回覆地址訊息

使用 reply_message 的「LocationSendMessage」方法 ( 需要 import ),能夠回覆地址訊息,相關參數如下:

參數 說明
title 地圖標題。
address 地址標示。
latitude 緯度。
longitude 經度。

下方的程式碼執行後,當使用者傳送了某個地點的文字,LINE BOT 就會回覆跟這個地點的地圖 ( 先建立文字和地址、經緯度的對照字典 ),如果找不到文字對應的地址,就會回傳「找不到相關地點」。

注意,如果是 ngrok + Colab 產生的網址,每次重新執行就要再進入 LINE Developer 更新 Webhook。

from flask_ngrok import run_with_ngrok                             # colab 使用,本機環境請刪除
from flask import Flask, request
from linebot import LineBotApi, WebhookHandler
from linebot.models import TextSendMessage, LocationSendMessage    # 載入 TextSendMessage 和 LocationSendMessage 模組
import json

app = Flask(__name__)

@app.route("/", methods=['POST'])
def linebot():
    body = request.get_data(as_text=True)
    json_data = json.loads(body)
    print(json_data)
    try:
        line_bot_api = LineBotApi('你的 Channel access token')
        handler = WebhookHandler('你的 LINE Channel secret')
        signature = request.headers['X-Line-Signature']
        handler.handle(body, signature)
        tk = json_data['events'][0]['replyToken']
        msg = json_data['events'][0]['message']['text']
        location_dect = reply_location(msg)     # 取得對應的地址,如果沒有取得,會是 False
        if location_dect:
            # 如果有地點資訊,回傳地點
            location_message = LocationSendMessage(title=location_dect['title'],
                                                  address=location_dect['address'],
                                                  latitude=location_dect['latitude'],
                                                  longitude=location_dect['longitude'])
            line_bot_api.reply_message(tk,location_message)
        else:
            # 如果是 False,回傳文字
            text_message = TextSendMessage(text='找不到相關地點')
            line_bot_api.reply_message(tk,text_message)
    except:
        print('error')
    return 'OK'
# 建立回覆地點的函式
def reply_location(text):
    # 建立地點與文字對應的字典
    location = {
        '101':{
            'title':'台北 101',
            'address':'110台北市信義區信義路五段7號',
            'latitude':'25.034095712145003',
            'longitude':'121.56489941996108'
        },
        '總統府':{
            'title':'總統府',
            'address':'100台北市中正區重慶南路一段122號',
            'latitude':'25.040319874750914',
            'longitude':'121.51162883484746'
        }
    }
    if text in location:
      return location[text]
    else:
      # 如果找不到對應的地點,回傳 False
      return False

if __name__ == "__main__":
    run_with_ngrok(app)         # colab 使用,本機環境請刪除
    app.run()

LINE BOT 教學 ( Python ) - 自動回覆訊息

部署程式到 Google Cloud Functions

因為使用 ngrok + Colab 的 Python 程式,只會運作幾個小時就停止,甚至再次執行時需要重新安裝相關函式庫,所以只能作為「開發中」使用,如果要真正建構 LINE BOT 的 Python 程式,除了可以使用類似 Heroku 之類的雲端伺服器,也可以直接使用 Google Cloud Functions 部署程式。

參考:使用 Google Cloud Functions

登入 Google 帳號,啟用 Google Cloud 和 Cloud Functions 後,建立一支 Cloud Functions 的程式,環境設定為 Python 3.7~3.9,進入點設定為 linebot。

LINE BOT 教學 ( Python ) - 自動回覆訊息

編輯 requirements.txt,在 Cloud Functions 安裝 line-bot-sdk 函式庫。

LINE BOT 教學 ( Python ) - 自動回覆訊息

編輯 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 BOT 教學 ( Python ) - 自動回覆訊息

程式部署後,選擇「觸發條件」頁籤,複製觸發的網址,更新 LINE Developer 的 Webhook。

LINE BOT 教學 ( Python ) - 自動回覆訊息

驗證 Webhook 沒問題後,就可以在 LINE 與自己開發的 LINE BOT 聊天了。

LINE BOT 教學 ( Python ) - 自動回覆訊息

小結

了解 LINE Message API 回覆訊息的原理後,就能輕鬆做出一個會自動回覆訊息的 LINE BOT,不過回覆訊息的機制是「一來一往」,只有在發送訊息後取得 reply token 才能回覆訊息,如果要主動推播訊息,則需要使用 push messsage 的方式才能實現。

更多參考:LINE Messaging API SDK for Python

延伸閱讀

更多教學

大家好,我是 OXXO,是個即將邁入中年的斜槓青年,我有個超過一千篇教學的 STEAM 教育學習網,有興趣可以參考下方連結呦~ ^_^


上一篇
( Day 39.2 ) Python LINE BOT 解析 LINE 的訊息
下一篇
( Day 40.2 ) Python LINE BOT 主動推播訊息
系列文
跟著 OXXO 一起學 Python101
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言