閱讀本篇前,需要先架設 Nginx/Django 伺服器,並且要有自已的網域並使用 SSL 加密憑証。
上一篇的 Line BOT 簡介中,BOT 可以自動回覆訊息,但功能極為陽春。雖然也可以設定 AI 自動回覆訊息,但這功能將於 2024/05/15 停用。
所以我們必需架設一台伺服器,分析客戶端傳入的內容才決定要如何回應,最終將回應訊息透過 BOT 傳送給客戶端手機,示意圖如下。
Line Channel access token
在底下的伺服器代碼中,有二個很重要的變數要設定,分別是 Line Channel acccess token 及 Line secret。因為 Line 網站上查詢這二個變數的位置有變,所以先說明一下取得的方式。
請先由 https://developers.line.biz/zh-hant/ 選擇 Console,再按下 Messaging API。
接下來再選擇 Messageing API 分頁
往下拉後,會看到 Channel access token,第一次需按下 issue 按鈕產生新的 access token,日後若要變更,可以按下 Reissue。請把 access token 複製記下,等會要填入 python 代碼中的 access_token 變數。
再切換到 Basic settings 分頁
往下拉即可看到 Channel secret,此數字也需記要,要填入後面 python 代碼的 secret 變數中。
Line BOT 設定
請進入 Line BOT 網站的設定/Messaging API,將聊天關掉,Webhook 打開。
Django 新增 app
在 Django 專案下,執行 python manage.py startapp line,新增一個 line app。urls.py 新增如下網址設設。
from line import views as line urlpatterns = [ ................... path('line/', line.html, name="line_bot_webhook"), ]
view.py
在 line 目錄下的 views.py 修改如下
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
@csrf_exempt
def html(request):
try:
pass
except:
pass
return HttpResponse("OK")#隨便回覆一個字串,但不可以是空字串
測試
請由 https://developers.line.biz/zh-hant/ 然後按 Console ,選 Messaging API/Messaging API,再編輯 Webhook URL 並輸入 https://xxx.ddns.net/line/。 請注意 Django 架設的網站,必需在 Webhook URL 網址最後面要加入 “/”。 若是由 flask 架設的網站,則不需輸入 “/”。
然後按下 Verify,即可看到連線成功
取得客戶端 Line 傳入的訊息
安裝 line bot 套件
pip install line-bot-sdk
在 line/views.py 更改如下
from django.views.decorators.csrf import csrf_exempt from django.http import HttpResponse import json from linebot.models import TextSendMessage from linebot import LineBotApi from G import G line_bot_api = LineBotApi(G.line_access_token) @csrf_exempt#取消 CSRF保護 def html(request): try: body=request.body.decode() data=json.loads(body) tk = data['events'][0]['replyToken'] type = data['events'][0]['message']['type'] # 取得 LINe 收到的訊息類型 if type=='text': msg = data['events'][0]['message']['text'] # 取得 LINE 收到的文字訊息 reply = msg else: reply = '你傳的不是文字呦~' line_bot_api.reply_message(tk,TextSendMessage(reply))# 回傳訊息 except: pass return HttpResponse("不可以是空字串")
然後使用客戶端的 Line 對 Line bot 輸入文字,Line Bot 即會以相同的訊息傳給客戶端。
天氣預報/地震速報
底下的代碼,可以預報天氣及查詢地震
from django.views.decorators.csrf import csrf_exempt from django.http import HttpResponse import json from linebot.models import TextSendMessage, ImageSendMessage from linebot import LineBotApi import requests from G import G import time line_bot_api = LineBotApi(G.line_access_token) answer_menu=""" 本官網僅對上課內容發佈最新訊息 可供查詢的內容如下 天氣預報 地震速報 """ @csrf_exempt#取消 CSRF保護 def html(request): try: body=request.body.decode() data=json.loads(body) tk = data['events'][0]['replyToken'] type = data['events'][0]['message']['type'] # 取得 LINe 收到的訊息類型 user_id = data['events'][0]['source']['userId'] if type=='text': msg = data['events'][0]['message']['text'] # 取得 LINE 收到的文字訊息 reply = msg if '天氣預報' in msg: line_bot_api.push_message(user_id, TextSendMessage(text='抓取資料中....')) # 一開始先發送訊息 img_url = f'https://cwaopendata.s3.ap-northeast-1.amazonaws.com/Observation/O-A0058-001.png?{time.time_ns()}' img_message = ImageSendMessage(original_content_url=img_url, preview_image_url=img_url) line_bot_api.reply_message(tk, img_message) elif '地震速報' in msg: line_bot_api.push_message(user_id, TextSendMessage(text='抓取資料中....')) reply = earth_quake() # 執行函式,讀取數值 text_message = TextSendMessage(text=reply[0]) # 取得文字內容 line_bot_api.reply_message(tk,text_message) # 傳送文字 line_bot_api.push_message(user_id, ImageSendMessage(original_content_url=reply[1], preview_image_url=reply[1])) # 傳送圖片 else: line_bot_api.reply_message(tk, TextSendMessage(answer_menu)) else: reply = '你傳的不是文字呦~' line_bot_api.reply_message(tk,TextSendMessage(reply))# 回傳訊息 except: pass return HttpResponse("不可以是空字串") def earth_quake(): try: url = f'https://opendata.cwa.gov.tw/api/v1/rest/datastore/E-A0016-001?Authorization={G.earth_quake_code}' data = requests.get(url) # 爬取資料 data_json = data.json() # 轉換成 json eq = data_json['records']['Earthquake'][0] # 取得第一筆地震資訊 result = [eq['ReportContent'], eq['ReportImageURI']] # 回傳地震報告和地震圖 except Exception as e: print(e) result = ['抓取失敗...',''] return result