从像素到卡路里:使用 GPT-4o Vision 构建高精度餐食追踪器
Source: Dev.to
Introduction
说实话:算卡路里是最糟糕的事。🍕 我们都有过这种经历——盯着餐厅里一盘“神秘意面”,猜测上面的帕尔马干酪是 20 克还是 50 克。传统的应用让你在无尽的“中号苹果”或“大号香蕉”数据库里搜索,这简直是扫兴。
但如果你的手机只需要看一眼你的盘子,就能准确知道里面有什么呢?在本教程中,我们将使用 GPT‑4o Vision API、FastAPI 和 React Native 构建一个高精度的膳食分析系统。我们将利用 多模态 AI 和先进的 提示工程,把非结构化的食物照片转化为结构化的营养数据。
如果你想掌握 计算机视觉、大语言模型编排 和 结构化数据抽取,那么你来对地方了!🚀
架构:从图像到洞察
为了确保高精度,我们并不只是“询问”AI照片中有什么。我们实现了一个多步骤的估算逻辑,考虑到份量大小、密度以及隐藏的成分(如油脂和脂肪)。
graph TD
A[React Native App] -->|Capture Image| B(FastAPI Backend)
B -->|Image Processing| C{GPT‑4o Vision}
C -->|Reasoning| D[Volume & Density Estimation]
D -->|Structured JSON| E[PostgreSQL Database]
E -->|Nutritional Summary| A
C -.->|Reference Data| F[Nutritional DB]
前置条件
- GPT‑4o API 密钥 (OpenAI)
- FastAPI 用于后端
- React Native (Expo) 用于移动界面
- PostgreSQL 用于持久化日志
第一步:秘密酱(The Prompt)
“猜测”和“精准”之间的差别在于提示。我们使用 Chain‑of‑Thought (CoT) 方法:不是直接询问卡路里,而是让模型先识别组成部分,估算它们的体积(毫升/克),再计算营养成分。
SYSTEM_PROMPT = """
You are a professional nutritionist. Analyze the provided image and:
1. Identify every food item.
2. Estimate the portion size (weight in grams or volume in ml).
3. Calculate Calories, Protein, Carbs, and Fats.
4. Provide a confidence score (0‑1).
Return the data strictly in JSON format.
"""
第2步:使用 FastAPI 实现后端
我们使用 Pydantic 来强制执行严格的模式,确保在 AI 对响应进行“创意”处理时,移动应用不会崩溃。
from fastapi import FastAPI, UploadFile, File
from pydantic import BaseModel
import openai
import base64
app = FastAPI()
class NutritionResult(BaseModel):
food_name: str
calories: int
protein: float
carbs: float
fat: float
confidence: float
@app.post("/analyze-meal", response_model=list[NutritionResult])
async def analyze_meal(file: UploadFile = File(...)):
# Convert image to base64
contents = await file.read()
base64_image = base64.b64encode(contents).decode("utf-8")
response = openai.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": [
{"type": "text", "text": "Analyze this meal:"},
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}}
]}
],
response_format={"type": "json_object"},
)
return response.choices[0].message.content
步骤 3:使用 React Native 的移动 UI
在前端我们需要一个简洁的界面来拍摄照片并显示 “营养成分分解” 卡片。 🥑
import React, { useState } from "react";
import { View, Button, Image, Text } from "react-native";
import * as ImagePicker from "expo-image-picker";
export default function MealTracker() {
const [image, setImage] = useState<string | null>(null);
const [stats, setStats] = useState<any[] | null>(null);
const pickImage = async () => {
const result = await ImagePicker.launchCameraAsync({
allowsEditing: true,
aspect: [4, 3],
quality: 0.8,
});
if (!result.canceled) {
const uri = result.assets[0].uri;
setImage(uri);
uploadImage({ uri });
}
};
const uploadImage = async (photo: { uri: string }) => {
const formData = new FormData();
// @ts-ignore – React Native expects this shape
formData.append("file", {
uri: photo.uri,
name: "meal.jpg",
type: "image/jpeg",
});
const res = await fetch("https://your-api.com/analyze-meal", {
method: "POST",
body: formData,
});
const data = await res.json();
setStats(data);
};
return (
<View>
<Button title="Capture Meal" onPress={pickImage} />
{image && <Image source={{ uri: image }} style={{ width: 200, height: 200 }} />}
{stats && (
<Text>
Total Calories: {stats.reduce((acc: number, cur: any) => acc + cur.calories, 0)} kcal
</Text>
)}
</View>
);
}
高级模式与最佳实践 💡
上述实现适用于 MVP,但生产级 AI 应用需要更健全的错误处理、速率限制和缓存。对每一次扫描都使用 GPT‑4o 可能会导致成本飙升,因此为常见食品项目实现本地缓存是必不可少的。
专业提示: 想要获取包括处理“模糊照片”或“多盘子”等边缘情况的生产就绪示例,请查阅 WellAlly Tech 上的高级工程指南。
结论
我们刚刚搭建了 原始像素 与 结构化健康数据 之间的桥梁。通过将 GPT‑4o 的视觉能力与强大的 FastAPI 后端相结合,我们创建了一个解决实际问题的工具:让健康追踪变得毫不费力。
接下来怎么办?
- 微调:使用你的 PostgreSQL 数据对更小的模型进行微调,以适配特定菜系。
- AR 覆盖:利用 React Native 相机在实时中直接在食物上叠加卡路里数。
你正在用多模态 LLM 构建什么?在下方留下评论吧!👇
Blog – 这是一个为想要突破 AI 集成边界的开发者提供的绝佳资源。
