💡 Inspiration
The idea for EatWise AI was born from a deeply personal frustration: most nutrition apps feel either too clinical to use daily, or too shallow to actually help you make meaningful changes. People don't fail at healthy eating because they don't want to eat well - they fail because the gap between knowing what to eat and understanding why it matters is enormous.
What really pushed us over the edge was looking at the United Nations Sustainable Development Goal 3: Good Health and Well-Being. Diet-related non-communicable diseases (NCDs) - diabetes, heart disease, obesity - are among the leading causes of preventable death globally. And yet, actionable, personalized nutritional guidance remains largely inaccessible to the average person without a dietitian.
We asked ourselves: what if an AI could bridge that gap for everyone - for free, on any device, in seconds?
That question became EatWise AI.
🔨 How We Built It
EatWise AI is a client-side React + Vite progressive web application backed by Supabase (PostgreSQL + Auth) for secure, multi-device data persistence.
The Architecture
The app follows a clean layered design:
- React 19 + React Router for the SPA shell and page routing
- Zustand for low-boilerplate global state management synced with Supabase
- TanStack React Query for async data fetching with caching and mutation handling
- Framer Motion + GSAP for fluid, physics-aware UI transitions
User → React UI Components
↕
Custom React Hooks
↕
Zustand Store ←→ Supabase (PostgreSQL + Auth)
↕
External Services:
• Open Food Facts API (nutritional data)
• Google Gemini 2.5 Flash (primary AI)
• OpenRouter (fallback AI provider)
The Nutrition Science Under the Hood
We didn't want to make up calorie targets - we grounded them in clinical science. Personalised daily calorie goals are calculated using the Mifflin-St Jeor equation for Basal Metabolic Rate (BMR):
$$ \text{BMR (men)} = 10W + 6.25H - 5A + 5 $$
$$ \text{BMR (women)} = 10W + 6.25H - 5A - 161 $$
where $W$ is weight in kg, $H$ is height in cm, and $A$ is age in years. This is then multiplied by an activity factor (1.2 - 1.9) to yield the user's Total Daily Energy Expenditure (TDEE), from which macro splits are derived based on their goal (cut / maintain / bulk).
BMI is calculated in real-time within the Health & Wellness Hub:
$$ \text{BMI} = \frac{\text{weight (kg)}}{\text{height (m)}^2} $$
and categorised into WHO standard risk bands displayed with contextual NCD prevention tips.
The AI Layer
The most technically ambitious part of EatWise AI is its AI Meal Analyzer. Users can:
Upload a photo of their meal → the image is converted to Base64 and sent to Google Gemini 2.5 Flash with a carefully engineered prompt requesting structured JSON output: estimated calories, macros (protein, carbs, fat), a health score out of 10, health impact badges, and actionable suggestions.
Type a text description → the same structured analysis pipeline handles pure text prompts.
The Recipe Suggester uses the same AI foundation - the user supplies whatever ingredients they have on hand, optionally filtering by dietary preferences (Vegan, Keto, Gluten-Free, etc.), and the model returns a fully formatted recipe with step-by-step instructions, prep/cook times, macro estimates, and active health benefits.
The Holistic Wellness Score
Beyond macros, EatWise tracks a composite Wellness Score that aggregates five signals into a unified $[0, 100]$ metric:
$$ W_{\text{score}} = 0.25 \cdot S_{\text{BMI}} + 0.25 \cdot S_{\text{meals}} + 0.20 \cdot S_{\text{water}} + 0.20 \cdot S_{\text{sleep}} + 0.10 \cdot S_{\text{mood}} $$
Each component $S_i \in [0, 1]$ is normalised independently (e.g. BMI score peaks at the "Normal" band; meal score rewards hitting 80%+ of calorie goal without exceeding it). This makes the score resistant to gaming any single axis and rewards genuinely balanced living.
Backend & Security
The Supabase schema underpinning the app was designed with Row Level Security (RLS) as a first principle. Every table - profiles, meals, favorites, water_intake, wellness_checkins, streak_days, ai_analysis_logs - enforces auth.uid() equality checks on all CRUD paths. No user can ever read or write another user's data via the public API key, even if they know the endpoint.
🧗 Challenges We Faced
1. Prompt Engineering for Consistent Structured Output
Getting Gemini to reliably return machine-parseable JSON - not markdown prose, not partial JSON, not JSON wrapped in code fences - required significant iteration. We solved this with explicit schema specification in the system prompt, output format enforcement, and a JSON sanitisation layer on the client that strips fences and handles partial parse failures gracefully.
2. Image Handling
Browsers give you a File object; Gemini expects a Base64 string with a MIME type declaration. Building an async FileReader → Base64 pipeline that handles large images without blocking the UI, and capping uploads to avoid hitting API payload limits, required careful async state management using React refs and useEffect cleanup patterns.
3. AI Provider Failover Without User-Facing Latency
The silent Gemini → OpenRouter fallback needed to be invisible to the user. We implemented this with a try/catch waterfall in the API service layer: a failed Gemini call triggers an immediate retry to OpenRouter with the same payload schema, so the user simply sees a slightly longer loading spinner - never an error (unless both fail simultaneously).
4. Avoiding Stale State in a Zustand + Supabase Hybrid
Zustand is synchronous and in-memory; Supabase is async and remote. Keeping them consistent required careful ordering: Supabase insert → on confirmation → Zustand setState. Optimistic updates were considered but ultimately deferred in favour of correctness - a meal that fails to persist should not appear on the dashboard.
5. Meaningful Wellness Metrics That Don't Shame Users
Health apps can easily become anxiety-inducing. Designing the Wellness Score so it rewards progress rather than punishing imperfection required multiple design iterations. The final formula heavily weights sleep and hydration - areas where small improvements have outsized health impacts - and treats mood as a lighter signal to avoid over-medicalising normal emotional variation.
📚 What We Learned
- Multimodal AI is genuinely ready for consumer use. Gemini 2.5 Flash's ability to estimate macros from a food photo - even imperfectly - is a step-change from what was possible two years ago.
- The hardest part of health tech is not the tech. Deciding what to show users and how to frame it so it motivates rather than overwhelms is a UX and ethics challenge as much as an engineering one.
- Supabase RLS is production-grade security done right. Enforcing data isolation at the database policy layer - not the application layer - is the correct mental model for multi-tenant apps.
- Nutrition science is humbling. The more we dug into dietary guidelines, the more we appreciated how much nuance professional dietitians hold. AI estimates are powerful starting points, not clinical ground truth - and we designed the copy and UX to make this clear.
🌍 Impact & SDG 3 Alignment
EatWise AI directly supports UN SDG 3: Good Health and Well-Being by:
- Making evidence-based nutrition tracking accessible without specialist knowledge or expensive apps
- Providing preventive health education targeting the four major NCD categories (cardiovascular disease, diabetes, cancer, mental health)
- Encouraging holistic self-monitoring - sleep, hydration, mood - not just calorie counting
- Surfacing actionable, contextual AI guidance rather than raw data dumps
We believe the future of preventive healthcare is personal, intelligent, and free at the point of use. EatWise AI is our contribution to that future.
Built With
- 2.5-openrouter
- food
- gsap-react
- motion
- query-recharts-framer
- react
- router-open
- supabase-gemini
- vite
- zustand
Log in or sign up for Devpost to join the conversation.