前言
前陣子我的藥師朋友經常需要手動計數藥丸,以便進行包藥作業.這個過程既耗時又容易出錯。為了解決這一問題,我幫他設計了一個簡單的應用程式,使用 YOLOv8 模型來自動識別並計算照片中藥丸的數量,從而快速提供準確的結果
專案說明
專案的詳細介紹我把他整理到 Notion 上,裏面有更詳細的說明
Ref: GitHub Repo
系統架構
這個專案需求非常簡單,其實單純一個 Monolithic 的架構就可以應付,但為了練習看看微服務(Micro service)的切分,就嘗試將不同的功能切分成不同的服務,彼此用 Restful API 溝通
Tech Stack
簡單列一下使用到的技術
Backend
- Python(FastAPI)
- Node.js(Express) written in TypeScript
Auth
- JWT
- Google Auth
- Redis
AI Model
- YOLOv8
- Label-Studio (Labeling Tool)
Frontend
- React written in TypeScript
- PWA
Storage
- PostgreSQL (database)
- Minio (Image storage)
心得
這是第一次嘗試 React 的 PWA,用 service worker 滿直覺也滿簡單的,配置一下部署到 Netlify 上,就可以把網站下載到手機桌面上充當一個 APP 使用
這是第一次嘗試 Yolov8 的模型,並使用 Label-Studio 工具作為標註,使用起來相當直覺,當有多人需要同時標註時,簡單在電腦啟動 server,然後用 ngrok 臨時建個 tunnel,開放給別人一起標註
這是第一次使用 Python 的 alembic 函式庫作為 SQLAlchemy 的資料庫版本管理工具
- alembic 提供
upgrade
和downgrade
的函式來撰寫每一版本的資料庫更新腳本,可隨時針對資料庫的 schema 做升版或降版 - 之前在開發另個電商專案時有類似的體驗,使用 Node.js 生態系的 TypeORM,一樣透過升降版的腳本來保留資料庫的歷史紀錄,可以隨時執行
up
和down
腳本修改資料庫的 schema,所以這次使用 alembic 除了語法差異以外,概念上不會太陌生
- alembic 提供
這是第一次使用 MinIO 這個 Object Storage,概念上有點類似 AWS 的 S3,適合儲存圖片類的資源
部署過程有遇到 web 在 Docker network 內沒辦法連接到 minIO 中儲存的圖片,原因在 hostname 的解析,寫個腳本執行即可
#!/bin/sh # @Example: `sh first-start.sh` source ../.env docker exec -it pillCounter-minio sh -c " mc config host add local http://minio:9000 $MINIO_ROOT_USER $MINIO_ROOT_PASSWORD --api S3v4 --lookup auto mc anonymous set public local/$MINIO_BUCKET_NAME "
這時候連接
http://localhost:9001/pill-counter-images/xxx.png
就可以在網頁上成功顯示圖片
Auth Service 擔任 Reverse Proxy 和 Authenticate 的 API Gateway
使用 JWT 和 Redis 實作認證,我將 session 存在 Redis 中,這樣可以減少頻繁的資料庫查詢,從而提高響應速度和整體性能
JWT 的 payload 記錄一些不敏感的資訊,例如
user_id
、username
、avatar_uri
,這樣可以隨時解析 JWT 就可以獲取user_id
,不用再向資料庫查詢一次,多增加一次 round trip 的成本Reverse proxy 不使用 Nginx,純粹是希望在這層 API Gateway 上有更多彈性可以滿足客製化的需求
使用 Docker-compose 作為容器化部署
- 單一 node 情況下,簡單使用 Docker compose,而沒有使用 Kubernetes
- 每個服務都有一個
/health
的 API endpoint,可在部署後作為 health check 的依據
Payment Service 串接藍新金流
- 前陣子有串接過綠界金流,對於金流的串接流程大致理解,這次改嘗試串接藍新金流,主要是因為訂閱制的需求
- 整體串接起來的過程比綠界金流好很多,但與串接國外的 Stripe 體感上還是落差一大截
結論
這次藉由一個簡單的專案需求,嘗試了幾種技術的組合,也在過程中踩到不同的坑,實作中也學到不少東西,算是一次滿好的經驗,當然使用微服務就有更多面向需要考量,以這個專案來說確實有點過度複雜化.