A modern, chat-style desktop application that lets you converse naturally with an AI about cooking, recipes, and food preparation. Built with Python 3.8+ and PyQt5, it works with eight LLM providers — local or cloud — and renders beautifully parsed, interactive recipe cards.
| Category | Highlights |
|---|---|
| Conversational UI | Chat bubbles, an animated "cooking…" indicator, and rich recipe cards |
| Real chat memory | Full multi-turn context — follow up with "make it vegan" and it remembers |
| Token streaming | Watch answers arrive live for OpenAI-compatible, Anthropic and Ollama |
| 8 providers | OpenAI, Anthropic, Google Gemini, HuggingFace, Cohere, LM Studio, Ollama, Custom |
| Live dark / light theme | One click re-themes the whole app, chat history included |
| Recipe library | Save, favorite, search and re-open recipes (local SQLite) |
| 🧺 Pantry planning | Track what you have → "Cook from pantry", plus one-click shopping lists |
| Serving scaler | Rescale any recipe (×0.25–×12); amounts and servings recompute instantly |
| Hands-free, step-by-step view with optional text-to-speech | |
| 📎 Multimodal | Attach a dish photo for vision models (OpenAI, Anthropic, Gemini) |
| Structured output | JSON-mode + a Pydantic schema validate/normalise every recipe |
| Export | Copy to clipboard or export any recipe as Markdown / JSON / text |
| CLI + REST API | The same core runs headless — script it or serve it to a web/mobile app |
| Persistent settings | Provider, model, timeout and theme are remembered between launches |
| Robust networking | Sane configurable timeouts, retry/backoff, and clear error messages |
| File | Responsibility |
|---|---|
models.py |
Data models: APIConfig, Message (with image), ParsedRecipe (Markdown export), provider metadata |
theme.py |
Central ThemeManager with dark/light palettes, live switching, palette + app stylesheet |
config.py |
Load/save settings to config.json; .env and env-var API-key fallback; build_api_config |
paths.py |
Cross-platform app-data directory for config, logs and the database |
logging_setup.py |
Console + rotating-file logging |
response_parser.py |
Extracts JSON recipes (code fences, trailing commas, prose); plain-text fallback |
schema.py |
Pydantic schema — validates & normalises structured recipe output |
api_client.py |
One client, eight providers: streaming, JSON-mode, vision, retries, timeouts |
recipe_store.py |
SQLite recipe library (save / search / favorite / delete) |
pantry_store.py |
SQLite pantry of on-hand ingredients |
scaling.py |
Serving scaling and shopping-list computation (pure functions) |
tts.py |
Text-to-speech for Cooking Mode (native Qt, graceful fallback) |
engine.py |
UI-agnostic RecipeEngine facade — the reusable core |
cli.py |
Headless command-line interface |
server.py |
Stdlib REST API over the engine (for web/mobile front-ends) |
widgets.py |
Themed UI: recipe cards, bubbles, cooking mode, pantry, library, settings, toasts |
main.py |
Main window: streaming worker, memory, pantry/library, scaling, multimodal, theming |
tests/ |
74-test pytest suite across parser, models, config, stores, scaling, schema, engine, client |
# 1. Clone
git clone https://github.com/Roialfassi/Recipe-Chat-Assistant-Application.git
cd Recipe-Optimizer
# 2. Create & activate a virtual environment
python -m venv venv
venv\Scripts\activate # Windows
# source venv/bin/activate # macOS / Linux
# 3. Install dependencies
pip install -r requirements.txt # or: make install
# 4. Run
python main.py # or: make runOpen ⚙️ Settings, choose a provider, enter an API key (not needed for LM Studio / Ollama), pick or refresh a model, and Save. Then start asking for recipes.
Tip: You can also supply keys via environment variables (
OPENAI_API_KEY,ANTHROPIC_API_KEY, …) or a local.envfile — no need to type them into the UI.
Settings, logs and the recipe database are stored in your OS app-data folder
(e.g. %APPDATA%\RecipeAssistant on Windows). API keys are only written to disk if you tick
"Remember API key", and even then they're obfuscated rather than stored in the clear.
The assistant requests recipes in a strict JSON envelope so they can be rendered as rich cards:
If valid JSON isn't found, the parser falls back to rendering the reply as text.
The desktop app is just one front-end over a UI-agnostic core (engine.py).
# CLI
python cli.py ask "quick vegan pasta for two" # prints Markdown
python cli.py ask "dinner" --pantry --save # cook from pantry, save it
python cli.py ask "carbonara" --json --stream # stream JSON to stdout
python cli.py list --search taco # browse the library
python cli.py pantry add "olive oil" # manage the pantry
python cli.py serve --port 8765 # start the REST API
# REST API (same core; CORS-enabled for web clients)
curl -X POST localhost:8765/api/chat -d '{"message":"quick soup"}'
curl localhost:8765/api/recipes
curl localhost:8765/api/pantrymake dev # install runtime + dev tooling
make test # run the pytest suite (74 tests)
make lint # ruff
make format # black + ruff --fixRecently shipped
- Multimodal photo input for vision models
- Hands-free Cooking Mode with text-to-speech
- Pantry-aware planning, serving scaling & shopping lists
- Structured output via JSON mode + Pydantic schema
- Reusable core engine with CLI & REST API
Next
- Inline generated step photos (image output)
- Speech-to-text voice input
- Cloud sync of favourite recipes
- Keyring-backed secret storage
- Companion web / mobile front-end on the REST API
Distributed under the MIT License.
Bon appétit 👨🍳
{ "name": "Spaghetti Carbonara", "description": "A classic Roman pasta.", "prep_time": "10 minutes", "cook_time": "15 minutes", "servings": "4", "difficulty": "Medium", "ingredients": [ { "amount": "200 g", "item": "spaghetti" }, { "amount": "100 g", "item": "pancetta, diced" } ], "instructions": ["Cook spaghetti until al dente.", "Fry pancetta until crispy."], "tips": ["Use freshly grated parmesan."], "tags": ["italian", "quick", "comfort-food"], "nutrition": { "calories": "600", "protein": "25g" } }