This feature uses OpenAI's GPT-4.1-mini to generate natural language nutrition summaries from meal descriptions. Users can input text like "two scrambled eggs with toast and butter" and receive estimated calorie counts and macronutrient breakdowns.
- Handles POST requests to generate AI nutrition summaries
- Sends user's meal description to OpenAI API
- Returns a concise paragraph (max 50 words) with estimated calories, carbs, protein, and fat
- Includes reasonable assumptions when quantities are unclear
- Defines the route
/api/ai/nutrition/summary - Requires authentication via JWT token
- Maps POST requests to the nutrition controller
Added aiSummary column to the FoodLog model in prisma/schema.prisma:
model FoodLog {
// ... existing fields
aiSummary String? @map("ai_summary")
// ... rest of model
}Apply schema changes to Supabase:
npx prisma db push
npx prisma generateThe db push command syncs your schema directly to the database without creating migration files. You should see:
🚀 Your database is now in sync with your Prisma schema.
Modified CreateFoodLogInput in queries.ts:
interface CreateFoodLogInput {
// ... existing fields
aiSummary?: string // Added
}npm install openaiAdded to .env:
OPENAI_API_KEY=sk-your-key-here
Updated server.ts:
import nutritionRoutes from "./routes/nutritionRoutes.js";
app.use("/api/ai", nutritionRoutes);Modified nutritionRoutes.ts to require authentication:
router.use(authMiddleware);npm run build
npm startEndpoint: POST /api/ai/nutrition/summary
Headers:
Authorization: Bearer <jwt_token>
Content-Type: application/json
Request Body:
{
"text": "two scrambled eggs with toast and butter"
}Response:
{
"summary": "Your meal of two scrambled eggs with toast and butter is roughly 300-350 kcal, with about 20g protein, 20-25g carbs, and 15-20g fat. This estimate assumes one slice of toast with a pat of butter and standard-sized eggs. A balanced, satisfying start!"
}Error Responses:
400 Bad Request:
{
"error": "text is required"
}502 Bad Gateway:
{
"error": "no_content"
}500 Server Error:
{
"error": "server_error",
"detail": "error message"
}npm run build
npm startcurl -X POST http://localhost:5001/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "john@example.com", "password": "password123"}'Save the token from the response.
Using curl:
TOKEN="your_token_here"
curl -X POST http://localhost:5001/api/ai/nutrition/summary \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"text": "chicken breast with rice and broccoli"}'Using Thunder Client (VS Code):
- Method: POST
- URL:
http://localhost:5001/api/ai/nutrition/summary - Headers:
Authorization:Bearer YOUR_TOKENContent-Type:application/json
- Body (JSON):
{ "text": "grilled salmon with quinoa and asparagus" }
After getting the AI summary, include it when creating a food log:
Using curl:
curl -X POST http://localhost:5001/api/food-logs \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"loggedDate": "2025-10-02",
"mealType": "lunch",
"foodName": "Chicken with rice and broccoli",
"calories": 450,
"protein": 40,
"carbs": 50,
"fat": 10,
"servingSize": 1,
"servingUnit": "plate",
"aiSummary": "Your meal of chicken breast with rice and broccoli is approximately 450 kcal with 40g protein, 50g carbs, and 10g fat. A well-balanced, nutritious meal!"
}'Using Thunder Client:
- Method: POST
- URL:
http://localhost:5001/api/food-logs - Headers:
Authorization:Bearer YOUR_TOKENContent-Type:application/json
- Body (JSON):
{ "loggedDate": "2025-10-02", "mealType": "dinner", "foodName": "Grilled Chicken", "calories": 400, "protein": 50, "carbs": 10, "fat": 15, "servingSize": 1, "servingUnit": "plate", "aiSummary": "Your grilled chicken dinner has about 400 kcal with 50g protein, 10g carbs, and 15g fat. A lean, high-protein meal!" }
Check via API:
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:5001/api/food-logs/daily/2025-10-02The response should include the aiSummary field.
Check via Tableviewer:
- Open
http://localhost:5001in browser - Navigate to food_logs table
- Hard refresh the page (Ctrl+Shift+R)
- You should see the
ai_summarycolumn with your saved data
- User enters meal description in a text field
- Frontend calls
/api/ai/nutrition/summaryto get AI estimation - Frontend displays the summary to the user
- User can edit/confirm the values
- Frontend includes
aiSummaryin the POST request to/api/food-logs - AI summary is saved with the food log entry
- When viewing past meals, the stored AI summary is displayed
To minimize OpenAI API costs:
- Only generate summaries when explicitly requested by the user
- Store the summary in the database on first generation
- Return stored summaries on subsequent fetches (don't regenerate)
- Consider adding a "Regenerate Summary" button for updates only
Important: The /api/ai/nutrition/summary endpoint only generates text - it does NOT save anything to the database. The frontend must explicitly include the aiSummary field when calling /api/food-logs to persist it.
- Authentication Required: All requests must include a valid JWT token
- OpenAI API Key: Ensure
OPENAI_API_KEYis set in.env - Model: Uses
gpt-4.1-minifor cost efficiency - Temperature: Set to 0.2 for consistent, less creative responses
- Accuracy: AI estimates are approximations and may not be precise
- Storage: The
aiSummaryfield is optional in the database - Two Separate Endpoints:
/api/ai/nutrition/summary- generates AI text (does NOT save)/api/food-logs- saves food log (includeaiSummaryin body to persist)
The controller handles:
- Missing or invalid text input (400)
- OpenAI API failures (500)
- Empty responses from OpenAI (502)
All errors are logged to the console for debugging.
If the ai_summary column doesn't appear in the tableviewer after running npx prisma db push:
- Hard refresh the browser (Ctrl+Shift+R)
- Check Supabase dashboard → Table Editor → food_logs to verify column exists
- Restart the server after schema changes
JWT tokens expire after 7 days, or may expire for other reasons. Get a new token by calling the login endpoint again.
Check that OPENAI_API_KEY is correctly set in .env and that you have API credits in your OpenAI account.