Skip to content

Repository files navigation

PantryChef

Cook with what you already have. Tell PantryChef your ingredients and it finds recipes and cooking tutorial videos, scores how healthy each meal is, helps you check packaged ingredients, and answers cooking questions in plain language — grounded in a retrieval-augmented (RAG) knowledge base.

Live demo: mealguidance.vercel.app

Visitors

Demo

Watch the demo video

(GitHub doesn't inline-embed video from repo files — click the thumbnail to play it.)

Features

  • Discover — find recipes and YouTube tutorials ranked by how many of your ingredients they use (/discover). Scanned products link in two ways: a "Find recipes with this" button on the product detail page, and a "From your scans" picker right on the Discover page — tap-to-add/remove chips for your scan history, collapsed to the 2 most recent with a "Show all" toggle so it doesn't crowd out the rest of the page.
  • Ask PantryChef — a RAG-powered chat that answers cooking and nutrition questions, grounded in a local knowledge base of meal-prep guides and nutrition facts, with cited sources (/ask).
  • Scan — point your phone's camera at a barcode (or type it in) to see a product's Nutri-Score, NOVA processing group, and additives, via the open Open Food Facts database (/scan). Camera scanning runs entirely in the browser via ZXing — no app install required. Works well for European users specifically: Nutri-Score and NOVA are EU nutrition standards, and the scanner reads EAN-13 (the standard European barcode format) out of the box. Ingredient text is shown in whatever language the product was originally logged in on Open Food Facts (not auto-translated).
  • Health scoring — every recipe gets an explainable A–E grade from a Nutri-Score-inspired formula over its nutrition facts (lib/health-score/nutriScore.ts).
  • Meal Prep guide — a curated, MDX-driven collection of ingredients, ready-to-eat combo meals, and full weekly plans (/meal-prep). Combo meals (e.g. avocado-egg pita, chicken & rice power bowls) include an ingredient list and assembly steps, not just storage tips, filterable by type (protein, grain, vegetable, sauce, combo). Weekly plans (/meal-prep/plans/[slug]) bundle those into five-day rotations — a Balanced Week and a higher-protein, lower-calorie Cutting Week — each with a day-by-day breakfast/lunch/dinner/snack breakdown, calorie/protein targets, and a grocery list.
  • My Meal Preps — record your own meal prep with a photo, notes, storage life, and tags (/meal-prep/mine). Photos are downscaled and compressed client-side before being saved to IndexedDB (localStorage's ~5-10MB cap is too small for photos); everything stays on-device and is never uploaded anywhere.

No accounts — ingredients, favorites, scan history, and your own meal preps (including photos) are stored in your browser (localStorage + IndexedDB) only.

Tech stack

Next.js (App Router) + TypeScript + Tailwind CSS, deployed to Vercel:

  • Recipes: Spoonacular (lib/apis/spoonacular.ts)
  • Videos: YouTube Data API v3 (lib/apis/youtube.ts)
  • Product scanning: Open Food Facts (lib/apis/openFoodFacts.ts), no API key required
  • RAG: embeddings via Google's Generative AI API (gemini-embedding-001, free tier — see below) + brute-force cosine similarity over a small JSON index — no vector database needed at this scale. (Local ONNX embeddings were tried first but dropped: onnxruntime-node's native binary isn't available in Vercel's serverless runtime.)
  • LLM: Vercel AI SDK with a pluggable provider (lib/llm/client.ts) — see below
  • Tests: Vitest, covering the pure health-score and similarity-search logic
  • Observability: Langfuse (optional, free tier) — traces every RAG request end-to-end (retrieval + generation), giving latency, token cost, and full input/output per call. Wired via instrumentation.ts; left unconfigured, tracing is skipped entirely.

Why the LLM provider is swappable

LLM_PROVIDER picks the provider at runtime with zero code changes — this matters because a publicly shared demo link could otherwise run up the deployer's API bill from strangers' usage:

  • groq (default) — free tier, safe for a public demo.
  • anthropic — for a higher-quality personal demo (e.g. Claude).
  • openai — also supported.

If you clone this repo, bring your own key for whichever provider you choose (see .env.example) — your usage, your bill, isolated from anyone else running their own copy.

When a hosted model disappears

On 2026-08-17 the app started answering every question on /ask with "PantryChef couldn't generate an answer right now." Nothing had been deployed for six days. Groq had retired llama-3.3-70b-versatile, which had been the default since the feature was built, and the API began returning:

404  The model `llama-3.3-70b-versatile` does not exist or you do not have access to it.

No Llama model remains in Groq's lineup, so the default moved to openai/gpt-oss-120b (131k context, the closest replacement). Free hosted inference is the trade here: providers rotate their catalogue without notice, and a working deployment can break with no commit behind it.

Two things this cost more time than it should have, both now fixed:

  • The error was swallowed. /api/rag collapsed every non-config failure into one friendly sentence, so the 404 never reached the browser and finding it meant testing the embedding API and the LLM API by hand. Upstream messages now travel in a detail field (key-shaped strings scrubbed first, since detail is client-visible).
  • LLM_MODEL lives in four places. .env.local, .env.example, the fallback in lib/llm/client.ts, and Vercel's own store — where Production, Preview, and Development are each set separately. Fixing the first three left production broken; fixing production left a stale Development value that vercel env pull would have silently written back over the local fix.

If /ask breaks again, check the model still exists before anything else:

curl -s https://api.groq.com/openai/v1/models \
  -H "Authorization: Bearer $GROQ_API_KEY" | grep -o '"id":"[^"]*"'

Getting started

git clone <this-repo-url>
cd mealguidance
npm install
cp .env.example .env.local
# fill in at least YOUTUBE_API_KEY, SPOONACULAR_API_KEY, GROQ_API_KEY, and
# GOOGLE_GENERATIVE_AI_API_KEY (all free) in .env.local
npm run ingest   # builds the RAG knowledge base — data/kb/embeddings.json is already committed, but re-run after editing content/
npm run dev

Open http://localhost:3000.

Getting free API keys

Variable Where to get it Free tier
YOUTUBE_API_KEY Google Cloud Console → enable "YouTube Data API v3" → Credentials ~100 searches/day
SPOONACULAR_API_KEY spoonacular.com/food-api ~150 points/day
GROQ_API_KEY console.groq.com generous free tier
GOOGLE_GENERATIVE_AI_API_KEY aistudio.google.com/apikey 10M tokens/min free
Open Food Facts no key needed

A note on free-tier quotas

YouTube (~100 searches/day) and Spoonacular (~150 points/day) both have small free quotas. Results are cached aggressively (7–30 day TTLs) to stretch them as far as possible, and the app degrades gracefully — e.g. if the YouTube quota is exhausted, recipe results still show without videos rather than erroring out. If you fork this for real traffic, request a quota increase from Google early (it takes a few days to approve).

Groq's free tier also has a small daily token budget (100k TPD as of writing) — a full npm run eval run uses a meaningful chunk of it, which is why the CI eval job (below) only runs when RAG-relevant paths change, not on every PR.

Evals

npm run eval runs evals/rag-eval-set.json (25 real questions against the meal-prep/meal-plan/nutrition knowledge base) through the full RAG pipeline and checks two things per question:

  • Retrieval relevance — does the expected source chunk actually show up in the top-5 retrieved results?
  • Answer correctness — does the generated answer contain the expected facts (checked as case-insensitive substrings, with alternate phrasings per fact so paraphrasing doesn't cause a false fail)?

It prints a pass rate for each and exits non-zero if either drops below threshold (90% retrieval / 80% correctness by default, overridable via EVAL_RETRIEVAL_THRESHOLD / EVAL_CORRECTNESS_THRESHOLD). Wired into CI (.github/workflows/ci.yml) as a required check on PRs that touch lib/rag/, lib/llm/, lib/embeddings/, content/, or the eval set itself — needs GROQ_API_KEY and GOOGLE_GENERATIVE_AI_API_KEY set as repo secrets, and skips cleanly if they aren't (e.g. on forked PRs).

Scripts

npm run dev         # start the dev server
npm run build        # production build
npm run lint          # ESLint
npm run typecheck  # tsc --noEmit
npm run test          # Vitest
npm run ingest       # rebuild the RAG knowledge base from content/
npm run eval          # run the RAG eval set (retrieval relevance + answer correctness)

Deploying

  1. Push this repo to your own GitHub account.
  2. Import it into Vercel.
  3. Add the environment variables from .env.example in the Vercel project settings.
  4. Deploy — data/kb/embeddings.json is committed, so no build-time ingest step is required.

Project structure

app/                  # Next.js App Router pages + API routes (proxy every external API call)
components/            # UI primitives (components/ui/) + feature components
lib/
  apis/                 # typed, cached fetch wrappers for Spoonacular / YouTube / Open Food Facts
  health-score/    # pure Nutri-Score-inspired grading function (+ tests)
  embeddings/        # hosted embedding model client + cosine similarity (+ tests)
  rag/                    # retrieval + generation over the knowledge base
  llm/                    # pluggable LLM provider client + prompts
  content/              # Meal Prep + Meal Plan MDX parsing
  storage/             # localStorage + IndexedDB helpers (no backend user data)
  utils/                # small client helpers, e.g. client-side image compression
content/meal-prep/*.mdx   # curated Meal Prep entries (components + combo meals) — add a file here to add one
content/meal-plans/*.mdx  # curated weekly plans that reference meal-prep slugs — add a file here to add one
content/nutrition-knowledge.json  # hand-authored nutrition facts fed into the RAG index
scripts/ingest.ts     # builds data/kb/embeddings.json from content/
data/kb/embeddings.json  # generated RAG index (committed so a fresh clone works immediately)

License

MIT — see LICENSE.

About

Tell PantryChef what's in your kitchen — get matching recipes and cooking videos, a Nutri-Score-style health grade, and RAG-powered Q&A grounded in a meal-prep knowledge base. Next.js + Vercel AI SDK.

Topics

Resources

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages