Spaces:
Sleeping
Sleeping
File size: 3,957 Bytes
93e2220 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | """TransitPulse configuration β paths, thresholds, and feature flags."""
from __future__ import annotations
import os
from dataclasses import dataclass, field
from pathlib import Path
from typing import Literal
@dataclass(frozen=True)
class DataScale:
"""Defines a data-generation scale tier."""
name: str
num_routes: int
num_days: int
ping_interval_sec: int
approx_rows: str # human-readable label
# Pre-defined scale tiers for benchmarking
SCALES: dict[str, DataScale] = {
"small": DataScale("small", num_routes=20, num_days=30, ping_interval_sec=30, approx_rows="~1.1M"),
"medium": DataScale("medium", num_routes=80, num_days=30, ping_interval_sec=30, approx_rows="~25M"),
"full": DataScale("full", num_routes=200, num_days=30, ping_interval_sec=30, approx_rows="~150M"),
}
@dataclass
class TransitPulseConfig:
"""Master configuration for the TransitPulse pipeline."""
# ββ Paths ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
project_root: Path = field(default_factory=lambda: Path(__file__).resolve().parent)
@property
def data_dir(self) -> Path:
return self.project_root / "data"
@property
def pings_dir(self) -> Path:
return self.data_dir / "pings"
@property
def output_dir(self) -> Path:
return self.data_dir / "output"
# ββ Mode βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
mode: Literal["local", "cloud"] = "local"
# ββ GCP settings (cloud mode) ββββββββββββββββββββββββββββββββββββββ
gcp_project: str = field(default_factory=lambda: os.getenv("GCP_PROJECT", ""))
gcs_bucket: str = field(default_factory=lambda: os.getenv("GCS_BUCKET", "transitpulse-data"))
bq_dataset: str = field(default_factory=lambda: os.getenv("BQ_DATASET", "transitpulse"))
# ββ Gemini βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
gemini_api_key: str = field(default_factory=lambda: os.getenv("GEMINI_API_KEY", ""))
gemini_model: str = "gemini-2.5-flash"
# ββ Reliability scoring thresholds βββββββββββββββββββββββββββββββββ
bunching_threshold: float = 0.25 # headway < 25 % of scheduled β bunching
gap_threshold: float = 2.0 # headway > 200 % of scheduled β gap
weight_headway_cov: float = 0.40
weight_bunching: float = 0.30
weight_gap: float = 0.30
# ββ Server βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
host: str = "0.0.0.0"
port: int = 8000
# ββ Delhi bounding box (for synthetic lat/lon) βββββββββββββββββββββ
delhi_lat_min: float = 28.40
delhi_lat_max: float = 28.88
delhi_lon_min: float = 76.84
delhi_lon_max: float = 77.35
# ββ Synthetic generator tuning βββββββββββββββββββββββββββββββββββββ
stops_per_route_min: int = 15
stops_per_route_max: int = 45
buses_per_route_min: int = 8
buses_per_route_max: int = 25
peak_hours: tuple[int, ...] = (8, 9, 17, 18)
def ensure_dirs(self) -> None:
"""Create data directories if they don't exist."""
self.pings_dir.mkdir(parents=True, exist_ok=True)
self.output_dir.mkdir(parents=True, exist_ok=True)
# Singleton
CFG = TransitPulseConfig()
|