還有口罩嗎? - 口罩地圖 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 後開發自己的版本
  • 成為口罩地圖開發的參考範例

後記與反思

這個專案讓我深刻體會到:

  1. 快速開發的重要性 - 疫情初期,每天都有新需求,需要快速迭代
  2. 社會責任感 - 技術可以幫助解決實際的社會問題
  3. 開源的力量 - 開放原始碼讓更多人受益
  4. 效能最佳化的必要性 - 當使用者暴增時,系統穩定性至關重要

最後,感謝健保署提供開放資料,也感謝所有使用者的回饋。希望這個專案在疫情期間為大家帶來一些幫助。

請把資源優先留給有需要購買口罩的人。

連結