iT邦幫忙

2026 iThome 鐵人賽

DAY 13
0
ChatGPT & Codex

這隻 LINE Bot 不是我寫的:30 天讓 Codex 從零幫我做到上線系列 第 13

Day 13 - 從記住偏好到選好時間:我用 Codex Luna 和 LINE Datetime Picker 把咖啡廳推薦變成真的行程

  • 分享至 

  • xImage
  •  

上一篇,我讓 LINE Cafe Companion 開始記住使用者的咖啡偏好。

使用者可以說「安靜、有插座、適合工作」,下一次分享位置時,Bot 就會把這些條件帶進推薦。那一版解決的是「我想去哪一種咖啡廳」:Bot 不必每次都從頭認識我。

不過偏好記住了,推薦也出來了,還有一個很日常的斷點沒有被處理:看到一間喜歡的店後,通常會想著「改天去」,然後就沒有然後了。

所以這次我做了一個更小、但剛好把流程接起來的功能:讓每張咖啡廳推薦卡都能直接開啟 LINE 原生的 Datetime Picker,選好時間後再一鍵加入 Google Calendar。

這次我也特別改用 Codex Luna 來完成開發。

換句話說,上一篇讓 Bot 知道我想去什麼地方;這一篇,則是讓我可以把「想去」變成一個具體時間。

如果你還沒看過上一篇,可以先從這裡開始:從提醒到偏好記憶:我用 Codex Terra 讓 LINE Cafe Bot 不再每次都從頭認識你

使用者實際會怎麼用?

流程很短:

  1. 使用者傳送目前位置。
  2. Bot 依照位置與已保存的偏好,推薦附近咖啡廳。
  3. 在想去的店家卡片上點「安排喝咖啡時間」。
  4. LINE 跳出原生日期時間選擇器。
  5. 選完後,Bot 顯示店名、時間,以及「加入 Google Calendar」按鈕。

使用者不需要輸入 下週三下午三點去第二間 這種容易有歧義的句子,也不用自己在聊天視窗和行事曆之間切來切去。選擇店家、挑時間、建立行程,留在同一條 LINE 對話裡就能完成。

https://ithelp.ithome.com.tw/upload/images/20260824/20183556sD4zDNNtIa.jpg

為什麼用 LINE 原生的 Datetime Picker?

一開始也可以讓使用者直接輸入時間。但日期、下午晚上、跨月份和不同寫法,會讓自然語言解析變得複雜;更重要的是,使用者很難知道 Bot 最後理解成哪個時間。

LINE Message API 已經提供 Datetime Picker Action,所以這次我直接用它:

{
  "type": "datetimepicker",
  "label": "安排喝咖啡時間",
  "data": "v=2&a=pick_time&s=abc123&c=2",
  "mode": "datetime"
}

mode: "datetime" 會讓 LINE 顯示日期與時間的原生選擇介面。使用者選完後,LINE 會把結果放在 postback event 的 params.datetime,格式是:

2026-08-24T15:30

這很適合一個明確的操作:時間由使用者親手選定,程式只需要負責驗證、轉換和建立下一步行程,不必猜測語意。

https://ithelp.ithome.com.tw/upload/images/20260824/20183556K88fKA8Ert.jpg

按鈕不能只帶「店名」

真正麻煩的地方,不是把 Datetime Picker 放進卡片,而是使用者選完時間後,系統怎麼知道他剛剛點的是哪一間店?

我沒有把完整店名、座標或推薦資料塞進按鈕的 data 裡,而是先把這次搜尋存成短期的 Firestore session。每張店家卡片只帶這些必要資訊:

v=2&a=pick_time&s=abc123&c=2
  • v=2:Postback 資料版本。
  • a=pick_time:這次要處理的是選時間。
  • s=abc123:短期搜尋 session ID。
  • c=2:這張卡片在本次推薦中的店家編號。

收到 postback 後,後端再用 session ID 找回當時的推薦結果,取得正確店名。這樣做還有兩個好處:按鈕資料很小,而且不會把使用者的位置或其他推薦內容暴露在訊息裡。

一個行程按鈕,也要驗證是誰按的

搜尋 session 不只保存咖啡廳資料,也綁定了發起搜尋的 LINE userId 和對話來源,並設定 30 分鐘有效期限。

所以 Bot 收到 Datetime Picker 回傳的結果時,會依序確認:

  1. session 是否還有效;
  2. 按按鈕的人是不是原本傳送位置的人;
  3. 目前是不是同一個對話;
  4. 店家編號是否真的存在於那次推薦裡;
  5. LINE 回傳的日期時間格式是否有效。

這在一對一聊天看起來有點多,但 Bot 也可能被加進群組。多做這些驗證,才能避免 A 分享位置後,B 拿著舊按鈕替自己或別人建立錯誤行程。

時間處理比看起來更容易出錯

LINE Datetime Picker 回傳的是台北當地時間,但字串本身沒有時區資訊。像 2026-08-24T15:30 如果直接當成 UTC 儲存,行事曆就會偏移八小時。

因此程式在驗證格式後,會把它明確轉成台灣時區的時間點,再建立 Google Calendar 的預填連結。最後 Bot 回覆的不是一串技術格式,而是使用者看得懂的內容:

已安排 8 月 24 日 15:30 到 XX Cafe 喝咖啡

下方再附上「加入 Google Calendar」。Datetime Picker 解決選時間,Calendar 則負責讓這個選擇真的留在使用者每天會看的地方。

偏好記憶在這一版扮演什麼角色?

這個 Datetime Picker Bot 也整合了上一篇的偏好記憶功能。使用者可以先說:

設定我的偏好:安靜、有插座、適合工作

確認後再傳送位置,推薦會顯示已套用的偏好;接著才從符合需求的店家裡挑一間、選時間。

兩個功能各自做一件事:偏好記憶幫忙縮小「去哪裡」的範圍,Datetime Picker 把「什麼時候去」定下來。它們放在一起後,推薦才不只是資訊列表,而更像一條可以走完的行動路徑。

設定偏好
    ↓
分享位置,取得適合的推薦
    ↓
選擇一家店
    ↓
LINE Datetime Picker 選時間
    ↓
加入 Google Calendar

這次用 Codex Luna 開發,實際遇到了什麼?

前一篇偏好記憶功能,我使用的是 Codex Terra;這次我想試試看 Codex Luna。

Datetime Picker 乍看之下很像是「加一個按鈕」的功能,但它其實牽涉到既有的推薦卡片、LINE postback、Firestore 狀態、時區和 Google Calendar。Luna 在這次很適合協助我把工作切小:先讀現有流程,確認 LINE Action 的格式,再補上 session、訊息處理和測試,最後才部署到 Cloud Run。

開發中最容易踩到的幾個問題是:

  • 不知道選的是哪一間店。 Datetime Picker 回傳的是時間,不會自動附上店名;因此要用短期 session ID 和店家編號,把選擇結果找回原本的推薦卡片。
  • 舊按鈕或群組裡的按鈕被誤用。 同一份 session 必須綁定使用者、對話和有效期限,否則按鈕被轉傳或放太久,都可能建立到錯誤的行程。
  • 時間少了時區。 LINE 回傳的時間字串沒有 offset,若直接交給 Calendar,很容易出現八小時偏移;後端必須明確以台北時區解讀。
  • 功能寫完不代表手機上能用。 Cloud Run 部署後,還要確認 health endpoint 正常、LINE Webhook 指向正確服務並能收到 200 OK,才能真的在 LINE 裡測。

我的感受是,Luna 很適合這種邊界清楚、可以逐步驗證的功能:它能快速協助梳理既有程式和小範圍改動。我仍會把資料驗證、時區和部署檢查當成必做的人工確認,因為真正容易出錯的,往往是功能與功能接起來的地方。

那 Sol、Terra 和 Luna 該怎麼選?

這幾篇文章剛好讓我用不同模型做了不同類型的工作。依照 OpenAI 官方文件,Sol 適合複雜、開放式且需要更多判斷與打磨的任務;Terra 是日常工作的平衡型選擇;Luna 則適合目標清楚、可重複驗證的工作。

放到這個 LINE Bot 專案裡,我會這樣理解:

  • Sol:當問題還沒有很清楚的答案,例如要重整整個推薦架構、追查難以重現的 bug,或要做需要更多取捨的設計時,我會優先選它。
  • Terra:像上一篇的偏好記憶,需要讀懂既有程式、串起 Firestore、Function Calling、LINE 訊息和地圖推薦,同時顧好流程一致性;這種日常但跨模組的整合很適合 Terra。
  • Luna:這次的 Datetime Picker 有明確的完成條件:按鈕格式正確、能找回對應店家、時間不偏移、行事曆連結可用。這種可以拆成小步驟、每一步都能測試的任務,很適合用 Luna 快速推進。

這不是把三者排成高低,而是先看問題的輪廓。需求還模糊、需要大量判斷時,用 Sol;需要穩定完成日常整合時,用 Terra;規格清楚、想有效率地反覆完成同類工作時,用 Luna。這次也提醒我:模型選擇只是起點,測試、部署檢查和手機上的實際操作,才是最後決定功能能不能交付的地方。

部署與測試

這次我把功能部署到 Cloud Run 的 codex-datetime-picker-action 服務,並保留原本的地圖推薦、「換一批」和「更適合工作」流程。部署後確認 health endpoint 正常,LINE Webhook 測試也回覆 200 OK

實際用手機測試時,我會走一次完整流程:先設定偏好、傳送位置、確認推薦有套用偏好、點選其中一間店的時間按鈕、選擇日期時間,最後開啟 Google Calendar 檢查店名和時間。

這種測試比只看單元測試更重要。因為這個功能真正的價值,正是 LINE 的按鈕、postback、時區和行事曆能不能在同一支手機上順順地接起來。

最後:少一個「改天」,多一個真的行程

上一篇的偏好記憶,讓 Bot 開始理解使用者想找什麼樣的地方;Datetime Picker 則提醒我,產品體驗不能只停在「推薦得不錯」。

人們常常不是不知道要去哪,而是少了一個把念頭變成行動的步驟。把選時間放在推薦卡片上,聽起來只是多一個按鈕,實際上卻把「這家看起來不錯」往前推到了「我已經安排好了」。

對我來說,這次最有意思的不是多了一個日期時間選擇器,而是讓推薦終於有了下一步:從「這家看起來不錯」,走到「我已經把時間留好了」。

本篇完整程式碼

👉 GitHub:
https://github.com/zonawang/codex-datetime-picker-action

👉 更多 LINE Bot 與 AI 實作紀錄: https://github.com/zonawang/zona-ai-learning-lab


上一篇
Day 12 - 從提醒到偏好記憶:我用 Codex Terra 讓 LINE Cafe Bot 不再每次都從頭認識你
下一篇
Day 14 - Bot 功能都做好了,我卻忘了怎麼用:用 Codex App 和 Sol 替 LINE Cafe Bot 補上 Rich Menu
系列文
這隻 LINE Bot 不是我寫的:30 天讓 Codex 從零幫我做到上線16
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言