還有口罩嗎? - 口罩地圖 LINE Chatbot
專案背景
2020 年初,COVID-19 疫情爆發,台灣開始出現口罩搶購潮。親朋好友每天都在問「哪裡還有口罩?」,藥局門口大排長龍,卻經常撲空。
為了解決這個問題,我決定開發一個口罩地圖查詢系統。考量到目標使用者包含年長的家人,為了降低學習門檻,選擇使用大家都熟悉的 LINE 作為介面,開發一個口罩查詢 Chatbot。
開發時間軸
2020/02/03 - V1.0 網友回報版
一個晚上完成第一版
當時口罩實名制尚未上路,超商和藥妝店都還買得到口罩。第一版的特色:
- 基於「網友回報」機制
- 使用者可以回報各店家的口罩庫存狀況
- 支援超商、藥妝店查詢
技術挑戰:
- 資訊不即時,容易有誤報
- 需要處理惡意回報
- 資料正確性難以驗證
2020/02/06 - V2.0 官方資料版
口罩實名制上路
健保署開始提供「特約藥局口罩庫存開放資料」,立即進行改版:
- 整合健保署 Open Data API
- 顯示即時口罩庫存數量(成人/兒童)
- 僅查詢有配合實名制的藥局
- 每 30 秒更新一次資料
資料來源:
https://data.nhi.gov.tw/Datasets/Download.ashx?rid=A21030000I-D50001-001&l=https://data.nhi.gov.tw/resource/mask/maskdata.csv
2020/02/16 - 媒體曝光與流量暴增
接受三立新聞採訪報導後,機器人使用量暴增:
- 單日使用者從 100 人 → 10,000+ 人
- 需要緊急最佳化架構應對流量
- 新增 CDN 加速資料查詢
核心功能
1. 位置查詢
- GPS 定位 - 自動偵測使用者位置
- 地址搜尋 - 輸入地址查詢附近藥局
- 藥局名稱搜尋 - 直接搜尋指定藥局
2. 即時庫存顯示
- 成人口罩剩餘數量
- 兒童口罩剩餘數量
- 最後更新時間
- 藥局營業時間
3. 地圖導航
- Google Maps 快速導航
- 顯示藥局詳細資訊
- 計算距離與預估時間
4. 訂閱通知(進階功能)
- 訂閱常去的藥局
- 當該藥局有口罩時推播通知
- 避免白跑一趟
技術架構
LINE Chatbot
- LINE Messaging API - 對話介面
- Webhook - 接收使用者訊息
- Flex Message - 視覺化呈現口罩資訊
- Quick Reply - 快速選單
後端服務
- Python + Flask - Web 框架
- Redis - 快取口罩資料
- Celery - 定時任務排程
- PostgreSQL - 儲存使用者訂閱資料
資料處理流程
Health Insurance API
↓
Parse CSV Data
↓
Transform & Cache (Redis)
↓
User Query (LINE Bot)
↓
Quick Response (< 200ms)
位置搜尋演算法
使用 Haversine Formula 計算兩點間的距離:
def haversine(lat1, lon1, lat2, lon2):
R = 6371 # 地球半徑(公里)
dlat = radians(lat2 - lat1)
dlon = radians(lon2 - lon1)
a = sin(dlat/2)**2 + cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon/2)**2
c = 2 * atan2(sqrt(a), sqrt(1-a))
return R * c
高流量最佳化
1. 資料快取策略
- 使用 Redis 快取健保署資料(30 秒更新一次)
- 避免每次查詢都呼叫 API
- 減少健保署伺服器壓力
2. CDN 加速
- 將靜態資源放到 CDN
- 地圖資料使用 CloudFlare 加速
- 降低伺服器負載
3. 非同步處理
使用 Celery 處理耗時任務:
- 資料更新任務
- 推播通知任務
- 使用者查詢記錄
4. 資料庫最佳化
- 為經緯度欄位建立空間索引(Spatial Index)
- 最佳化查詢效能從 500ms → 50ms
- 使用 Connection Pool 管理資料庫連線
技術挑戰
1. 健保署 API 不穩定
政府 API 經常因為流量過大而回應緩慢或失敗:
- 解決方案:實作重試機制 + 本地快取
- 當 API 失敗時,繼續使用上一次的快取資料
2. 地理位置計算效能
需要計算使用者與數千家藥局的距離:
- 解決方案:使用 R-Tree 空間索引
- 先篩選出一定範圍內的藥局,再進行精確計算
3. LINE Messaging API 限制
LINE 有每秒請求次數限制:
- 解決方案:實作訊息佇列
- 使用 Rate Limiter 控制請求頻率
4. 惡意使用與爬蟲
部分使用者短時間內大量查詢:
- 解決方案:IP 頻率限制
- 同一使用者 1 分鐘內最多查詢 10 次
社會影響
使用數據
- 累積使用者:50,000+
- 單日查詢次數:100,000+
- 服務時長:3 個月
- 幫助民眾減少找口罩的時間
媒體報導
- 三立新聞專訪
- 多家科技媒體報導
- 開發者社群分享
開源貢獻
將程式碼開源在 GitHub,收到許多開發者的建議與貢獻:
- GitHub Stars: 100+
- 其他開發者 Fork 後開發自己的版本
- 成為口罩地圖開發的參考範例
後記與反思
這個專案讓我深刻體會到:
- 快速開發的重要性 - 疫情初期,每天都有新需求,需要快速迭代
- 社會責任感 - 技術可以幫助解決實際的社會問題
- 開源的力量 - 開放原始碼讓更多人受益
- 效能最佳化的必要性 - 當使用者暴增時,系統穩定性至關重要
最後,感謝健保署提供開放資料,也感謝所有使用者的回饋。希望這個專案在疫情期間為大家帶來一些幫助。
請把資源優先留給有需要購買口罩的人。