Skip to content

Latest commit

 

History

48 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CrowdShield – AI-Powered Crowd Management System

Hackathon MVP — AI early-warning system that turns reactive crowd monitoring into predictive public safety.

Crowd telemetry is generated by a 3D simulation, ingested by a FastAPI backend, stored & secured in Supabase, visualized on a live admin dashboard, and pushed as alerts to a citizen mobile app.


📌 Overview

CrowdShield continuously monitors crowd density, movement speed, surges, and bottlenecks across zones of a venue, computes a 0–100 risk score, and surfaces level-based responses (SAFE → WARNING → HIGH → CRITICAL) to both security operators and citizens.

One line: Simulate → Analyze → Alert → Act.


🎯 Key Features

  • 🎮 3D crowd simulation (React Three Fiber) generating realistic telemetry
  • 📊 Real-time crowd monitoring (live metrics, history, heatmaps)
  • ⚠️ AI risk engine (0–100 score, 4 levels, explainable reasons)
  • 🧠 Recommendation engine (level-gated operational actions)
  • 🗺️ Admin dashboard (React + Vite) with live map + camera feed, alerts, telemetry panel, analytics
  • 📱 Citizen mobile app (Expo) with alerts, safe routes, incident reporting
  • 🔔 Push notifications via Expo Notifications
  • 🔐 Auth & RLS via Supabase (roles: citizen / authority / admin)

🏗️ Architecture

flowchart TD

subgraph group_simulation["Telemetry sources"]
  node_sim_app["Digital-twin simulator<br/>React simulation<br/>[App.jsx]"]
  node_crowd_engine["Crowd engine<br/>simulation engine<br/>[CrowdEngine.js]"]
  node_telemetry_sync["Telemetry sync<br/>API producer<br/>[TelemetrySync.js]"]
  node_cv_pipeline["Camera CV prototype<br/>planned producer<br/>[detect.py]"]
end

subgraph group_backend["FastAPI service"]
  node_api["FastAPI entrypoint<br/>Python API<br/>[main.py]"]
  node_crowd_router["Crowd ingestion<br/>crowd router<br/>[crowd.py]"]
  node_live_store["Latest metrics store<br/>process-local state<br/>[shared_data.py]"]
  node_risk_router["Risk API<br/>risk router<br/>[risk.py]"]
  node_risk_engine["Risk engine<br/>decision engine<br/>[risk_engine.py]"]
  node_recommendations["Recommendation engine<br/>decision engine"]
  node_db_adapter["Persistence adapter<br/>database adapter<br/>[db.py]"]
end

subgraph group_data["Data and identity"]
  node_supabase[("Supabase<br/>Postgres, auth, RLS")]
  node_schema["Domain schema<br/>SQL migrations<br/>[0001_db_init.sql]"]
end

subgraph group_clients["Operator and citizen clients"]
  node_web_app["Operator web console<br/>Vite React app<br/>[main.jsx]"]
  node_web_routes["Web routes and auth<br/>route composition<br/>[AppRoutes.jsx]"]
  node_web_live_data["Web live polling<br/>API client hook<br/>[useLiveData.js]"]
  node_mobile_app["Citizen mobile app<br/>Expo Router app<br/>[_layout.tsx]"]
  node_mobile_api["Mobile live-risk client<br/>API client<br/>[api.ts]"]
  node_notifications["Risk notifications<br/>notification provider"]
end

node_expo_notifications{{"Expo notification services<br/>external service"}}

node_sim_app -->|"runs"| node_crowd_engine
node_crowd_engine -->|"zone state"| node_telemetry_sync
node_telemetry_sync -->|"POST metrics"| node_crowd_router
node_cv_pipeline -.->|"planned metrics source"| node_crowd_router
node_api -->|"mounts"| node_crowd_router
node_api -->|"mounts"| node_risk_router
node_crowd_router -->|"updates"| node_live_store
node_crowd_router -->|"persists metrics"| node_db_adapter
node_crowd_router -->|"scores metrics"| node_risk_engine
node_risk_engine -->|"creates risk events"| node_db_adapter
node_risk_router -->|"calculates and reads events"| node_risk_engine
node_risk_router -->|"generates"| node_recommendations
node_db_adapter -->|"durable persistence"| node_supabase
node_schema -->|"defines tables"| node_supabase
node_web_app -->|"composes"| node_web_routes
node_web_routes -->|"auth and roles"| node_supabase
node_web_app -->|"uses"| node_web_live_data
node_web_live_data -->|"polls telemetry and events"| node_api
node_mobile_app -->|"auth and domain data"| node_supabase
node_mobile_app -->|"uses"| node_mobile_api
node_mobile_api -->|"polls live risk"| node_api
node_mobile_app -->|"provides alerts"| node_notifications
node_notifications -->|"delivers notifications"| node_expo_notifications

click node_sim_app "https://github.com/chandrakantamandal/crowdshield/blob/main/Simulation/src/App.jsx"
click node_crowd_engine "https://github.com/chandrakantamandal/crowdshield/blob/main/Simulation/src/engine/CrowdEngine.js"
click node_telemetry_sync "https://github.com/chandrakantamandal/crowdshield/blob/main/Simulation/src/engine/TelemetrySync.js"
click node_cv_pipeline "https://github.com/chandrakantamandal/crowdshield/blob/main/Ai/detect.py"
click node_api "https://github.com/chandrakantamandal/crowdshield/blob/main/Server/main.py"
click node_crowd_router "https://github.com/chandrakantamandal/crowdshield/blob/main/Server/routers/crowd.py"
click node_live_store "https://github.com/chandrakantamandal/crowdshield/blob/main/Server/shared_data.py"
click node_risk_router "https://github.com/chandrakantamandal/crowdshield/blob/main/Server/routers/risk.py"
click node_risk_engine "https://github.com/chandrakantamandal/crowdshield/blob/main/Server/services/risk_engine.py"
click node_recommendations "https://github.com/chandrakantamandal/crowdshield/blob/main/Server/services/recommendation_engine.py"
click node_db_adapter "https://github.com/chandrakantamandal/crowdshield/blob/main/Server/db.py"
click node_schema "https://github.com/chandrakantamandal/crowdshield/blob/main/App/db/migrations/0001_db_init.sql"
click node_web_app "https://github.com/chandrakantamandal/crowdshield/blob/main/Web/src/main.jsx"
click node_web_routes "https://github.com/chandrakantamandal/crowdshield/blob/main/Web/src/router/AppRoutes.jsx"
click node_web_live_data "https://github.com/chandrakantamandal/crowdshield/blob/main/Web/src/lib/useLiveData.js"
click node_mobile_app "https://github.com/chandrakantamandal/crowdshield/blob/main/App/app/_layout.tsx"
click node_mobile_api "https://github.com/chandrakantamandal/crowdshield/blob/main/App/lib/api.ts"
click node_notifications "https://github.com/chandrakantamandal/crowdshield/blob/main/App/components/RiskNotificationProvider.tsx"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a

class node_sim_app,node_crowd_engine,node_telemetry_sync,node_cv_pipeline toneBlue
class node_api,node_crowd_router,node_live_store,node_risk_router,node_risk_engine,node_recommendations,node_db_adapter toneAmber
class node_supabase,node_schema toneMint
class node_web_app,node_web_routes,node_web_live_data,node_mobile_app,node_mobile_api,node_notifications toneRose
class node_expo_notifications toneNeutral
Loading

Data Flow (end-to-end)

Simulation tick (1/s)
    ↓
Per-zone metrics
    ↓
POST /api/crowd/metrics (5 zones)
    ↓
FastAPI validates (Pydantic)
    ↓
Upsert in-memory latest_metrics
    ↓
Insert into Supabase crowd_data (if migrations applied)

Risk Engine
(density / speed / surge / bottleneck / flow_conflict)
    ↓
0–100 score + level + reasons
    ↓
Insert into Supabase risk_events (on level change only)

Dashboard polls (2s)
    ↓
GET /api/crowd/metrics + /api/risk/events
    ↓
Live cards + map + camera feed + alert feed + telemetry

🧱 Tech Stack

Layer Technology
Simulation React 18 + Vite 5 + React Three Fiber / drei / Three.js
Backend API FastAPI + Uvicorn (Python 3.10+)
Data / Auth Supabase (Postgres, Auth, Row Level Security)
Admin Dashboard React 19 + Vite 8 + Tailwind CSS v4 + zustand + React Three Fiber
Mobile App React Native + Expo SDK 54 + Expo Router + NativeWind
Notifications Expo Notifications
Computer Vision (planned) YOLO + OpenCV

📁 Repository Layout

Path Purpose
Server/ FastAPI backend: API, risk engine, recommendations, Supabase persistence
Simulation/ 3D crowd simulation that streams telemetry to the Server
Web/ Admin dashboard (operator console)
App/ Citizen mobile app (Expo)
App/db/migrations/ Supabase SQL migrations (0001_db_init.sql, 0002_backend_persistence.sql)

🧠 Risk Engine

Defined in Server/services/risk_engine.py.

Signal Weight Trigger
High Crowd Density 35 density > 0.00005
High Movement Speed 20 average_speed > 1.5
Crowd Surge 15 surge_detected == true
Bottleneck 10 bottleneck == true
Flow Conflict 10 flow_conflict == true (opposing movement in a zone)

Risk Levels

Level Score Operator Response (recommendation_engine.py)
SAFE 0–30 Situation normal, continue monitoring
WARNING 31–60 Increase CCTV monitoring, alert nearby security
HIGH 61–80 Deploy security team, control entry gate, broadcast warning
CRITICAL 81–100 Close gate G3, open exit E2, redirect crowd, call emergency team

Input keys: density, average_speed, surge_detected, bottleneck, flow_conflict

Output:

{
  "risk_score": int,
  "risk_level": "SAFE"|"WARNING"|"HIGH"|"CRITICAL",
  "reasons": string[]
}

On the dashboard, risk levels map to green (SAFE) / yellow (WARNING) / orange (HIGH) / red (CRITICAL).


⚙️ API Reference (FastAPI, port 8000)

Method Endpoint Description Params / Body
GET / Health message
GET /status Service status
GET /api/crowd/metrics Latest in-memory metrics
GET /api/crowd/history Crowd history from Supabase limit=50, zone_id=
POST /api/crowd/metrics Ingest telemetry (persists to crowd_data) Metrics JSON
GET /api/risk/events Latest risk events limit=50
POST /api/risk/calculate Compute risk score + persist event Metrics JSON
POST /api/recommendations Compute risk + get level-gated actions Metrics JSON

Metrics Payload

Pydantic model — Server/models.py

{
  "camera_id": "SIM_ZONE_A",
  "zone_id": "ZONE_A",
  "people_count": 84,
  "density": 0.0003,
  "speed": 0.4,
  "surge_detected": false,
  "bottleneck": false,
  "flow_conflict": false,
  "direction": "NORTH",
  "timestamp": "2026-08-09T12:34:56.789Z"
}

Note: POST /api/crowd/metrics accepts speed (alias) and internally maps it to average_speed (ConfigDict(populate_by_name=True) + validation_alias="speed"), so the API also emits average_speed.


🗄️ Database (Supabase)

Run migrations in order in the Supabase SQL Editor:

  1. App/db/migrations/0001_db_init.sql — schema + RLS + auto-profile trigger
  2. App/db/migrations/0002_backend_persistence.sql — adds surge_detected / bottleneck columns and anon INSERT policies for backend persistence

Tables:

  • profiles
  • venues
  • crowd_data
  • risk_events
  • incidents
  • alerts

Note: The anon key cannot run DDL — applying 0002 is required for live inserts to work from the Server (see the Blocked note in Work State).

Known gap: flow_conflict is consumed by the risk engine and posted by the simulation, but it is not yet persisted to crowd_data (the insert in Server/db.py omits it). A 0003 migration adding the column + an insert_crowd_data update would close this gap.


🚀 Getting Started

0. Prerequisites

  • Python 3.10+
  • Node.js 18+ (npm)
  • A Supabase project (free tier) with URL + anon key

0b. Docker (dev-mode, optional)

All three services (Server, Web, Simulation) run as Vite/Vitest-style dev containers — code is mounted fresh at build time, so no hot-reload bind-mount is configured. Requires Docker Desktop running.

# from repo root — build images (first time, a few minutes)
docker compose build

# start everything: server :8000, web :5173, simulation :3000
docker compose up

# background mode (Ctrl+C won't stop it)
docker compose up -d

# tail logs / stop / full reset
docker compose logs -f
docker compose down
docker compose down -v   # also drops container volumes

Notes:

  • Server reads credentials from Server/.env via env_file. No Supabase credentials? The container still boots — persistence just degrades gracefully.
  • Web/Simulation receive VITE_API_URL from your shell (VITE_API_URL=http://localhost:8000 default). Override without editing files: VITE_API_URL=http://<your-lan-ip>:8000 docker compose up web.
  • Healthcheck: server must be healthy before web/simulation start (depends_on: condition: service_healthy).
  • Everything here is the dev path; the built/non-dev path is out of scope

1. Backend (Server/)

cd Server
pip install -r requirements.txt

# create Server/.env
# SUPABASE_URL=https://<project>.supabase.co
# SUPABASE_ANON_KEY=<anon key>

uvicorn main:app --reload --port 8000

Swagger UI:

http://localhost:8000/docs

No SUPABASE_URL/key? The server still boots and the in-memory metrics + risk engine work — only DB persistence degrades gracefully.

2. Admin Dashboard (Web/)

cd Web
npm install

# create Web/.env
# VITE_SUPABASE_URL=https://<project>.supabase.co
# VITE_SUPABASE_ANON_KEY=<anon key>
# VITE_API_URL=http://localhost:8000

npm run dev
npm run build
npm run lint

Dashboard:

http://localhost:5173

3. Simulation (Simulation/)

cd Simulation
npm install
npm run dev

Simulation:

http://localhost:3000

Streaming to the server is off by default (TelemetrySync.js). Enable it in the simulation UI (toggle) so it starts posting each zone's telemetry to:

POST /api/crowd/metrics

The sim streams 5 zones (ZONE_A…ZONE_E) once per tick, each with:

  • density
  • speed
  • surge_detected
  • bottleneck
  • flow_conflict

If the server is offline it retries with a 15-second backoff so the console stays clean.

4. Citizen App (App/)

cd App
npm install

# create App/.env
# EXPO_PUBLIC_API_URL=http://<your-lan-ip>:8000
# EXPO_PUBLIC_SUPABASE_URL=...
# EXPO_PUBLIC_SUPABASE_ANON_KEY=...

npx expo start

Scan the QR code with Expo Go.

Expo SDK 54 — consult the versioned docs at https://docs.expo.dev/versions/v54.0.0/ before changing Expo code.


🔐 Environment Variables (summary)

Variable Component Required
SUPABASE_URL Server Yes (falls back to default project)
SUPABASE_ANON_KEY Server Yes for persistence
VITE_SUPABASE_URL Web Yes
VITE_SUPABASE_ANON_KEY Web Yes
VITE_API_URL Web Yes (http://localhost:8000)
EXPO_PUBLIC_API_URL App Yes
EXPO_PUBLIC_SUPABASE_URL / EXPO_PUBLIC_SUPABASE_ANON_KEY App Yes for auth

🎬 Demo Flow

1. Launch Server (uvicorn :8000)

2. Launch Simulation (:3000)
   → toggle streaming ON

3. Launch Dashboard (:5173)
   → login (Supabase auth)
   → dashboard

4. Simulation drives crowds in 5 zones
   → per-zone telemetry POSTed every second

5. Dashboard polls live metrics + risk events
   → cards/map/camera feed/alert feed update

6. Trigger a surge/bottleneck/flow-conflict in the simulation
   → risk_score climbs
   → CRITICAL alert (red) appears in dashboard + app

7. App user reports an incident / receives a push notification

🛣️ Roadmap / Production Notes

  • Real-time: replace 2s polling with WebSocket/SSE + push
  • Ingestion: decouple via message bus (Kafka / Redis Streams / SQS)
  • Time-series: TimescaleDB/InfluxDB for crowd_data (aggregation + retention)
  • Config: move venue/zones to a DB config table (currently hardcoded)
  • Vision: wire YOLO + OpenCV camera pipeline as a telemetry source
  • Scaling: N camera ingestors → bus → risk-engine workers → events + aggregates

🌟 Future Scope

  • Digital twin simulation
  • AI crowd prediction (ML on historical crowd_data)
  • Voice dashboard
  • Multilingual assistant

📄 License

This project is licensed under the MIT License.

See the LICENSE file for the full license text.


👨‍💻 Author

Built for hackathon innovation 🚀

Focus: AI + Real-time systems + Public Safety

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages