Open source. A full-stack conversational commerce app built to explore multi-agent LLM pipelines in a real-world setting. A customer types naturally β "I want a latte and a croissant" β and a pipeline of specialized agents handles intent classification, menu validation, personalized recommendations, and order state across the conversation. The result is a cross-platform mobile app backed by a fully async Python API with SSE streaming, SQLite session persistence, 120 passing tests, LLM evals, and a live observability dashboard.
End-to-end walkthrough: multi-item ordering, guard agent, RAG-powered Q&A, and cart auto-population from chat
Live dashboard at http://localhost:8000/dashboard β request latency, token usage, agent distribution, and guard block rate. Auto-refreshes every 5s.
| Feature | What it does |
|---|---|
| π§ Multi-agent pipeline | Guard β Classification β Details / Order / Recommendation |
| π RAG (Retrieval-Augmented Generation) | Answers menu & shop questions via ChromaDB (local, no API key) |
| π Smart ordering | Multi-turn conversation with menu validation and persistent state |
| π― Personalized recommendations | Apriori market basket analysis + popularity rankings |
| π± React Native app | Browse menu, chat, review cart β one unified flow |
| β‘ SSE streaming | Responses stream token-by-token via POST /chat/stream; first token at ~1s |
| πΎ Session persistence | SQLite-backed sessions; conversation restores on reload; "New chat" to reset |
| π Provider-agnostic LLM | Swap Groq, RunPod, or OpenAI with a single .env change |
| β 160 passing tests | 126 backend (pytest) + 34 frontend (Jest) β no API key needed for unit tests |
| π Live search | Filter menu by name in real time, combined with category chips |
| π Size selection | S / M / L adjusts price live on the detail screen; size-adjusted totals in cart |
| πΌοΈ Products in chat | Image cards appear below recommendation and order-confirmation bubbles |
| π Smart cart merge | Chat orders merge with browse-screen adds β no more cart-wipe on agent response |
| π Observability dashboard | Live /dashboard β latency, tokens, routing, guard block rate |
| π§ͺ LLM evals | Guard, classification, recommendation accuracy tested against real LLM |
| πΌοΈ Bundled product images | Served from local assets β no Firebase Storage required |
React Native App (Expo)
β
β POST /chat/stream { messages, session_id } (SSE)
βΌ
FastAPI Server (local_server.py) β fully async
β
βΌ
AgentController
β
βββ GuardAgent β blocks off-topic / harmful queries
β
βββ ClassificationAgent β routes intent
β
βββ DetailsAgent β RAG: sentence-transformers β ChromaDB (local) β LLM
OrderTakingAgent β multi-turn order + auto-upsell
RecommendationAgent β Apriori / popularity rankings
β
βΌ
Groq API (llama-3.3-70b-versatile)
π‘ Design note: Every agent uses
AsyncOpenAIwith a configurablebase_urlβ no vendor lock-in. Invalid routing returns a graceful error rather than crashing the pipeline.
| Layer | Technology | Why |
|---|---|---|
| LLM | Groq API (llama-3.3-70b) |
Free tier, fast inference |
| Embeddings | sentence-transformers (all-MiniLM-L6-v2) | Runs locally, no API cost |
| Vector DB | ChromaDB | Local persistent index β no API key, no account |
| Backend | Python 3.12 + FastAPI | Async, type-safe |
| Frontend | React Native + Expo Router | Cross-platform, hot reload |
| Styling | NativeWind (Tailwind) | Utility-first, rapid UI |
| Recommendations | scikit-learn (Apriori) | Market basket analysis |
| Testing | pytest + jest-expo | 126 backend + 34 frontend, no API key needed for unit tests |
| Observability | structlog + Chart.js dashboard | Structured logs + live /dashboard |
| Product catalog | Firebase Realtime DB | Live product data |
| Product images | Bundled local assets | No Firebase Storage required |
# Required
Python 3.12+
Node.js 18+
# Recommended
uv # fast Python package manager
# Free accounts needed
Groq API key β https://console.groq.com# Clone and enter repo
git clone https://github.com/silvaxxx1/Cafe.AI.git
cd Cafe.AI
# Create virtual environment
uv venv .venv --python 3.12
source .venv/bin/activate # Windows: .venv\Scripts\activate
# Install dependencies
cd python_code/api
uv pip install -r requirements.txt
# Pin httpx β newer versions break the openai async client
uv pip install "httpx==0.27.2"
# Configure environment
cp .env_example .envEdit .env with your credentials:
# Note: these variable names reflect RunPod origins β they work equally for Groq
RUNPOD_TOKEN=your-groq-api-key-here
RUNPOD_CHATBOT_URL=https://api.groq.com/openai/v1
MODEL_NAME=llama-3.3-70b-versatileStart the server:
python local_server.py
# β
Agents ready.
# π Uvicorn running on http://0.0.0.0:8000# Open a new terminal
cd coffee_shop_app
# Copy config and fill in Firebase + backend URL
cp .env_example.txt .env
# Install and run
npm install
npm run web # Opens at http://localhost:8081# Streaming endpoint (what the app uses)
curl -N -X POST http://localhost:8000/chat/stream \
-H "Content-Type: application/json" \
-d '{"input": {"messages": [{"role": "user", "content": "I want a latte and a croissant"}]}}'Expected: SSE token stream ending with {"type":"done","memory":{"order":[...]}} β both items captured with correct prices. π―
# Backend unit tests (no API key needed)
make test # 126 pytest tests
# Frontend unit tests
make test-frontend # 34 Jest tests (CartContext, MessageItem, SizesSection, productService)
# Both suites in sequence
make test-all
# LLM evals (requires valid Groq key in .env)
make evals126 backend tests cover all agents, the server (streaming and session endpoints), and eval runner logic. All LLM calls are mocked with AsyncMock β no API key needed.
34 frontend tests cover CartContext (13), MessageItem (12), SizesSection (8), and productService (4).
Evals hit the real LLM and report per-case PASS/FAIL with a pass rate. Exit 1 if below 80%.
| You say⦠| Agent handles it |
|---|---|
| "Who won the World Cup?" | π‘οΈ Guard blocks |
| "What are your opening hours?" | π Details (RAG) |
| "Tell me about Fero Cafe" | π Details (RAG) |
| "What do you recommend?" | π― Recommendation |
| "What pastry should I get?" | π― Recommendation (category-filtered) |
| "I want a latte and a croissant" | π Order β 2 items captured |
| "Also add an espresso" | π Order β context remembered |
| "No thanks, that's all" | π Order β finalised with total |
No account or API key needed β the index lives on disk.
# 1. Build the index (runs locally, ~30 seconds)
cd coffee_shop_customer_service_chatbot/python_code
python build_index.py
# β Writes index to api/chroma_db/
# 2. Restart the backend
# β [DetailsAgent] RAG enabled β local embeddings + ChromaDB.Uses sentence-transformers/all-MiniLM-L6-v2 for embeddings locally. Without the index, DetailsAgent is gracefully disabled and the rest of the app functions normally.
Firebase is pre-configured for the fero-ai project. To use your own:
# 1. Create a project at console.firebase.google.com
# 2. Enable Realtime Database (Spark / free plan β Storage NOT required)
# 3. Download service account JSON from Project Settings β Service Accounts
# 4. Fill python_code/.env with service account fields
# 5. Seed products (images are local, no upload needed):
cd python_code
jupyter notebook firebase_uploader.ipynb
# 6. Add Firebase web config to coffee_shop_app/.envProduct images are bundled in coffee_shop_app/assets/images/products/ and mapped by filename in constants/productImages.ts. Firebase stores only the filename (e.g. cappuccino.jpg), not a remote URL.
Without Firebase, the home tab shows an empty menu β but the chat tab works fully. The agent validates orders against
menu.json, which is always loaded server-side.
- Install Expo Go on your phone
- Ensure your phone and computer are on the same Wi-Fi network
- Update
coffee_shop_app/.env:EXPO_PUBLIC_RUNPOD_API_URL='http://192.168.x.x:8000/chat' # your local IP
- Run and scan the QR code:
npm start
cd python_code/api
docker build -t your-dockerhub/fero-cafe:latest .
docker push your-dockerhub/fero-cafe:latest- Create a RunPod serverless endpoint with the image
- Set env vars from
.env_example - Update
EXPO_PUBLIC_RUNPOD_API_URLin the frontend to your RunPod endpoint
Cafe.AI/
βββ π± coffee_shop_app/ # React Native (Expo)
β βββ app/
β β βββ _layout.tsx # Root layout: providers + web frame
β β βββ index.tsx # Splash / landing screen
β β βββ details.tsx # Product detail
β β βββ thankyou.tsx # Order confirmation
β β βββ (tabs)/
β β βββ _layout.tsx # Tab bar with cart badge
β β βββ home.tsx # Menu browse + category filter
β β βββ chatRoom.tsx # AI chat β auto-fills cart
β β βββ order.tsx # Cart review + checkout
β βββ components/ # CartContext, MessageList, UI components
β βββ constants/
β β βββ theme.ts # Light/dark token system + useTheme()
β β βββ responsive.ts # useGridColumns(), webPointer utils
β β βββ productImages.ts # filename β require() map
β βββ services/ # chatBot.ts, productService.ts (cached)
β βββ assets/images/products/ # Bundled product images (18 items)
β βββ polyfills.ts # setImmediate shim for web
β βββ config/ # Firebase config
β
βββ π python_code/
βββ api/
β βββ agents/
β β βββ guard_agent.py
β β βββ classification_agent.py
β β βββ details_agent.py
β β βββ order_taking_agent.py
β β βββ recommendation_agent.py
β β βββ agent_protocol.py # async Protocol
β β βββ utils.py
β βββ tests/ # 126 tests β
(unit + eval runners)
β βββ recommendation_objects/
β βββ local_server.py # Dev server (async FastAPI)
β βββ main.py # RunPod entry point
β βββ agent_controller.py # Pipeline orchestration
β βββ session.py # SQLite session store
β βββ menu.json # Single source of truth for product names
βββ products/
β βββ products.jsonl # Full product data (seeded to Firebase)
β βββ images/ # Source images
βββ firebase_uploader.ipynb # Seeds Firebase (no Storage needed)
βββ build_vector_database.ipynb
βββ recommendation_engine_training.ipynb
| Variable | Required | Description |
|---|---|---|
RUNPOD_TOKEN |
β Yes | Your Groq API key (legacy name β works for any provider) |
RUNPOD_CHATBOT_URL |
β Yes | https://api.groq.com/openai/v1 |
MODEL_NAME |
β Yes | llama-3.3-70b-versatile |
CHROMA_DB_PATH |
β Optional | Path to ChromaDB index (default: api/chroma_db/). Run build_index.py once to create it. |
| Variable | Description |
|---|---|
FIREBASE_* |
Service account fields from Firebase console |
FIREBASE_DATABASE_URL |
Realtime Database URL |
| Variable | Required | Description |
|---|---|---|
EXPO_PUBLIC_RUNPOD_API_URL |
β Yes | Backend URL (e.g. http://localhost:8000/chat) |
EXPO_PUBLIC_FIREBASE_API_KEY |
β Yes | Firebase web API key |
EXPO_PUBLIC_FIREBASE_DATABASE_URL |
β Yes | Realtime Database URL |
EXPO_PUBLIC_FIREBASE_* |
β Yes | Remaining Firebase web config fields |
V1 β Complete β
- Multi-agent pipeline β Guard β Classification β Details / Order / Recommendation
- Fully async FastAPI + all agents
- SSE streaming β
POST /chat/stream; first token at ~1s - SQLite session persistence β restores conversation on reload
- Dynamic menu β
menu.jsonsingle source of truth, injected at startup - Observability β structlog structured logging + live
/dashboard - LLM evals β guard, classification, recommendation runners (80% threshold)
- 120 passing tests β unit + eval runners, no API key needed for unit tests
- Production hardening β rate limiting, CORS, startup validation, typed input
- CI/CD β GitHub Actions on every push
V2 β Complete β
- Live search β filters menu by name in real time, combined with category chips
- Size selection β S/M/L adjusts price live; size-adjusted totals flow through cart
- Product images in chat β cards below recommendation and final-order bubbles, tappable to detail
- Fix cart-wipe bug β
syncCartFromOrdermerges LLM orders without wiping browse-screen adds - RecommendationAgent turn memory β
last_recommendationsstored; repeats avoided next turn - Wider context window β
CONTEXT_WINDOW=6across guard, classification, recommendation - Response variation β
temperature=0.7on recommendation language calls - Full TypeScript types β
AgentMemoryunion replacingmemory?: anyeverywhere - Frontend tests β CartContext (13), MessageItem (12), SizesSection (8), productService (4)
-
make test-allβ runs backend + frontend suites in sequence - RAG β ChromaDB local index (no API key);
build_index.pypopulatesapi/chroma_db/in ~30s
V3 β Possible Next Steps
- Cart β agent context β agent awareness of items added via browse screen
- Product images on menu/details agent responses
- Multi-tenant deployment β one backend serving multiple cafΓ© clients
See V2_PLAN.md for the full breakdown with file references and implementation details.
MIT β free for personal and commercial use.
- Groq for free, fast LLM inference
- ChromaDB for local vector storage
- Expo for React Native tooling
- Firebase for real-time product catalog
Built with β and π€ by SilvaLAB

