feat(vision): scaffold apps/vision ANPR microservice (FastAPI, stub recognizer)
Skeleton of the host-side vision service per the packaging decision: a Python/FastAPI app at apps/vision/, uv-managed, wired into the Turbo graph via a thin package.json shim (dev/lint/test/build → uv/uvicorn/ruff/pytest). A per-package turbo.json sets build outputs [] so the no-op build is warning-free. Endpoints: GET /health (readiness + model version) and POST /analyze (raw octet-stream body, so Node POSTs Snapshot.bytes directly; empty→400, oversize→413, recognizer-not-ready→503). The recognizer is a Protocol with a StubRecognizer (no models, boots/tests offline — the dev/CI default) and a FastAlprRecognizer (the real MIT YOLOv9+CCT/ONNX stack, lazily imported; missing models ⇒ ready=False, not a crash) — the device-adapter pattern applied to the model. fast-alpr + onnxruntime are an optional `alpr` extra, so `uv sync` needs no model download. Verified: turbo run lint|test|build includes @parking/vision and stays green; uv run mypy strict-clean; uvicorn boots and serves /health + /analyze live; pnpm workspace 6→7. Not built yet: the Node VisionClient adapter, a Dockerfile + model fetch, and Job 2 (vehicle verification). Updates the packaging decision (As-scaffolded) + log. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -75,16 +75,33 @@ isolated, license-wise, as one in its own repo.
|
||||
- **A Python package under `packages/`** — `packages/` is for shared *JS* libraries imported by other
|
||||
workspaces; the vision service is a deployable app, so `apps/vision/` is the right bucket.
|
||||
|
||||
## Consequences
|
||||
## As-scaffolded (2026-06-19)
|
||||
|
||||
- Add `apps/vision/` (`pyproject.toml` + `uv.lock`, FastAPI `app.py`, a thin `package.json` shim);
|
||||
`apps/*` glob picks it up. Update the repo-layout block in the root `CLAUDE.md` + this wiki.
|
||||
- A `Dockerfile`/process unit builds the Python service as its own image/process for the appliance;
|
||||
CI runs `ruff`/`pytest` (via the shim or a dedicated job).
|
||||
- The Node backend gains a `VisionClient` adapter (localhost HTTP) + per-camera opt-in wiring (the
|
||||
open item in [[opencv-anpr-service]]).
|
||||
- **Not built yet** — this is the packaging decision; scaffolding follows when the vision work starts
|
||||
(the "scaffold as the work reaches them" rule in CLAUDE.md).
|
||||
The skeleton is **built and wired** (no recognizer models yet):
|
||||
|
||||
- `apps/vision/` — `pyproject.toml` (+ `uv.lock`, uv-managed), the thin `package.json` shim, a
|
||||
per-package `turbo.json` (`extends: ["//"]`, `build` outputs `[]` so the no-op build is warning-
|
||||
free), `.gitignore` (venv/caches/`*.onnx`/`models/` out), `README`.
|
||||
- `vision_service/`: `app.py` (FastAPI `GET /health` + `POST /analyze`, raw octet-stream body so Node
|
||||
POSTs `Snapshot.bytes` directly; oversize→413, empty→400, recognizer-not-ready→503), `settings.py`
|
||||
(env `VISION_*`), `schemas.py` (the `/analyze` contract incl. a not-yet-populated `vehicle` field
|
||||
for Job 2), `recognizer.py` (a `Recognizer` **Protocol** + `StubRecognizer` and `FastAlprRecognizer`
|
||||
— the [[device-adapter-pattern]] applied to the model).
|
||||
- **Light-core, heavy-optional:** core deps boot in **stub mode** (no model download) so `uv sync` +
|
||||
tests work offline; the real stack is the `alpr` extra (`uv sync --extra alpr` →
|
||||
fast-alpr + onnxruntime). `VISION_RECOGNIZER=fast_alpr` switches it on.
|
||||
- **Verified:** `turbo run lint|test|build` includes `@parking/vision` (ruff/pytest/no-op via the
|
||||
shim) and stays green; `uv run mypy` strict-clean; uvicorn boots and serves `/health` (`ready`,
|
||||
stub-0) + `/analyze` (contract shape) live. pnpm workspace count 6→7.
|
||||
|
||||
## Still to build (next, when vision work proceeds)
|
||||
|
||||
- The Node-side **`VisionClient`** adapter (localhost HTTP) + per-camera **opt-in** wiring (the open
|
||||
item in [[opencv-anpr-service]]).
|
||||
- A **`Dockerfile`**/process unit for the appliance (its own image/process); model-weight fetch at
|
||||
deploy (the `alpr` extra), kept out of git ([[opencv-anpr-service|weight-provenance]] check first).
|
||||
- **Job 2** (vehicle attributes / fingerprint) — the `vehicle` field is scaffolded but unpopulated;
|
||||
fast-alpr is plate-only. Built later on the same ONNX runtime.
|
||||
|
||||
## Open
|
||||
|
||||
|
||||
Reference in New Issue
Block a user