LuckyHappyFish commited on
Commit
453dfb0
·
0 Parent(s):

PlateMate: AI food recognition with RAG-powered nutrition advice

Browse files

- Streamlit app with camera + upload support (mobile-friendly)
- HuggingFace Transformers food image classifier (local inference)
- ChromaDB RAG pipeline with 49 curated nutrition documents
- Google Gemini 3 Flash for ingredient + healthier alternative generation
- Ready for HuggingFace Spaces deployment

Made-with: Cursor

.gitignore ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ __pycache__/
2
+ *.pyc
3
+ .env
4
+ chroma_db/
5
+ .streamlit/secrets.toml
6
+ *.egg-info/
7
+ .venv/
8
+ venv/
9
+ .DS_Store
README.md ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: PlateMate
3
+ emoji: 🍽️
4
+ colorFrom: green
5
+ colorTo: yellow
6
+ sdk: streamlit
7
+ sdk_version: "1.44.1"
8
+ app_file: app.py
9
+ pinned: false
10
+ short_description: AI food recognition with RAG-powered nutrition advice
11
+ ---
12
+
13
+ # PlateMate — AI-Powered Culinary Assistant
14
+
15
+ PlateMate identifies foods from photos and provides nutritional insights using a **Retrieval-Augmented Generation (RAG)** pipeline. Upload or snap an image of your meal and get the detected food, its ingredients, and healthier alternatives backed by a curated nutrition knowledge base.
16
+
17
+ ## Architecture
18
+
19
+ ```
20
+ User (upload / camera)
21
+
22
+
23
+ ┌────────────────────────────┐
24
+ │ HuggingFace Transformers │ Food image classification (local)
25
+ │ food-image-classification │
26
+ └────────────┬───────────────┘
27
+
28
+
29
+ ┌────────────────────────────┐
30
+ │ Google Gemini 3 Flash │ Ingredient generation
31
+ └────────────┬───────────────┘
32
+
33
+
34
+ ┌────────────────────────────┐
35
+ │ ChromaDB vector search │ Retrieve top-5 nutrition docs
36
+ │ + Gemini 3 Flash (RAG) │ Generate grounded response
37
+ └────────────────────────────┘
38
+ ```
39
+
40
+ ## Tech Stack
41
+
42
+ | Layer | Technology |
43
+ |---------------|------------------------------------------------ |
44
+ | Frontend | Streamlit |
45
+ | ML Inference | HuggingFace Transformers (image classification) |
46
+ | LLM | Google Gemini 3 Flash |
47
+ | Vector DB | ChromaDB (cosine similarity) |
48
+ | RAG Pipeline | Retrieve from ChromaDB → augment prompt → Gemini|
49
+
50
+ ## How the RAG Pipeline Works
51
+
52
+ 1. **Indexing** — On startup, 49 curated nutrition and recipe documents are embedded and stored in ChromaDB.
53
+ 2. **Retrieval** — When a user queries for healthier alternatives, the top-5 most semantically relevant documents are retrieved via cosine similarity.
54
+ 3. **Generation** — Retrieved context is injected into a prompt sent to Gemini 3 Flash, producing a grounded response.
app.py ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from PIL import Image
3
+
4
+ from backend.classifier import classify_image
5
+ from backend.rag import get_ingredients, get_healthier_alternatives, seed_collection
6
+
7
+
8
+ @st.cache_resource
9
+ def _init():
10
+ seed_collection()
11
+
12
+
13
+ _init()
14
+
15
+ st.set_page_config(
16
+ page_title="PlateMate",
17
+ page_icon="🍽️",
18
+ layout="centered",
19
+ initial_sidebar_state="collapsed",
20
+ )
21
+
22
+ st.markdown(
23
+ """
24
+ <style>
25
+ /* ---------- Base ---------- */
26
+ .main-title {
27
+ text-align: center;
28
+ font-size: 2.6rem;
29
+ font-weight: 800;
30
+ background: linear-gradient(135deg, #2E7D32, #66BB6A);
31
+ -webkit-background-clip: text;
32
+ -webkit-text-fill-color: transparent;
33
+ margin-bottom: 0;
34
+ }
35
+ .subtitle {
36
+ text-align: center;
37
+ color: #777;
38
+ font-size: 1.1rem;
39
+ margin-top: 0;
40
+ margin-bottom: 1.5rem;
41
+ }
42
+ .section-header {
43
+ font-size: 1.25rem;
44
+ font-weight: 600;
45
+ color: #333;
46
+ border-bottom: 2px solid #E8F5E9;
47
+ padding-bottom: 0.4rem;
48
+ margin-top: 1.5rem;
49
+ }
50
+ div[data-testid="stMetric"] {
51
+ background: #F1F8E9;
52
+ border-radius: 10px;
53
+ padding: 12px 16px;
54
+ }
55
+
56
+ /* ---------- Mobile (<640px) ---------- */
57
+ @media (max-width: 640px) {
58
+ .main-title { font-size: 2rem; }
59
+ .subtitle { font-size: 0.95rem; }
60
+
61
+ /* Full-width buttons & inputs */
62
+ button, .stButton > button,
63
+ [data-testid="stFileUploader"],
64
+ [data-testid="stCameraInput"] {
65
+ width: 100% !important;
66
+ }
67
+
68
+ /* Prevent iOS zoom on input focus */
69
+ input, select, textarea { font-size: 16px !important; }
70
+
71
+ /* Larger tap targets */
72
+ .stButton > button {
73
+ min-height: 3rem;
74
+ font-size: 1.05rem !important;
75
+ }
76
+
77
+ /* Stack metric cards vertically */
78
+ [data-testid="stHorizontalBlock"] {
79
+ flex-direction: column !important;
80
+ }
81
+ }
82
+ </style>
83
+ """,
84
+ unsafe_allow_html=True,
85
+ )
86
+
87
+ st.markdown('<p class="main-title">🍽️ PlateMate</p>', unsafe_allow_html=True)
88
+ st.markdown(
89
+ '<p class="subtitle">Snap or upload a food photo for AI-powered nutritional insights</p>',
90
+ unsafe_allow_html=True,
91
+ )
92
+
93
+ with st.sidebar:
94
+ st.header("About")
95
+ st.write(
96
+ "**PlateMate** uses computer vision to identify foods, "
97
+ "then retrieves nutritional advice from a curated knowledge base "
98
+ "using Retrieval-Augmented Generation (RAG)."
99
+ )
100
+ st.divider()
101
+ st.markdown(
102
+ "**Tech stack:** FastAPI · ChromaDB · HuggingFace Transformers · "
103
+ "Google Gemini · Streamlit"
104
+ )
105
+
106
+ # --------------- Image input ---------------
107
+ tab_upload, tab_camera = st.tabs(["📁 Upload", "📷 Camera"])
108
+
109
+ with tab_upload:
110
+ uploaded_file = st.file_uploader(
111
+ "Upload a food image",
112
+ type=["jpg", "jpeg", "png", "webp"],
113
+ )
114
+
115
+ with tab_camera:
116
+ camera_photo = st.camera_input("Take a photo of your food")
117
+
118
+ image = None
119
+ if uploaded_file is not None:
120
+ image = Image.open(uploaded_file).convert("RGB")
121
+ elif camera_photo is not None:
122
+ image = Image.open(camera_photo).convert("RGB")
123
+
124
+ if image is not None:
125
+ st.image(image, caption="Your image", use_container_width=True)
126
+
127
+ if st.button("🔍 Analyze", type="primary", use_container_width=True):
128
+ with st.spinner("Classifying image..."):
129
+ predictions = classify_image(image)
130
+
131
+ if not predictions:
132
+ st.error("Classification returned no results.")
133
+ else:
134
+ top_food = predictions[0]["label"]
135
+ confidence = predictions[0]["confidence"]
136
+
137
+ st.markdown(
138
+ '<p class="section-header">🎯 Classification</p>',
139
+ unsafe_allow_html=True,
140
+ )
141
+ col1, col2 = st.columns(2)
142
+ col1.metric("Detected Food", top_food.replace("_", " ").title())
143
+ col2.metric("Confidence", f"{confidence * 100:.1f}%")
144
+
145
+ if len(predictions) > 1:
146
+ with st.expander("Other possibilities"):
147
+ for p in predictions[1:]:
148
+ st.write(
149
+ f"- **{p['label'].replace('_', ' ').title()}** "
150
+ f"— {p['confidence'] * 100:.1f}%"
151
+ )
152
+
153
+ with st.spinner("Fetching ingredients..."):
154
+ ingredients = get_ingredients(top_food)
155
+ st.markdown(
156
+ '<p class="section-header">📝 Ingredients</p>',
157
+ unsafe_allow_html=True,
158
+ )
159
+ st.write(ingredients)
160
+
161
+ with st.spinner("Generating healthier alternatives via RAG..."):
162
+ alternatives, sources_used = get_healthier_alternatives(top_food)
163
+ st.markdown(
164
+ '<p class="section-header">💡 Healthier Alternatives</p>',
165
+ unsafe_allow_html=True,
166
+ )
167
+ st.info(
168
+ f"Retrieved from {sources_used} knowledge-base documents via RAG"
169
+ )
170
+ st.write(alternatives)
171
+ else:
172
+ st.info("👆 Upload a food image or snap a photo to get started.")
backend/__init__.py ADDED
File without changes
backend/classifier.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image
2
+ from transformers import pipeline
3
+ from functools import lru_cache
4
+
5
+ from .config import get_settings
6
+
7
+
8
+ @lru_cache(maxsize=1)
9
+ def _load_pipeline():
10
+ settings = get_settings()
11
+ return pipeline("image-classification", model=settings.classification_model)
12
+
13
+
14
+ def classify_image(image: Image.Image, top_k: int = 5) -> list[dict]:
15
+ pipe = _load_pipeline()
16
+ predictions = pipe(image)
17
+ return [
18
+ {"label": p["label"], "confidence": round(p["score"], 4)}
19
+ for p in predictions[:top_k]
20
+ ]
backend/config.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic_settings import BaseSettings
2
+ from functools import lru_cache
3
+
4
+
5
+ class Settings(BaseSettings):
6
+ gemini_api_key: str = ""
7
+ chroma_persist_dir: str = "./chroma_db"
8
+ classification_model: str = "Shresthadev403/food-image-classification"
9
+ gemini_model: str = "gemini-3-flash-preview"
10
+
11
+ model_config = {"env_file": ".env"}
12
+
13
+
14
+ @lru_cache
15
+ def get_settings() -> Settings:
16
+ return Settings()
backend/rag.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+
5
+ import chromadb
6
+ from google import genai
7
+
8
+ from .config import get_settings
9
+ from .seed_data import DOCUMENTS
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ _chroma_client: chromadb.PersistentClient | None = None
14
+ _collection: chromadb.Collection | None = None
15
+ _gemini_client: genai.Client | None = None
16
+
17
+
18
+ def _get_collection() -> chromadb.Collection:
19
+ global _chroma_client, _collection
20
+ if _collection is None:
21
+ settings = get_settings()
22
+ _chroma_client = chromadb.PersistentClient(path=settings.chroma_persist_dir)
23
+ _collection = _chroma_client.get_or_create_collection(
24
+ name="recipes",
25
+ metadata={"hnsw:space": "cosine"},
26
+ )
27
+ return _collection
28
+
29
+
30
+ def _get_gemini_client() -> genai.Client:
31
+ global _gemini_client
32
+ if _gemini_client is None:
33
+ settings = get_settings()
34
+ _gemini_client = genai.Client(api_key=settings.gemini_api_key)
35
+ return _gemini_client
36
+
37
+
38
+ def seed_collection() -> None:
39
+ collection = _get_collection()
40
+ if collection.count() > 0:
41
+ logger.info("ChromaDB already seeded (%d documents).", collection.count())
42
+ return
43
+
44
+ ids = [f"doc_{i}" for i in range(len(DOCUMENTS))]
45
+ collection.add(
46
+ documents=[d["text"] for d in DOCUMENTS],
47
+ metadatas=[{"category": d["category"], "food": d["food"]} for d in DOCUMENTS],
48
+ ids=ids,
49
+ )
50
+ logger.info("Seeded ChromaDB with %d recipe/nutrition documents.", len(DOCUMENTS))
51
+
52
+
53
+ def get_ingredients(food_name: str) -> str:
54
+ client = _get_gemini_client()
55
+ settings = get_settings()
56
+
57
+ response = client.models.generate_content(
58
+ model=settings.gemini_model,
59
+ contents=(
60
+ f"List only the main ingredients for {food_name}. "
61
+ "Respond in a concise, comma-separated list without extra text."
62
+ ),
63
+ )
64
+ return response.text.strip()
65
+
66
+
67
+ def get_healthier_alternatives(food_name: str) -> tuple[str, int]:
68
+ collection = _get_collection()
69
+ client = _get_gemini_client()
70
+ settings = get_settings()
71
+
72
+ results = collection.query(
73
+ query_texts=[f"healthy alternative for {food_name}"],
74
+ n_results=5,
75
+ )
76
+
77
+ context_docs = results["documents"][0] if results["documents"] else []
78
+ context = "\n\n".join(context_docs)
79
+ sources_used = len(context_docs)
80
+
81
+ prompt = (
82
+ "You are a knowledgeable nutritionist and chef. Use the provided context "
83
+ "to give specific, actionable advice about healthier versions of foods. "
84
+ "Include calorie comparisons and a brief recipe when possible. "
85
+ "If the context doesn't cover the exact food, use relevant principles from it.\n\n"
86
+ f"Context from nutrition knowledge base:\n\n{context}\n\n"
87
+ f"What are healthier alternatives or modifications for {food_name}? "
88
+ f"Include a brief healthy recipe suggestion."
89
+ )
90
+
91
+ response = client.models.generate_content(
92
+ model=settings.gemini_model,
93
+ contents=prompt,
94
+ )
95
+ return response.text.strip(), sources_used
backend/seed_data.py ADDED
@@ -0,0 +1,545 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ DOCUMENTS = [
2
+ # --- Pizza & Italian ---
3
+ {
4
+ "food": "pizza",
5
+ "category": "italian",
6
+ "text": (
7
+ "Traditional pizza dough is made from refined white flour, which spikes blood sugar. "
8
+ "A healthier alternative uses whole-wheat flour or a cauliflower crust, cutting carbs by up to 60%. "
9
+ "Top with fresh vegetables like bell peppers, spinach, and mushrooms instead of processed meats. "
10
+ "Use part-skim mozzarella or nutritional yeast to reduce saturated fat. A thin-crust vegetable pizza "
11
+ "with a drizzle of olive oil provides fiber, vitamins, and healthy fats while keeping calories around 200 per slice."
12
+ ),
13
+ },
14
+ {
15
+ "food": "pizza",
16
+ "category": "italian",
17
+ "text": (
18
+ "Cauliflower crust pizza recipe: pulse one head of cauliflower into rice-sized pieces, microwave 4 minutes, "
19
+ "squeeze out moisture, mix with one egg and 1/2 cup mozzarella. Press onto a parchment-lined baking sheet "
20
+ "and bake at 425°F for 12 minutes. Top with marinara, fresh basil, cherry tomatoes, and a sprinkle of feta. "
21
+ "This version has roughly 150 calories per slice compared to 300+ for traditional pizza."
22
+ ),
23
+ },
24
+ {
25
+ "food": "pasta",
26
+ "category": "italian",
27
+ "text": (
28
+ "Swap regular pasta for whole-grain, chickpea, or lentil-based pasta to increase protein and fiber. "
29
+ "Chickpea pasta contains about 25g protein per serving compared to 7g in white pasta. "
30
+ "Replace cream-based sauces with marinara or pesto made from fresh basil, pine nuts, and olive oil. "
31
+ "Add roasted vegetables like zucchini, eggplant, and cherry tomatoes for volume without excess calories."
32
+ ),
33
+ },
34
+ {
35
+ "food": "lasagna",
36
+ "category": "italian",
37
+ "text": (
38
+ "Healthy lasagna substitutes: use thinly sliced zucchini or eggplant in place of pasta sheets. "
39
+ "Replace ricotta with blended cottage cheese for higher protein and lower fat. Use ground turkey "
40
+ "or lentils instead of ground beef to cut saturated fat by 50%. Layer with spinach and roasted "
41
+ "red peppers for extra vitamins. A veggie-forward lasagna can have 250 calories per serving "
42
+ "compared to 400+ for traditional versions."
43
+ ),
44
+ },
45
+ # --- Burgers & Sandwiches ---
46
+ {
47
+ "food": "hamburger",
48
+ "category": "burgers",
49
+ "text": (
50
+ "A standard fast-food burger has 500-700 calories with high saturated fat. Healthier alternatives: "
51
+ "use lean ground turkey (93% lean) or make black bean patties blended with oats and spices. "
52
+ "Wrap in lettuce leaves instead of a white bun, or use a whole-grain bun. Top with avocado slices "
53
+ "instead of cheese, and add plenty of fresh vegetables. A turkey burger in a lettuce wrap "
54
+ "with avocado runs about 300 calories with 25g protein."
55
+ ),
56
+ },
57
+ {
58
+ "food": "hamburger",
59
+ "category": "burgers",
60
+ "text": (
61
+ "Black bean burger recipe: mash one can of black beans, mix with 1/2 cup oats, one egg, "
62
+ "diced onion, garlic, cumin, and smoked paprika. Form into patties and bake at 375°F for "
63
+ "10 minutes per side. Each patty has about 180 calories, 10g protein, and 8g fiber. "
64
+ "Serve on a whole-wheat bun with arugula, tomato, and a tahini drizzle."
65
+ ),
66
+ },
67
+ {
68
+ "food": "sandwich",
69
+ "category": "burgers",
70
+ "text": (
71
+ "Upgrade sandwiches by swapping white bread for whole-grain or sourdough, which has a lower "
72
+ "glycemic index. Use hummus or mashed avocado instead of mayo to add fiber and healthy fats. "
73
+ "Choose grilled chicken or turkey breast over deli meats, which are high in sodium and nitrates. "
74
+ "Load up on vegetables: spinach, cucumber, roasted peppers, and sprouts add crunch and nutrients."
75
+ ),
76
+ },
77
+ # --- Asian Cuisine ---
78
+ {
79
+ "food": "sushi",
80
+ "category": "asian",
81
+ "text": (
82
+ "Sushi can be healthy but watch portion sizes of white rice, which is high-glycemic. "
83
+ "Request brown rice sushi for more fiber and nutrients. Choose sashimi (just fish) to skip "
84
+ "rice entirely. Avoid tempura rolls and spicy mayo, which add 200+ calories per roll. "
85
+ "Opt for rolls with salmon, tuna, or vegetables. Edamame is an excellent protein-rich side. "
86
+ "A salmon avocado roll with brown rice has about 250 calories with omega-3 fatty acids."
87
+ ),
88
+ },
89
+ {
90
+ "food": "ramen",
91
+ "category": "asian",
92
+ "text": (
93
+ "Traditional ramen broth is rich but calorie-dense. For a lighter version, use a miso or "
94
+ "chicken bone broth base with less sodium. Swap instant noodles for shirataki (konjac) noodles "
95
+ "which have nearly zero calories, or use whole-wheat ramen. Add soft-boiled egg for protein, "
96
+ "plenty of bok choy, mushrooms, and scallions. A bowl of miso ramen with shirataki noodles "
97
+ "and vegetables has about 200 calories compared to 500+ for standard tonkotsu ramen."
98
+ ),
99
+ },
100
+ {
101
+ "food": "fried rice",
102
+ "category": "asian",
103
+ "text": (
104
+ "Fried rice is typically made with day-old white rice and lots of oil. Healthier version: "
105
+ "use cauliflower rice or brown rice, cook with just one tablespoon of sesame oil, and load "
106
+ "with vegetables like peas, carrots, corn, and edamame. Use coconut aminos or low-sodium soy sauce. "
107
+ "Add scrambled egg or tofu for protein. Cauliflower fried rice has about 150 calories per cup "
108
+ "compared to 350+ for traditional fried rice."
109
+ ),
110
+ },
111
+ {
112
+ "food": "pad thai",
113
+ "category": "asian",
114
+ "text": (
115
+ "Pad Thai is high in calories from rice noodles, sugar, and oil. A healthier version uses "
116
+ "spiralized zucchini or sweet potato noodles, replaces sugar with a small amount of honey "
117
+ "or date paste, and uses less oil. Add shrimp or tofu for lean protein, plenty of bean sprouts, "
118
+ "and crushed peanuts for healthy fats. Zucchini noodle pad thai runs about 250 calories "
119
+ "compared to 400+ for the original."
120
+ ),
121
+ },
122
+ # --- Salads & Vegetables ---
123
+ {
124
+ "food": "salad",
125
+ "category": "salads",
126
+ "text": (
127
+ "Not all salads are healthy — Caesar salad with dressing can exceed 600 calories. "
128
+ "Build a nutritious salad: start with dark leafy greens (spinach, kale, arugula) "
129
+ "which have more nutrients than iceberg lettuce. Add lean protein (grilled chicken, "
130
+ "chickpeas, or hard-boiled eggs), healthy fats (avocado, nuts, olive oil), and fiber "
131
+ "(quinoa, roasted sweet potato). Use vinaigrette instead of creamy dressings."
132
+ ),
133
+ },
134
+ {
135
+ "food": "salad",
136
+ "category": "salads",
137
+ "text": (
138
+ "Power salad recipe: combine 2 cups mixed greens, 1/2 cup quinoa, 4 oz grilled chicken, "
139
+ "1/4 avocado, cherry tomatoes, cucumber, and toasted almonds. Dress with lemon-tahini "
140
+ "dressing (2 tbsp tahini, juice of one lemon, 1 tbsp water, pinch of salt). "
141
+ "This meal has about 450 calories, 35g protein, 10g fiber, and covers multiple food groups."
142
+ ),
143
+ },
144
+ {
145
+ "food": "caesar salad",
146
+ "category": "salads",
147
+ "text": (
148
+ "Lighten Caesar salad: replace croutons with roasted chickpeas (more protein, more fiber). "
149
+ "Make dressing from Greek yogurt, lemon juice, garlic, and a small amount of Parmesan "
150
+ "instead of the traditional egg-and-oil version. Use romaine hearts with added kale for "
151
+ "extra nutrients. Add grilled shrimp or salmon instead of just cheese. "
152
+ "This version cuts calories by 40% while adding 15g more protein."
153
+ ),
154
+ },
155
+ # --- Breakfast ---
156
+ {
157
+ "food": "pancakes",
158
+ "category": "breakfast",
159
+ "text": (
160
+ "Traditional pancakes are made with white flour and topped with syrup, creating a blood sugar spike. "
161
+ "Healthier version: blend one banana with two eggs for a 2-ingredient pancake, or use oat flour. "
162
+ "Top with fresh berries, a drizzle of pure maple syrup (less than regular syrup), "
163
+ "and a tablespoon of almond butter for protein and healthy fats. Banana-egg pancakes "
164
+ "have about 150 calories per serving with 10g protein."
165
+ ),
166
+ },
167
+ {
168
+ "food": "french toast",
169
+ "category": "breakfast",
170
+ "text": (
171
+ "Make french toast healthier by using whole-grain or sourdough bread instead of white bread. "
172
+ "Use an egg wash with unsweetened almond milk and cinnamon instead of heavy cream. "
173
+ "Cook in coconut oil spray rather than butter. Top with Greek yogurt and fresh fruit "
174
+ "instead of powdered sugar and syrup. This version provides 250 calories per serving "
175
+ "with 15g protein from the egg and yogurt."
176
+ ),
177
+ },
178
+ {
179
+ "food": "omelette",
180
+ "category": "breakfast",
181
+ "text": (
182
+ "Omelettes are already a great protein source. Make them healthier by using one whole egg "
183
+ "plus two egg whites to reduce cholesterol. Fill with spinach, tomatoes, mushrooms, and "
184
+ "bell peppers instead of just cheese and ham. Use feta or goat cheese (stronger flavor, "
185
+ "so you need less). Cook in olive oil instead of butter. A veggie omelette with feta "
186
+ "has about 250 calories and 20g protein."
187
+ ),
188
+ },
189
+ # --- Mexican & Latin ---
190
+ {
191
+ "food": "tacos",
192
+ "category": "mexican",
193
+ "text": (
194
+ "Swap fried taco shells for soft corn tortillas, which are lower in calories and gluten-free. "
195
+ "Use grilled fish (mahi-mahi or shrimp) or seasoned black beans instead of ground beef. "
196
+ "Top with fresh pico de gallo, shredded cabbage, and a squeeze of lime instead of sour cream "
197
+ "and shredded cheese. Fish tacos with corn tortillas have about 200 calories each "
198
+ "with 20g protein and omega-3 fatty acids."
199
+ ),
200
+ },
201
+ {
202
+ "food": "burrito",
203
+ "category": "mexican",
204
+ "text": (
205
+ "Burritos are calorie-dense (800+ calories) due to large tortillas, rice, cheese, and sour cream. "
206
+ "Make a burrito bowl instead: skip the tortilla and serve over cauliflower rice or a small portion "
207
+ "of brown rice. Use chicken or carnitas, black beans, corn salsa, and guacamole. "
208
+ "A burrito bowl with lean protein runs about 450 calories with 30g protein and plenty of fiber."
209
+ ),
210
+ },
211
+ {
212
+ "food": "nachos",
213
+ "category": "mexican",
214
+ "text": (
215
+ "Replace tortilla chips with baked sweet potato rounds or baked whole-grain pita chips. "
216
+ "Use black bean dip instead of processed cheese sauce. Top with grilled chicken, "
217
+ "fresh jalapeños, diced tomatoes, and a dollop of Greek yogurt instead of sour cream. "
218
+ "Sweet potato nachos have about 300 calories per serving compared to 500+ for loaded nachos."
219
+ ),
220
+ },
221
+ # --- Seafood ---
222
+ {
223
+ "food": "fish and chips",
224
+ "category": "seafood",
225
+ "text": (
226
+ "Traditional fish and chips are deep-fried, adding 300+ unnecessary calories. "
227
+ "Bake the fish instead: coat cod or haddock in a mixture of panko breadcrumbs, "
228
+ "lemon zest, and herbs, then bake at 400°F for 15 minutes. Make oven-baked fries "
229
+ "by tossing potato wedges with a tablespoon of olive oil and baking until crispy. "
230
+ "Baked fish and chips has about 350 calories compared to 800+ for the fried version."
231
+ ),
232
+ },
233
+ {
234
+ "food": "shrimp",
235
+ "category": "seafood",
236
+ "text": (
237
+ "Shrimp is naturally low-calorie (about 7 calories per shrimp) and high in protein. "
238
+ "Avoid breaded and fried preparations. Instead, grill or sauté with garlic and olive oil. "
239
+ "Pair with roasted vegetables and quinoa for a complete meal. Shrimp is also rich in "
240
+ "selenium and vitamin B12. A grilled shrimp bowl with vegetables and quinoa "
241
+ "has about 350 calories and 35g protein."
242
+ ),
243
+ },
244
+ # --- Desserts & Sweets ---
245
+ {
246
+ "food": "ice cream",
247
+ "category": "desserts",
248
+ "text": (
249
+ "Blend frozen bananas into 'nice cream' for a creamy, dairy-free alternative with no added sugar. "
250
+ "Add cocoa powder for chocolate flavor, or frozen berries for fruit varieties. "
251
+ "For a protein boost, blend in a tablespoon of peanut butter or protein powder. "
252
+ "Banana nice cream has about 100 calories per serving compared to 250+ for regular ice cream, "
253
+ "plus it provides potassium and fiber."
254
+ ),
255
+ },
256
+ {
257
+ "food": "cake",
258
+ "category": "desserts",
259
+ "text": (
260
+ "Healthier cake alternatives: use almond flour or oat flour instead of white flour for more "
261
+ "protein and fiber. Replace butter with applesauce or mashed banana (cuts fat by 75%). "
262
+ "Use honey or maple syrup instead of refined sugar. Greek yogurt frosting (Greek yogurt "
263
+ "whipped with a touch of honey and vanilla) replaces buttercream. An almond flour cake "
264
+ "has about 180 calories per slice compared to 350+ for traditional cake."
265
+ ),
266
+ },
267
+ {
268
+ "food": "chocolate",
269
+ "category": "desserts",
270
+ "text": (
271
+ "Choose dark chocolate (70% cacao or higher) over milk chocolate for more antioxidants "
272
+ "and less sugar. Dark chocolate contains flavonoids that support heart health. "
273
+ "Limit portions to 1-2 squares (about 1 oz). Pair with almonds or strawberries "
274
+ "for a satisfying, nutrient-rich dessert. An ounce of dark chocolate has about "
275
+ "170 calories with beneficial polyphenols and magnesium."
276
+ ),
277
+ },
278
+ {
279
+ "food": "cookies",
280
+ "category": "desserts",
281
+ "text": (
282
+ "Healthy cookie recipe: mix 2 ripe bananas, 1 cup oats, and a handful of dark chocolate chips. "
283
+ "Optional add-ins: chia seeds, shredded coconut, or walnuts. Drop spoonfuls onto a baking sheet "
284
+ "and bake at 350°F for 12 minutes. These 3-ingredient cookies have about 60 calories each "
285
+ "with no added sugar, flour, or butter. The oats provide fiber and the banana adds natural sweetness."
286
+ ),
287
+ },
288
+ # --- Chicken & Poultry ---
289
+ {
290
+ "food": "fried chicken",
291
+ "category": "poultry",
292
+ "text": (
293
+ "Fried chicken absorbs significant oil during cooking, adding 200+ calories per piece. "
294
+ "Oven-fried alternative: marinate chicken thighs in buttermilk, coat in seasoned whole-wheat "
295
+ "panko, and bake at 425°F for 25 minutes, flipping halfway. Use skinless chicken to reduce fat. "
296
+ "Air-frying is another excellent option. Oven-fried chicken has about 220 calories per piece "
297
+ "compared to 400+ for deep-fried, with the same satisfying crunch."
298
+ ),
299
+ },
300
+ {
301
+ "food": "chicken wings",
302
+ "category": "poultry",
303
+ "text": (
304
+ "Buffalo wings are typically deep-fried and coated in butter-based sauce. Healthier version: "
305
+ "bake wings at 400°F for 40 minutes until crispy, then toss in a sauce made from hot sauce "
306
+ "and a small amount of honey instead of butter. Serve with carrot and celery sticks with "
307
+ "Greek yogurt ranch dip. Baked wings have about 80 calories each versus 120+ for fried."
308
+ ),
309
+ },
310
+ # --- Rice & Grains ---
311
+ {
312
+ "food": "white rice",
313
+ "category": "grains",
314
+ "text": (
315
+ "White rice is a high-glycemic food with limited nutrients. Healthier alternatives: "
316
+ "brown rice (more fiber and B vitamins), quinoa (complete protein with all 9 essential amino acids), "
317
+ "cauliflower rice (90% fewer calories), or farro (chewy texture with high fiber). "
318
+ "Mixing half cauliflower rice with half regular rice is an easy way to cut calories by 45% "
319
+ "while maintaining a familiar texture."
320
+ ),
321
+ },
322
+ # --- Soups ---
323
+ {
324
+ "food": "soup",
325
+ "category": "soups",
326
+ "text": (
327
+ "Cream-based soups (chowder, bisque) can have 300+ calories per bowl. Switch to broth-based "
328
+ "soups with plenty of vegetables, beans, and lean protein. Blend a portion of the vegetables "
329
+ "to create creaminess without actual cream. Lentil soup is exceptionally nutritious: "
330
+ "one bowl has about 230 calories, 18g protein, and 15g fiber. Season with turmeric, "
331
+ "cumin, and lemon for anti-inflammatory benefits."
332
+ ),
333
+ },
334
+ # --- Snacks ---
335
+ {
336
+ "food": "chips",
337
+ "category": "snacks",
338
+ "text": (
339
+ "Potato chips are deep-fried and high in sodium. Healthier alternatives: bake thin-sliced "
340
+ "sweet potatoes or kale leaves with a light olive oil spray and sea salt at 300°F. "
341
+ "Air-popped popcorn seasoned with nutritional yeast is another excellent swap — "
342
+ "3 cups have only 90 calories with fiber. Roasted chickpeas (tossed with spices and "
343
+ "baked at 400°F for 30 minutes) provide protein and crunch at 120 calories per serving."
344
+ ),
345
+ },
346
+ {
347
+ "food": "french fries",
348
+ "category": "snacks",
349
+ "text": (
350
+ "French fries absorb a lot of oil during deep-frying. Healthier swaps: bake sweet potato fries "
351
+ "(more vitamin A and fiber) or regular potato wedges tossed in one tablespoon of olive oil "
352
+ "at 425°F for 25 minutes. Air-fried fries use 80% less oil. Jicama fries are a low-carb "
353
+ "alternative with a satisfying crunch. Baked sweet potato fries have about 130 calories "
354
+ "per serving compared to 365 for fast-food fries."
355
+ ),
356
+ },
357
+ # --- Drinks ---
358
+ {
359
+ "food": "smoothie",
360
+ "category": "drinks",
361
+ "text": (
362
+ "Many commercial smoothies are sugar bombs (60-80g sugar). Build a balanced smoothie: "
363
+ "use unsweetened almond milk as the base, add one cup of frozen berries (natural sweetness), "
364
+ "a handful of spinach (undetectable flavor, adds iron and vitamins), one tablespoon of "
365
+ "nut butter or chia seeds (healthy fats and protein), and half a banana for creaminess. "
366
+ "This balanced smoothie has about 250 calories with 10g protein and 8g fiber."
367
+ ),
368
+ },
369
+ # --- General Nutrition Principles ---
370
+ {
371
+ "food": "general",
372
+ "category": "nutrition",
373
+ "text": (
374
+ "The plate method is an easy way to build balanced meals: fill half your plate with "
375
+ "non-starchy vegetables (leafy greens, broccoli, peppers), one quarter with lean protein "
376
+ "(chicken, fish, tofu, legumes), and one quarter with whole grains or starchy vegetables. "
377
+ "This approach naturally controls portions and ensures nutrient diversity without counting calories."
378
+ ),
379
+ },
380
+ {
381
+ "food": "general",
382
+ "category": "nutrition",
383
+ "text": (
384
+ "Healthy cooking methods ranked by calorie impact: steaming and poaching add zero calories; "
385
+ "grilling and roasting need minimal oil; sautéing uses moderate oil; deep-frying adds the most. "
386
+ "Switching from frying to baking typically saves 100-300 calories per serving. "
387
+ "Use non-stick pans, cooking sprays, or small amounts of high-quality olive or avocado oil."
388
+ ),
389
+ },
390
+ {
391
+ "food": "general",
392
+ "category": "nutrition",
393
+ "text": (
394
+ "Common healthy ingredient swaps: Greek yogurt for sour cream (more protein, less fat), "
395
+ "avocado for mayo (healthy monounsaturated fats), coconut aminos for soy sauce (less sodium), "
396
+ "nutritional yeast for cheese (B vitamins, lower calories), date paste for refined sugar "
397
+ "(adds fiber and minerals), and lettuce wraps for tortillas (saves 100+ calories per wrap)."
398
+ ),
399
+ },
400
+ {
401
+ "food": "general",
402
+ "category": "nutrition",
403
+ "text": (
404
+ "Protein is the most satiating macronutrient, helping you feel full longer. "
405
+ "Aim for 20-30g protein per meal. Best lean protein sources: chicken breast (31g per 4 oz), "
406
+ "Greek yogurt (17g per cup), lentils (18g per cup cooked), eggs (6g each), "
407
+ "salmon (25g per 4 oz with heart-healthy omega-3s), and tofu (20g per cup)."
408
+ ),
409
+ },
410
+ {
411
+ "food": "general",
412
+ "category": "nutrition",
413
+ "text": (
414
+ "Fiber is crucial for digestive health and satiety but most people only get half "
415
+ "the recommended 25-30g per day. High-fiber foods: lentils (15g per cup), "
416
+ "black beans (15g per cup), avocado (10g each), raspberries (8g per cup), "
417
+ "chia seeds (10g per ounce), and oats (4g per cup cooked). Adding these to meals "
418
+ "increases fullness and supports healthy blood sugar levels."
419
+ ),
420
+ },
421
+ # --- Indian ---
422
+ {
423
+ "food": "curry",
424
+ "category": "indian",
425
+ "text": (
426
+ "Many curries use heavy cream and ghee, pushing calories to 500+ per serving. "
427
+ "Healthier version: use coconut milk (light variety) or blended cashews for creaminess. "
428
+ "Load with vegetables like cauliflower, chickpeas, and spinach. Spices like turmeric, "
429
+ "cumin, and ginger have anti-inflammatory properties. A chickpea spinach curry "
430
+ "with light coconut milk has about 280 calories per serving with 15g protein and 10g fiber."
431
+ ),
432
+ },
433
+ {
434
+ "food": "biryani",
435
+ "category": "indian",
436
+ "text": (
437
+ "Biryani is calorie-dense due to generous amounts of oil, white rice, and sometimes fried onions. "
438
+ "Lighter version: use brown basmati rice, reduce oil to 1 tablespoon, and increase vegetables. "
439
+ "Add lean protein like chicken breast or chickpeas. Use yogurt-based marinade for flavor "
440
+ "without excess fat. A lighter chicken biryani has about 350 calories per serving "
441
+ "compared to 550+ for the traditional version."
442
+ ),
443
+ },
444
+ # --- Steak & Red Meat ---
445
+ {
446
+ "food": "steak",
447
+ "category": "meat",
448
+ "text": (
449
+ "Choose lean cuts like sirloin, flank, or tenderloin over ribeye or T-bone to reduce "
450
+ "saturated fat. Trim visible fat before cooking. Grill or broil instead of pan-frying in butter. "
451
+ "Limit portion to 4-6 oz (about the size of a deck of cards). Pair with roasted vegetables "
452
+ "and a baked sweet potato instead of creamy sides. A 4 oz grilled sirloin has about "
453
+ "200 calories and 26g protein."
454
+ ),
455
+ },
456
+ # --- Breakfast cereals ---
457
+ {
458
+ "food": "cereal",
459
+ "category": "breakfast",
460
+ "text": (
461
+ "Most commercial cereals are high in added sugar (10-15g per serving). Healthier alternatives: "
462
+ "steel-cut oats (more filling, lower glycemic), overnight oats with chia seeds and berries, "
463
+ "or homemade granola with oats, nuts, and a small amount of honey. If buying cereal, "
464
+ "choose options with less than 5g sugar and at least 3g fiber per serving. "
465
+ "Top with fresh fruit instead of adding sugar."
466
+ ),
467
+ },
468
+ {
469
+ "food": "waffles",
470
+ "category": "breakfast",
471
+ "text": (
472
+ "Traditional waffles use white flour, sugar, and butter. Make protein waffles by blending "
473
+ "oats, banana, eggs, and a scoop of protein powder. The result is crispy outside, fluffy inside, "
474
+ "with about 200 calories and 20g protein per waffle. Top with Greek yogurt and fresh berries "
475
+ "instead of syrup and whipped cream for a balanced breakfast."
476
+ ),
477
+ },
478
+ # --- Mediterranean ---
479
+ {
480
+ "food": "falafel",
481
+ "category": "mediterranean",
482
+ "text": (
483
+ "Traditional falafel is deep-fried, absorbing significant oil. Baked falafel version: "
484
+ "blend chickpeas with parsley, cilantro, garlic, cumin, and a tablespoon of olive oil. "
485
+ "Form into balls and bake at 375°F for 25 minutes, flipping halfway. Serve in whole-wheat pita "
486
+ "with tahini, cucumber, and tomato. Baked falafel has about 60 calories per ball "
487
+ "compared to 100+ for deep-fried."
488
+ ),
489
+ },
490
+ {
491
+ "food": "hummus",
492
+ "category": "mediterranean",
493
+ "text": (
494
+ "Hummus is already a healthy snack — chickpeas provide protein and fiber, and tahini offers "
495
+ "healthy fats. To make it even healthier, use less tahini and more lemon juice, or add "
496
+ "roasted beets, roasted red pepper, or edamame as a base for variety and extra nutrients. "
497
+ "Pair with raw vegetables instead of pita chips. A quarter cup of hummus has about "
498
+ "100 calories with 5g protein and 3g fiber."
499
+ ),
500
+ },
501
+ # --- Chinese ---
502
+ {
503
+ "food": "sweet and sour chicken",
504
+ "category": "chinese",
505
+ "text": (
506
+ "Sweet and sour chicken is typically battered, deep-fried, and coated in sugary sauce (600+ calories). "
507
+ "Healthier version: use baked chicken breast pieces, and make sauce from rice vinegar, "
508
+ "a tablespoon of honey, tomato paste, and low-sodium soy sauce. Add pineapple chunks "
509
+ "and bell peppers. Serve over cauliflower rice. This version has about 300 calories "
510
+ "with 30g protein."
511
+ ),
512
+ },
513
+ {
514
+ "food": "lo mein",
515
+ "category": "chinese",
516
+ "text": (
517
+ "Lo mein noodles are stir-fried with oil, adding significant calories. Swap for zucchini noodles "
518
+ "or shirataki noodles. Use less oil (1 tbsp sesame oil is enough for flavor), add extra vegetables "
519
+ "(snap peas, bok choy, mushrooms, carrots), and include lean protein like shrimp or tofu. "
520
+ "Use low-sodium soy sauce or coconut aminos. Veggie lo mein with shirataki noodles "
521
+ "has about 180 calories per serving."
522
+ ),
523
+ },
524
+ # --- Baked Goods ---
525
+ {
526
+ "food": "muffin",
527
+ "category": "baked_goods",
528
+ "text": (
529
+ "Store-bought muffins can have 400-500 calories and 30g+ sugar. Healthy muffin recipe: "
530
+ "mix 2 cups oat flour, 2 mashed bananas, 2 eggs, 1/4 cup honey, 1 cup blueberries. "
531
+ "Bake at 350°F for 18 minutes. Each muffin has about 120 calories with natural sweetness "
532
+ "from banana and berries. Add walnuts for omega-3 fatty acids."
533
+ ),
534
+ },
535
+ {
536
+ "food": "bread",
537
+ "category": "baked_goods",
538
+ "text": (
539
+ "Choose bread wisely: whole-grain or sprouted-grain bread (like Ezekiel) has more fiber, "
540
+ "protein, and nutrients than white bread. Sourdough has a lower glycemic index due to "
541
+ "fermentation. Avoid breads with high-fructose corn syrup or long ingredient lists. "
542
+ "Two slices of sprouted-grain bread have about 160 calories with 8g protein and 6g fiber."
543
+ ),
544
+ },
545
+ ]
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ streamlit>=1.40.0
2
+ chromadb>=0.5.0
3
+ transformers>=4.40.0
4
+ torch
5
+ Pillow>=10.0
6
+ google-genai>=1.0.0
7
+ pydantic-settings>=2.0