Hazard Lens is a workplace-safety monitoring prototype with camera-based fall detection, a live incident dashboard, persistent storage, optional email alerts, and an optional Ollama Safety Coach.
- Python 3.10–3.12
- Node.js LTS and npm
- A webcam, USB camera, or reachable camera stream
git clone https://github.com/meherajkhatri/Hazard-Lens.git
cd Hazard-Lens
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install -r backend/requirements.txt -r cv_engine/requirements.txt
cp backend/.env.example backend/.env
cp cv_engine/.env.example cv_engine/.env
cp frontend/.env.example frontend/.env.local
cd frontend && npm ci && cd ..For a local run, use STORAGE_BACKEND=sqlite and ALERT_PROVIDER=none in
backend/.env. Use the same API_KEY in the backend, CV engine, and frontend.
Replace /path/to/Hazard-Lens with the repository path. Start the terminals in
this order and leave each one running.
cd /path/to/Hazard-Lens
source .venv/bin/activate
cd backend
python -m uvicorn app.main:app --reload --host 127.0.0.1 --port 8000Check http://127.0.0.1:8000/health.
cd /path/to/Hazard-Lens
source .venv/bin/activate
python -m cv_engine.preflight --allow-local
python -m cv_engine.run --camera-id zone-1-cam-1 --camera-index 0 --port 8001Allow camera access when prompted. The stream is available at
http://127.0.0.1:8001/stream.
Run one CV process for each connected camera. Use a different camera index, camera ID, and stream port for every process:
# Terminal 4: camera 2
cd /path/to/Hazard-Lens
source .venv/bin/activate
python -m cv_engine.run --camera-id zone-1-cam-2 --zone-id "Zone 1" --camera-index 1 --port 8002List locally available camera indexes before starting the processes:
python -m cv_engine.run --list-camerasFor network cameras, replace --camera-index N with
--camera-url http://camera-address/stream. Each process recognizes people
and falls independently and sends incidents with its own camera_id.
To run several workers under one supervisor, create private files from
cameras/camera-1.env.example and cameras/camera-2.env.example, then run:
python tools/run_cameras.py --env-file cameras/camera-1.env --env-file cameras/camera-2.envcd /path/to/Hazard-Lens/frontend
npm run devOpen http://localhost:3000. Stop services with Control + C in each terminal.
-
frontend/.env.localshould useBACKEND_URL=http://127.0.0.1:8000and map every annotated CV output inNEXT_PUBLIC_CAMERA_STREAMS, for example:NEXT_PUBLIC_CAMERA_STREAMS={"zone-1-cam-1":"http://127.0.0.1:8001/stream","zone-1-cam-2":"http://127.0.0.1:8002/stream"} NEXT_PUBLIC_CAMERA_ZONES={"zone-1-cam-1":"Zone 1","zone-1-cam-2":"Zone 1"}
The dashboard's Camera selector can show one feed or all configured feeds at the same time. Use the CV output URLs, not raw camera URLs.
frontend/.env.localtakes precedence overfrontend/.env; when the browser is on another device, use the CV host's LAN address instead of127.0.0.1for every camera stream. -
For Brevo email, set
ALERT_PROVIDER=brevo_emailand fill its variables inbackend/.env. -
Automatic email alerts are sent only when model confidence is strictly above 90%. Configure this with
ALERT_MIN_CONFIDENCE=0.9. Incidents below that threshold are still stored in the dashboard but do not trigger email. -
Existing SQLite records are migrated automatically from the old SMS fields.
-
For existing Supabase data, run
backend/supabase/migrate_alerts.sqlonce. -
Keep credentials out of
NEXT_PUBLIC_*variables and do not expose this unauthenticated prototype directly to the public internet. -
The API uses a shared server-side API key. Put Caddy or Nginx in front of the frontend for HTTPS;
deploy/Caddyfile.exampleprovides a starting point. Keep backend and CV ports private. -
Back up SQLite data and incident snapshots with
tools/backup_data.sh. Each backup now includesMANIFEST.sha256; the command fails instead of silently creating an empty backup, so verify the manifest before deleting older copies. On macOS, copydeploy/com.hazardlens.backup.plist.example, replaceREPLACE_ME, and load it withlaunchctl bootstrap gui/$UID. -
GitHub Actions runs backend, CV engine, and frontend checks on every push and pull request. Copy the Caddy template in
deploy/for HTTPS deployment.
Place labeled clips in one directory. Names beginning with fall are positive
examples; names such as adl, sit, or nonfall are negative examples:
cd cv_engine
../.venv/bin/python -m cv_engine.eval_clips /path/to/labeled-clips --sweepThe report includes falls caught, missed falls, false alarms, and the threshold
settings tested. Keep the labeled footage private; use --export to save only
pose skeletons for repeatable evaluation.
ollama pull qwen2.5-coder:7b
ollama servecd backend && PYTHONPATH=. ../.venv/bin/python -m pytest -q
cd ../cv_engine && PYTHONPATH=. ../.venv/bin/python -m pytest -q
cd ../frontend && npm run lint && npm run buildSee LICENSE.