Skip to content

About

HealthPilot is an intelligent wellness app that provides personalized guidance on nutrition, fitness, sleep, and daily health habits. It uses AI to analyze user data, track progress, and generate actionable recommendations tailored to individual goals.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

AI Fitness Coach

Next.js + Supabase + Gemini scaffold covering four features:

  1. Meals — photo upload → Gemini vision estimates calories/macros (app/meals, app/api/meals/analyze)
  2. Workouts — deterministic set logging + progression rule, no model calls (app/workouts, app/api/workouts)
  3. Form check — short clip → client-side frame extraction → Gemini feedback (app/form-check, app/api/form/analyze)
  4. Habits — daily metric logging + Recharts trend (app/habits, app/api/habits)

Setup

npm install
cp .env.local.example .env.local   # fill in Supabase + Gemini keys

In your Supabase project:

  1. Run supabase/schema.sql in the SQL editor (creates tables + RLS policies).
  2. Create two private Storage buckets: meal-images and form-clips.
  3. Add storage policies on each bucket restricting reads/writes to paths prefixed with the requesting user's auth.uid() — the API routes already upload to ${user.id}/..., so a policy like bucket_id = 'meal-images' AND (storage.foldername(name))[1] = auth.uid()::text covers it.
  4. Enable email auth (or your provider of choice) under Authentication.
npm run dev

Auth UI isn't wired up yet — add a Supabase Auth flow (magic link or OAuth) before these routes are useful, since every route calls supabase.auth.getUser() and 401s without a session.

Why things are structured this way

  • RLS from day one (supabase/schema.sql) — every user-data table has policies scoped to auth.uid(). Retrofitting this after real user data exists is painful and risky; it's cheap now.
  • Usage metering before every Gemini call (lib/usage.ts) — meals/analyze and form/analyze both check a daily cap first. Without this, one user hammering uploads can run up unbounded API cost.
  • Prompt versioning (PROMPT_VERSIONS in lib/gemini.ts) — stored alongside every Gemini response in gemini_prompt_version. When you tweak a prompt and outputs get weird, you can tell which version produced which row.
  • Raw vs. corrected data kept separate (meals.gemini_response vs meals.corrected) — never overwrite the model's original output with a user's correction. That pairing is exactly the data you'd want later to evaluate or fine-tune against.
  • Frame extraction happens client-side (app/form-check/page.tsx) — the browser samples ~6 JPEG frames from the clip before anything is uploaded, so payload size and per-call Gemini cost stay bounded regardless of clip length, and raw video never has to be stored or sent to the model.
  • Workout progression is a plain function, not a model call (suggestNextLoad in app/api/workouts/route.ts) — progressive overload is deterministic; save the LLM budget for meals/form where vision is actually needed.

Known gaps to fill in next

  • Auth pages / session handling (sign-in, sign-out, middleware to protect routes)
  • Editing/correcting a meal's estimated macros (the corrected column exists; no UI yet)
  • Exercise + set entry UI for workouts (routes exist; only workout creation has a form)
  • Pagination on meals/form-session history
  • Server Actions could replace some of these Route Handlers if you prefer that pattern

About

HealthPilot is an intelligent wellness app that provides personalized guidance on nutrition, fitness, sleep, and daily health habits. It uses AI to analyze user data, track progress, and generate actionable recommendations tailored to individual goals.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages