National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 80 24°C PM2.5 21
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 12

專題:讀書會小幫手

選單、Flex、狀態、資料庫、推送組成一個完整的機器人
Interaction實作 45 minute(s)

Learning Objectives

  • 把 webhook、資料庫、卡片拆成不同檔案,讓程式維持好改
  • 用圖文選單、Flex Message 與 postback 做出報名流程,不必讓使用者打字
  • 用 SQLite 記住報名資料,並處理重複報名、額滿與取消
  • 做一個會推送的管理員路由,並說明它為什麼要自己驗證身分
  • 替機器人補上缺的功能,並測試不同使用者看到的結果

這個專題要做什麼

前面每一課都只處理一個觀念。真的機器人要把它們接起來:使用者加好友、從選單看到場次、按一下就報名、之後可以取消,負責的人還能通知報名的同學。這一課就做這個機器人,名字叫「讀書會小幫手」。

功能 用到 哪一課學過
加好友時傳歡迎訊息 FollowEvent 第 4 課
選單放在聊天室下方 Rich Menu 第 7 課
用卡片列出場次 Flex Message、carousel 第 8 課
按按鈕報名,使用者不必打字 PostbackAction、parse_qs 第 7 課
記住誰報名了哪一場 SQLite、user_id 第 9 課
通知報名的人 multicast、額度 第 6 課
用語音問(選做) get_message_content、Whisper 第 11 課

程式超過一個畫面就不好找,所以拆成三個檔案:

檔案 負責 不做
app.py webhook、判斷是哪種事件、決定回什麼 不寫 SQL,也不組卡片的 JSON
db.py 所有 SQL 不知道 LINE 的存在
flex.py 把查到的資料組成 Flex Message 不查資料庫

db.py 用的是後端開發軌第 9 課的 get_db() 寫法;SQL 不熟可以看 SQL 軌。資料表只有兩張:sessions 是場次,signups 記誰報名了哪一場,一人一場一列。

逐步看:資料變成卡片

場次是資料,卡片是由迴圈產生的,所以新增場次不必改卡片程式。按播放,注意 on_text 裡的迴圈每跑一次,cards 多一張;每張卡片的按鈕都帶著自己的 id。

逐步看:報名寫進資料庫

同一個人按兩次會發生什麼?這裡不是先查再寫,而是讓資料庫的 UNIQUE 擋下第二筆。看 try 和 except 各走了哪一次。

互動練習:做完報名流程

這是完整的機器人,但 db.py 有兩個地方還沒寫,要由你補上。按「▶ 啟動機器人」後,從手機下方的圖文選單開始操作,手機右上角可以切換王小明和林怡君。

要補的兩個函數在 db.py 最下面。改完按「存檔並重新啟動」,資料庫的內容會留著;想從頭來就按「清空資料庫」。

模擬手機是簡化的呈現,也不會載入任何圖片,圖文選單畫成按鈕。實際的樣式與排版要到第 13 課接上真的 LINE 才看得到。

誰都能呼叫的路由要自己驗證

/callback 有簽章驗證,只有 LINE 平台算得出正確的簽章。發公告的 /announce 是你自己開的路由,LINE 不會經過它,也沒有任何東西替它驗證。網址一旦公開,任何人都能 POST,而且它會用你的官方帳號傳訊息給使用者,額度也算你的。

這一課用一把金鑰(ADMIN_KEY,放環境變數)示範最簡單的做法,比對用 hmac.compare_digest。實際的網站通常是管理員登入後才看得到發公告的頁面,做法見後端開發軌第 15、16 課。

用 multicast 而不是 broadcast,是因為公告只和報名這一場的人有關。額度的計算方式是收件人數:一則訊息傳給兩個人算兩則,封鎖的人不計入;reply 完全不計入。實際的額度與價格依方案與地區而不同,請看官方說明。

逐步看:驗證金鑰、推送、額度

發三次公告:第一次金鑰是猜的,第二次傳給兩個人,第三次其中一人已經封鎖。看 quota_used 怎麼變。

互動練習:補上管理員公告的驗證

這個版本的報名流程都完成了,多了 /announce 路由。右上方的兩顆按鈕代表兩個人呼叫這個路由:老師帶著正確的金鑰,陌生人的金鑰是猜的。

選做:語音問答。 手機下方的「🎤 問資料庫導論」會傳一段語音,內容是「請問明天下午三點的資料庫導論還有上課嗎?」(合成語音)。機器人下載音檔,在你自己的伺服器上用 Whisper 轉成文字,再找出提到的場次。實際轉出來的是「資料庫討論」,「導論」被聽錯了,所以程式只比對「資料庫」這個關鍵字,並把聽到的內容回給使用者確認。這裡重播的是事先用真的 faster-whisper 轉錄的結果。音訊會先存在 LINE 的伺服器,再傳到你的機器,要讓使用者知道;詳細說明在第 11 課。

動手做:候補遞補

報名額滿的人會排進候補。有人取消時,要把候補最前面的人轉成正取,並主動通知他。取消的人用 reply 回覆,遞補的人要用 push:他沒有傳任何訊息,手上沒有可以用的 reply token。

完成 promote_next()。資料表 waitlist 的 id 越小排越前面。

你的輸出
預期輸出

想一想

1.

資料表已經有 UNIQUE (user_id, session_id),這個限制主要解決什麼問題?

2.

/callback 驗證了簽章。為什麼 /announce 還要自己檢查金鑰?

3.

下面這段程式會印出什麼?

from urllib.parse import parse_qs
params = parse_qs('action=join&id=3')
print(params['id'])
4.

一則公告用 multicast 傳給 30 個 userId,其中 2 人封鎖了機器人。依官方的計算方式,這次計入額度多少則?

5.

遞補的同學要收到通知,為什麼不能用 reply_message?

第 1 次作答

重點整理

  • 程式拆成 webhook、資料庫、卡片三塊,每個檔案只管一件事
  • 圖文選單、Flex 按鈕、postback 讓使用者不必打字,data 由你設計
  • 重複與額滿這類規則,要在伺服器和資料庫判斷,不能只靠畫面
  • 換一個使用者試試看:每個人的狀態以 user_id 分開
  • 自己開的路由沒有 LINE 的簽章保護,要自己驗證身分
  • 推送要想清楚:該通知誰、算幾則、對方想不想收

接下來可以加的功能

方向 要處理的事
開場前一天自動提醒 排程工作(cron);時間要以使用者所在時區思考
建立場次的管理頁面 登入、權限,見後端開發軌
用語言模型回答課程問題 第 10 課的逾時、成本與標示;模型可能答錯
同時報名的競爭 兩人同時按最後一個名額時,先算人數再寫入可能超收,要用交易處理
使用者刪除自己的資料 提供「刪除我的資料」功能,並寫在隱私說明裡

下一課離開模擬環境:申請官方帳號,把機器人接上真的 LINE。

這一課完成了!
Next lesson:接上真的 LINE
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。