# AGENTS.md — bytetrack-counter ## Architecture - **Edge AI counter**: RTSP camera → YOLO RKNN (NPU) → tracking → line-crossing → SQLite + JSON state → Flask dashboard. - **2 counter scripts**, only 1 deployed: - `counter_live.py` — Jetson TensorRT artifact (CUDA, NOT used on RK3588). - **`counter_live_rknn_bytetrack.py`** — RK3588 with ByteTrack. **This is what systemd runs.** Reference for C++ port. - `batch_store.py` — shared SQLite persistence + batch state machine. - `counter_dashboard.py` — Flask dashboard on port 5000, same DB. - `recounting_dashboard.py` — Flask recounting dashboard on port 5002, consumes live + recount APIs. - `recounting_dashboard_upload.py` — Flask upload+recount dashboard on port 5003; uploads MP4 first, then launches `RECOUNT_CMD --source `; START RECOUNT stays disabled until an upload completes. ## No build / test / lint There is no build system, no test framework, no linter config, no typechecker. Do not try to run `pytest`, `ruff`, `mypy`, etc. — they don't exist here. ## How to run ```bash # Copy env (required, .env is gitignored) cp config.env.example .env # Venv (must use system-site-packages for RKNN toolkit) python3 -m venv --system-site-packages venv source venv/bin/pip install -r requirements.txt # Run counter (RK3588 only — needs rknn-toolkit-lite2 & RKNN model) PYTHONNOUSERSITE=1 venv/bin/python counter_live_rknn_bytetrack.py # Run dashboard PYTHONNOUSERSITE=1 venv/bin/python counter_dashboard.py # Run upload recounting dashboard PYTHONNOUSERSITE=1 venv/bin/python recounting_dashboard_upload.py ``` ## Key environment & install quirks - **`PYTHONNOUSERSITE=1`** is mandatory when running from the venv — without it, system/user packages leak in. - **`.env` is gitignored** — always copy from `config.env.example` first. - **`numpy<2`** is required for `rknn-toolkit-lite2` compatibility. - **Install path in service files is `/opt/bytetrack-counter`** (not the `/opt/jetson-counter` mentioned in README/DEPLOY). The `.env.example` also reflects `/opt/bytetrack-counter`. - Service user is **`root`**, not `jetson` (despite README saying otherwise). - Three systemd units: `bytetrack-counter.service`, `bytetrack-counter-dashboard.service`, and `bytetrack-recounting-upload-dashboard.service` (upload recounting dashboard, port 5003). - `counter_live.py` (TensorRT) is Jetson-only and won't work on RK3588. - **Reset flow**: `POST /api/reset` → deletes state JSON + touches `{SHM_DIR}/.reset`. `batch_store._check_reset_signal()` watches this marker and clears in-memory state on next crossing. - **Upload filename contract**: uploads are expected as `batch_XX_YYYYMMDD_HHmmSS.mp4` (XX = batch number, timestamp = date). `recounting_dashboard_upload.py` parses both to query the live API's `/api/day-detail/` for the recorded count. - **`RECOUNT_CMD`** in the upload dashboard is a template with a `{path}` placeholder, e.g. `bytetrack-counter config.env --source {path}`; the uploaded file path is `shlex.quote()`d before substitution. - **Cross-dashboard header links**: `UPLOAD_DASHBOARD_URL` (live → upload dashboard, `counter_dashboard.py`) and `LIVE_DASHBOARD_URL` (upload → live dashboard, `recounting_dashboard_upload.py`); empty value hides the header link. ## Code conventions - All config lives in `.env` (dotenv), read via `os.getenv()` at module top-level in each script. - The 2 counter scripts share drawing/batch helpers. `counter_live_rknn_bytetrack.py` is the reference for C++ port. - `batch_store.py` has its own threading (cutoff watcher, batch timeout timer) — thread safety is via a single `state_lock`. - The dashboard re-creates DB tables on startup (`_ensure_db()`) independently from `batch_store.py`. - No formal version tracking exists anywhere in this codebase. - Dashboard template selectable via `DASHBOARD_TEMPLATE` env var — supports `dashboard.html`, `dashboard_lamborghini.html`, `dashboard_tesla.html`.