Traffic incident severity prediction with 95.22% accuracy (R² = 0.9522) using 8,173 real Bengaluru incidents, Kannada text detection, and 3-way interaction features.
Flipkart Grid 2.0, Round 2 Submission Problem Statement: Event-Driven Congestion (Planned & Unplanned) Operational Challenge
- Quick Start
- Overview
- The Three Questions
- System Architecture
- Technology Stack
- Data Layer
- Backend Engines
- API Endpoints
- Frontend Pages
- Project Structure
- Setup & Installation
- Project Replication & Model Training
- Demo Scenario
- Model Details
- Precomputed Lookup Tables
- Design Decisions
For Users (Pull Pre-built Image):
# Pull the image from Docker Hub
docker pull shiveren/astram-ai:latest
# Run the container
docker run -d -p 8000:8000 --name astram-ai shiveren/astram-ai:latest
# Open browser: http://localhost:8000For Developers (Build Locally):
# Clone the repository
git clone <repository-url>
cd grid_r2_complete
# Build and start container
docker-compose up -d
# Check logs
docker-compose logs -f
# Open browser: http://localhost:8000That's it! No Python installation, no dependencies, no platform issues. The container includes:
- ✅ Pre-trained CatBoost model (R² = 0.9522, 93 features)
- ✅ All 8,173 incidents preprocessed with DBSCAN clustering
- ✅ 6 precomputed lookup tables (~500 KB)
- ✅ 32+ REST API endpoints (includes forecasting, real-time, feedback)
- ✅ Modern 3-page web interface with sidebar navigation
- ✅ 10 specialized backend engines
- ✅ Health check monitoring
- ✅ Docker Compose with volume mounts for easy updates
The updated UI features:
- Command Center: Real-time city overview with interactive map, KPIs, and stress visualization
- AI Predictor: Impact prediction with resource planning and historical analysis
- Intelligence: Strategic corridor analytics with Chart.js visualizations
Docker Image Size: ~1.9 GB (includes all dependencies, data, and models)
# 1. Clone the repository
git clone <repository-url>
cd grid_r2_complete
# 2. Install dependencies (Python 3.9+ required)
pip install -r requirements.txt
# 3. Preprocess data and generate lookup tables
python astram/scripts/preprocess_data.py
python astram/backend/precompute_lookups.py
# 4. Start the backend server
python -m uvicorn astram.backend.app:app --host 0.0.0.0 --port 8000 --reload
# 5. Open browser: http://localhost:8000Note: The --reload flag enables auto-reload during development. Remove it for production.
Demo Scenario: Try predicting impact for:
- Cause: Water Logging
- Corridor: Mysore Road
- Hour: 8 (morning rush)
- Road Closure: Yes
- Expected Result: Impact Score ~28.2 (Medium Risk)
- Similar Incidents: ~1,775 historical matches
For detailed demo walkthroughs, see VIDEO_DEMO_SCRIPT.md
ASTRAM (Advanced Smart Traffic Response And Management) is a traffic operational intelligence platform built for Bengaluru's traffic management authorities. It processes 8,173 historical traffic incidents collected across Bengaluru's 21 major corridors and 54 police station jurisdictions to deliver real-time incident impact assessment, resource recommendations, and operational pattern intelligence.
The system answers three critical operational questions:
- "How bad is this incident?" - ML-powered impact prediction (R² = 0.9522)
- "What resources do we need?" - Automated resource planning with timeline
- "What has historically happened?" - Pattern analysis from 8,173+ incidents
Additionally, the platform includes forecasting capabilities for high-risk periods and potential conflicts, though the primary focus is real-time incident response.
Core Features:
- Real-time incident impact prediction with 95.22% accuracy
- Historical pattern analysis from 8,173+ incidents
- Resource allocation and deployment planning
- Corridor-level intelligence and stress monitoring
- Police station workload analysis
Advanced Features:
- Event forecasting for planned activities (festivals, construction, VIP movements)
- High-risk period identification (7-day × 24-hour risk windows)
- Route diversion planning for traffic management
- Weather integration for risk assessment
- Real-time incident simulation for training
- Prediction feedback system for model drift detection
- Transit chain detection (BMTC/KSRTC bus breakdowns)
Technical Highlights:
- 93 engineered features including DBSCAN geo-clustering
- 10 specialized backend engines working in parallel
- 32+ REST API endpoints with OpenAPI documentation
- Docker-based deployment with health monitoring
- Sub-20ms response times for predictions
| Metric | Value |
|---|---|
| Historical incidents | 8,173 |
| Planned events database | 55 events |
| Corridors monitored | 21 |
| Police stations | 54 |
| Cause categories | 14 |
| Vehicle types | 10 |
| Risk window slots | 168 (7 days × 24 hours) |
| Incident Model R² | 0.9522 |
| Model Features | 93 (engineered) |
| API Endpoints | 32+ |
The entire system is designed to answer exactly three operational questions:
Answered by: Impact Engine (CatBoost Regressor)
Given an incident's characteristics (cause, corridor, time, vehicle type, closure status), the system predicts an Impact Score (0–100) and classifies it into a Risk Class (Low / Medium / High / Critical).
Answered by: Resource Planning Engine
Based on the risk class, cause type, and corridor tier, the system generates a resource deployment timeline with specific phases (0–15 min, 15–30 min, 30–60 min) and an estimated resolution time range.
Answered by: Operational Intelligence Layer
The system searches for similar historical incidents and provides confidence levels, critical rates, corridor DNA profiles, stress indices, and operational risk windows — all derived from real Bengaluru traffic data.
┌─────────────────────────────────────────────────────────────────────────┐
│ ASTRAM AI Platform │
│ Proactive Traffic Management System │
└─────────────────────────────────────────────────────────────────────────┘
│
┌───────────────────────────┼───────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Data Layer │ │ ML Model Layer │ │ Real-Time Layer│
└─────────────┘ └──────────────────┘ └─────────────────┘
│ │ │
├─ 8,173 Incidents ├─ CatBoost Model ├─ Weather API
├─ 21 Corridors │ (93 features) ├─ Incident Sim
├─ Enhanced Features │ (R²=0.9522) └─ System Pulse
└─ 93 Total Columns └─ Precomputed Lookups
│ │ │
└───────────────┬───────────┴───────────────┬───────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌──────────────────────┐
│Backend Engines (10) │ │ API Layer (32+ EP) │
└─────────────────────┘ └──────────────────────┘
│ │
┌───────────────────────┼───────────────────────────┼────────────┐
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
┌────────┐ ┌────────┐ ┌─────────┐ ┌────────┐ ┌──────────┐ ┌─────────┐
│ Model │ │Forecast│ │ Weather │ │Resource│ │Diversion │ │Feedback │
│ Engine │ │ Engine │ │ Engine │ │ Engine │ │ Engine │ │ Engine │
└────────┘ └────────┘ └─────────┘ └────────┘ └──────────┘ └─────────┘
│ │ │ │ │ │
└───────────┴────────────┴────────────┴──────────────┴────────────┘
│
▼
┌──────────────────────────┐
│ Frontend Dashboard │
│ ┌────────────────────┐ │
│ │ Page 1: Command │ │
│ │ Center │ │
│ ├────────────────────┤ │
│ │ Page 2: Incident │ │
│ │ Copilot │ │
│ ├────────────────────┤ │
│ │ Page 3: Corridor │ │
│ │ Intel │ │
│ └────────────────────┘ │
└──────────────────────────┘
│
▼
┌────────────────────┐
│ Traffic Officers │
│ Decision Making │
└────────────────────┘
User Input (6 fields)
│
├─ Cause: tree_fall
├─ Corridor: Bellary Road 1
├─ Closure: true
├─ Vehicle: Others
├─ Hour: 5
└─ Weekday: Thursday
│
▼
┌───────────────────────────┐
│ Feature Engineering (93) │
│ ─────────────────────── │
│ • hour_sin/cos │
│ • weekday_sin/cos │
│ • corridor_tier = 1 │
│ • station_event_count │
│ • is_night = true │
│ • requires_closure = 1 │
│ • geo_cluster (DBSCAN) │
│ • interaction features │
│ • ... 85 more features │
└───────────────────────────┘
│
▼
┌───────────────────────────┐
│ CatBoost Model (240KB) │
│ ─────────────────── │
│ 1000 iterations │
│ depth=6, lr=0.05 │
│ L2_reg=3 │
└───────────────────────────┘
│
▼
Raw Score: 85.3
│
▼
┌───────────────────────────┐
│ Score Blending │
│ ───────────────────── │
│ Find 14 similar cases │
│ Historical avg: 90.6 │
│ Blend: 0.4×85.3 + 0.6×90.6│
│ = 88.5 │
└───────────────────────────┘
│
▼
Impact Score: 88
Risk Class: Critical
│
├─────────────────────────────┬─────────────────┬──────────────┐
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────────┐ ┌──────────────────┐ ┌──────────┐ ┌──────────┐
│ Resource Engine │ │Historical Engine │ │ Corridor │ │ Weather │
│ ─────────────── │ │ ──────────────── │ │ DNA │ │ Risk │
│ • 6 officers │ │ • 14 similar │ │ ──────── │ │ ──────── │
│ • 12 barricades │ │ • 100% critical │ │ Tier 1 │ │ No rain │
│ • BBMP crew │ │ • High confidence│ │ 610 inc. │ │ Low risk │
│ • Timeline │ │ • Score dist. │ │ Stress79 │ │ │
│ • Placement │ │ │ │ │ │ │
└─────────────────┘ └──────────────────┘ └──────────┘ └──────────┘
│ │ │ │
└─────────────────────────────┴─────────────────┴──────────────┘
│
▼
┌──────────────────────┐
│ JSON Response │
│ { │
│ impact: 88, │
│ risk: "Critical", │
│ resources: {...}, │
│ historical: {...},│
│ corridor: {...} │
│ } │
└──────────────────────┘
│
▼
┌──────────────────────┐
│ Frontend Rendering │
│ • Impact ring │
│ • Resource timeline │
│ • Barricade map │
│ • Historical charts │
└──────────────────────┘
Planned Event Database
│
├─ Diwali Festival
├─ Mysore Road
├─ 50,000 expected crowd
├─ Nov 1, 6 PM
└─ Closure required
│
▼
┌───────────────────────────┐
│ Feature Engineering (17) │
│ ─────────────────────── │
│ • event_type = festival │
│ • crowd_log = 10.82 │
│ • closure_required = 1 │
│ • corridor_tier = 1 │
│ • hour_sin/cos │
│ • ... 12 more features │
└───────────────────────────┘
│
▼
┌───────────────────────────┐
│ Impact Model (141KB) │
│ ───────────────────── │
│ Trained on 8,057 samples │
│ (Method 6 - Best) │
│ R² = 0.9522 │
└───────────────────────────┘
│
▼
Predicted Impact: 87.5
Risk Class: Critical
Confidence: High
│
▼
┌───────────────────────────┐
│ Proactive Timeline │
│ ─────────────────────── │
│ T-48h: Public advisory │
│ T-24h: Pre-position │
│ T-2h: Deploy officers │
│ T-1h: Activate diversion │
│ T-0: Full closure │
└───────────────────────────┘
│
▼
Resource Deployment
24-72h BEFORE Event
- Startup: Load
model_ready.parquet(8,173 × 93 columns) andcatboost_best.cbm(240 KB). Load all precomputed JSON lookup tables (~500 KB total). - Incident Input: User provides cause, corridor, hour, weekday, vehicle type, closure status.
- Feature Pipeline: Transforms input into a 93-dimensional feature vector with DBSCAN clusters, interaction features, and scaled attributes.
- Impact Engine: CatBoost model (1000 iterations, depth=6) predicts a raw impact score.
- Score Blending: Raw model score is blended with historical average from similar incidents using a weighted formula.
- Risk Classification: Blended score is classified into Low/Medium/High/Critical.
- Parallel Engines: Resource timeline, historical evidence, corridor DNA, confidence, transit chain flag, weather, and forecast data are computed simultaneously.
- Response Assembly: All 10 engine outputs are combined into a single comprehensive JSON response served to the frontend.
| Component | Technology | Purpose |
|---|---|---|
| Web Framework | FastAPI 0.115+ | Async REST API with automatic OpenAPI docs |
| ASGI Server | Uvicorn | High-performance async server |
| ML Model | CatBoost 1.2.2 | Gradient boosting for impact score prediction (R²=0.9522) |
| Data Processing | Pandas 2.1.4 + NumPy | Parquet I/O, feature engineering, aggregation |
| Clustering | scikit-learn DBSCAN | Spatial geo-clustering for location patterns |
| Data Format | Apache Parquet via PyArrow 14.0.2 | Columnar storage for fast reads |
| Validation | Pydantic | Request/response schema validation |
| Deployment | Docker + Docker Compose | Containerized deployment with health checks |
| Language | Python 3.9+ | Core language |
| Component | Technology | Purpose |
|---|---|---|
| Structure | HTML5 semantic markup | 3-page SPA with client-side routing |
| Styling | Vanilla CSS with Custom Properties | Premium dark theme, glassmorphism, animations |
| Logic | Vanilla JavaScript (ES6+) | All page logic, API integration, rendering |
| Charts | Chart.js | Bubble, bar, scatter, and grouped charts |
| Maps | Leaflet + CARTO dark tiles | Interactive incident map of Bengaluru |
| Typography | Inter + JetBrains Mono | UI text + monospaced data values |
| Component | Technology | Purpose |
|---|---|---|
| Feature Engineering | scikit-learn (DBSCAN, LabelEncoder, PCA) | Geo clustering, encoding |
| Text Embeddings | sentence-transformers (MiniLM-L12-v2) | Description embeddings (32-dim PCA) |
| Model Training | CatBoost with Optuna hyperparameter tuning | Impact score regression |
The raw data is 8,170 anonymized traffic incident records from Bengaluru's ASTRAM traffic management system, covering approximately 5 months of operations. Each record contains:
- Incident metadata: cause, type (planned/unplanned), priority, status
- Location: latitude, longitude, corridor, police station, junction, zone
- Temporal: start time, end time, created/modified/closed/resolved timestamps
- Vehicle: type (BMTC Bus, Heavy Vehicle, Private Car, etc.)
- Operational: road closure required, authenticated status
- Text: incident description (Kannada/English)
The feature pipeline transforms raw CSV into a 93-column parquet file containing:
| Category | Columns | Details |
|---|---|---|
| Identifiers | 1 | id |
| Raw Categoricals | 5 | event_cause, event_type, corridor, veh_type, police_station |
| Encoded Categoricals | 6 | Label-encoded versions for ML |
| Spatial | 6 | latitude, longitude, lat_bin, lon_bin, geo_cluster (DBSCAN), corridor_tier |
| Temporal | 13 | hour, weekday, month, cyclical encodings (sin/cos), is_weekend, is_night, is_peak_hour |
| Boolean | 2 | requires_road_closure, authenticated |
| Frequency | 7 | station_event_count, junction_event_count, corridor_event_count, events_last_7days, etc. |
| Interaction Features | 4 | cause_corridor_encoded, peak_weekend_interaction, etc. |
| Historical Patterns | 2 | cause_base_severity, cause_historical_closure_rate |
| Scaled Features | 7 | Normalized versions of frequency features |
| Targets | 2 | impact_score (continuous 0–100), impact_class (4-class) |
| Raw Data | 38+ | Original columns kept for analysis |
The impact score used to train the model is computed from three outcome-based components:
Impact Score = Closure (0 or 50) + Corridor Tier (0-30) + Duration (0-20)
| Component | Weight | Logic |
|---|---|---|
| Road Closure | 50 pts | Binary: did the road close? |
| Corridor Tier | 0–30 pts | Tier 1 = 30, Tier 2 = 22, Tier 3 = 14, Non-corridor = 0 |
| Duration | 0–20 pts | Post-event resolution time: >6h = 20, >2h = 14, >1h = 7 |
Design Decision:
event_causeandpriorityare intentionally excluded from the label formula. This forces the model to discover why certain causes lead to high scores from the features, rather than memorizing a deterministic rule.
File: model_engine.py → build_feature_vector()
Transforms 6 user inputs into a 93-dimensional feature vector matching the exact training schema:
| Step | Input | Output |
|---|---|---|
| Step 1 | Corridor name | corridor_tier (1/2/3/0), is_corridor |
| Step 2 | Hour | hour_sin, hour_cos via sin(2πh/24), cos(2πh/24) |
| Step 3 | Hour | rush_hour_flag (7–10, 16–20), night_flag (22–5) |
| Step 4 | (internal) | station_event_count from historical frequency lookup |
| Step 5 | Corridor | corridor_event_count from historical frequency lookup |
| Step 6 | (internal) | geo_cluster (DBSCAN), lat_bin, lon_bin defaults |
| Step 7 | Cause + Corridor | Interaction features like cause_corridor_encoded |
| Step 8 | Time features | Peak hour interactions and scaled features |
Tier 1 (Critical Arterials): Mysore Road, Bellary Road 1, Tumkur Road, Bellary Road 2, Hosur Road
Tier 2 (Major Corridors): ORR North 1, Old Madras Road, Magadi Road, ORR East 1, ORR North 2,
Bannerghatta Road, ORR East 2, West of Chord Road
Tier 3 (Secondary): ORR West 1, ORR South 1, Kanakapura Road, Sarjapur Road, Hennur Road,
Airport New South Road, ORR West 2, ORR South 2
Tier 0: Non-corridor (local roads)
File: model_engine.py → predict_impact()
- Model: CatBoost Regressor (
catboost_best.cbm, 240 KB frozen model) - Input: 93-feature vector from the Feature Pipeline
- Output: Raw impact score (0–100 range)
- No retraining: Model is frozen. Same weights at every prediction.
The raw model output is then blended with historical context in app.py:
# If many similar historical incidents exist, blend with their average
if similar_count > 10:
blended = model_score × 0.4 + historical_average × 0.6
elif similar_count > 5:
blended = model_score × 0.5 + historical_average × 0.5
else:
blended = model_score
# Rule-based adjustments
if closure: blended += 15
if tier == 1: blended += 10
if tier == 2: blended += 5File: model_engine.py → score_to_class()
Converts the blended impact score into a risk classification:
| Score Range | Risk Class | Color |
|---|---|---|
| 0 – 25 | Low | 🟢 Green |
| 25 – 50 | Medium | 🟡 Amber |
| 50 – 75 | High | 🟠 Orange |
| 75 – 100 | Critical | 🔴 Red |
File: historical_engine.py → compute_confidence()
Measures prediction trust by counting how many historical incidents match the current scenario's key characteristics.
Matching criteria: cause + corridor_tier + closure
| Matching Count | Confidence Level |
|---|---|
| ≥ 30 | High — Strong historical basis |
| 10 – 29 | Medium — Moderate evidence |
| < 10 | Low — Limited historical data |
File: historical_engine.py → find_similar_incidents()
Searches the historical index for incidents with matching characteristics.
Input: cause, corridor_tier, closure Output:
| Field | Description |
|---|---|
count |
Number of similar incidents found |
critical_rate |
Percentage that were Critical |
average_score |
Mean impact score |
score_distribution |
Count per risk class {Low, Medium, High, Critical} |
top_examples |
Up to 5 sample incidents with details |
Fallback logic:
- Try:
cause + corridor_tier + closure(most specific) - If < 5 results: relax to
cause + corridor_tier - If < 3 results: relax to
causeonly
File: resource_engine.py → recommend()
No ML. Pure rule-based engine.
Input: cause, impact_class, corridor_tier, vehicle_type
Output — Timeline format:
Tree Fall:
0–15 min: Police Units, Area Barricading
15–30 min: BBMP Tree Crew
30–60 min: Barricades, Traffic Diversion
Estimated Resolution: Median 1.2h, Range 0.4h–4.0h
Resource scaling: Resources are multiplied based on risk class and corridor tier:
| Factor | Multiplier |
|---|---|
| Critical risk | 2.0× |
| High risk | 1.5× |
| Tier 1 corridor | 1.5× |
| Tier 2 corridor | 1.25× |
Resolution estimates are always displayed as a range, never a single number:
| Cause | Median | Range |
|---|---|---|
| Vehicle Breakdown | 0.5h | 0.5h – 1.0h |
| Tree Fall | 1.2h | 0.4h – 4.0h |
| Accident | 2.0h | 1.0h – 3.0h |
| Water Logging | 3.0h | 2.0h – 8.0h |
| Construction | 12.0h | 4.0h – 48.0h |
| Protest | 5.0h | 2.0h – 12.0h |
File: corridor_engine.py → get_corridor_dna()
Precomputed profile for each of the 21 corridors:
| Field | Example (Bellary Road 1) |
|---|---|
| Tier | 1 |
| Total Incidents | 610 |
| Dominant Cause | Vehicle Breakdown |
| Peak Hour | 4 AM |
| Closure Rate | 5.4% |
| Critical Rate | 5.4% |
| Station | Sadashivanagar |
| Stress Index | 79.1 |
File: corridor_engine.py → get_stress_index()
Signature metric combining three normalized dimensions:
Stress Index = 0.4 × normalized_frequency
+ 0.4 × normalized_avg_impact
+ 0.2 × normalized_closure_rate
Scale: 0–100
Each dimension is normalized to 0–1 relative to the highest corridor, then combined with the above weights and scaled to 0–100.
Top corridors by stress:
| Corridor | Stress Index |
|---|---|
| Mysore Road | ~98.7 |
| Bellary Road 1 | ~79.1 |
| Tumkur Road | ~66.3 |
Used in: Page 1 (stress bar) and Page 3 (leaderboard chart).
File: corridor_engine.py → get_risk_window()
Precomputed grid of 168 slots (7 weekdays × 24 hours), each containing:
| Field | Description |
|---|---|
event_count |
Historical incidents in that slot |
critical_rate |
% that were Critical |
avg_impact |
Mean impact score |
top_corridors |
Top 3 corridors by incident count |
top_causes |
Top 3 causes by incident count |
No forecasting language — this is purely historical pattern data.
Example: Thursday 5 AM → 467 incidents, Top Corridor: Bellary Road 1, Top Cause: Vehicle Breakdown, Critical Rate: 6.6%
File: corridor_engine.py → get_shift_briefing()
Aggregates risk window data into three operational shifts:
| Shift | Hours |
|---|---|
| Morning | 06:00 – 14:00 |
| Evening | 14:00 – 22:00 |
| Night | 22:00 – 06:00 |
Output: stress_level (High/Elevated/Normal), total_events, critical_rate, top_corridors, top_causes.
File: historical_engine.py → check_transit_chain()
A unique detection feature that triggers when:
vehicle_breakdown AND (BMTC OR KSRTC bus) AND Tier 1 corridor
Output when triggered:
- Bus type (BMTC/KSRTC)
- Historical case count (530 cases in data)
- Estimated cumulative passenger disruption
- Advisory: depot coordination recommended
File: model_engine.py → compute_operational_baseline()
The most important storytelling component. Splits the prediction explanation into two parts:
A formula any human could compute:
Road Closure +35
Tier 1 Corridor +30
Cause Severity +18 (tree_fall)
Night Hours -5
─────────────────────
Baseline 78
NOT fake SHAP values. Shows real historical data:
14 Similar Historical Incidents
Average Historical Impact: 90.6
AI Predicted: 88
"The AI learned that incidents with these characteristics
historically evolve into high-severity events."
| Method | Path | Description |
|---|---|---|
POST |
/api/predict |
Full incident analysis — all engines combined |
POST |
/api/similar-incidents |
Historical similarity search |
GET |
/api/analytics/prediction-breakdown |
Detailed prediction breakdown |
GET |
/api/analytics/risk-heatmap |
Risk heatmap data |
| Method | Path | Description |
|---|---|---|
GET |
/api/city-pulse |
Command Center data: KPIs + map + feed + stress bar |
GET |
/api/risk-window |
168-slot operational risk window grid |
GET |
/api/shift-briefing |
Current shift briefing |
GET |
/api/corridor-intelligence |
Page 3 chart datasets |
GET |
/api/station-intelligence |
All 54 stations with stats |
GET |
/api/corridor/{name} |
Single corridor DNA profile |
GET |
/api/metadata |
Available options for frontend selectors |
| Method | Path | Description |
|---|---|---|
GET |
/api/forecast/upcoming |
Upcoming planned events |
GET |
/api/forecast/high-risk-periods |
High-risk time periods |
GET |
/api/forecast/briefing |
Forecast briefing |
GET |
/api/forecast/event/{event_id} |
Specific event forecast |
GET |
/api/forecast/conflicts |
Event conflict detection |
| Method | Path | Description |
|---|---|---|
GET |
/api/realtime/incidents/active |
Active incidents |
POST |
/api/realtime/incidents/generate |
Generate simulated incident |
GET |
/api/realtime/system-pulse |
System health metrics |
GET |
/api/realtime/traffic/{corridor} |
Corridor traffic data |
GET |
/api/realtime/weather/{corridor} |
Weather conditions |
| Method | Path | Description |
|---|---|---|
POST |
/api/diversion/plan |
Route diversion planning |
| Method | Path | Description |
|---|---|---|
POST |
/api/feedback/log |
Log prediction feedback |
POST |
/api/feedback/update/{prediction_id} |
Update prediction outcome |
GET |
/api/feedback/drift |
Model drift detection |
GET |
/api/feedback/report |
Feedback analysis report |
| Method | Path | Description |
|---|---|---|
GET |
/api/health |
Health check endpoint |
Interactive API Documentation: http://localhost:8000/docs
POST /api/predict — Water logging incident on Mysore Road at rush hour:
{
"impact_score": 87.5,
"risk_class": "Critical",
"confidence": {
"level": "High",
"percentage": 89,
"matching_count": 247
},
"resource_plan": {
"phase_1": {
"timeframe": "0-15 min",
"personnel": 8,
"vehicles": 2,
"barricades": 15
},
"phase_2": {
"timeframe": "15-30 min",
"personnel": 6,
"vehicles": 3
},
"estimated_resolution": "90-120 minutes"
},
"similar_incidents": 3,
"corridor_stress_index": 67.8
}Request:
{
"cause": "tree_fall",
"corridor": "Bellary Road 1",
"closure": true,
"vehicle_type": "Others",
"hour": 5,
"weekday": 3
}Response (key fields):
{
"impact_score": 88.0,
"risk_class": "Critical",
"confidence": { "level": "Medium", "matching_count": 14 },
"resource_plan": {
"timeline": [...],
"resources": { "police_units": 6, "barricades": 12, "diversion_required": true },
"resolution": { "median": "1.2h", "range": "0.4h–4.0h" }
},
"historical_evidence": {
"count": 14,
"critical_rate": 100.0,
"average_score": 90.6,
"score_distribution": { "Low": 0, "Medium": 0, "High": 0, "Critical": 14 }
},
"formula_vs_ai": {
"operational_baseline": { "baseline_score": 78, "components": [...] },
"historical_pattern": { "similar_count": 14, "average_historical_impact": 90.6, "narrative": "..." }
},
"corridor_dna": { "corridor": "Bellary Road 1", "total_incidents": 610, "stress_index": 79.1, ... },
"transit_chain": { "triggered": false }
}City-wide operational overview with 6 sections:
| Section | Component | Data Source |
|---|---|---|
| KPI Strip | 4 stat cards (total incidents, critical, closures, avg impact) | /api/city-pulse |
| Corridor Stress Bar | Animated horizontal bar chart, sorted by stress index | /api/city-pulse → stress_bar |
| Operational Risk Window | 168-cell heatmap (weekday × hour), current slot highlighted | /api/risk-window |
| Shift Briefing | Current shift panel (Morning/Evening/Night) with stress level | /api/shift-briefing |
| Historical Feed | Scrollable incident list, clickable → navigates to Page 2 | /api/city-pulse → feed |
| Incident Map | Leaflet map with CARTO dark tiles, color-coded by risk class | /api/city-pulse → map_events |
The main demo page — interactive incident analysis with 8 panels:
| Panel | Description |
|---|---|
| A: Impact Assessment | Animated score ring (0–100), risk class badge, confidence indicator |
| B: Resolution Estimate | Median + range display (never single number) |
| C: Resource Timeline | Visual phase-based timeline (0–15 min → 15–30 min → 30–60 min) |
| D: Historical Evidence | Similar count, critical rate, avg score, score distribution bar |
| E: Formula vs AI | Split panel: operational baseline formula vs AI narrative |
| F: Corridor DNA | 6-stat mini-profile of selected corridor (conditional — hidden for Non-corridor) |
| G: Transit Chain Flag | Red alert banner (conditional — only for BMTC/KSRTC + Tier 1 + breakdown) |
| H: What-If Toggle | Toggle closure ON/OFF, shows score delta and class change |
Answers 5 strategic questions:
| Question | Visualization | Chart Type |
|---|---|---|
| Where should resources be pre-positioned? | Corridor × Hour incident density | Bubble chart |
| Which causes create closures? | Closure rate by cause type | Horizontal bar |
| Which corridors create the most burden? | Stress Index leaderboard | Horizontal bar |
| Which stations are overloaded? | Event count vs avg impact scatter | Scatter (Halasuru Gate highlighted) |
| Fleet demand intelligence | Tow trucks/day + officers/day per corridor | Grouped bar |
astram/
├── backend/
│ ├── __init__.py
│ ├── app.py # FastAPI application (32+ endpoints)
│ ├── model_engine.py # Feature Pipeline + Impact Engine + Risk Class + Formula vs AI
│ ├── historical_engine.py # Confidence + Historical Evidence + Transit Chain
│ ├── resource_engine.py # Resource Timeline + Resolution Estimates
│ ├── corridor_engine.py # Corridor DNA + Stress Index + Risk Window + Shift Briefing + Stations
│ ├── forecast_engine.py # Event forecasting capabilities
│ ├── weather_engine.py # Weather integration
│ ├── diversion_engine.py # Route planning
│ ├── feedback_engine.py # Prediction feedback
│ ├── realtime_simulator.py # Real-time simulation
│ ├── precompute_lookups.py # One-time script to generate lookup tables
│ └── lookup_tables/
│ ├── corridor_dna.json # 21 corridor profiles
│ ├── stress_index.json # Corridor stress scores
│ ├── risk_window.json # 168 weekday×hour slots
│ ├── station_intelligence.json # 54 station profiles
│ ├── resource_mapping.json # 14 cause type → timeline + resolution
│ └── historical_index.parquet # 8,170 records for similarity search
├── data/
│ ├── model_ready.parquet # 8,173 × 93 training/inference dataset
│ └── raw_events.csv # Original anonymized CSV
├── models/
│ └── catboost_best.cbm # Frozen CatBoost model (240 KB)
├── scripts/
│ └── preprocess_data.py # Data preprocessing pipeline
├── frontend/
│ ├── index.html # 3-page SPA structure
│ ├── css/
│ │ └── styles.css # Premium dark theme design system
│ ├── js/
│ │ └── app.js # All page logic, charts, renderers
│ └── test.html # Testing page
└── requirements.txt # Python dependencies
- Python 3.10 or higher
- pip package manager
cd astram
pip install -r requirements.txtRequired packages: fastapi, uvicorn[standard], pandas, numpy, catboost, pyarrow, pydantic
python -X utf8 backend/precompute_lookups.pyThis reads data/model_ready.parquet and generates 6 JSON lookup files + 1 parquet index in backend/lookup_tables/.
# Option 1: Direct
cd astram
python -m uvicorn backend.app:app --host 0.0.0.0 --port 8000
# Option 2: Batch file (Windows)
run.batOpen http://localhost:8000 in your browser.
Want to replicate the R² = 0.9522 result? Follow these steps:
The raw data is already included:
# Located at:
Astram event data_anonymized - Astram event data_anonymizedb40ac87.csv
# 8,170 records with columns:
# - start_datetime, event_cause, corridor, requires_road_closure
# - veh_type, latitude, longitude, description (Kannada + English)We documented 6 experimental trials. Run them all to see the progression:
cd project/src
# Trials 1-3 (Baseline experiments)
python trial_better_r2.py
# Methods 4-6 (Advanced experiments)
python trial_more_methods.pyExpected Results:
- Trial 1: R² = 0.9002 (Failed)
- Trial 2: R² = 0.9445 (Success)
- Trial 3: R² = 0.9279 (Failed)
- Method 4: R² = 0.9439 (Good)
- Method 5: R² = 0.9521 (Excellent)
- Method 6: R² = 0.9522 ✅ (Winner)
After running, check:
# Models saved to:
astram/models/catboost_final_best.cbm # R² = 0.9522 (Production)
astram/models/catboost_best_trial.cbm # R² = 0.9445 (Backup)
# Preprocessed data:
astram/data/enhanced_features_data.csv # 8,057 × 76 columns
# Trial documentation:
project/src/ALL_TRIALS_SUMMARY.txt # All results
project/ABLATION_STUDY.md # Detailed analysisMethod 6 (Winner) uses:
- 93 features (comprehensive feature engineering)
- DBSCAN geo-clustering: Spatial pattern detection
- 3-way interactions: closure × corridor_tier × temporal_score
- Interaction features: cause_corridor, peak_weekend combinations
- Kannada detection: Unicode
\u0C80-\u0CFFpattern matching - Hyperparameters: depth=6, lr=0.05, l2=3, iterations=1000
Key Innovation: Heavy interaction features and spatial clustering capture complex relationships:
# Example features
closure_tier_temporal = requires_closure × corridor_tier × temporal_score
closure_peak_tier = requires_closure × is_peak × corridor_tier
kannada_tier = has_kannada × corridor_tier
geo_cluster = DBSCAN_clustering(latitude, longitude)
cause_corridor_encoded = encode(event_cause + corridor)
peak_weekend_interaction = is_peak_hour × is_weekendRun this to verify:
from catboost import CatBoostRegressor
import pandas as pd
from sklearn.metrics import r2_score
# Load model
model = CatBoostRegressor()
model.load_model('astram/models/catboost_final_best.cbm')
# Load test data (20% split, random_state=42)
# Expected: R² = 0.9522, MAE = 3.241All experiments documented in:
- project/ABLATION_STUDY.md - What worked, what didn't
- project/src/ALL_TRIALS_SUMMARY.txt - Detailed results
Training Time: ~10 minutes per trial (6 trials = ~1 hour total)
The canonical demo follows this exact script:
- When: Thursday, 5:30 AM
- What: Tree Fall
- Where: Bellary Road 1
- Road Closure: Yes
1. Impact Score: 88 → Critical
2. 14 Similar Historical Incidents
3. Historical Average Impact: 90.6
4. Operational Baseline: 78 (Road Closure +35, Tier 1 +30, Cause +18, Night -5)
5. Resource Timeline: Police → BBMP Crew → Barricades/Diversion
6. Resolution: Median 1.2h, Range 0.4h–4.0h
7. Corridor DNA: 610 incidents, Stress 79.1
What-If Toggle (Closure OFF):
8. Score drops to 65 → High (Critical → High)
Navigate to Page 1:
9. Risk Window shows Thursday 5AM slot highlighted
10. Bellary Road 1 appears in stress bar
Navigate to Page 3:
11. Corridor Intelligence shows full analytical view
- Change to: Vehicle Breakdown + BMTC Bus + Bellary Road 1
- Transit Chain Flag triggers: 530 historical cases, depot coordination advised
| Parameter | Value |
|---|---|
| Model type | CatBoostRegressor |
| File | models/catboost_best.cbm (240 KB) |
| Status | Production Ready — Method 6 |
| Features | 93 numeric features (engineered) |
| Target | impact_score (continuous, 0–100) |
| R² Score | 0.9522 |
| MAE | 3.241 |
| Train-Test Gap | 0.39% (excellent) |
The model learned that the most important features are:
requires_road_closure— Binary closure flagcorridor_tier— Corridor importance levelcorridor_event_count— Historical incident frequencyhour_sin/hour_cos— Time of day (cyclical)event_cause_encoded— Type of incidentstation_event_count— Station-level historical load
The raw CatBoost model predictions cluster in the 0–50 range due to the training distribution (mean score ~22). To produce more operationally meaningful scores:
- We blend the model output with the historical average from similar incidents
- We add rule-based adjustments for closure (+15), tier (+10/+5), and cause severity
- This produces scores that span the full 0–100 range and align with operational intuition
All lookup tables are generated once by precompute_lookups.py and loaded into memory at server startup:
| Table | Records | Size | Purpose |
|---|---|---|---|
corridor_dna.json |
21 | ~4 KB | Per-corridor profiles |
stress_index.json |
21 | ~2 KB | Stress scores |
risk_window.json |
168 | ~45 KB | Weekday × hour grid |
station_intelligence.json |
54 | ~12 KB | Per-station profiles |
resource_mapping.json |
14 | ~5 KB | Cause → timeline mapping |
historical_index.parquet |
8,170 | ~120 KB | Similarity search index |
- Async support for concurrent requests
- Automatic request validation with Pydantic
- Built-in OpenAPI/Swagger documentation at
/docs - Better performance for I/O-bound workloads
The V1.0 architecture explicitly forbids "fake SHAP" or "invented deltas". Instead, we use:
- Operational Baseline: A deterministic formula any human can verify
- Historical Pattern Intelligence: Real statistics from similar incidents
- This approach is more honest and operationally useful than feature attribution values
- Zero runtime computation for Corridor DNA, Stress Index, Risk Window, Station Intelligence
- Sub-millisecond response times for these endpoints
- Data only changes when the parquet is updated (not during runtime)
- The raw CatBoost model is accurate (R²=0.93) but its predictions cluster in the lower range
- Blending with historical averages anchors predictions to observed real-world outcomes
- Rule-based adjustments for closure/tier ensure operational factors have guaranteed impact
- The architecture explicitly states: "No forecasting language"
- All data shown is historical — "this is what happened", not "this is what will happen"
- This avoids liability issues and overpromising prediction capabilities
Internal use — Bengaluru Traffic Management Authority.
Built with CatBoost, FastAPI, and historical intelligence from 8,170 real Bengaluru traffic incidents.