File size: 8,562 Bytes
1c0c94d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# AVIS β€” Project Status & Context Tracker

> Living document for managing context across sessions. Update it as work lands.
> Source of truth for *design* stays `docs/DESIGN.md`; this file tracks *state*.
> Last updated: **2026-06-21**.

---

## 1. One-line status

End-to-end vertical slice works and is demo-ready: upload β†’ detect β†’ evidence graph β†’
rules β†’ confidence routing β†’ (optional VLM audit) β†’ legal mapping β†’ annotated evidence β†’
**interpretable React dashboard**. Helmet detection now runs on a **local model (zero API
calls)**; plate OCR works via **fast-alpr**; all 7 violation types are represented.
**Quality gates green:** 49 tests pass, ruff clean, ruff-format clean, mypy clean.

---

## 2. Architecture snapshot

```
upload (api/) β†’ queue (quality gate β†’ preprocess) β†’ pipeline:
  detect (YOLO11 COCO)               core/detect
  β†’ build Evidence Graph             core/graph     (single source of truth)
  β†’ helmet attrs (LOCAL YOLO model)  core/detect    (no API; was Gemini)
  β†’ plates (fast-alpr β†’ Gemini fb)   core/plates
  β†’ light state (HSV)                core/detect
  β†’ load calibration zones           core/calibration  configs/<camera>.json
  β†’ run rules (pure)                 core/rules
  β†’ fuse scores + route + VLM audit  core/pipeline  (VLM = auditor only)
  β†’ legal mapping                    core/legal
  β†’ hash + annotate + persist        core/evidence + core/storage
React dashboard (frontend/) ← FastAPI (api/main.py) ← storage (SQLite/Postgres + files/MinIO)
```

Invariants held: VLM is an auditor (never the detector); only Tier A may auto-confirm;
abstain over guess; the Evidence Graph drives all reasoning; rules are pure/deterministic.

---

## 3. Violation coverage (vs the problem statement's 7)

| Violation | Tier | Status | How it's decided |
|---|---|---|---|
| Helmet non-compliance | A | βœ… Working, **offline** | Local 7-class YOLO model β†’ rider helmet status; auto-confirm/VLM-skip |
| Triple riding | A | βœ… Working | Count `rides` edges β‰₯ 3; routed (VLM/human) unless very high fused |
| Seatbelt non-compliance | B | βœ… Implemented (gated) | `SEATBELT_CHECK=true` β†’ speculative candidate β†’ VLM verify; dropped if not confirmed |
| Stop-line crossing | C | βœ… Working w/ calibration | Vehicle ground-point in `stop_line` zone; never auto-confirm |
| Red-light violation | C | βœ… Working w/ calibration | Red light + vehicle past stop-line; candidate |
| Illegal parking | C | βœ… Working w/ calibration | Vehicle in `no_parking` zone; candidate |
| Wrong-side driving | D | βšͺ Inert by design | A single frame can't prove direction β†’ abstains (needs video) |

Plate OCR (all types): βœ… fast-alpr (ONNX) + Indian-plate regex; Gemini fallback when empty.

---

## 4. Problem-statement task coverage

| Task | Status | Notes |
|---|---|---|
| Image preprocessing (low-light/blur/etc.) | βœ… | CLAHE + denoise + gamma; quality gate abstains on too-dark/blurry/over-exposed |
| Vehicle + road-user detection & classification | βœ… | YOLO11 COCO; rider/driver/pedestrian roles in the graph |
| Violation detection (7 types) | βœ… 6 active + 1 inert | see Β§3 |
| Violation classification + confidence | βœ… | per-source scores (detection/rule/attribute/vlm) β†’ fused; tier-aware routing |
| License-plate detection + OCR | βœ… | fast-alpr + regex; Gemini fallback |
| Evidence generation (annotated + metadata + timestamps) | βœ… | annotated copy, SHA-256 hash, audit trail, created_at |
| Analytics & reporting (trends/search/summary) | βœ… | `/analytics`, charts, review queue, search filters |
| Performance evaluation (P/R/F1, etc.) | βš™οΈ harness ready | `eval/` computes P/R/F1, ablation, OCR acc, latency β€” **needs labelled images in `data/eval/`** |
| Efficiency / scalability | βœ… design | modular monolith; Redis-worker + Postgres + MinIO documented scale-out |

---

## 5. Task board

**Done (this iteration)**
- [x] Local helmet model wired in (`models/helmet/best.pt`, 7-class) β€” helmet detection needs **zero** API calls.
- [x] Plate OCR fixed (root cause: missing `onnxruntime`) + per-char-confidence bug + Gemini fallback chain.
- [x] Seatbelt (Tier B) rule + speculative drop-on-negative adjudication (off by default).
- [x] Interpretability API: `GET /violations/{id}`, image dims on `/images/{id}`, extended `/runtime`.
- [x] New **React + Vite + Chart.js** dashboard with full interpretability + e-challan view.
- [x] Tests: 33 β†’ **49**; ruff/format/mypy all clean.

**Backlog / next**
- [ ] Add a labelled `data/eval/` set and publish real P/R/F1 + ablation numbers.
- [ ] Persist the Evidence Graph (per image) to enable client-side bbox overlays in the detail view.
- [ ] Optional: seatbelt via a local classifier (avoid VLM quota) instead of VLM-only.
- [ ] Optional: ChromaDB legal-RAG bonus (static table stays load-bearing).
- [x] Docker: multi-stage build compiles `frontend/dist` in a node stage (one-command deploy).

---

## 6. Change log

- **2026-06-21**
  - Helmet: replaced per-rider Gemini classification with a local YOLO11 model run once on
    the full image; matches helmet boxes to riders by containment (head boxes have tiny IoU
    but high containment) and augments riders COCO missed. Fixes the free-tier rate-limit flood.
  - Plates: added `onnxruntime` (the missing piece that made fast-alpr silently return nothing);
    fixed `confidence`-is-a-list crash; added `GeminiPlateRecognizer` + `ChainPlateRecognizer`.
  - Seatbelt: new Tier-B rule (gated by `SEATBELT_CHECK`); `Candidate.speculative` + adjudication
    that **drops** unconfirmed guesses instead of flooding human review.
  - API: `GET /violations/{id}`, `width`/`height` on `GET /images/{id}`, `vlm_enabled` + thresholds on `/runtime`.
  - Frontend: full React rewrite (interpretable cards, confidence breakdown, route explainer,
    e-challan, audit trail, evidence hash, charts, review, search).
  - Quality: brought the whole repo to ruff/format/mypy clean (cleared pre-existing debt).
  - Config fix: `.env` had `GEMINI_MODEL=gGemma-4-31B` (invalid id) β†’ `gemma-3-27b-it`
    (vision-capable; Gemma 3 free tier ~30 RPM / ~15,000 RPD, much higher than Flash).

---

## 7. Issue / error log (root causes)

| Symptom | Root cause | Fix |
|---|---|---|
| "VLM unavailable" flooding human review on busy images | ~14 Gemini calls/image (helmet Γ—N + verify Γ—N) > 10 req/min free limit | Local helmet model (0 calls) + helmet candidates `pre_verified` (skip 2nd call) + retry/backoff |
| Number plate never shown | `fast_alpr` installed but `onnxruntime` missing β†’ ONNX models couldn't run β†’ silent "no plate" | `pip install onnxruntime` (added to requirements) |
| fast-alpr crash `float() ... not 'list'` | OCR `confidence` is a per-character list | `_as_conf()` collapses list β†’ mean |
| Dashboard "too raw" | vanilla HTML dumped enums | React dashboard with friendly labels, badges, breakdowns, e-challan |

---

## 8. Known honest limitations

- **Seatbelt (Tier B)** is genuinely unreliable from a traffic cam; it never auto-confirms and
  is dropped unless the VLM can substantiate it. Off by default to protect quota.
- **Wrong-side (Tier D)** is inert β€” direction needs video; a single frame abstains.
- **Tier C** (stop-line/red-light/parking) needs per-camera calibration (`configs/<camera>.json`);
  without it, those rules simply don't fire (no fabrication).
- **Eval numbers** require a labelled `data/eval/` set β€” not shipped, so we publish no fake metrics.
- **Gemini free tier** (~1,500/day, ~10/min): plate fallback + seatbelt are the only paths that
  can spend it; both are sparing/optional.

---

## 9. Setup & run (quick reference)

```powershell
# deps (one-time)
venv\Scripts\python.exe -m pip install -r requirements.txt          # incl. onnxruntime
cd frontend ; npm install ; npm run build ; cd ..                    # builds frontend/dist

# run (serves the built React app at http://127.0.0.1:8000)
venv\Scripts\python.exe -m uvicorn api.main:app --reload

# frontend dev mode (hot reload, proxies API to :8000)
cd frontend ; npm run dev

# quality gates
venv\Scripts\python.exe -m pytest -q
venv\Scripts\python.exe -m ruff check . ; venv\Scripts\python.exe -m ruff format --check .
venv\Scripts\python.exe -m mypy core/ api/
```

Key env (`.env`): `HELMET_WEIGHTS=models/helmet/best.pt`, `PLATE_PROVIDER=fastalpr`,
`LLM_PROVIDER=gemini`, `GEMINI_MODEL=gemini-2.5-flash`, `SEATBELT_CHECK=false`.
**Security:** rotate `GEMINI_API_KEY` (it was shared in chat); `.env` is gitignored.