先求有再求好,我們先以陽春麵版的機器人文字查詢與回覆方式,帶各位引入門與了解邏輯,下一篇會介紹漂漂亮亮版,讓你的機器人看起來很有格局~
這邊提供三筆範例課程評價資料供讀者使用,欄位依序為類型、課名、老師名、投稿者、內容、投稿學期,其內容為真實投稿內容改編,而其中兩筆評價描寫的課程名稱相同,以便進行程式教學。
先在 http://127.0.0.1:8000/admin/chatbot/course/ 或是直接進入後台 courses Table 手動新增三筆資料,讓資料庫開始有了生氣~
為什麼沒有對應的評價,會選擇以不回應處理,而不是回應「查不到」呢?因為在做小生物 LINE Bot 的時候,我們發現到許多學生會將機器人作為備忘錄使用,如果不斷回覆反而造成使用困擾,所以在這邊選擇了不回覆,當然,這只是觀察使用者使用習慣後的一種選擇,在這裡也提醒開發者,除了技術外,使用者體驗也是非常重要的。
views.py 接收訊息與引入資料表進行搜尋回覆hulolo > hulolo > models.py 的資料表類別引入,再將 handle_message 函式原本貓貓的內容做移除,首先從變數 event 中取得使用者所發送的文字:
# 此檔案位置: hulolo > chatbot > views.py
from .models import *
@parser.add(MessageEvent, message=TextMessage)
def handle_message(event):
user_message = event.message.text # 取得使用者發送的文字
- 判定使用者想要進行評價搜尋,因為此時搜尋評價的規則是「王小明-海洋生命科學導論」,無論如何都會有 -,並以 - 為界做字串分割,前者為老師,後者為課名:
# 接續上一步程式碼
if "-" in user_message:
teacher_name = user_message.split("-")[0]
course_name = user_message.split("-")[1]
teacher_name 以及 course_name ,以此當作關鍵字進行搜尋,這邊會使用到一個資料庫 ORM 查詢的方式,Course.objects.filter 代表的是從 Course 類別/資料表中進行過濾,過濾的條件則是希望欄位 teacher_name 等於 teacher_name;欄位 course_name 等於 course_name,注意兩變數雖然一樣但是代表意義不同,前者是來自 models.py field 所命名,後者則是來自第 2 步所宣告的變數:
# 接續上一步程式碼
filtered_courses = Course.objects.filter(teacher_name=teacher_name, course_name=course_name)[:5]
LINE 官方文件規定一次回覆最多為 5 則,因此這邊取的資料為最多前 5 筆。
filtered_courses,可以透過 exists() 判斷裡面有沒有查詢到,若有就可以準備打包給使用者,這邊使用了迴圈是因為可能搜尋到的評價不只一則:
# 接續上一步程式碼
if filtered_courses.exists():
messages = []
for course in filtered_courses:
messages.append(TextSendMessage(
text=f"""
課程: {course.course_name}\
評價: {course.feedback_content}
"""))
line_bot_api.reply_message 準備回覆:
# 接續上一步程式碼
line_bot_api.reply_message(
event.reply_token,
messages #回覆所有 messages 陣列中的值
)
else 加上了 print("Empty"),這樣會一查無此評價就可以在 Terminal 顯示,讓開發的你有一些安全感,至少不是壞了,其 handle_message 所有程式碼如下:
@parser.add(MessageEvent, message=TextMessage)
def handle_message(event):
user_message = event.message.text # 取得使用者發送的文字
if "-" in user_message:
teacher_name = user_message.split("-")[0]
course_name = user_message.split("-")[1]
filtered_courses = Course.objects.filter(teacher_name=teacher_name, course_name=course_name)[:5]
if filtered_courses.exists():
messages = []
for course in filtered_courses:
messages.append(TextSendMessage(
text=f"""課程: {course.course_name}\
評價: {course.feedback_content}
"""))
line_bot_api.reply_message(
event.reply_token,
messages
)
else:
print("Empty")
當輸入 王小明-海洋生命科學導論 就會得到一筆訊息回覆,輸入 吳小峰-特殊教育學生評量 則會收到兩筆訊息回覆,這樣就對啦~
@parser.add(MessageEvent, message=TextMessage) 是一種監聽的裝飾器,每當使用者發送 TextMessage 文字類型訊息的時候,就會請裝飾器下面的 handle_message 做處理,換言之也可以監聽圖片、影片、聲音等類型。Course.objects.filter 與沒有介紹的 Course.objects.get 都是常用的取得資料方式,前者無論有無結果都會回傳;而 .objects.get只允許一個結果回來,如果多個就會跳 Exception,適用在預期結果只有唯一,例如 id 或是身分證字號具有唯一性的搜尋條件,其效率會較高。line_bot_api.reply_message 中的 event.reply_token 是每一封使用者發送訊息時,LINE 轉傳過來的識別碼,需要在數秒內 帶著要回的訊息與識別碼回覆給 LINE 伺服器,使用者才會成功收到我們要給的訊息,且識別碼只能使用一次。可以想看看如果識別碼不會過期的話,那我們就可以一直一直吵對方了,這樣很快就天下大亂了: D在這篇文章中,我們學會了:
objects.filter 篩選資料表的方式event.message.text 接收使用者訊息與解讀的方法messages 可以是一個陣列,最多五個回覆給使用者TextSendMessage 回覆訊息