Learning Objectives
- 列出常見的事件種類,說明哪些可以回覆
- 用 handler.add 與 handler.default 把事件交給不同的函數
- 從訊息事件讀出文字、貼圖、位置、語音的內容
- 用 event.source.user_id 分辨使用者,用 get_profile 取得顯示名稱
- 說明 userId 的範圍,以及為什麼要把它當個人資料保管
機器人收到的不只是文字
第 2 課的機器人只處理文字,使用者傳貼圖時毫無反應;有人加好友時也不會打招呼。使用者的每個動作都是一種事件,這一課學怎麼分辨事件、怎麼知道是誰。
一對一聊天常見的事件(官方完整清單):
| 事件 | SDK 類別 | 什麼時候收到 | 可以回覆? |
|---|---|---|---|
| message | MessageEvent |
使用者傳訊息 | 可以 |
| follow | FollowEvent |
加好友,或解除封鎖 | 可以 |
| unfollow | UnfollowEvent |
封鎖機器人 | 不可以,沒有 reply token |
| postback | PostbackEvent |
按下 postback 按鈕(第 7 課) | 可以 |
| unsend | UnsendEvent |
收回訊息 | 不可以 |
使用者收回訊息時,官方建議尊重他的意思,把存下來的該則訊息刪掉,讓它之後不會再被看到或使用。群組還有 join、leave 等事件,這一軌不細講。
follow 事件的 follow.is_unblocked 可以區分新加好友和解除封鎖,不過官方說明這個值不保證完全準確,不要用它做重要的判斷。
逐步看:五種動作走進五個函數
為了專心看事件分流,這個範例只用 print,沒有回覆,也省略了驗簽失敗的處理(第 2、3 課的完整寫法請照舊)。注意 follow 與 unfollow 最後印出的差別。
訊息事件的內容
MessageEvent 的 event.message 依種類是不同的類別:
| 內容 | SDK 類別 | 主要欄位 |
|---|---|---|
| 文字 | TextMessageContent |
text |
| 貼圖 | StickerMessageContent |
package_id、sticker_id |
| 位置 | LocationMessageContent |
title、address、latitude、longitude |
| 圖片 | ImageMessageContent |
id、content_provider |
| 語音 | AudioMessageContent |
id、duration(毫秒) |
| 影片、檔案 | VideoMessageContent、FileMessageContent |
id 等 |
圖片、語音這類內容不在 webhook 裡,只給一個 id,要再呼叫 API 下載。第 11 課會實際下載語音檔來轉成文字。
handler.handle 依這個順序找函數,都找不到就不處理、照常回 200:
- 訊息事件先找「事件+內容」,例如
@handler.add(MessageEvent, message=TextMessageContent) - 再找只寫事件類別的函數,例如
@handler.add(MessageEvent)、@handler.add(FollowEvent) - 最後是
@handler.default()
message= 也可以給一個串列,例如 message=[ImageMessageContent, VideoMessageContent],讓一個函數處理好幾種內容。
逐步看:handler 怎麼選函數
三個動作,分別會走進哪個函數?先猜再按播放。
是誰傳的:userId
事件的 event.source 告訴你來源。一對一聊天時是 UserSource,編號在 event.source.user_id;群組裡是 GroupSource,另外還有 group_id。
userId 不是顯示名稱,也不是使用者在 LINE 上設定的 LINE ID。 官方說明:
- 格式是
U加上 32 個十六進位字元(這個課程用縮短的假值) - 依 Provider 發放:同一個人在同一個 Provider 底下的 Channel 拿到相同的值,換到別的 Provider 就是另一個值
- 使用者沒有同意取得個人資料時,webhook 裡不會有 userId,程式要能處理
user_id是None的情況
要存使用者的資料時,鍵用 userId,不要用顯示名稱:顯示名稱可以隨時改,也可能重複。
要取得顯示名稱等資料,呼叫 get_profile(user_id)。回傳的 display_name、user_id 一定有;picture_url、status_message、language 不一定有。使用者封鎖了機器人就查不到,這個課程的模擬平台回 404。
userId 和個人資料屬於個資。 只存真的用得到的欄位,不要印在公開的紀錄裡,不要傳給無關的服務,也要讓使用者知道你存了什麼、可以怎麼刪除。
逐步看:兩個人,兩個 userId
同一段程式,兩位虛構的使用者各傳一句話。看 user_id 怎麼變,再看林怡君封鎖之後查詢會怎樣。
動手做:記錄誰是好友
完成三個函數:
on_follow:把使用者加進friends,回覆「歡迎加入」on_unfollow:把使用者從friends移除,這個事件不能回覆on_location:回覆「你在 <地點名稱>」
friends 存在記憶體裡,重新啟動就不見了,第 9 課會改存資料庫。
想一想
使用者封鎖機器人時,程式在 UnfollowEvent 的函數裡想回覆「再見」。會怎樣?
程式登記了 @handler.add(MessageEvent) 與 @handler.default(),沒有其他函數。使用者傳文字時走哪一個?
使用者在你的機器人和另一個 Provider 的機器人都加了好友。兩邊看到的 userId 會怎樣?
要存使用者的報名資料,下面哪個最適合當鍵?
使用者傳了一張圖片,webhook 的 event.message 裡有什麼?
重點整理
- 使用者的動作都是事件:message、follow、unfollow、postback……
@handler.add(事件, message=內容)由具體到一般比對,最後才到@handler.default()- unfollow 沒有 reply token,不能回覆
- 圖片、語音等內容不在 webhook 裡,要用訊息 id 另外下載
event.source.user_id分辨使用者。它依 Provider 發放,要當個資保管,不一定存在get_profile查顯示名稱,封鎖後查不到
下一課換個方向:機器人除了文字,還能傳哪些訊息。