🏆 3rd Place — BugsByte Hackathon · Built for the Nutrium challenge track
A full-stack AI-powered nutrition and wellness platform. Upload a photo of your fridge, get a recipe. Scan a restaurant menu, get the healthiest pick. Log how you feel, get a clinical report. All personalized to your profile.
| Module | Route | Description |
|---|---|---|
| NutriChat | POST /chat |
Conversational AI nutritionist "Vitium" — answers questions about food, supplements, and wellness |
| NutriUpgrade | POST /healthier-ref |
Transforms any dish into a healthier version targeting Nutri-Score A or B, while preserving the dish's identity |
| FoodSwap | POST /switch-refs |
Suggests a completely different healthy alternative to a meal, based on your preferences |
| Photo to Recipe | POST /photo-to-recipe |
GPT-4o Vision scans a photo of your fridge or pantry and generates a complete recipe |
| Menu Scout | POST /analyze-menu |
GPT-4o Vision reads a restaurant menu photo and recommends the healthiest dish |
| Food Compare | POST /compare |
AI head-to-head nutritional comparison of two food items with a justified verdict |
| NutriMap | GET /places/nearby |
Finds healthy restaurants and health stores near you via Google Places API |
| Insights | POST /voice-log/text |
Logs dietary reflections, analyzes sentiment, detects plan deviations |
| Clinical Report | GET /report/download/{user_id} |
Generates a downloadable PDF clinical behaviour report from a user's insight history |
| Food Search | GET /product |
Searches the FatSecret food database (with Portuguese → English translation) |
Every AI feature is context-aware: once a user completes their profile, all recommendations automatically account for allergies, dietary preferences, biometrics, and nutritional goals.
The repo follows a bones / skin metaphor:
healthium/
├── bones/ # Backend — FastAPI (Python)
│ └── app/
│ ├── main.py
│ ├── database.py
│ ├── models.py
│ ├── schemas.py
│ ├── helpers/
│ │ ├── chat_gpt.py # Translation utilities
│ │ ├── fat_secret.py # FatSecret API client
│ │ └── user_context.py # Builds personalized AI prompts from user profile
│ └── router/
│ ├── auth.py
│ ├── nutrichat.py
│ ├── healthier_ref.py
│ ├── substituir_ref.py
│ ├── photo_to_recipe.py
│ ├── best_ref.py # Menu Scout
│ ├── compare_aliments.py
│ ├── places_near.py
│ └── insigths.py # Insights + PDF report
└── skin/ # Frontend — Vue 3 + TypeScript
└── src/
├── views/ # One view per feature module
├── components/ # Shared UI + map + chat widget
├── api/ # axios client, queries, mutations
├── stores/ # Pinia auth store
└── router/ # Vue Router with auth guards
- FastAPI — async REST API
- SQLModel + SQLite — ORM and local database
- OpenAI Python SDK — GPT-4o (vision) and GPT-4o-mini
- passlib + bcrypt — password hashing
- fpdf — PDF generation for clinical reports
- httpx — async HTTP client (FatSecret, Google Places, Nominatim)
- uv — fast Python package manager
- Vue 3 + TypeScript + Vite
- Pinia — state management
- Vue Router v5 — client-side routing with auth guards
- TanStack Query — async data fetching and caching
- Tailwind CSS v4 — utility-first styling
- shadcn-vue / reka-ui — accessible UI components
- Vue Leaflet — interactive map for NutriMap
- vee-validate + Zod — form validation
- Python 3.12+
- Node.js 18+ (or Bun)
- API keys (see Environment Variables)
cd bones
# Install dependencies with uv
pip install uv
uv sync
# Create a .env file (see Environment Variables section)
cp .env.example .env # or create manually
# Start the development server
uv run uvicorn app.main:app --reload --port 8000The API will be available at http://localhost:8000.
Interactive docs: http://localhost:8000/docs
cd skin
# Install dependencies
npm install
# or: bun install
# Start the development server
npm run dev
# or: bun devThe app will be available at http://localhost:5173.
Create a .env file inside the bones/ directory:
# OpenAI — Required for all AI features
OPEN_AI_KEYS=sk-...
# FatSecret — Required for food database search (/product endpoint)
# Get credentials at https://platform.fatsecret.com/
FAT_SECRET_CLIENT_ID=your_client_id
FAT_SECRET_KEY=your_client_secret
# Google Places API — Required for NutriMap (/places/nearby endpoint)
# Falls back to mock data (Braga) if not provided
GOOGLE_API_KEY=your_google_api_key
# Session middleware secret — any random secure string
RANDOM_KEY_MIDDLEWARE=your_random_secret_stringNote: The app works without
GOOGLE_API_KEY— it will return a mock healthy restaurant in Braga as a fallback. All AI features require a validOPEN_AI_KEYS.
| Method | Endpoint | Description |
|---|---|---|
POST |
/auth/register |
Register a new user |
POST |
/auth/login |
Login and receive user session |
POST |
/auth/complete-profile/{user_id} |
Set health profile (goals, allergies, biometrics) |
GET |
/auth/me/{user_id} |
Get user profile |
| Method | Endpoint | Body / Params |
|---|---|---|
POST |
/chat |
{ message, user_id? } |
POST |
/healthier-ref |
?dish_name=...&user_id=... |
POST |
/switch-refs |
?dish_name=...&user_preferences=...&user_id=... |
POST |
/photo-to-recipe |
multipart/form-data — file (image) |
POST |
/analyze-menu |
multipart/form-data — file (menu image) |
POST |
/compare |
{ product_a, product_b } + ?user_id=... |
| Method | Endpoint | Description |
|---|---|---|
GET |
/product?product=... |
Search FatSecret food database |
GET |
/default-list |
Returns a default list of 10 common foods |
GET |
/places/nearby?lat=...&lon=...&city=...&distance=... |
Find healthy places nearby |
| Method | Endpoint | Description |
|---|---|---|
POST |
/voice-log/text |
Submit a text insight — analyzed for sentiment and dietary deviation |
GET |
/report/download/{user_id} |
Download a GPT-generated clinical PDF report |
User
├── id, email, hashed_password
├── name, dob, gender, weight, height
├── activity, goal
├── allergies: JSON[]
├── preferences: JSON[]
├── profile_completed: bool
└── insights → UserInsight[]
UserInsight
├── id, user_id → User
├── resume (AI summary)
├── sentiment (e.g. "Frustrado", "Motivado")
├── is_deviation: bool
└── created_at
The database is SQLite and is created automatically on first run at bones/healthium.db.
The frontend enforces a three-state auth flow via Vue Router guards:
- Not logged in → redirected to
/loginfor any protected route - Logged in, no profile → redirected to
/formsto complete health profile - Logged in, profile complete → full access to all modules;
/loginand/formsredirect to/
Protected routes include: /upgrade, /foto, /compare, /reserve, /menu-scout, /insights, /nutrimap.
| View | Route | Module |
|---|---|---|
HomeView |
/ |
Landing page |
AuthView |
/login |
Login / Register |
FormsView |
/forms |
Health profile onboarding |
NutriUpgradeView |
/upgrade |
NutriUpgrade |
ReceitaFotoView |
/foto / /lab |
Photo to Recipe |
CompareView |
/compare |
Food Compare |
MenuScoutView |
/menu-scout |
Menu Scout |
NutriMapView |
/nutrimap |
NutriMap |
InsightsView |
/insights |
Voice/Text Insights |
ReServeView |
/reserve |
Reservations |
ServicosView |
/servicos |
Services overview |
ProfileView |
/profile |
User profile |
- The backend currently uses SQLite for simplicity. The
pyproject.tomlalso includesasyncpgandpsycopg2-binaryfor a future migration to PostgreSQL. - CORS is configured to allow all origins (
*) — restrict this in production. - The session middleware secret is hardcoded as a fallback in
main.py— always setRANDOM_KEY_MIDDLEWAREin your.envfor real deployments. - The AI prompts are written in European Portuguese — all model responses come back in PT-PT.
This project was built as a hackathon submission. All rights reserved.