還記得前面學習 ImageSendMessage
、TextSendMessage
,以及 FlexSendMessage
的時候,我們都是用什麼樣的事件觸發嗎?
# 處理訊息的事件
@parser.add(MessageEvent, message=TextMessage)
def handle_message(event):
答案是
MessageEvent
,指的是使用者發送了文字、圖片、影片、貼圖等訊息,就會觸發MessageEvent
,而TextMessage
則是限定這個函數只處理文字訊息。
無論在 Day 06 歸剛回貓貓機器人、Day 09 陽春麵版查評價關鍵字 以及 Day 10 金箔陽春麵版查評價關鍵字,都是藉由使用者輸入任意文字訊息,去觸發 handle_message
函式。
而如果今天想要讓使用者按我發送的 FlexSendMessage
裡頭的按鈕來做回覆呢?畢竟懶得打字可說是大家的共識,能用選的就用選的~
像是醬子,透過
FlexSendMessage
按鈕讓使用者不用再同時輸入課名與老師名,這設計可真是趕時間跑加簽的福音(?
有別於前面提到的 MessageEvent
,PostbackEvent
處理的就是使用者點擊含有回傳資料的按鈕。
FlexSendMessage
方式回覆建立一個 JSON 檔案: 先將課程列表回覆模板 JSON 的內容放到一個新檔案:hulolo > chatbot > reply_course_list.json
引入 PostbackEvent
套件:
# hulolo > chatbot > views.py
from linebot.models import MessageEvent, PostbackEvent, TextMessage,
TextSendMessage, ImageSendMessage, FlexSendMessage
使用者輸入老師名的處理邏輯: 重新寫一個觸發事件的函式 handle_teacher_name_msg
,用來處理使用者輸入老師名。邏輯是:
teacher_lists_flex_message_package
套漂亮的模板# hulolo > chatbot > views.py
@parser.add(MessageEvent, message=TextMessage)
def handle_teacher_name_msg(event):
user_message = event.message.text # 取得使用者發送的文字
filtered_teacher = Course.objects.filter(teacher_name=user_message)
if filtered_teacher.exists():
teacher_name = user_message
# values_list 是以陣列裝課程名稱
# distinct 可以把可能重複的老師名做過濾
candidate_courses = filtered_teacher.values_list(
'course_name', flat=True).distinct()
# 稍後會製作這個漂亮的函式,先呼叫它
flex_message = teacher_lists_flex_message_package(
teacher_name, candidate_courses)
message = FlexSendMessage(
alt_text=f"{teacher_name} 老師的課程",
contents=flex_message
)
line_bot_api.reply_message(
event.reply_token,
message)
else:
print("Empty")
處理漂亮的課程列表 Flex message 回覆: 新增 teacher_lists_flex_message_package
函式處理漂亮的課程列表 Flex message 回覆,這邊要特別介紹 Flex message 若有按鈕,是需要在裡面加上按鈕按下去會傳遞的資料,也就是註解中按鈕背後藏著真正的資料 (詳見程式碼內的註解)。
# hulolo > chatbot > views.py
def teacher_lists_flex_message_package(teacher_name, candidate_courses):
# 引入 JSON 檔案
json_path = os.path.join(BASE_DIR,
'chatbot', 'reply_course_list.json')
flex = json.load(open(json_path, 'r', encoding='utf-8'))
# 設定標題為老師名稱
flex['body']['contents'][0]['text'] = f"{teacher_name}老師的哪堂課?"
# 課程列表的選項用了十個顏色!
colors = ['#F0C29E', '#A1DE95', '#F5C578', '#91D9C2', '#DFC493',
'#F0C29E', '#A1DE95', '#F5C578', '#91D9C2', '#DFC493']
# 根據上述顏色動態生成課程按鈕,而且是根據幾堂課就產生幾個按鈕~
for i, course in enumerate(candidate_courses, start=1):
button = {
'type': 'box',
'layout': 'vertical',
'spacing': 'none',
'contents': [{
'type': 'button',
'style': 'primary',
'action': {
'type': 'postback',
'label': course,
#注意! 這很重要,此處代表按鈕背後真正的資料
'data': f"{teacher_name}-{course}"
},
'color': colors[i-1],
'margin': 'xs',
'offsetTop': 'none',
'height': 'sm'
}],
'flex': 0,
'borderWidth': 'medium',
'cornerRadius': 'xxl',
'offsetTop': 'none',
'margin': 'md',
'backgroundColor': colors[i-1]
}
flex['body']['contents'].append(button)
return flex
使用者按下後的 PostbackEvent
處理: 新增一個函式 handle_postback
,這邊就會使用到 PostbackEvent
,用來觸發與分析剛剛按鈕內的資料,並進行查詢回覆後告知評價內容,讀者可以觀察其與 handle_message
函式的差異,會發現幾乎相同哦~
# hulolo > chatbot > views.py
@parser.add(PostbackEvent)
def handle_postback(event):
# 取得使用者點按鈕時回傳的資料
postback_data = event.postback.data
# 還記得前面提及按鈕背後的資料嗎? 在這!
# postback_data 格式為 "課程名稱-老師名稱"
if "-" in postback_data:
teacher_name = postback_data.split("-")[0]
course_name = postback_data.split("-")[1]
filtered_courses = Course.objects.filter(
teacher_name=teacher_name, course_name=course_name)[:5]
if filtered_courses.exists():
messages = []
# 使用 enumerate 給每個課程加上編號
for idx, course in enumerate(filtered_courses, start=1):
# 準備課程資料以傳入 flex_message_package 函式
course_info = {
'course_name': course.course_name,
'teacher_name': course.teacher_name,
'course_type': course.course_type,
'feedback_content': course.feedback_content,
'evaluation_semester': course.evaluation_semester,
'submitter_name': course.submitter_name,
'number': str(idx), # 這裡的 idx 是第幾則的意思
}
# 呼叫 flex_message_package 函式來產生 Flex Message
flex_message = flex_message_package(course_info)
# 使用 FlexSendMessage 回傳 Flex Message
messages.append(FlexSendMessage(
alt_text=f"課程評價:{course.course_name}",
contents=flex_message
))
line_bot_api.reply_message(
event.reply_token,
messages # 回傳 Flex Message 列表
)
else:
print("Empty")
else:
print("Empty")
當輸入 吳小峰 就會得到一筆訊息回覆,包含一個 特殊教育學生評量 的課程~可以到後台試著增加同老師不同課程,就會有多的按鈕出現 (在這邊教學方便我們上限設為 10 種不同課程):
handle_message
與 handle_postback
內容很相近時,可以考慮將其回覆評價內容的邏輯,獨立一個函式,就能避免重複造輪子的問題。在這篇文章中,我們學會了:
PostbackEvent
觸發事件,在這邊是按下 Flex message 裡的按鈕觸發