AI-powered recipe discovery app with agentic RAG, LangGraph orchestration, and real-time nutritional analysis.
Live demo: http://13.63.129.183
RecipAI is a conversational recipe assistant that uses an agentic Corrective RAG pipeline to find, recommend, and format recipes with full nutritional breakdowns. Users describe what they want to cook, and the AI agent retrieves relevant recipes, suggests options, and generates detailed formatted recipes with metric/US measurements.
- Agentic Corrective RAG — Retrieve → pre-filter by similarity score → batch-grade with LLM → rewrite query if needed → rank and inject curated context
- LangGraph Workflow — 5-node state machine with conditional routing, interrupt-based recipe selection, and conversation persistence
- Real-time Nutritional Analysis — CalorieNinjas API integration with cooking-method calorie adjustments and per-serving breakdowns
- Dual Measurement System — Automatic metric-to-US conversion with density-aware ingredient handling (flour ≠ sugar ≠ butter)
- MCP Protocol Support — Tools exposed via Model Context Protocol for external agent consumption
- Streaming UI — Server-Sent Events for real-time progress updates during agent execution
┌─────────────┐ POST /api/search ┌──────────────────────────────────┐
│ Next.js │ ──────────────────────── │ LangGraph Workflow │
│ Frontend │ SSE streaming response │ │
│ │ ◄─────────────────────── │ clarification → rag_retrieve │
└─────────────┘ │ → agent ↔ tools │
│ → wait_for_selection │
│ → agent ↔ tools → __end__ │
└──────────┬───────────────────────┘
│
┌──────────────────────┼──────────────────────┐
│ │ │
┌─────┴─────┐ ┌──────┴──────┐ ┌──────┴──────┐
│ ChromaDB │ │ PostgreSQL │ │ CalorieNinjas│
│ Vectors │ │ Checkpointer │ │ API │
└───────────┘ └─────────────┘ └─────────────┘
The Corrective RAG module (lib/rag.ts) implements a multi-stage retrieval pipeline:
- Retrieve — Fetch candidate documents with cosine similarity scores from ChromaDB
- Pre-filter — Discard documents below a minimum similarity threshold (0.25) before expensive LLM grading
- Batch Grade — Grade all remaining documents in a single LLM call (reduces API calls from N to 1) using structured output
- Rewrite — If fewer than 2 documents pass grading, the LLM rewrites the query informed by grading reasons and retries (up to 2 rewrites)
- Rank & Curate — Relevant documents are sorted by similarity score and injected as ranked context for the agent
__start__ → clarification_check
├─ (clarify) → __end__
└─ (continue) → rag_retrieve → agent ↔ tools
↓
wait_for_selection (interrupt)
↓ (user picks recipe)
agent ↔ tools → __end__
Nodes:
| Node | Purpose |
|---|---|
clarification_check |
Detects vague queries (single word, "anything", "whatever") |
rag_retrieve |
Corrective RAG pipeline — retrieve, filter, grade, inject context |
agent |
GPT-4o-mini with tool bindings — decides to call tools or respond |
tools |
Executes retrieve, get_nutrition, convert_to_us |
wait_for_selection |
interrupt() pauses graph until user picks a recipe |
| Tool | Description |
|---|---|
retrieve |
Semantic search against ChromaDB recipe vectors |
get_nutrition |
Fetches nutrition from CalorieNinjas API, applies cooking-method multipliers, calculates per-serving values |
convert_to_us |
Converts metric → US measurements with ingredient-density awareness |
| Layer | Technology |
|---|---|
| Frontend | Next.js 16, React 19, Tailwind CSS 4 |
| AI Agent | LangGraph, LangChain, GPT-4o-mini |
| Embeddings | OpenAI text-embedding-3-large |
| Vector Store | ChromaDB |
| Persistence | PostgreSQL (LangGraph checkpointer) |
| Nutrition API | CalorieNinjas |
| Reverse Proxy | Caddy (automatic HTTPS) |
| Containerization | Docker Compose |
- Node.js 22+
- pnpm
- Docker & Docker Compose
- OpenAI API key
- CalorieNinjas API key (free at calorieninjas.com)
Create a .env.local file:
OPENAI_API_KEY=sk-...
CALORIE_NINJAS_API_KEY=...
CHROMA_URL=http://localhost:8000
DATABASE_URL=postgresql://recipai:your_password@localhost:5432/recipai# Install dependencies
pnpm install
# Start ChromaDB and PostgreSQL
docker compose up chromadb postgres -d
# Run the dev server
pnpm devThe app starts at http://localhost:3000. On first run, the recipe dataset (public/recipes.csv) is automatically embedded and indexed into ChromaDB.
# Set environment variables
export OPENAI_API_KEY=sk-...
export CALORIE_NINJAS_API_KEY=...
export POSTGRES_PASSWORD=your_secure_password
# Update Caddyfile with your domain
# Replace YOUR_DOMAIN with your actual domain name
# Deploy
docker compose up -dThis starts 4 services:
- app — Next.js standalone server (port 3000, internal)
- chromadb — Vector database (port 8000, internal)
- postgres — Conversation persistence (port 5432, internal)
- caddy — Reverse proxy with automatic HTTPS (ports 80/443)
├── app/
│ ├── page.tsx # Root page (renders SearchComponent)
│ ├── layout.tsx # Root layout with fonts and metadata
│ ├── globals.css # Magazine-style CSS variables and animations
│ ├── error.tsx # Error boundary
│ ├── global-error.tsx # Critical error page
│ ├── loading.tsx # Suspense fallback
│ ├── not-found.tsx # 404 page
│ └── api/
│ ├── search/route.ts # POST /api/search — SSE streaming endpoint
│ └── [transport]/route.ts # MCP protocol handler
├── components/
│ ├── SearchComponent.tsx # Orchestrator (Header + ChatPanel + RecipeDisplay)
│ ├── Header.tsx # Magazine masthead with measurement toggle
│ ├── ChatPanel.tsx # Conversation history and input
│ ├── RecipeDisplay.tsx # Recipe markdown + nutrition sidebar
│ ├── MarkdownRenderer.tsx # Custom react-markdown with magazine styling
│ ├── MeasurementToggle.tsx # US/Metric toggle switch
│ └── StateGraphVisual.tsx # Graph visualization (debug)
├── hooks/
│ └── useRecipeSearch.ts # SSE stream hook with progress tracking
├── lib/
│ ├── agent.ts # LangGraph workflow (5 nodes, routers, stream processing)
│ ├── rag.ts # Corrective RAG (retrieve → filter → grade → rewrite → rank)
│ ├── graph-state.ts # State schema (Annotation.Root)
│ ├── tools.ts # LangChain tool wrappers
│ ├── mcp-tools.ts # Pure handler functions (framework-agnostic)
│ ├── indexRecipes.ts # CSV → embeddings → ChromaDB indexing
│ ├── checkpointer.ts # PostgreSQL/MemorySaver singleton
│ └── logger.ts # Pino structured logging
├── public/
│ └── recipes.csv # Recipe dataset
├── docker-compose.yml # 4-service stack (app, chromadb, postgres, caddy)
├── Dockerfile # 3-stage build (deps → build → runner)
├── Caddyfile # Reverse proxy config
└── package.json
This project was created as part of the Turing College AI Engineering program. Code is shared for portfolio purposes only. Reuse or redistribution is not permitted.