LOAD MP4 on an OUTPUT_DIR file copies it into UPLOAD_DIR (chunked, progress via /api/copy-progress) before spawning RECOUNT_CMD; collision in UPLOAD_DIR fails with 400. New read-only folder-grouped browser mirrors recounting_dashboard.py. Docs updated.
5.5 KiB
5.5 KiB
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 LOAD MP4 spawnsRECOUNT_CMD(process loads and pauses), then START RECOUNT touches{SHM_DIR}/.continueto begin counting.
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
# 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=1is mandatory when running from the venv — without it, system/user packages leak in..envis gitignored — always copy fromconfig.env.examplefirst.numpy<2is required forrknn-toolkit-lite2compatibility.- Install path in service files is
/opt/bytetrack-counter(not the/opt/jetson-countermentioned in README/DEPLOY). The.env.examplealso reflects/opt/bytetrack-counter. - Service user is
root, notjetson(despite README saying otherwise). - Three systemd units:
bytetrack-counter.service,bytetrack-counter-dashboard.service, andbytetrack-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. - Recount continue flow (upload dashboard, port 5003):
POST /api/load-mp4 {path}kills the old process, spawnsRECOUNT_CMD(loads + pauses), and POSTs/api/resetto the recount node.POST /api/start-recount(no body, requires a loaded file) touches{SHM_DIR}/.continue; the C++ process consumes that marker to begin counting. The dashboard never clears the marker. - OUTPUT_DIR browser + copy-on-load (upload dashboard, port 5003):
GET /api/mp4-fileslists MP4s fromOUTPUT_DIRfolder-grouped (mirrorsrecounting_dashboard.py's/api/mp4-filesshape). Selecting one and pressing LOAD MP4 makesPOST /api/load-mp4copy it intoUPLOAD_DIRfirst (chunked, progress reported viaGET /api/copy-progress→{active,name,total,done,pct}, frontend polls every 250 ms to drive the progress bar). Name collision inUPLOAD_DIR→ 400 error (no overwrite). The OUTPUT_DIR browser is read-only (no delete). - Recount STOP sweep:
POST /api/stop-recountkills the tracked process group (killpgTERM→5s→KILL) then sweeps the host via/procfor any process whose argv matches theRECOUNT_CMDbinary name (basename of the first token, so it also catches orphans from a dashboard restart); TERM→_SWEEP_GRACE_SEC→KILL with_SWEEP_MAX_RETRIESretries, all under_recount_lock. Returns{success, killed, remaining};remainingis 0 in the normal path, and survivors (e.g. D-state) are logged rather than force-hanging. - Upload filename contract: uploads are expected as
batch_XX_YYYYMMDD_HHmmSS.mp4(XX = batch number, timestamp = date).recounting_dashboard_upload.pyparses both to query the live API's/api/day-detail/<YYYY-MM-DD>for the recorded count. RECOUNT_CMDin the upload dashboard is a template with a{path}placeholder, e.g.bytetrack-counter-cpp config.env --source {path}; the uploaded file path isshlex.quote()d before substitution, and the command is spawned by LOAD MP4 (loads + pauses until.continueis touched).- Cross-dashboard header links:
UPLOAD_DASHBOARD_URL(live → upload dashboard,counter_dashboard.py) andLIVE_DASHBOARD_URL(upload → live dashboard,recounting_dashboard_upload.py); empty value hides the header link.
Code conventions
- All config lives in
.env(dotenv), read viaos.getenv()at module top-level in each script. - The 2 counter scripts share drawing/batch helpers.
counter_live_rknn_bytetrack.pyis the reference for C++ port. batch_store.pyhas its own threading (cutoff watcher, batch timeout timer) — thread safety is via a singlestate_lock.- The dashboard re-creates DB tables on startup (
_ensure_db()) independently frombatch_store.py. - No formal version tracking exists anywhere in this codebase.
- Dashboard template selectable via
DASHBOARD_TEMPLATEenv var — supportsdashboard.html,dashboard_lamborghini.html,dashboard_tesla.html.