Files
proitlab fccc285ab3 Add OUTPUT_DIR browser + copy-on-load with progress to upload dashboard
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.
2026-08-13 13:33:26 +07:00

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 spawns RECOUNT_CMD (process loads and pauses), then START RECOUNT touches {SHM_DIR}/.continue to 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=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.
  • Recount continue flow (upload dashboard, port 5003): POST /api/load-mp4 {path} kills the old process, spawns RECOUNT_CMD (loads + pauses), and POSTs /api/reset to 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-files lists MP4s from OUTPUT_DIR folder-grouped (mirrors recounting_dashboard.py's /api/mp4-files shape). Selecting one and pressing LOAD MP4 makes POST /api/load-mp4 copy it into UPLOAD_DIR first (chunked, progress reported via GET /api/copy-progress → {active,name,total,done,pct}, frontend polls every 250 ms to drive the progress bar). Name collision in UPLOAD_DIR → 400 error (no overwrite). The OUTPUT_DIR browser is read-only (no delete).
  • Recount STOP sweep: POST /api/stop-recount kills the tracked process group (killpg TERM→5s→KILL) then sweeps the host via /proc for any process whose argv matches the RECOUNT_CMD binary name (basename of the first token, so it also catches orphans from a dashboard restart); TERM→_SWEEP_GRACE_SEC→KILL with _SWEEP_MAX_RETRIES retries, all under _recount_lock. Returns {success, killed, remaining}; remaining is 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.py parses both to query the live API's /api/day-detail/<YYYY-MM-DD> for the recorded count.
  • RECOUNT_CMD in the upload dashboard is a template with a {path} placeholder, e.g. bytetrack-counter-cpp config.env --source {path}; the uploaded file path is shlex.quote()d before substitution, and the command is spawned by LOAD MP4 (loads + pauses until .continue is touched).
  • 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.