# Retail analyst assistant — the OpenAI SDK course project

Ask questions about the SQL course's retail database (`sql/project/retail.db`) in plain English. The
assistant writes SQL through a **read-only gateway**, returns a **structured answer** (summary, key numbers,
the SQL it used, caveats), can **search products by meaning**, and reports **tokens and cost** per question.
The walkthrough is `openai-sdk/20-project.html`.

```bash
cd openai-sdk/project
python demo.py                       # offline: real SDK + real SQL, a stand-in "model" (no key needed)
python -m pytest tests               # 21 tests, offline, ~5 s
OPENAI_API_KEY=sk-... python cli.py  # the real thing (PowerShell: $env:OPENAI_API_KEY="sk-..."; python cli.py)
```

Requires `openai` (written against 2.44), `pydantic`, `numpy`. If your global Python has broken pytest
plugins, set `PYTEST_DISABLE_PLUGIN_AUTOLOAD=1` or use a virtual environment.

| File | Lessons | What it shows |
|------|---------|---------------|
| `analyst/db.py` | 07, 16 | read-only SQLite (`mode=ro`), an authorizer that denies writes, one statement only, row cap, time limit |
| `analyst/assistant.py` | 03, 06, 07, 13, 15 | tool loop with `responses.parse`, structured `Answer`, `previous_response_id`, errors returned to the model, round cap, cost tracking |
| `analyst/search.py` | 10 | batched embeddings and cosine search in NumPy |
| `demo.py` | 02 | the whole pipeline offline via `../fake_openai.py` |
| `cli.py` | 12 | the real API with timeouts and retries |
| `tests/` | 18 | unit tests with the fake client, including write attempts disguised as `WITH … DELETE` |
