An AI-powered nutrition logging web app. Just say what you ate!
https://github.com/user-attachments/assets/4ff9301f-64b4-4f1a-9798-3883028fa9ec
YouTube video demo - In better quality
This project aims to track 48+ total nutrients using a centralized definition system:
Adding nutrients is now super easy! See Nutrient System Documentation
See the full list of defined nutrients here.
Quick Add Example:
# Add to config/nutrients.yml
- key: taurine_mg
type: float64
unit: mg
category: amino_acid
per_100g: true
original: true
go_field_name: Taurine
json_tag: taurine_mg
display_name: Taurine
Then run: script/generate-nutrients → All 20+ files automatically updated!
This diagram shows the simplified user journey from input to saved meal data, focusing on the user experience and key business logic rather than technical implementation details. The full technical flow is documented separately here.
graph TB
%% User journey starts - Multiple input methods
Start([User Input Options:<br/>🎤 Voice Recording<br/>✏️ Text Description<br/>⭐ Duplicate Favorite]) --> Auth{User Authentication<br/>JWT or API Key}
%% Authentication - simplified
Auth -->|✅ Authenticated User| AuthOK[User Verified<br/>JWT or Pro API Key]
Auth -->|❌ Not Logged In| AuthFail[Login Required]
AuthFail --> End([End])
%% Input processing flow
AuthOK --> InputMethod{Input Method?}
%% Three input paths
InputMethod -->|🎤 Voice| AudioProcess[Audio Upload & Transcription<br/>Max 50MB, AI converts speech to text]
InputMethod -->|✏️ Text| TextProcess[Direct Text Processing<br/>Skip transcription step]
InputMethod -->|⭐ Duplicate| DuplicateProcess[Copy Existing Favorite<br/>Skip AI processing entirely]
%% Error handling
AudioProcess -->|❌ Invalid File| UploadError[Error: Invalid Audio File]
TextProcess -->|❌ Empty Text| TextError[Error: Text Required]
DuplicateProcess -->|❌ Not Found| DuplicateError[Error: Favorite Not Found]
UploadError --> End
TextError --> End
DuplicateError --> End
%% Success paths converge
AudioProcess -->|✅ Transcribed| AIProcess[AI Processing Pipeline]
TextProcess -->|✅ Text Ready| AIProcess
DuplicateProcess -->|✅ Copied| SaveDirect[Save Duplicated Meal]
%% AI Processing - simplified into logical steps
AIProcess --> Step1[Step 1: Extract Food Items<br/>AI identifies individual foods from text]
Step1 -->|✅ Foods Identified| Step2[Step 2: Get Nutrition Data<br/>Smart lookup with AI assistance]
Step1 -->|❌ Failed| ProcessError[Error: Could not understand input]
ProcessError --> End
%% Smart nutrition lookup - business logic
Step2 -->|✅ Success| NutritionLookup{How do we find nutrition data?}
Step2 -->|❌ Failed| ProcessError
%% Different data sources - simplified
NutritionLookup --> Cache[Check Our Database<br/>for Previously Calculated Foods]
NutritionLookup --> ProductDB[Search External Product Databases<br/>for Branded Items]
NutritionLookup --> AI[Ask AI for Nutrition<br/>Analysis and Estimates]
Cache -->|Found| UseCache[✅ Use Cached Data<br/>Fast Response]
Cache -->|Not Found| ProductDB
ProductDB -->|Found Brand Match| UseProduct[✅ Use Product Data as Context<br/>AI gets real product info for<br/>more accurate nutrition calculation]
ProductDB -->|Not Found| AI
AI --> UseAI[✅ AI Calculates Nutrition<br/>Comprehensive Analysis]
%% All paths lead to nutrition data
UseCache --> NutritionReady[Nutrition Data Ready<br/>for All Food Items]
UseProduct --> NutritionReady
UseAI --> NutritionReady
%% Final steps - user value
NutritionReady --> Summary[Calculate Meal Summary<br/>48+ Total Nutrients including<br/>Calories, Protein, Vitamins, Minerals]
Summary --> Save[Save to User's Meal History<br/>with Labels and Timestamps]
SaveDirect --> DirectSuccess[Return Duplicated Meal<br/>📱 User sees copied nutrition data]
%% Success response
Save -->|✅ Saved Successfully| Success[Return Complete Results<br/>📱 User sees comprehensive nutrition data]
Save -->|⚠️ Save Failed| PartialSuccess[Return Nutrition Data<br/>⚠️ Not saved to history]
Success --> UserActions[User Can:<br/>📊 View on Dashboard<br/>📝 Add to Log<br/>⭐ Mark as Favorite<br/>🏷️ Add Labels]
PartialSuccess --> UserActions
DirectSuccess --> UserActions
UserActions --> End
%% Key benefits callout
NutritionReady --> Benefits[Key Benefits:<br/>🚀 Fast responses via 4-tier caching<br/>🎯 Real product data guides AI decisions<br/>🤖 AI fills gaps for everything else<br/>📊 48+ comprehensive nutrients tracked<br/>⭐ Easy favorites and duplication<br/>🏷️ Flexible labeling system]
%% Styling for business audience - High contrast for accessibility
classDef userAction fill:#0D47A1,stroke:#000000,stroke-width:3px,color:#FFFFFF
classDef success fill:#1B5E20,stroke:#000000,stroke-width:3px,color:#FFFFFF
classDef error fill:#B71C1C,stroke:#000000,stroke-width:3px,color:#FFFFFF
classDef process fill:#E65100,stroke:#000000,stroke-width:3px,color:#FFFFFF
classDef benefit fill:#4A148C,stroke:#000000,stroke-width:3px,color:#FFFFFF
classDef input fill:#6A1B9A,stroke:#000000,stroke-width:3px,color:#FFFFFF
class Start userAction
class AuthOK,UseCache,UseProduct,UseAI,Success,PartialSuccess,DirectSuccess,SaveDirect success
class AuthFail,UploadError,TextError,DuplicateError,ProcessError error
class AudioProcess,TextProcess,DuplicateProcess,AIProcess,Step1,Step2,Summary,Save process
class Benefits,UserActions benefit
class InputMethod input
Setup Dependencies:
script/bootstrap
Get API Keys:
Configure:
# create .env file
# Required
OPENAI_API_KEY=<key>
# Server Configuration - Use port 3001 for API to avoid conflict with SvelteKit frontend
PORT=3001
ENV=development
# CORS Configuration - Allow SvelteKit frontend
CORS_ALLOWED_ORIGINS=http://localhost:3000
# Logging & Debugging (Enable detailed error reporting)
LOG_LEVEL=DEBUG
DEBUG=true
# OpenAI Configuration
OPENAI_TRANSCRIBE_MODEL=gpt-4o-mini-transcribe
TRANSCRIBE_LANGUAGE=en
#OPENAI_TRANSCRIBE_RESPONSE_FORMAT=
# Upload Configuration
MAX_UPLOAD_BYTES=104857600 # Maximum upload size in bytes (default: 100MB)
# Database Configuration - Use Supabase for local and production
# Follow Supabase local development setup: https://supabase.com/docs/guides/local-development
Run the API: PORT=3001 script/server (use --production for production mode).
Setup Dependencies:
script/bootstrap
Run the web app:
script/frontend
Or to start without opening the browser:
script/frontend --no-open
Use:
First, in two separate terminal windows, run the backend and frontend:
script/server (backend)script/frontend (frontend)Now, in a third terminal, run:
npm run mobile:sync
npm run ios
GET /api/v1/health — Health check with server statusPOST /api/v1/consumption — Multipart form with audio field (webm/opus/mp3/wav)GET /api/v1/consumptions — View stored consumptions with optional date range filtering. Supports tier-based limits: Free users can access up to 7 days, Pro users up to 365 days (development mode only)GET /api/v1/docs — Interactive API documentation via Swagger UI (development mode only)GET /api/v1/openapi.yaml — OpenAPI 3.0.3 specification (development mode only)GET /version — Version and build information including commit SHA, build time, and git tagNote: The embedded static frontend has been removed. The API now runs on port 3001 by default, and the SvelteKit frontend runs on port 3000.
script/testscript/lint script/build (or script/build --single-target for faster iteration)PORT=3001 script/server (use script/server --production for production mode)script/frontend (runs on port 3000 and opens browser)script/frontend --no-opencd apps/web && npm run dev (alternative manual approach)cd apps/web && npm run buildcd apps/web && npm run checkcd apps/web && npm run generate:api (regenerates types from OpenAPI spec)The API follows OpenAPI 3.0.3 specification:
/api/v1/openapi.yaml/api/v1/docs (Swagger UI, development only)script/generate-types (requires oapi-codegen via the go toolchain - vendored in this project)openapi-typescript from the OpenAPI specscript/db reset — Drop all tables and start freshscript/db dump — View database contents in human-readable formatThe application supports automated deployment with built-in version tracking:
script/deploy frontend — Deploy SvelteKit app to Cloudflare Workers with git metadatascript/deploy backend — Deploy Go API to Railwayscript/deploy — Deploy both frontend and backendVersion Tracking:
/version endpoint (both JSON API and UI page)Requirements:
CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN environment variablesRAILWAY_TOKEN environment variable