Download main.py from HarryDataScience/mumbai-crowd-predictor: direct link, hf CLI and curl.
- Browser
- Download file 8.09 kB
-
https://huggingface.co/spaces/HarryDataScience/mumbai-crowd-predictor/resolve/main/main.py
- Command line
-
hf download hf://spaces/HarryDataScience/mumbai-crowd-predictor/main.py
-
curl -L -o main.py https://huggingface.co/spaces/HarryDataScience/mumbai-crowd-predictor/resolve/main/main.py
8.09 kB
| """ | |
| Mumbai Local Train Crowd Density Predictor | |
| FastAPI Backend - Advanced Edition | |
| """ | |
| import os | |
| import sys | |
| import json | |
| from typing import Optional | |
| from pathlib import Path | |
| import pandas as pd | |
| import numpy as np | |
| from fastapi import FastAPI, HTTPException, Request | |
| from fastapi.responses import HTMLResponse, JSONResponse | |
| from fastapi.staticfiles import StaticFiles | |
| from fastapi.templating import Jinja2Templates | |
| from pydantic import BaseModel | |
| # Fix path | |
| sys.path.insert(0, str(Path(__file__).parent)) | |
| from src.model import ( | |
| train_model, load_model, predict_crowd, | |
| LINE_MAP, DIR_MAP, DAY_MAP, HOUR_WEIGHTS | |
| ) | |
| from src.risk_engine import ( | |
| get_risk_info, build_reasoning, get_best_hours, | |
| get_travel_tip, RISK_CONFIG, | |
| WESTERN_STATIONS_ORDER, CENTRAL_STATIONS_ORDER, HARBOUR_STATIONS_ORDER | |
| ) | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| # App Setup | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| app = FastAPI( | |
| title="Mumbai Train Crowd Predictor", | |
| description="AI-powered crowd density prediction for Mumbai Local Trains", | |
| version="2.0.0" | |
| ) | |
| BASE_DIR = Path(__file__).parent | |
| DATA_PATH = BASE_DIR / "data" / "raw" / "mumbai_local_crowd_data.csv" | |
| app.mount("/static", StaticFiles(directory=str(BASE_DIR / "static")), name="static") | |
| templates = Jinja2Templates(directory=str(BASE_DIR / "templates")) | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| # Global State | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| MODEL = None | |
| LE_STATION = None | |
| LE_DEST = None | |
| DF = None | |
| MODEL_ACCURACY = None | |
| MODEL_REPORT = None | |
| STATIONS_BY_LINE = { | |
| "Western": WESTERN_STATIONS_ORDER, | |
| "Central": CENTRAL_STATIONS_ORDER, | |
| "Harbour": HARBOUR_STATIONS_ORDER | |
| } | |
| async def startup_event(): | |
| global MODEL, LE_STATION, LE_DEST, DF, MODEL_ACCURACY, MODEL_REPORT | |
| print("π Loading dataset...") | |
| DF = pd.read_csv(DATA_PATH) | |
| # Try loading cached model first | |
| MODEL, LE_STATION, LE_DEST = load_model() | |
| if MODEL is None: | |
| print("π§ Training model...") | |
| MODEL, MODEL_ACCURACY, MODEL_REPORT, LE_STATION, LE_DEST = train_model(DF) | |
| print(f"β Model trained! Accuracy: {MODEL_ACCURACY:.2%}") | |
| else: | |
| # Quick retrain to get accuracy | |
| _, MODEL_ACCURACY, MODEL_REPORT, _, _ = train_model(DF) | |
| print(f"β Model loaded! Accuracy: {MODEL_ACCURACY:.2%}") | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| # Schemas | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| class PredictRequest(BaseModel): | |
| line: str | |
| station: str | |
| destination: str | |
| direction: str | |
| hour: int | |
| day_of_week: str | |
| class HourlyRequest(BaseModel): | |
| line: str | |
| station: str | |
| destination: str | |
| direction: str | |
| day_of_week: str | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| # Routes | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| async def home(request: Request): | |
| return templates.TemplateResponse("index.html", {"request": request}) | |
| async def get_stations(line: str): | |
| if line not in STATIONS_BY_LINE: | |
| raise HTTPException(status_code=404, detail="Line not found") | |
| return {"stations": STATIONS_BY_LINE[line]} | |
| async def get_lines(): | |
| return {"lines": list(STATIONS_BY_LINE.keys())} | |
| async def get_days(): | |
| return {"days": list(DAY_MAP.keys())} | |
| async def get_hours(): | |
| return {"hours": list(HOUR_WEIGHTS.keys())} | |
| async def predict(req: PredictRequest): | |
| if MODEL is None: | |
| raise HTTPException(status_code=503, detail="Model not loaded yet") | |
| result = predict_crowd( | |
| MODEL, LE_STATION, LE_DEST, | |
| req.line, req.station, req.destination, | |
| req.direction, req.hour, req.day_of_week | |
| ) | |
| risk_info = get_risk_info(result["crowd_level"]) | |
| reasons = build_reasoning( | |
| req.line, req.station, req.destination, | |
| req.direction, req.hour, req.day_of_week, | |
| result["crowd_level"] | |
| ) | |
| tip = get_travel_tip(result["crowd_level"], req.direction, req.hour) | |
| return { | |
| "crowd_level": result["crowd_level"], | |
| "crowd_code": result["crowd_code"], | |
| "confidence": result["confidence"], | |
| "probabilities": result["probabilities"], | |
| "risk_score": risk_info["score"], | |
| "risk_color": risk_info["color"], | |
| "risk_bg": risk_info["bg"], | |
| "risk_emoji": risk_info["emoji"], | |
| "risk_badge": risk_info["badge"], | |
| "advice": risk_info["advice"], | |
| "travel_tip": tip, | |
| "reasons": reasons, | |
| "input": { | |
| "line": req.line, | |
| "station": req.station, | |
| "destination": req.destination, | |
| "direction": req.direction, | |
| "hour": req.hour, | |
| "day": req.day_of_week | |
| } | |
| } | |
| async def hourly_forecast(req: HourlyRequest): | |
| if MODEL is None: | |
| raise HTTPException(status_code=503, detail="Model not loaded yet") | |
| results = get_best_hours( | |
| MODEL, LE_STATION, LE_DEST, | |
| req.line, req.station, req.destination, | |
| req.direction, req.day_of_week, | |
| predict_crowd | |
| ) | |
| # Enrich with colors | |
| for r in results: | |
| info = RISK_CONFIG[r["crowd_level"]] | |
| r["color"] = info["color"] | |
| r["bg"] = info["bg"] | |
| r["emoji"] = info["emoji"] | |
| r["score"] = info["score"] | |
| best = sorted(results, key=lambda x: x["risk_score"])[:3] | |
| return { | |
| "hourly": results, | |
| "best_hours": best, | |
| "peak_hour": max(results, key=lambda x: x["risk_score"]) | |
| } | |
| async def get_stats(): | |
| if DF is None: | |
| raise HTTPException(status_code=503, detail="Data not loaded") | |
| total = len(DF) | |
| by_line = DF.groupby("line").size().to_dict() | |
| by_crowd = DF.groupby("crowd_level").size().to_dict() | |
| return { | |
| "total_records": total, | |
| "by_line": by_line, | |
| "by_crowd": by_crowd, | |
| "model_accuracy": round(MODEL_ACCURACY * 100, 2) if MODEL_ACCURACY else None, | |
| "lines": list(STATIONS_BY_LINE.keys()), | |
| "total_stations": sum(len(v) for v in STATIONS_BY_LINE.values()) | |
| } | |
| async def get_heatmap(line: str, direction: str = "Southbound", day: str = "Monday"): | |
| if MODEL is None or line not in STATIONS_BY_LINE: | |
| raise HTTPException(status_code=404) | |
| stations = STATIONS_BY_LINE[line] | |
| hours = list(range(5, 23)) | |
| heatmap = [] | |
| for station in stations[:6]: # Limit for performance | |
| row = {"station": station, "hours": {}} | |
| for h in hours: | |
| dest = stations[-1] if station != stations[-1] else stations[0] | |
| try: | |
| pred = predict_crowd(MODEL, LE_STATION, LE_DEST, line, station, dest, direction, h, day) | |
| row["hours"][h] = { | |
| "level": pred["crowd_level"], | |
| "score": RISK_CONFIG[pred["crowd_level"]]["score"], | |
| "color": RISK_CONFIG[pred["crowd_level"]]["color"] | |
| } | |
| except Exception: | |
| row["hours"][h] = {"level": "Low", "score": 15, "color": "#10b981"} | |
| heatmap.append(row) | |
| return {"heatmap": heatmap, "hours": hours, "stations": stations[:6]} | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) | |