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:
@@ -912,3 +912,7 @@ Q: LPR/ANPR options — YOLO, OpenCV, both, another framework? Reframed: "YOLO v
|
||||
## [2026-06-19] decision | Vision service packaging — apps/vision/ in this monorepo, Turbo shim
|
||||
|
||||
Q: how to IMPLEMENT the vision service — can we use this Turborepo? Settled (status:settled): the Python/FastAPI ANPR service lives in THIS monorepo at `apps/vision/`, NOT a separate repo. Key clarification: Turbo orchestrates JS/TS package.json TASKS (+ caches outputs); it has no native Python build — but "in the repo" ≠ "in the Turbo graph", and "separate process" ≠ "separate repo". Decision: (1) co-locate source at apps/vision/ (pnpm-workspace already globs apps/*, so it auto-joins) for atomic cross-cutting changes (the /analyze contract + the Node adapter together), one wiki/history; (2) still a SEPARATE OS process (uvicorn over localhost HTTP) — co-location is source-level only, runtime isolation intact; (3) wire into Turbo via a THIN package.json shim whose scripts shell to Python (dev→uv run uvicorn, lint→ruff, test→pytest, build→no-op/model-fetch since Python has no dist/**), so `turbo run lint/test` covers vision too — deps stay uv/pyproject, not pnpm; (4) Node talks to it via a VisionClient interface (device-adapter style), swappable. WHY co-location honors the [[vision-service]] isolation decision: that decision is about RUNTIME + LICENSE isolation (separate process; AGPL doesn't reach Node because it's not LINKED, just HTTP) — AGPL's reach is a linking/distribution-boundary question, NOT a which-folder question. And with the MIT-end-to-end [[opencv-anpr-service|fast-alpr]] baseline the AGPL pressure to split the repo largely evaporates anyway. Rejected: separate repo (loses atomic changes; fallback if AGPL acute or another team owns it), embed-in-Node (already rejected by vision-service), packages/ (that's for shared JS libs, vision is a deployable app). NOT built yet — packaging decision only; scaffold when vision work starts. New page [[vision-service-packaging]]; updated [[vision-service]], [[opencv-anpr-service]], CLAUDE.md layout, index.
|
||||
|
||||
## [2026-06-19] build | Scaffold apps/vision (ANPR microservice skeleton)
|
||||
|
||||
Scaffolded the [[opencv-anpr-service|vision service]] per [[vision-service-packaging]]: `apps/vision/` Python/FastAPI, uv-managed, wired into Turbo via a thin package.json shim. Structure: pyproject.toml (light core: fastapi/uvicorn/pydantic; HEAVY recognizer = optional `alpr` extra = fast-alpr+onnxruntime, so `uv sync`+tests run OFFLINE in stub mode with no model download), per-package turbo.json (extends ["//"], build outputs [] → warning-free no-op), .gitignore (venv/caches/*.onnx/models out). vision_service/: app.py (GET /health + POST /analyze, raw octet-stream body so Node POSTs Snapshot.bytes directly; empty→400, oversize→413, not-ready→503), settings.py (env VISION_*), schemas.py (the /analyze contract + a not-yet-populated `vehicle` field for Job 2), recognizer.py (a Recognizer Protocol + StubRecognizer/FastAlprRecognizer — the device-adapter pattern applied to the model; fast-alpr imported lazily so missing models ⇒ ready=False, not a crash). VERIFIED: turbo run lint|test|build includes @parking/vision (ruff/pytest/no-op shim) green; uv run mypy strict-clean; uvicorn boots + serves /health (ready, stub-0) and /analyze (contract shape) live; pnpm workspace 6→7. NOT built: the Node VisionClient adapter, a Dockerfile + model fetch, and Job 2 (vehicle verification). Updated [[vision-service-packaging]] (As-scaffolded section), CLAUDE.md layout already lists apps/vision.
|
||||
|
||||
Reference in New Issue
Block a user