Real-time AI-powered PPE compliance monitoring platform for industrial environments.
Detects safety violations (missing helmets, missing vests) across multiple live camera feeds and delivers instant WebSocket alerts to a React dashboard.
- Overview
- Architecture
- Tech Stack
- Features
- Project Structure
- Getting Started
- Configuration
- API Reference
- Detection Pipeline
- PPE Compliance Logic
- Alert System
- Frontend Pages
- Default Credentials
- Known Limitations
Worker Safety Detection System v2 is a full-stack platform that monitors CCTV/webcam feeds in real time, detects Personal Protective Equipment (PPE) compliance violations using YOLOv8, and immediately alerts supervisors via a live dashboard and optional email.
The system processes video frames through a multi-threaded camera manager, publishes events to Redis, and broadcasts them to all connected browser clients over WebSockets β all with sub-second latency.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Browser (React + Vite) β
β Dashboard Β· Cameras Β· Violations Β· Analytics Β· Alerts Β· Login β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β REST + WebSocket (port 8001)
ββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ
β FastAPI Backend (Python 3.11) β
β β
β βββββββββββββββ ββββββββββββββββββ ββββββββββββββββββββββββ β
β β Auth Router β β Violation/Statsβ β WebSocket Router β β
β β (JWT + OTP) β β Routers β β (real-time alerts) β β
β βββββββββββββββ ββββββββββββββββββ ββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Detection Layer (detection/) β β
β β β β
β β CameraManager β CameraStream (per thread) β β
β β β β β β
β β SafetyDetector PPEDetector β β
β β (YOLOv8 + FPS HUD) (multi-class spatial matching) β β
β β β β β
β β EventPublisher β Redis Pub/Sub β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β β AlertService β β ViolationConsumerβ β
β β (severity class) β β (background task)β β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β β
β SQLite (violations + users) Redis (pub/sub + frame cache) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Each camera runs in its own background thread. Detected frames are JPEG-encoded and stored in Redis (5-second TTL). Violations are published to the violations.raw channel, consumed by AlertService, enriched with severity, and broadcast over WebSocket to all browser clients.
| Layer | Technology |
|---|---|
| Detection / ML | YOLOv8 (ultralytics), OpenCV |
| Backend API | FastAPI, Uvicorn, Pydantic v2 |
| Auth | JWT (python-jose), bcrypt (passlib), OTP |
| Database | SQLAlchemy + SQLite |
| Message Broker | Redis 7 (Pub/Sub + frame cache) |
| Frontend | React 19, TypeScript, Vite 8 |
| State / Data | TanStack Query v5, Axios |
| UI | Recharts, Lucide React, React Hot Toast |
| Routing | React Router v7 |
| Containerisation | Docker + Docker Compose |
- Multi-camera live streaming β MJPEG stream endpoint per camera; supports webcam (index), RTSP, and HTTP sources
- Dual-model detection pipeline β General
SafetyDetector(YOLOv8n) with a specialisedPPEDetector(multi-class model with spatial region matching) - PPE compliance classification β Per-worker status:
FULLY_COMPLIANT,NO_HELMET,NO_VEST,NON_COMPLIANT - Real-time alerts β WebSocket broadcast to all dashboard tabs within milliseconds of a detection
- Severity classification β Violations rated
HIGH(helmet),MEDIUM(vest),LOW(other) - Snapshot saving β Annotated JPEG snapshots written to disk on every violation, served as static files
- Cooldown-based alert throttling β Configurable per camera+violation type to prevent alert spam
- SMTP email alerts β Optional async email delivery to configurable recipient list
- JWT + OTP auth β Password login and 6-digit OTP login; admin/viewer role separation
- Analytics dashboard β Violation trends by hour, by type, per-camera breakdown
- Docker-native deployment β Two-stage Dockerfile builds frontend then serves everything from one container
Worker-safety-detection-System-v2/
βββ app.py # Standalone Streamlit prototype (legacy, not part of main system)
βββ Dockerfile # Multi-stage: frontend build β Python backend
βββ docker-compose.yml # Backend + Frontend (dev) + Redis
βββ .env.example # All configurable environment variables
β
βββ detection/ # Core ML detection layer (framework-agnostic)
β βββ engine.py # SafetyDetector: YOLOv8 inference, FPS tracking, snapshot saving
β βββ camera_manager.py # CameraManager + CameraStream (threaded per-camera capture)
β βββ ppe_detector.py # PPEDetector: spatial region matching for helmet/vest compliance
β βββ event_publisher.py # Redis publisher (violations.raw, frame cache, metrics)
β βββ alert_manager.py # Cooldown logic + SMTP email alerts
β
βββ backend/
β βββ app/
β βββ main.py # FastAPI app: lifespan, camera seeding, MJPEG stream, CORS
β βββ config.py # Pydantic Settings (reads .env)
β βββ core/
β β βββ redis_client.py # Async Redis client wrapper
β β βββ ws_manager.py # WebSocket connection manager (broadcast)
β βββ models/
β β βββ database.py # SQLAlchemy models: User, Violation, Camera
β β βββ schemas.py # Pydantic request/response schemas
β βββ routers/
β β βββ auth.py # /api/auth/* β register, login, OTP, /me
β β βββ cameras.py # /api/cameras/* β add, remove, list, info
β β βββ detect.py # /api/detect β upload frame for inference
β β βββ violations.py # /api/violations β CRUD + filtering
β β βββ stats.py # /api/stats β aggregated metrics
β β βββ ppe.py # /api/ppe β PPE-specific detection endpoint
β β βββ websockets.py # /ws β WebSocket upgrade
β βββ services/
β β βββ detection_service.py
β β βββ ppe_service.py
β β βββ alert_service.py # Consumes violations.raw, classifies severity, broadcasts
β βββ workers/
β βββ event_consumer.py # Background task: persists Redis events to SQLite
β
βββ frontend/
βββ src/
βββ App.tsx # Router + layout
βββ api/client.ts # Axios instance with auth interceptors
βββ context/
β βββ AuthContext.tsx # JWT storage + login state
β βββ WebSocketContext.tsx # WS connection + incoming alert stream
βββ pages/
βββ LoginPage.tsx # JWT login form
βββ DashboardPage.tsx # Live stats + recent alerts
βββ CamerasPage.tsx # Add/remove cameras + live MJPEG feed
βββ IncidentsPage.tsx # Filterable violations table + snapshot preview
βββ AnalyticsPage.tsx # Recharts: violations by hour + by type
βββ AlertsPage.tsx # Real-time incoming alert feed
- Docker β₯ 24 and Docker Compose v2 or Python 3.11+ and Node.js 20+
- A YOLOv8n model file (
yolov8n.pt) in the project root β downloaded automatically byultralyticson first run if absent - (Optional) A specialised PPE model at
backend/models/ppe.ptβ the system falls back gracefully toyolov8n.ptwithout it
# 1. Clone the repo
git clone https://github.com/<your-username>/Worker-safety-detection-System-v2.git
cd Worker-safety-detection-System-v2
# 2. Copy and edit environment file
cp .env.example .env
# Minimum: change SECRET_KEY
# 3. Build and start all services
docker compose up --build
# Backend API: http://localhost:8000
# Frontend: http://localhost:5173
# Redis: localhost:6379Note: The Docker Compose file maps port
8000for the backend container. The app internally starts on8001in manual mode β make sure your.envALLOWED_ORIGINSmatches whichever URL the frontend is served from.
Backend
# Create and activate virtual environment
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# Install dependencies
pip install -r backend/requirements.txt
# Copy environment file
cp .env.example .env
# Start Redis (requires Docker or a local Redis install)
docker run -d -p 6379:6379 redis:7-alpine
# Run the backend
uvicorn backend.app.main:app --host 0.0.0.0 --port 8001 --reloadFrontend
cd frontend
npm install
npm run dev
# Runs at http://localhost:5173All settings are loaded from environment variables or a .env file at the project root. Copy .env.example to .env and set values as needed.
| Variable | Default | Description |
|---|---|---|
SECRET_KEY |
change-me-in-production |
JWT signing key β must change in production |
ACCESS_TOKEN_EXPIRE_MINUTES |
480 |
JWT lifetime (8 hours) |
OTP_EXPIRY_MINUTES |
10 |
OTP code validity window |
DB_URL |
sqlite:///./data/safety.db |
SQLAlchemy database URL |
REDIS_URL |
redis://localhost:6379/0 |
Redis connection string |
MODEL_PATH |
yolov8n.pt |
Path to primary YOLO model |
SNAPSHOT_DIR |
snapshots |
Directory for violation images |
CONF_THRESHOLD |
0.4 |
Minimum YOLO confidence to flag a detection |
ALERT_COOLDOWN_SECONDS |
30 |
Minimum gap between repeat alerts per camera |
ALLOWED_ORIGINS |
http://localhost:5173,... |
CORS allowed origins (comma-separated) |
SMTP_HOST |
(empty) | SMTP server for email alerts |
SMTP_PORT |
587 |
SMTP port |
SMTP_USER |
(empty) | SMTP username / sender address |
SMTP_PASSWORD |
(empty) | SMTP password or app password |
ALERT_RECIPIENTS |
(empty) | Comma-separated alert email recipients |
All protected routes require Authorization: Bearer <token> header.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/api/auth/register |
None | Create new user (admin or viewer role) |
POST |
/api/auth/login |
None | Returns JWT token |
POST |
/api/auth/otp/send |
None | Generate and send OTP for email |
POST |
/api/auth/otp/verify |
None | Verify OTP, returns JWT |
GET |
/api/auth/me |
Required | Returns current user profile |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/api/cameras |
Required | Add a camera by ID and source |
DELETE |
/api/cameras/{id} |
Admin | Stop and remove a camera |
GET |
/api/cameras |
Required | List all cameras with status |
GET |
/api/cameras/{id}/stream |
Required | MJPEG live stream |
GET |
/api/cameras/{id}/info |
Required | Camera runtime info (FPS, uptime, violation count) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/api/detect |
Required | Upload a JPEG/PNG frame, returns detections + annotated image (base64) |
POST |
/api/ppe |
Required | Run PPE-specific detection on an uploaded frame |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/violations |
Required | Paginated list; filter by type, camera_id, from, to |
GET |
/api/violations/{id} |
Required | Single violation record |
DELETE |
/api/violations/{id} |
Admin | Delete a record |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/stats |
Required | Totals, today count, active cameras, violations by type and hour |
GET |
/api/stats/cameras |
Required | Per-camera violation breakdown |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/health |
None | Health check |
GET |
/api/alerts/recent |
None | Last 20 processed alerts |
WS |
/ws |
None | WebSocket β receives real-time SAFETY_ALERT events |
GET |
/snapshots/{filename} |
None | Static violation snapshot image |
Interactive docs available at http://localhost:8001/docs (Swagger UI).
Camera Source (webcam / RTSP / HTTP)
β
CameraStream thread (15 FPS cap)
β
SafetyDetector.process_frame()
β’ YOLOv8 inference at conf β₯ 0.4
β’ Person class β NO_HELMET violation (fallback when no PPE model)
β’ Bounding box annotation + HUD overlay (FPS, violation count, camera ID)
β’ Snapshot JPEG saved to /snapshots/
β
EventPublisher (sync Redis)
β’ Frame bytes β Redis key frame_{camera_id} (TTL: 5s)
β’ Violation dict β Redis channel violations.raw
β’ Metrics (FPS, uptime) β Redis channel stats.metrics (every 30 frames)
β
ViolationConsumer (async background task)
β’ Reads violations.raw
β’ Persists Violation record to SQLite
β
AlertService (async background task)
β’ Reads violations.raw
β’ Classifies severity: HIGH (helmet) / MEDIUM (vest) / LOW (other)
β’ Broadcasts SAFETY_ALERT JSON over WebSocket to all browser clients
The PPEDetector uses regional spatial matching to associate helmet and vest detections with each detected person:
- Head region β top 30% of each person bounding box; helmets must have their centre within this region
- Torso region β 30%β80% of person height; vests must centre within this band
- Helmet and vest matches require confidence β₯ 0.5
Compliance status assigned per worker:
| Status | Condition |
|---|---|
FULLY_COMPLIANT |
Helmet β + Vest β |
NO_VEST |
Helmet β, Vest β |
NO_HELMET |
Helmet β, Vest β |
NON_COMPLIANT |
Helmet β + Vest β |
Bounding box colour coding: green (compliant), yellow (partial), red (non-compliant).
If the specialised backend/models/ppe.pt model is absent, the system falls back to yolov8n.pt and flags every detected person as NO_HELMET β a conservative safe-fail mode.
AlertManager applies per (camera_id, violation_type) cooldown windows (default 30 seconds) to prevent the same camera from flooding the alert feed. After cooldown, it:
- Records the alert in a 500-entry in-memory ring buffer
- Logs a warning
- Fires an async SMTP email to all configured recipients (non-blocking thread)
AlertService additionally enriches each violation with a severity label and broadcasts to all WebSocket clients:
{
"type": "SAFETY_ALERT",
"severity": "HIGH",
"camera_id": "webcam",
"violation_type": "NO_HELMET",
"timestamp": 1717000000.0,
"confidence": 0.87,
"snapshot_path": "snapshots/violation_webcam_1717000000_a1b2c3.jpg",
"message": "HIGH Severity: NO_HELMET detected on webcam"
}| Page | Route | Description |
|---|---|---|
| Login | /login |
JWT authentication |
| Dashboard | / |
Live KPI cards (total violations, today count, active cameras) + recent alert feed |
| Cameras | /cameras |
Add/remove cameras, live MJPEG stream embed, per-camera stats |
| Incidents | /incidents |
Searchable/filterable violation log with snapshot thumbnails |
| Analytics | /analytics |
Recharts bar charts: violations by hour (last 24h) and by type |
| Alerts | /alerts |
Real-time incoming WebSocket alert stream |
The WebSocketContext maintains the WS connection globally; any tab receives live alerts immediately without polling.
On first startup, the system seeds a default admin account:
| Field | Value |
|---|---|
admin@safeguard.local |
|
| Password | admin1234 |
Change this immediately in any non-local environment.
The OTP debug endpoint also returns the generated OTP in the response body β remove otp_debug from auth.py before deploying to production.
- Fallback violation logic β When no specialised PPE model (
ppe.pt) is available, every detected person is flagged asNO_HELMET. This is intentionally conservative but will produce false positives. Supply a proper multi-class PPE model for accurate compliance detection. - SQLite concurrency β SQLite works fine for single-node deployments. Replace with PostgreSQL for multi-instance or high-throughput scenarios.
- OTP email delivery β OTP sending (
/api/auth/otp/send) requires SMTP credentials; without them the OTP is returned in the response body (dev convenience only β remove before production). - Redis required β The background workers depend on Redis. If Redis is unavailable at startup, alert processing and WebSocket broadcasts will be disabled; frame capture and local violation recording still function.
- 15 FPS cap β Camera streams are capped at 15 FPS by default to manage CPU usage on YOLO inference. Adjustable via
CameraStream.fps_limit.
Arjun R K
GitHub: https://github.com/AxArjun
MIT License