使用 React Native (Expo) 與 Node.js/Express 建置的 AI 驅動食物辨識與熱量估算系統。透過 Gemini Vision API 自動識別食物、計算營養素,並提供個人化飲食建議。
- 📸 智能食物辨識 - 拍照或上傳圖片,AI 自動識別食物並計算熱量
- 📊 營養分析 - 詳細的蛋白質、碳水、脂肪、纖維等營養素分析
- 🎯 個人化目標 - 根據身高、體重、性別生成每日飲食目標
- 📈 歷史追蹤 - 記錄並分析飲食歷史,提供趨勢圖表
- 💾 雲端同步 - 使用 Supabase 儲存資料,支援多裝置同步
- 🎨 現代化 UI - 精美的視覺設計,直觀的使用體驗
- 作業系統: Windows 10/11, macOS, 或 Linux
- Node.js: 18.0.0 或更高版本
- npm 或 yarn
- Expo CLI (隨
npm install自動安裝) - Supabase 帳號 (用於資料儲存)
- Google Gemini API Key (用於 AI 辨識)
- ngrok - 用於對外測試 (非必需)
- 夜神模擬器 或其他 Android/iOS 模擬器
food_app/
├── foodidentify/ # React Native (Expo) 前端
│ ├── App.js # 應用程式入口
│ ├── app.json # Expo 配置
│ ├── app.config.js # 動態配置(含環境變數)
│ ├── package.json
│ ├── .env # 環境變數(需自行建立)
│ ├── src/
│ │ ├── core/ # 核心功能
│ │ │ ├── AuthContext.js # 認證管理
│ │ │ ├── MealContext.js # 餐點管理
│ │ │ ├── AIService.js # AI 服務整合
│ │ │ └── HistoryRepository.js # 歷史記錄管理
│ │ ├── screens/ # 頁面元件
│ │ │ ├── HomeScreen.js # 首頁
│ │ │ ├── ScanLanding.js # 掃餐頁面
│ │ │ ├── ResultScreen.js # 結果頁面
│ │ │ ├── HistoryScreen.js # 歷史記錄
│ │ │ └── AccountScreen.js # 帳戶管理
│ │ ├── ui/ # UI 元件
│ │ │ ├── Card.js # 卡片元件
│ │ │ └── NutrientBar.js # 營養進度條
│ │ ├── navigation/ # 導航設定
│ │ └── lib/ # 工具庫
│ │ └── supabase.js # Supabase 客戶端
│ └── assets/ # 圖片與字型
│
└── foodidentify-server/ # Node.js 後端
├── server.js # Express 伺服器
├── package.json
├── .env # 環境變數(需自行建立)
└── uploads/ # 圖片暫存目錄
git clone <your-repo-url>
cd food_app# 後端
cd foodidentify-server
npm install
# 前端
cd ../foodidentify
npm install💡 提示:
npm install會自動安裝所有必要的套件,詳見下方 套件列表 章節。
詳見 環境設定 章節。
# 終端 1: 啟動後端
cd foodidentify-server
npm start
# 終端 2: 啟動前端
cd foodidentify
npm start執行 npm install 會自動安裝以下套件:
核心框架:
express^4.21.2 - Web 框架cors^2.8.5 - 跨域資源共享dotenv^16.6.1 - 環境變數管理
AI 與圖像處理:
@google/generative-ai^0.21.0 - Google Gemini APIsharp^0.34.5 - 高性能圖像處理jimp^0.22.12 - JavaScript 圖像處理庫@tensorflow/tfjs^4.22.0 - TensorFlow.js
檔案處理:
multer^1.4.5-lts.2 - 檔案上傳中間件node-fetch^3.3.2 - HTTP 請求(跨平台 fetch)
工具:
uuid^13.0.0 - UUID 生成器
執行 npm install 會自動安裝以下套件:
核心框架:
expo~54.0.25 - Expo SDKreact19.1.0 - React 核心react-dom19.1.0 - React DOMreact-native0.81.5 - React Native 核心
導航:
@react-navigation/native^7.1.19 - React Navigation 核心@react-navigation/native-stack^7.6.2 - Stack 導航@react-navigation/drawer^7.7.2 - Drawer 導航react-native-screens~4.16.0 - 原生螢幕管理react-native-safe-area-context^5.6.2 - 安全區域處理react-native-gesture-handler2.16.2 - 手勢處理react-native-reanimated^4.1.3 - 動畫庫
Expo 模組:
expo-image-picker~17.0.8 - 圖片選擇器expo-file-system~19.0.19 - 檔案系統expo-sharing^14.0.7 - 分享功能expo-print~14.0.1 - PDF 列印expo-status-bar~3.0.8 - 狀態列
資料管理:
@supabase/supabase-js^2.83.0 - Supabase 客戶端@react-native-async-storage/async-storage^2.2.0 - 本地儲存
圖表與視覺化:
react-native-chart-kit^6.12.0 - 圖表庫(BarChart, LineChart)react-native-svg15.12.1 - SVG 支援
UI 元件:
@react-native-picker/picker2.11.1 - 選擇器元件react-native-view-shot^4.0.3 - 視圖截圖@expo/vector-icons- 圖標庫(MaterialCommunityIcons, Ionicons 等,隨 Expo SDK 自動包含)
網路與工具:
axios^1.12.2 - HTTP 客戶端react-native-url-polyfill^3.0.0 - URL Polyfillreact-native-get-random-values^2.0.0 - 隨機值生成react-native-web^0.21.0 - Web 支援react-native-worklets0.5.1 - Worklets 支援
加密與工具:
bcryptjs^3.0.3 - 密碼雜湊crypto-js^4.2.0 - 加密工具uuid^13.0.0 - UUID 生成器dotenv^16.4.5 - 環境變數管理
開發工具 (devDependencies):
@types/react~19.1.10 - React TypeScript 類型typescript~5.9.2 - TypeScript 編譯器
💡 提示: 所有套件會透過
npm install自動安裝,無需手動下載。版本號前的^或~表示允許安裝兼容的更新版本。
建立 .env 檔案:
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_ANON_KEY=your_anon_key💡 提示: 這些變數會在打包時自動注入到
app.config.js,不會暴露在程式碼中。
建立 .env 檔案:
PORT=3000
GEMINI_API_KEY=your_gemini_api_key
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE=your_service_role_key
ALLOWED_ORIGINS=*-
Supabase:
- 前往 Supabase Dashboard
- 建立新專案或選擇現有專案
- 在 Settings > API 中取得 URL 和 Keys
-
Google Gemini API:
- 前往 Google AI Studio
- 建立 API Key
- 複製金鑰到
.env檔案
cd foodidentify-server
npm start伺服器將在 http://localhost:3000 啟動。
cd foodidentify
npm start
# 或
npm run lannpm run tunnelnpm run localhost- 實體手機: 使用 Expo Go 掃描 QR Code
- Android 模擬器: 自動連接(使用
10.0.2.2:3000) - iOS 模擬器: 自動連接(使用
localhost:3000) - Web: 按
w鍵在瀏覽器中開啟
- 註冊/登入: 使用 Email 和密碼註冊帳號
- 個人資料: 設定身高、體重、性別(用於個人化建議)
- 資料同步: 所有資料儲存在 Supabase,支援多裝置同步
- 進入「掃餐」頁面
- 選擇「拍照」或「從相簿選擇」
- 可選填備註(如:午餐、外食等)
- 點擊「送到 AI 估算」
- 查看辨識結果與營養分析
- 食物名稱: AI 識別的食物名稱
- 熱量: 總熱量(大卡)
- 營養素: 蛋白質、碳水、脂肪、纖維、糖、鈉
- 信心度: AI 辨識的信心百分比
- AI 建議: 營養師建議
- 查看所有已儲存的餐點
- 點擊查看詳細資訊
- 支援編輯、刪除、分享功能
- 自動計算每日/每週營養總和
- 在首頁輸入今日需求(如:減脂、增肌、外食較多)
- 點擊「生成個人化目標」
- AI 根據你的資料生成:
- 每日熱量目標
- 營養素分配(蛋白質、碳水、脂肪)
- 餐次建議
- 7 天趨勢: 查看近一週的營養攝取
- 30 天趨勢: 查看近一個月的營養攝取
- PDF 匯出: 匯出包含個人資料的營養報表
分析食物圖片並回傳營養資訊。
請求格式: multipart/form-data
參數:
image(File, 必填): 食物圖片note(String, 選填): 使用者備註
回應範例:
{
"success": true,
"prediction": {
"food": "漢堡",
"calories": 500,
"macros": {
"protein": 20,
"carbs": 30,
"fat": 25,
"fiber": 3,
"sugar": 5,
"sodium_mg": 800
},
"confidence": 0.85,
"advice": ["建議搭配蔬菜", "注意鈉含量"]
},
"mode": "gemini-vision"
}生成個人化飲食目標。
請求格式: application/json
參數:
{
"heightCm": 180,
"weightKg": 70,
"gender": "male",
"preference": "減脂"
}回應範例:
{
"success": true,
"goals": {
"calories": 2000,
"macros": {
"protein": 150,
"carbs": 200,
"fat": 65
},
"meals": [
{
"meal": "早餐",
"suggestion": "燕麥片配水果"
}
]
}
}檢查伺服器狀態。
回應:
{
"status": "ok",
"timestamp": "2025-12-09T15:00:00.000Z",
"gemini": true
}Android 模擬器:
- 確保使用
10.0.2.2:3000(已在程式碼中自動設定) - 檢查後端伺服器是否正在運行
實體手機:
- 確保手機和電腦在同一 WiFi 網路
- 使用 LAN 模式啟動 Expo
- 檢查防火牆設定
解決方法:
# 檢查伺服器是否運行
curl http://localhost:3000/health
# 檢查 IP 地址
ipconfig # Windows
ifconfig # macOS/Linux錯誤: Supabase 設定缺失
解決方法:
- 確認
.env檔案存在於foodidentify/目錄 - 確認變數名稱正確:
SUPABASE_URL和SUPABASE_ANON_KEY - 重新啟動 Expo 伺服器
錯誤: 429 Too Many Requests
解決方法:
- 檢查 Google AI Studio 的配額設定
- 等待配額重置(通常每分鐘/每天)
- 考慮升級到付費方案
錯誤: permission denied 或 RLS policy violation
解決方法:
- 前往 Supabase Dashboard
- 進入 SQL Editor
- 執行以下 SQL(僅用於開發環境):
ALTER TABLE profiles DISABLE ROW LEVEL SECURITY;
⚠️ 警告: 關閉 RLS 僅適用於開發環境,生產環境請設定正確的 RLS 策略。
錯誤: 無法掃描 QR Code 或連接失敗
解決方法:
# 清除快取並重新啟動
npx expo start -c
# 或使用 LAN 模式
npm run lan# 前端開發模式(自動重新載入)
cd foodidentify
npm start
# 後端開發模式(需要手動重啟)
cd foodidentify-server
npm start-
Context: 使用 React Context 管理全域狀態
AuthContext: 使用者認證與個人資料MealContext: 餐點分析與歷史記錄ThemeContext: 主題切換(亮色/暗色)
-
服務層:
AIService: 處理與後端的通訊HistoryRepository: 管理歷史記錄的 CRUD 操作
-
UI 元件:
Card: 統一的卡片樣式NutrientBar: 營養進度條MacroPill: 營養素標籤
- 在
src/screens/建立新頁面 - 在
src/navigation/RootDrawer.js註冊路由 - 如需新 API,在
AIService.js新增方法 - 如需新 UI 元件,在
src/ui/建立
- React Native 0.81.5
- Expo 54.0.25
- React Navigation 7.x
- Supabase JS 2.83.0
- Axios 1.12.2
- Node.js 18+
- Express 4.x
- Google Gemini API (Vision)
- Multer (檔案上傳)
- Supabase (PostgreSQL)
歡迎提交 Issue 或 Pull Request!
請包含:
- 問題描述
- 重現步驟
- 預期行為 vs 實際行為
- 環境資訊(OS, Node 版本等)
- Fork 專案
- 建立功能分支 (
git checkout -b feature/AmazingFeature) - 提交變更 (
git commit -m 'Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 開啟 Pull Request
本專案採用 MIT 授權。
- Expo - 優秀的 React Native 開發平台
- Supabase - 開源 Firebase 替代方案
- Google Gemini - 強大的 AI 模型
- React Navigation - 導航解決方案
如有問題或建議,請透過以下方式聯絡:
- 提交 Issue
- Email: C112156246@nkust.edu.tw
Made with ❤️ using React Native & Expo