Successfully implemented 13 new AI-extracted fields that provide deeper nutrition insights with zero additional user input. All data is automatically extracted from meal photos and descriptions.
File: backend/src/main/resources/db/migration/V11__add_enhanced_ai_fields.sql
Added 13 new columns to meals table:
cooking_method- VARCHAR(50) - How food was preparednova_score- DECIMAL(3,2) - Food processing level (1-4)is_ultra_processed- BOOLEAN - Quick UPF flagis_fried- BOOLEAN - Fried food detectionhas_refined_grains- BOOLEAN - White bread/rice/pastaestimated_gi- INTEGER - Glycemic index (0-100)estimated_gl- INTEGER - Glycemic loadplant_count- INTEGER - Number of unique plant speciesunique_plants- JSONB - List of plant namesis_fermented- BOOLEAN - Fermented food flagprotein_source_type- VARCHAR(50) - animal/plant/dairy/seafood/mixedfat_quality- VARCHAR(20) - healthy/neutral/unhealthymeal_type_guess- VARCHAR(20) - breakfast/lunch/dinner/snack
File: backend/src/main/java/com/nutritheous/meal/Meal.java
Added 13 new fields with proper JPA annotations and @Builder.Default for booleans.
Files Updated:
backend/src/main/java/com/nutritheous/common/dto/AnalysisResponse.java- Added 13 fieldsbackend/src/main/java/com/nutritheous/common/dto/MealResponse.java- Added 13 fields
Both DTOs include proper @JsonProperty annotations for snake_case API responses.
File: backend/src/main/java/com/nutritheous/meal/MealService.java
Updated updateMealWithAnalysis() method to map all 13 new fields from AnalysisResponse to Meal entity.
File: backend/src/main/java/com/nutritheous/analyzer/OpenAIVisionService.java
- Image analysis prompt (
getAnalysisPrompt) - Added detailed field definitions and examples - Text-only prompt (
getTextOnlyPrompt) - Added same fields with text-based inference
- cooking_method: raw/steamed/boiled/grilled/baked/fried/roasted/pressure_cooked/sauteed
- nova_score: 1-4 decimal (1=whole foods, 4=ultra-processed)
- estimated_gi/gl: Based on typical glycemic values
- plant_count: Count ALL distinct plant species
- unique_plants: List each plant by name
- is_fermented: yogurt, kimchi, sourdough, etc.
- protein_source_type: Categorize primary protein
- fat_quality: Based on fat sources and cooking method
- meal_type_guess: Infer from food types and portions
- Added
getBooleanValue()helper method for safe boolean extraction - Updated
parseResponse()to extract all 13 new fields - Graceful handling of missing/null values
File: backend/src/main/resources/application.properties
Increased OpenAI max tokens: 800 → 2000 to accommodate expanded JSON response.
{
"cooking_method": "grilled",
"nova_score": 1.2,
"is_ultra_processed": false,
"is_fried": false,
"has_refined_grains": false,
"estimated_gi": 45,
"estimated_gl": 13,
"plant_count": 2,
"unique_plants": ["broccoli", "garlic"],
"is_fermented": false,
"protein_source_type": "animal",
"fat_quality": "healthy",
"meal_type_guess": "dinner"
}{
"cooking_method": "fried",
"nova_score": 3.8,
"is_ultra_processed": true,
"is_fried": true,
"has_refined_grains": true,
"estimated_gi": 78,
"estimated_gl": 42,
"plant_count": 3,
"unique_plants": ["lettuce", "tomato", "potato"],
"is_fermented": false,
"protein_source_type": "animal",
"fat_quality": "unhealthy",
"meal_type_guess": "lunch"
}cd backend
./gradlew flywayMigrateThe V11 migration will add all 13 columns to existing meals table.
cd backend
./gradlew bootRuncurl -X POST http://localhost:8081/api/meals/upload \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-F "image=@/path/to/meal.jpg" \
-F "description=grilled chicken with broccoli"{
"id": "...",
"calories": 450,
"cooking_method": "grilled",
"nova_score": 1.2,
"estimated_gi": 45,
"plant_count": 2,
"unique_plants": ["broccoli", "garlic"],
...
}{
"calories": 450,
"protein_g": 35,
"carbohydrates_g": 28,
"ingredients": ["chicken", "broccoli"],
"confidence": 0.85
}{
"calories": 450,
"protein_g": 35,
"carbohydrates_g": 28,
"ingredients": ["chicken", "broccoli"],
"confidence": 0.85,
"cooking_method": "grilled",
"nova_score": 1.2,
"is_ultra_processed": false,
"is_fried": false,
"has_refined_grains": false,
"estimated_gi": 45,
"estimated_gl": 13,
"plant_count": 2,
"unique_plants": ["broccoli", "garlic"],
"is_fermented": false,
"protein_source_type": "animal",
"fat_quality": "healthy",
"meal_type_guess": "dinner"
}- Processing Awareness - See NOVA scores and UPF flags
- Glycemic Control - GI/GL estimates for blood sugar management
- Plant Diversity Tracking - Count unique plants per day/week
- Quality Indicators - Fat quality and cooking method insights
- Weekly Reports - "You averaged NOVA 2.1 this week (mostly whole foods!)"
- Plant Diversity Goals - "12/30 unique plants this week"
- Glycemic Patterns - "Your low-GI meals keep you fuller longer"
- Processing Trends - "Restaurant meals have 60% higher NOVA scores"
- Token increase: 800 → 2000 (+150% tokens)
- Estimated cost per meal: ~$0.003 → ~$0.007 (still negligible)
- For 1000 meals/month: ~$3 → ~$7 (+$4/month)
Phase 1B will add photo metadata extraction and location intelligence:
- Extract GPS coordinates from EXIF data
- Reverse geocode with Google Maps API
- Enhance AI prompts with location context ("taken at Chipotle")
- Better estimates for restaurant vs home-cooked meals
Estimated effort: 4-6 hours
backend/src/main/resources/db/migration/V11__add_enhanced_ai_fields.sql
backend/src/main/java/com/nutritheous/meal/Meal.javabackend/src/main/java/com/nutritheous/meal/MealService.javabackend/src/main/java/com/nutritheous/common/dto/AnalysisResponse.javabackend/src/main/java/com/nutritheous/common/dto/MealResponse.javabackend/src/main/java/com/nutritheous/analyzer/OpenAIVisionService.javabackend/src/main/resources/application.properties
Total lines changed: ~200 lines
If issues arise, rollback with:
-- Revert V11 migration
ALTER TABLE meals
DROP COLUMN cooking_method,
DROP COLUMN nova_score,
DROP COLUMN is_ultra_processed,
DROP COLUMN is_fried,
DROP COLUMN has_refined_grains,
DROP COLUMN estimated_gi,
DROP COLUMN estimated_gl,
DROP COLUMN plant_count,
DROP COLUMN unique_plants,
DROP COLUMN is_fermented,
DROP COLUMN protein_source_type,
DROP COLUMN fat_quality,
DROP COLUMN meal_type_guess;Then revert code changes via git.
- All new fields are nullable - won't break existing meals
- Existing meals can be re-analyzed to populate new fields
- AI confidence scores may be lower for complex fields (GI/GL, NOVA)
- Frontend can display these fields gradually (no big bang UI change needed)
- Fields are future-proof - will improve as AI models improve