diff --git a/Dockerfile.backend b/Dockerfile.backend index 60a5521..ecec60b 100644 --- a/Dockerfile.backend +++ b/Dockerfile.backend @@ -6,18 +6,18 @@ WORKDIR /app COPY requirements.txt . COPY backend/requirements.txt backend/requirements.txt COPY earnings/earnings/requirements.txt earnings/earnings/requirements.txt -COPY drivepulse_stress_model/requirements.txt drivepulse_stress_model/requirements.txt +COPY driveintel_stress_model/requirements.txt driveintel_stress_model/requirements.txt # Install Python dependencies RUN pip install --no-cache-dir -r requirements.txt \ && pip install --no-cache-dir -r backend/requirements.txt \ && pip install --no-cache-dir -r earnings/earnings/requirements.txt \ - && pip install --no-cache-dir -r drivepulse_stress_model/requirements.txt + && pip install --no-cache-dir -r driveintel_stress_model/requirements.txt # Copy source code COPY backend/ backend/ COPY earnings/ earnings/ -COPY drivepulse_stress_model/ drivepulse_stress_model/ +COPY driveintel_stress_model/ driveintel_stress_model/ ENV PYTHONUNBUFFERED=1 diff --git a/Procfile b/Procfile index 0a0a6fc..8c8d0c2 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: uvicorn backend.main:app --host 0.0.0.0 --port ${PORT:-8000} +web: sh -c "cd backend && uvicorn main:app --host 0.0.0.0 --port ${PORT:-8000}" diff --git a/README.md b/README.md index 813edcc..a9e218b 100644 --- a/README.md +++ b/README.md @@ -1,168 +1,152 @@ -# Driver Pulse: Team ACE +# DriverIntel: Advanced Driver Safety & Behavior Analytics -- **Demo Video:** https://youtu.be/PL-XsfVfLA0?feature=shared -- **Live Application:** https://driver-pulse-gamma.vercel.app/ +
+

A state-of-the-art Web Application designed to improve driver safety, behavior, and efficiency in the ride-hailing industry through Artificial Intelligence.

+
-- **Judge Login Credentials:** - Username: judge@uber.com - Password: hackathon2026 +--- + +## ๐Ÿš€ Welcome to DriverIntel + +**DriverIntel** is a real-time driver safety & behavior analytics platform built exclusively for ride-hailing drivers. By leveraging on-device sensor data (accelerometer, gyroscope, and microphone) via Machine Learning (ML) models, it detects stressful driving situations, analyzes dangerous behavior patterns, and provides highly personalized safety coachingโ€”all wrapped in a stunning, premium dark-themed glassmorphic user interface. + +- **Live Application:** [DriverIntel Alpha Vercel](https://driveintel-alpha.vercel.app/) +- **Demo Video:** [YouTube Demo](https://youtu.be/PL-XsfVfLA0?feature=shared) + +**Demo Credentials:** +> **Username:** `demo@driveintel.com` +> **Password:** `demo2026` -- **Note to Judges:** The backend is hosted on Render and may take around 60 seconds to wake up on the first request. +--- + +## โœจ Core Features + +DriverIntel provides a complete suite of powerful tools designed for both individual drivers and ride-hailing platform analysts: -Real-time driver wellness & earnings intelligence platform for ride-hailing drivers. Uses on-device sensor data (accelerometer, gyroscope, microphone) with ML models to detect stressful driving situations and forecast earnings velocity. +* **๐Ÿ“Š Dynamic Dashboard** โ€” Get a comprehensive daily trip overview, your overall safety score, a stress event timeline, and high-level behavior insights at a glance. +* **๐Ÿ—บ๏ธ Interactive Trip Mapping** โ€” **Risk along route:** Leaflet maps with dynamically severity-colored route segments based on live event timestamps. Includes playback cursors and rich popups explaining the severity, model confidence, and safety logic. +* **๐Ÿ“ˆ Advanced Trends** โ€” Understand your driving behavior over time with weekly/monthly patterns, fatigue tracking, and stress event analytics. +* **๐ŸŽฏ Goal Tracking** โ€” Improve your daily safety by setting, committing to, and tracking behavioral modifications (e.g., reduce harsh braking, defensive driving). +* **๐Ÿ”ฎ Predict & Preview** โ€” Enter raw sensor telemetry for instant stress prediction. Also features a preview Map with high-risk geographical zones. +* **๐Ÿ“ Batch Processing** โ€” Built for analysts. Upload a CSV of multi-driver telemetry and run large-scale inference simultaneously for macro-level safety analysis. +* **๐Ÿค– AI Co-Pilot Assistant** โ€” An integrated, context-aware AI Safety Assistant (powered by Google Gemini) ready to provide interactive, personalized coaching and guidance on demand. +* **๐Ÿ” Explainable AI (XAI)** โ€” Understand *why* an event was flagged. DriverIntel provides per-event feature contributions (e.g., high lateral acceleration) and model confidence percentages. --- -## Features +## ๐ŸŽจ Premium UI/UX -- **Dashboard** โ€” Daily trips, earnings, stress score, timeline -- **Trip Detail** โ€” Map playback, sensor charts, event detection with explainability -- **Trends** โ€” Weekly/monthly earnings, stress, and velocity charts -- **Goals** โ€” Set and track daily earnings targets -- **Predict** โ€” Enter sensor/earnings values โ†’ instant ML prediction *(judge-facing)* -- **Batch Upload** โ€” Upload CSV โ†’ run inference on multiple trips at once *(judge-facing)* -- **Explainability** โ€” Per-event feature contributions, confidence badges -- **Feedback** โ€” Thumbs up/down on detected events -- **Auth** โ€” Login / register with demo accounts or new profile +DriverIntel utilizes a custom **High-Contrast Dark Glassmorphism** design language. +The entire application was built iteratively to reflect an ultra-modern aesthetic standard using Tailwind CSS: -To log **multiple trips at once**, go to the `Trips` tab and use **Import CSV**. +* **Vibrant Gradients over Deep Backgrounds** (`slate-950` / `slate-900`) +* **Translucent Frosted Glass** layered panels (`backdrop-blur-xl`, `bg-white/5` borders) +* **Sleek Micro-animations**, customized chart tooltips, and dynamic states +* Zero legacy light-mode elementsโ€”providing drivers with maximum visibility, luxury, and eye comfort even during late-night shifts. --- -## Architecture +## ๐Ÿ—๏ธ Architecture +DriverIntel uses a robust split architecture designed for performance and scale. + +```mermaid +flowchart LR + UI[Frontend: React 18, Vite, Tailwind] + API[Backend: FastAPI, Uvicorn, Python] + DB[(In-Memory Trips / Data Store)] + ML[Stress ML Inference Engine] + AI[AI Safety Assistant / Gemini] + + UI <==>|JSON via /api/*| API + API <--> DB + API <--> ML + API <--> AI ``` -Driver-Pulse/ -โ”œโ”€โ”€ backend/ # FastAPI REST API (25 endpoints) -โ”‚ โ”œโ”€โ”€ main.py # Routes, middleware, Pydantic models -โ”‚ โ”œโ”€โ”€ data/ -โ”‚ โ”‚ โ”œโ”€โ”€ sample_data.py # Synthetic trip/route/event generator -โ”‚ โ”‚ โ”œโ”€โ”€ batch_processor.py # Loads ML models, runs batch inference -โ”‚ โ”‚ โ”œโ”€โ”€ trips_import.py # CSV trip import parser -โ”‚ โ”‚ โ”œโ”€โ”€ users.py # In-memory auth store -โ”‚ โ”‚ โ””โ”€โ”€ config.py # Batch limits & constants -โ”‚ โ””โ”€โ”€ utils/ -โ”‚ โ””โ”€โ”€ logging.py # Timestamped structured logging -โ”‚ + +### Folder Structure +```text +DriverIntel/ +โ”œโ”€โ”€ backend/ # FastAPI REST API +โ”‚ โ”œโ”€โ”€ main.py # Core routing and controllers +โ”‚ โ”œโ”€โ”€ agent.py # LLM Integration (AI Safety Assistant) +โ”‚ โ””โ”€โ”€ data/ # Batch Processing, Import handling, config โ”œโ”€โ”€ frontend/ # React 18 + Vite + Tailwind SPA โ”‚ โ””โ”€โ”€ src/ -โ”‚ โ”œโ”€โ”€ pages/ # 8 pages: Home, Dashboard, Trips, TripDetail, -โ”‚ โ”‚ # Trends, Goals, Predict, BatchUpload -โ”‚ โ”œโ”€โ”€ components/ # 16 reusable components -โ”‚ โ”œโ”€โ”€ api/client.js # Centralised API client -โ”‚ โ””โ”€โ”€ utils/sanityChecks.js # Input validation helpers -โ”‚ -โ”œโ”€โ”€ drivepulse_stress_model/ # Stress Detection ML pipeline -โ”‚ โ”œโ”€โ”€ run.py # CLI entry (--generate --calibrate --train --demo) -โ”‚ โ”œโ”€โ”€ src/ -โ”‚ โ”‚ โ”œโ”€โ”€ generate_data.py # Synthetic sensor window generator (3,150 samples) -โ”‚ โ”‚ โ”œโ”€โ”€ train.py # RF classifier training + evaluation -โ”‚ โ”‚ โ”œโ”€โ”€ inference.py # InferenceEngine with rule-based fallback -โ”‚ โ”‚ โ””โ”€โ”€ hal.py # Hardware Abstraction Layer (device calibration) -โ”‚ โ”œโ”€โ”€ model/ # Trained artifacts (rf_model.pkl, baselines, contract) -โ”‚ โ””โ”€โ”€ calibration/ # Device calibration profile -โ”‚ -โ”œโ”€โ”€ earnings/earnings/ # Earnings Forecasting ML pipeline -โ”‚ โ”œโ”€โ”€ run.py # Sequential pipeline entry -โ”‚ โ”œโ”€โ”€ src/ -โ”‚ โ”‚ โ”œโ”€โ”€ build_dataset.py # Merges drivers + goals + velocity + trips -โ”‚ โ”‚ โ”œโ”€โ”€ features.py # 14-feature engineering (lags, rolling avg, rush flags) -โ”‚ โ”‚ โ”œโ”€โ”€ augment.py # 5ร— Gaussian noise augmentation -โ”‚ โ”‚ โ”œโ”€โ”€ train.py # RF regressor training + evaluation -โ”‚ โ”‚ โ””โ”€โ”€ inference.py # Batch velocity prediction -โ”‚ โ”œโ”€โ”€ model/ # Trained artifacts (rf_model.pkl, contract) -โ”‚ โ””โ”€โ”€ data/ # Source CSVs (drivers, goals, velocity, trips) -โ”‚ -โ”œโ”€โ”€ streamlit_app.py # Standalone Streamlit demo (3 tabs) -โ”œโ”€โ”€ tests/data/ # Example CSVs for batch & import testing -โ””โ”€โ”€ requirements.txt # Root Python dependencies +โ”‚ โ”œโ”€โ”€ pages/ # Full Page Views (Dashboard, Predict, etc.) +โ”‚ โ”œโ”€โ”€ components/ # Reusable UI (Leaflet Maps, Charts, Copilot) +โ”‚ โ”œโ”€โ”€ api/ # Centralized application client +โ”œโ”€โ”€ driveintel_stress_model/ # ML Pipeline for Stress Detection +โ”‚ โ”œโ”€โ”€ src/ # Random Forest training, XAI logic +โ”‚ โ””โ”€โ”€ model/ # Artifacts (.pkl) +โ””โ”€โ”€ streamlit_app.py # Standalone Streamlit rapid diagnostic tool ``` -```mermaid -flowchart LR - browser[Browser_ReactApp] --> api[FastAPI_Backend] - api --> tripsStore[InMemory_Trips_+_Goals] - api --> stressBatch[Stress_Batch_Processor] - api --> earningsBatch[Earnings_Batch_Processor] - stressBatch --> stressModel[Stress_Model_Files] - earningsBatch --> earningsModel[Earnings_Model_Files] -``` +--- + +## ๐Ÿ’ป Tech Stack + +| Layer | Technologies | +|-------|------| +| **Frontend** | React 18, Vite, Tailwind CSS, Recharts, Leaflet, Lucide Icons | +| **Backend** | Python 3.9+, FastAPI, Uvicorn, Pydantic | +| **AI / ML** | Scikit-Learn, Pandas, NumPy, Google Gemini API | +| **Deploy Target**| Vercel (Frontend Component) & Render (Backend Service) | --- -## Setup +## ๐Ÿ› ๏ธ Setup & Local Development ### Prerequisites - Python 3.9+ - Node.js 18+ - - Docker Desktop (for judge-friendly containerisation) -### Install & Run (local dev) +### 1. Install & Run Directly +Start the backend: ```bash -# Install Python dependencies -pip install -r requirements.txt - -# Start backend (http://localhost:8000) -cd backend && python main.py - -# In a new terminal โ€” start frontend (http://localhost:5173) -cd frontend && npm install && npm run dev +cd backend +pip install -r ../requirements.txt +python main.py ``` +*(Runs on `http://localhost:8000`)* -Open **http://localhost:5173** in your browser. - ---- +Start the frontend: +```bash +cd frontend +npm install +npm run dev +``` +*(Runs on `http://localhost:5173`)* -### Run with Docker +Open **http://localhost:5173** to use the application. -With [Docker Desktop](https://www.docker.com/products/docker-desktop/) running: +### 2. Run via Docker Compose ```bash -# From the repo root (Driver-Pulse/) +# Navigate to repository root docker compose up --build ``` - -Then open: - -- Frontend: `http://localhost:5173` -- Backend (direct): `http://localhost:8000/api/health` - -The frontend talks to the backend via `/api/*`, which is proxied by Nginx inside the `frontend` container to the `backend` container. - -**Judge login (demo account):** - -- Username: `judge@uber.com` -- Password: `hackathon2026` +Then visit `http://localhost:5173`! All API calls are locally proxied by NGINX inside the container. --- -## Tech Stack +## ๐Ÿ”ฎ Roadmap (Next Steps) -| Layer | Tech | -|-------|------| -| Frontend | React 18, Vite, Tailwind CSS, Recharts, Leaflet | -| Backend | FastAPI, Uvicorn | -| ML | scikit-learn, NumPy, Pandas | +* [ ] **Predictive High-Risk Routing** โ€” Seamless integration of the *Predict* UI with production historical accident dataset grids for live hazard routing. +* [ ] **In-Trip Voice Coaching** โ€” Expand the AI Assistant into an active voice companion that speaks safely contextualized warnings. +* [ ] **Telematics Database Integration** โ€” Migrate the in-memory data store to a production-ready PostgreSQL instance with PostGIS for geo-queries. --- -## Data Flow +## ๐Ÿค Contributing -- **Trips & goals**: Manual entry or CSV import hit `/api/trips` or `/api/trips/import-csv`, which update an in-memory trips list. Goals (`/api/goals`) and dashboard (`/api/dashboard`) recompute current earnings, hours, and forecast from those trips. -- **Batch stress & earnings**: Batch CSV uploads are processed by backend helpers that engineer features, call local models, and return per-row predictions plus summaries as JSON. - ---- - -## Scalability & Modularity - -- **Backend**: FastAPI routes in `backend/main.py` delegate to small modules in `backend/data/` for trips, goals, imports, and batch processing, so swapping the in-memory store for a database or separate ML service is a local change. -- **Frontend**: The React app uses a single API client layer (`frontend/src/api/client.js`) plus page/component separation, making it easy to plug in global state, auth, or feature flags without rewriting screens. -- **Batch endpoints**: Batch CSV processing is stateless per request, so multiple backend instances can handle uploads in parallel behind a load balancer. - ---- +This prototype was built with a vision for safer streets. We highly encourage contributions! +Feel free to fork the repository, cut a feature branch, and submit a PR for review. -## Testing & Validation Notes +## ๐Ÿ“„ License +This project operates under the **MIT License**. Refer to `LICENSE` for exact specifications. -- **Frontend sanity checks** โ€” lightweight helpers in `frontend/src/utils/sanityChecks.js` validate money inputs, time ranges, and clamp goal targets. -- **Example test files** โ€” illustrative, non-wired tests live in `frontend/src/__tests__/` (e.g. `EarningsProgress.test.jsx`, `TripsAddTrip.test.jsx`) to show how key components and behaviours could be validated in a full test setup. +
+ Built for the future of Ride-Hailing. +
diff --git a/backend/agent.py b/backend/agent.py index c36492a..8e0a8d9 100644 --- a/backend/agent.py +++ b/backend/agent.py @@ -2,7 +2,7 @@ import google.generativeai as genai from dotenv import load_dotenv # Add get_profile to your imports -from backend.data.sample_data import ( +from data.sample_data import ( get_trips, get_goals, get_profile, # <--- Added this @@ -61,16 +61,15 @@ def run_co_pilot(user_prompt: str): model_name='models/gemini-flash-latest', tools=[get_navigation_assistant], system_instruction=( - f"You are the DrivePulse AI Co-pilot. You are assisting {driver_name}." + f"You are the DriveIntel Safety Assistant. You are assisting {driver_name}." "\n\nSTRICT OPERATING PROCEDURES:\n" - "1. IDENTITY: Your name is 'DrivePulse Co-pilot'. Never call yourself Alex. " + "1. IDENTITY: Your name is 'DriveIntel Safety Assistant'. " "Address the driver as 'Alex' or 'Partner' when appropriate." - "\n2. GOALS: Mention the daily earnings target (โ‚น1,800) only if Alex asks about " - "money, performance, or 'how am I doing?'. Don't bring it up unprompted." + "\n2. BEHAVIOR INSIGHTS: Provide personalized safety tips and behavior analysis based on their trip data." "\n3. NAVIGATION: Use the get_navigation_assistant tool for food/break requests. " "Suggest Mumbai-based spots and ask before providing the navigation link." "\n4. LINK FORMATTING: Use the [Start Navigation](URL) format only when Alex says yes." - "\n5. TONE: Professional, efficient, and supportive. Use โ‚น for all currency." + "\n5. TONE: Professional, efficient, and supportive. Focus on driver safety and behavior improvement." ) ) diff --git a/backend/data/batch_processor.py b/backend/data/batch_processor.py index 3962f78..44a6c03 100644 --- a/backend/data/batch_processor.py +++ b/backend/data/batch_processor.py @@ -1,6 +1,6 @@ """ -DrivePulse Backend โ€” Batch CSV processing. -Loads trained stress + earnings models, runs inference on uploaded CSV data. +DriveIntel Backend โ€” Batch CSV processing. +Loads trained stress models and runs inference on uploaded CSV data. """ import io @@ -19,7 +19,7 @@ # โ”€โ”€ Stress model โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -STRESS_MODEL_DIR = ROOT / "drivepulse_stress_model" / "model" +STRESS_MODEL_DIR = ROOT / "driveintel_stress_model" / "model" STRESS_SITUATIONS = { 0: {"name": "NORMAL", "emoji": "โœ…", "severity": "low"}, @@ -138,134 +138,6 @@ def _stress_fallback(row: dict) -> dict: } -# โ”€โ”€ Earnings model โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -EARNINGS_MODEL_DIR = ROOT / "earnings" / "earnings" / "model" - -EARNINGS_FEATURES = [ - "elapsed_hours", "current_velocity", "velocity_delta", - "trips_completed", "trip_rate", "hour_of_day", - "is_morning_rush", "is_lunch_rush", - "velocity_last_1", "velocity_last_2", "velocity_last_3", - "rolling_velocity_3", "rolling_velocity_5", "goal_pressure", -] - -_earnings_clf = None - - -def _load_earnings_model(): - global _earnings_clf - if _earnings_clf is not None: - return True - try: - _earnings_clf = joblib.load(EARNINGS_MODEL_DIR / "rf_model.pkl") - print(f"[batch] Earnings model loaded") - return True - except Exception as e: - print(f"[batch] Earnings model load failed: {e}") - return False - - -def predict_earnings_row(row: dict) -> dict: - """Run earnings prediction on a single row dict.""" - if not _load_earnings_model(): - return {"predicted_velocity": None, "error": "Model not loaded"} - - x = np.array( - [float(row.get(f, 0.0)) for f in EARNINGS_FEATURES], dtype=np.float32 - ).reshape(1, -1) - predicted = float(_earnings_clf.predict(x)[0]) - predicted = max(0, round(predicted, 2)) - - target_velocity = float(row.get("target_velocity", 200)) - current_velocity = float(row.get("current_velocity", 0)) - target_earnings = float(row.get("target_earnings", 1800)) - current_earnings = float(row.get("cumulative_earnings", 0)) - elapsed = float(row.get("elapsed_hours", 0)) - remaining_earnings = max(0, target_earnings - current_earnings) - - if predicted > 0: - hours_needed = remaining_earnings / predicted - else: - hours_needed = None - - if predicted >= target_velocity * 1.1: - forecast = "ahead" - elif predicted >= target_velocity * 0.9: - forecast = "on_track" - else: - forecast = "at_risk" - - return { - "predicted_velocity": round(predicted, 2), - "target_velocity": target_velocity, - "current_velocity": current_velocity, - "forecast_status": forecast, - "remaining_earnings": round(remaining_earnings, 2), - "hours_to_target": round(hours_needed, 2) if hours_needed else None, - "pct_target": round(min(100, (current_earnings / max(target_earnings, 1)) * 100), 1), - } - - -# โ”€โ”€ Feature engineering for earnings (from raw trip CSV) โ”€โ”€โ”€โ”€โ”€โ”€ - -def engineer_earnings_features(df: pd.DataFrame) -> pd.DataFrame: - """ - Takes a raw trip-level DataFrame and engineers the 14 features - needed for the earnings model. Columns expected: - driver_id, timestamp, cumulative_earnings, elapsed_hours, - current_velocity, target_velocity, velocity_delta, - trips_completed, target_earnings - """ - df = df.copy() - - # Parse timestamp โ†’ hour info - if "timestamp" in df.columns: - ts = pd.to_datetime(df["timestamp"], errors="coerce") - df["hour_of_day"] = ts.dt.hour.fillna(12).astype(int) - elif "hour_of_day" not in df.columns: - df["hour_of_day"] = 12 - - df["is_morning_rush"] = df["hour_of_day"].between(7, 9).astype(int) - df["is_lunch_rush"] = df["hour_of_day"].between(12, 14).astype(int) - - # trip_rate - df["elapsed_hours"] = pd.to_numeric(df.get("elapsed_hours", 1), errors="coerce").fillna(1) - df["trips_completed"] = pd.to_numeric(df.get("trips_completed", 0), errors="coerce").fillna(0) - df["trip_rate"] = df["trips_completed"] / df["elapsed_hours"].replace(0, 1) - - # Velocity lags + rolling - df["current_velocity"] = pd.to_numeric(df.get("current_velocity", 0), errors="coerce").fillna(0).clip(0, 600) - df["velocity_delta"] = pd.to_numeric(df.get("velocity_delta", 0), errors="coerce").fillna(0) - df["target_velocity"] = pd.to_numeric(df.get("target_velocity", 200), errors="coerce").fillna(200) - - df = df.sort_values(["driver_id", "hour_of_day"] if "driver_id" in df.columns else ["hour_of_day"]) - grp = "driver_id" if "driver_id" in df.columns else None - - if grp: - df["velocity_last_1"] = df.groupby(grp)["current_velocity"].shift(1) - df["velocity_last_2"] = df.groupby(grp)["current_velocity"].shift(2) - df["velocity_last_3"] = df.groupby(grp)["current_velocity"].shift(3) - df["rolling_velocity_3"] = df.groupby(grp)["current_velocity"].transform( - lambda s: s.rolling(3, min_periods=1).mean() - ) - df["rolling_velocity_5"] = df.groupby(grp)["current_velocity"].transform( - lambda s: s.rolling(5, min_periods=1).mean() - ) - else: - df["velocity_last_1"] = df["current_velocity"].shift(1) - df["velocity_last_2"] = df["current_velocity"].shift(2) - df["velocity_last_3"] = df["current_velocity"].shift(3) - df["rolling_velocity_3"] = df["current_velocity"].rolling(3, min_periods=1).mean() - df["rolling_velocity_5"] = df["current_velocity"].rolling(5, min_periods=1).mean() - - df["goal_pressure"] = df["target_velocity"] - df["current_velocity"] - - # Fill NaNs from shifting - df = df.bfill().ffill().fillna(0) - - return df - # โ”€โ”€ Batch processing โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ @@ -344,80 +216,6 @@ def process_stress_csv(csv_content: str) -> dict: } -def process_earnings_csv(csv_content: str) -> dict: - """Process a CSV of earnings/trip data. Returns per-row velocity predictions + summary.""" - _load_earnings_model() - - df = pd.read_csv(io.StringIO(csv_content)) - - if df.empty: - return {"error": "CSV is empty", "results": [], "summary": {}} - - row_count = len(df) - row_limit_warning = None - if BATCH_ROW_SOFT_LIMIT and row_count > BATCH_ROW_SOFT_LIMIT: - row_limit_warning = ( - f"Processed {row_count} rows; consider chunking to {BATCH_ROW_SOFT_LIMIT} rows per upload for large workloads." - ) - - # Fill defaults for missing columns - for col, default in [ - ("driver_id", "driver-001"), - ("target_velocity", 200), - ("velocity_delta", 0), - ("target_earnings", 1800), - ("cumulative_earnings", 0), - ]: - if col not in df.columns: - df[col] = default - - df = engineer_earnings_features(df) - - results = [] - total_predicted = 0 - - for i, row in df.iterrows(): - row_dict = row.to_dict() - pred = predict_earnings_row(row_dict) - pred["row_index"] = int(i) - for k in ("driver_id", "timestamp", "trip_id", "hour_of_day"): - if k in row_dict: - pred[k] = row_dict[k] - if isinstance(pred[k], float) and not math.isnan(pred[k]): - pred[k] = int(pred[k]) if k == "hour_of_day" else pred[k] - elif isinstance(pred[k], float) and math.isnan(pred[k]): - pred[k] = None - - pred["cumulative_earnings"] = round(float(row_dict.get("cumulative_earnings", 0)), 2) - pred["elapsed_hours"] = round(float(row_dict.get("elapsed_hours", 0)), 2) - - results.append(pred) - if pred["predicted_velocity"] is not None: - total_predicted += pred["predicted_velocity"] - - total = len(results) - avg_velocity = round(total_predicted / max(total, 1), 2) - - forecast_counts = {"ahead": 0, "on_track": 0, "at_risk": 0} - for r in results: - forecast_counts[r.get("forecast_status", "on_track")] += 1 - - summary = { - "total_entries": total, - "avg_predicted_velocity": avg_velocity, - "forecast_counts": forecast_counts, - "best_velocity": max((r["predicted_velocity"] for r in results if r["predicted_velocity"]), default=0), - "worst_velocity": min((r["predicted_velocity"] for r in results if r["predicted_velocity"]), default=0), - } - if row_limit_warning: - summary["row_limit_warning"] = row_limit_warning - - return { - "results": results, - "summary": summary, - } - - # โ”€โ”€ Template generators โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ def stress_csv_template() -> str: @@ -432,12 +230,3 @@ def stress_csv_template() -> str: row1 = "trip-001,08:15:00,1.2,0.6,1.1,0.8,0.5,35,35,5,68,62,67,4,0.1,0.15" row2 = "trip-002,09:30:00,5.1,1.8,4.8,4.9,2.1,40,40,25,94,82,91,8,0.72,0.95" return header + "\n" + row1 + "\n" + row2 + "\n" - - -def earnings_csv_template() -> str: - """Return a CSV template string for earnings upload.""" - header = "driver_id,timestamp,cumulative_earnings,elapsed_hours,current_velocity,target_velocity,velocity_delta,trips_completed,target_earnings" - row1 = "driver-001,08:00:00,0,0.5,0,200,0,0,1800" - row2 = "driver-001,09:00:00,185,1.5,185,200,-15,2,1800" - row3 = "driver-001,10:00:00,420,2.5,210,200,10,4,1800" - return header + "\n" + row1 + "\n" + row2 + "\n" + row3 + "\n" diff --git a/backend/data/sample_data.py b/backend/data/sample_data.py index e67c70a..f452154 100644 --- a/backend/data/sample_data.py +++ b/backend/data/sample_data.py @@ -1,5 +1,5 @@ """ -DrivePulse Backend โ€” Sample data generator. +DriveIntel Backend โ€” Sample data generator. Produces realistic trips, events, signals, and driver metrics. """ diff --git a/backend/data/users.py b/backend/data/users.py index f6eaac2..3e1a1d9 100644 --- a/backend/data/users.py +++ b/backend/data/users.py @@ -1,5 +1,5 @@ """ -DrivePulse Backend โ€” User authentication and driver profiles. +DriveIntel Backend โ€” User authentication and driver profiles. Manages login, registration, and driver data. """ diff --git a/backend/main.py b/backend/main.py index 8c9288c..b8ee4e1 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,6 +1,6 @@ """ -DrivePulse Backend โ€” FastAPI application. -Serves trip data, events, metrics, goals, and stress tips. +DriveIntel Backend โ€” FastAPI application. +Serves trip data, events, metrics, goals, and safety tips. """ from fastapi import FastAPI, HTTPException, Query, UploadFile, File @@ -10,36 +10,33 @@ from typing import Optional, List from datetime import datetime -# Absolute Imports for Agentic AI and Utilities -from backend.agent import run_co_pilot -from backend.utils.logging import log_info, log_warn +from agent import run_co_pilot +from utils.logging import log_info, log_warn -# Standardized Absolute Imports for Data and Logic -from backend.data.sample_data import ( +from data.sample_data import ( get_trips, get_profile, get_goals, set_goal_target, build_dashboard, build_weekly_metrics, build_monthly_metrics, STRESS_TIPS, SITUATIONS, create_user_trip, add_trip, ) -from backend.data.batch_processor import ( - process_stress_csv, process_earnings_csv, - stress_csv_template, earnings_csv_template, - predict_stress_row, predict_earnings_row, +from data.batch_processor import ( + process_stress_csv, stress_csv_template, + predict_stress_row, ) -from backend.data.trips_import import import_trips_csv, trips_csv_template -from backend.data.users import ( +from data.trips_import import import_trips_csv, trips_csv_template +from data.users import ( login_user, register_user, get_user_profile, list_all_users, ) # โ”€โ”€ App Initialization โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -app = FastAPI(title="DrivePulse API", version="1.0.0") +app = FastAPI(title="DriveIntel API", version="1.0.0") # Allow frontend origins for development and production allowed_origins = [ "http://localhost:5173", "http://localhost:3000", - "https://driver-pulse-gamma.vercel.app", + "https://driveintel-alpha.vercel.app", "https://*.vercel.app", ] @@ -289,13 +286,6 @@ def predict_stress(payload: dict): except Exception as e: raise HTTPException(400, str(e)) -@app.post("/api/predict/earnings") -def predict_earnings(payload: dict): - try: - return predict_earnings_row(payload) - except Exception as e: - raise HTTPException(400, str(e)) - # โ”€โ”€ Routes: Batch & Features โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ @app.post("/api/batch/stress") @@ -329,13 +319,7 @@ def stress_features(): {"name": "audio_db_max", "label": "Audio dB Max", "default": 65.0, "group": "Audio"}, ]} -@app.get("/api/features/earnings") -def earnings_features(): - return {"features": [ - {"name": "avg_earnings_per_hour", "label": "Avg Earnings/hr (โ‚น)", "default": 250.0, "group": "Earnings"}, - {"name": "target_earnings", "label": "Target Earnings (โ‚น)", "default": 2000.0, "group": "Earnings"}, - ]} - if __name__ == "__main__": import uvicorn - uvicorn.run("backend.main:app", host="0.0.0.0", port=8000, reload=True) \ No newline at end of file + # Use "main:app" when cwd is backend/ (matches Docker and flat imports) + uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) \ No newline at end of file diff --git a/backend/package-lock.json b/backend/package-lock.json new file mode 100644 index 0000000..dfb18f1 --- /dev/null +++ b/backend/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "backend", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/backend/requirements.txt b/backend/requirements.txt index c173067..3b69eff 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,13 +1,14 @@ -fastapi>=0.104 -uvicorn>=0.24 -pydantic>=2.0 -python-multipart>=0.0.6 -numpy>=1.24.0 pandas>=2.0.0 +numpy>=1.24.0 scikit-learn>=1.3.0 joblib>=1.3.0 +streamlit>=1.28.0 +fastapi>=0.104 +uvicorn>=0.24 +pydantic>=2.0 python-dateutil>=2.8 +python-multipart>=0.0.6 + -# --- AI Co-pilot Additions --- -google-generativeai>=0.8.0 -python-dotenv>=1.0.0 \ No newline at end of file +google-generativeai +python-dotenv \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 9a0de62..c4e98c7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,9 @@ -version: "3.9" - services: backend: build: context: . dockerfile: Dockerfile.backend - container_name: drivepulse-backend + container_name: driveintel-backend ports: - "8000:8000" @@ -13,7 +11,7 @@ services: build: context: . dockerfile: Dockerfile.frontend - container_name: drivepulse-frontend + container_name: driveintel-frontend ports: - "5173:80" depends_on: diff --git a/docs/PROGRESS_LOG.md b/docs/PROGRESS_LOG.md deleted file mode 100644 index c5631a3..0000000 --- a/docs/PROGRESS_LOG.md +++ /dev/null @@ -1,27 +0,0 @@ -# Progress Log (Development History) - -A chronological log of our problem-solving process and major iterations. - - ---- - -**Mar 4:** Project kickoff. Team discussion on requirements, user persona, and value proposition. Decided on stress + earnings as dual focus. - -**Mar 5:** Finalized tech stack (FastAPI, React, scikit-learn). Planned architecture and repo structure. Set up the project repository and initial folder structure. - -**Mar 6:** Backend development: implemented API skeleton (trips, goals, dashboard), created synthetic trip data generator, and batch processor. - -**Mar 7:** Backend ML: built and trained initial stress detection (RF, HAL, Platt calibration) and earnings velocity models. Added endpoints for batch inference and CSV import. - -**Mar 8:** Frontend development: built dashboard, trip list, trip detail, earnings progress bar. Integrated backend APIs. Added batch upload and explainability features. - -**Mar 9:** Documentation: wrote design doc (HTML), architecture diagram (SVG), and progress log. Re-checked all features, tested flows, and made final edits based on feedback. Prepared for deployment. - -**Mar 10:** Deployment and submission: added Dockerised deployment (FastAPI + React via Nginx, `docker-compose.yml` at repo root), verified end-to-end flows in containers, and documented judge login plus Docker run instructions in all README/docs before final submission. - ---- - -**Outcome:** -Successfully built and deployed DrivePulse โ€” a driver safety and earnings intelligence platform that transforms raw trip signals into actionable insights. The system combines real-time stress detection with earnings velocity forecasting while maintaining privacy through on-device processing. All core features (stress detection, earnings forecasting, explainability tools, batch testing, and feedback collection) were implemented as planned. Documentation, architecture diagrams, and progress logs were completed and the project was submitted on time. - ---- \ No newline at end of file diff --git a/docs/architecture_explanation.html b/docs/architecture_explanation.html index 88a0b2d..0f98527 100644 --- a/docs/architecture_explanation.html +++ b/docs/architecture_explanation.html @@ -3,68 +3,77 @@ - DrivePulse โ€” System Architecture + DriverIntel โ€” System Architecture
-

๐Ÿš— DrivePulse

-

System Architecture

-
UBER SHE++ HACKATHON 2026
-
MerinRishitLavisha
+

๐Ÿš— DriverIntel

+

System Architecture & Platform Design

+
Driver Safety Analytics Platform
@@ -72,157 +81,154 @@

๐Ÿš— DrivePulse

01 Architecture Diagram

-

End-to-end data flow: sensors โ†’ on-device processing โ†’ server โ†’ driver insights โ†’ feedback loop.

+

End-to-end data flow: sensors โ†’ edge processing โ†’ server API โ†’ AI Copilot โ†’ driver insights.

- + - - ON-DEVICE (EDGE) + + ON-DEVICE (EDGE) - - OFF-DEVICE (SERVER) + + OFF-DEVICE (SERVER API) - - FEEDBACK LOOP + + FEEDBACK & AI ASSISTANT - - ๐Ÿ“ฑ Accelerometer + + ๐Ÿ“ฑ Accelerometer 10 Hz x/y/z motion - - ๐ŸŽค Microphone + + ๐ŸŽค Microphone dB envelope only - - ๐Ÿ“ GPS + Speed - km/h, lat/lng + + ๐Ÿ“ GPS Location + lat/lng / speed - - ๐Ÿ’ฐ Trip Earnings - โ‚น per trip, hours + + โฑ๏ธ Gyroscope + Rotation forces - - - + + + - - HAL Calibration - Device normalisation - AGC + road baseline + + Hardware Abstraction + Device normalisation + Signal processing - + - + Feature Extraction - 30s windows, Z-score norm - ~12 stress / 14 earnings feats - - - + 30s sliding windows + Statistical XAI factors - + - + Local ML Inference - RF Classifier (stress) ยท <1ms - RF Regressor (earnings) + RF Classifier (stress) ยท <1ms + Fallback Rules applied - - REST + + REST - + - - ๐Ÿ”” Driver Alerts - Real-time, on-device + + ๐Ÿ”” Driver Alerts + Real-time coaching - - ๐Ÿ“Š Driver Dashboard - Glanceable UI - + + ๐Ÿ“Š Driver App (React) + Glassmorphic UI + - + FastAPI Backend - 25 REST endpoints - Auth, CORS, validation + Core REST API + XAI interpretation - - Data Store - In-memory (MVP) - Trips, goals, events - + + Data Store + Trips, events + Goals, user profiles + - + Batch Processor - CSV upload โ†’ inference - Stress + Earnings models - + CSV upload โ†’ inference + Analyst stress reporting + - - Model Artifacts - rf_model.pkl (ร—2) - baselines, contracts - + + Model Artifacts + rf_model.pkl + Safety baselines + - + Aggregation Engine - Dashboard summaries - Trends, goal tracking - + Dashboard summaries + Driver trends metrics + - - - Driver Web App (React) - 8 pages, 16 components - Maps, charts, modals - + + + Vite / React Hosting + React 18 SPA + Tailwind CSS compilation + - - - ๐Ÿ‘๐Ÿ‘Ž Feedback - Collected per event - + + + ๐Ÿค– AI Safety Agent + Gemini LLM Integration + - - - ๐Ÿ”„ Retrain Loop - Future: feedback โ†’ model - + + + ๐Ÿ”„ Human Feedback + Thumbs up/down tracking + - - - - + + + + - DrivePulse โ€” End-to-End Data Flow + DriverIntel โ€” End-to-End Data Flow

Right-click โ†’ "Save image as" or screenshot this diagram to export as PNG.

@@ -231,97 +237,99 @@

01 Architecture Diagram

-

02 Architecture Explanation

-

Design decisions and engineering trade-offs.

+

02 Architecture & Engineering Design

+

Design decisions and system infrastructure.

-

Real-Time vs. Post-Trip Processing

+

Responsive UI & Glassmorphism Design

    -
  • Stress detection โ†’ real-time, on-device. RF classifier runs per 30s window in <1ms. Driver gets alerts instantly, no network needed.
  • -
  • Earnings prediction โ†’ on-device per trip. Velocity forecasting runs locally after each trip completes.
  • -
  • Aggregation โ†’ server-side. Dashboard summaries, trends, and goal tracking are computed on the server where full trip history is available.
  • -
  • Why this split? A driver in danger can't wait for a network round-trip. Safety alerts must work in tunnels and dead zones.
  • +
  • Premium Aesthetics: Built entirely with a deeply dark, frosted glassmorphism interface heavily reliant on backdrop-blur-xl utilities.
  • +
  • Performant Renderings: Built using Vite and React 18 for massive speed gains during compilation. State management handled cleanly to avoid chart re-renders.
  • +
  • Accessible UI: High-contrast tokens created in CSS ensure data visualisations are distinct for night-driving without causing fatigue.
-

Connectivity & Resilience

+

Real-Time vs. Post-Trip Processing

    -
  • Both ML models run locally โ€” no network required for predictions.
  • -
  • Queued sync โ€” trip data and feedback stored locally, synced when connectivity returns.
  • -
  • Rule-based fallback โ€” if model files are missing, threshold rules (motion >3.5g + audio >80 dB โ†’ CONFLICT) keep the app functional.
  • -
  • SPA frontend โ€” once loaded, all navigation works offline; only API data calls need network.
  • +
  • Stress detection โ†’ real-time edge processing. Random Forest classifier runs per 30s window in <1ms. Driver gets alerts directly without needing continuous API polling.
  • +
  • Aggregation โ†’ Backend server. Detailed map popups, AI XAI outputs (explainable AI summaries), and history metrics load off device.
  • +
  • Why this split? A driver in a dangerous zone cannot rely on cellular reliability. Safety telemetry logic processes locally, while reporting requires sync.
-

Battery & Resource Management

+

AI Co-Pilot & XAI Feedback

    -
  • Lightweight RF models โ€” no GPU, <1ms inference, ~12 stress features (not hundreds).
  • -
  • 10 Hz sampling โ€” sufficient for brakes/road events; 10ร— less data than high-frequency approaches.
  • -
  • 30s windows โ€” model runs ~2ร—/min, not continuously.
  • -
  • dB envelope only โ€” loudness levels, not raw audio waveforms. No FFT/spectrogram cost.
  • -
  • EMA drift correction โ€” simple update every 10 min, not a full recalibration.
  • +
  • Explainable AI integrations โ€” The backend automatically generates XAI "Top Features" for every identified event using feature importance arrays.
  • +
  • Integrated LLM โ€” A Gemini-backed AI Safety Assistant takes event parameters and constructs human-readable, educational summaries of the incidents instantly.
  • +
  • Data Minimisation: The LLM handles only parsed data parameters (speeds, forces, time). Audio or geo-exact details are stripped pre-prompting for absolute privacy.
-

Privacy & Data Minimisation

+

Battery & Resource Management

    -
  • No raw audio โ€” mic input reduced to dB aggregates on-device. No recordings leave the phone.
  • -
  • No raw sensor logs โ€” accelerometer data consumed in 30s windows, converted to statistical features, then discarded.
  • -
  • All audio classification on-device โ€” server never receives audio data.
  • -
  • Minimal PII โ€” username + city + experience level. No phone number, no payment data.
  • -
  • Feedback is opt-in โ€” only event ID + boolean. No free-text harvested.
  • +
  • Lightweight RF models โ€” no GPU required, minimal RAM footprint, ~12 extracted hardware features instead of deep learning arrays.
  • +
  • 30s sliding windows โ€” Telemetry model only recalculates locally a few times a minute, minimizing continuous drain.
  • +
  • dB envelope only โ€” For privacy and size, mic data is reduced to local Db scales. Driver voice clips are definitively never transmitted.

Key Trade-offs

- - - - - + + + +
DecisionGainedGave Up
On-device inferenceZero-latency alerts, offline supportCan't use large models or cross-driver patterns
RandomForest over DLLightweight, interpretable, CPU-onlyLower accuracy on complex temporal patterns
dB envelope over raw audioPrivacy, low CPU, no storageNo speech-to-text or fine-grained analysis
In-memory store over DBZero setup for judgesNo persistence across restarts
Feedback collected, not loopedSimpler systemModel doesn't self-improve (yet)
On-device inferenceZero-latency alerts, offline supportCan't use massive parameters or cross-fleet correlations instantaneously
RandomForest over DLLightweight, interpretable, CPU-onlyLower accuracy on complex multi-temporal event chains
dB envelope over raw audioPrivacy, low CPU, zero cloud bandwidthNo immediate natural language incident classification from audio
In-memory store (MVP)Zero setup friction for deploymentsNo multi-node or persistent stability without Postgres update
-

03 Deployment & Docker

-

How a judge runs the full system in minutes.

+

03 Deployment Architecture

+

How to deploy or test the architecture.

- Hackathon requirement: Include a working Dockerfile and docker-compose.yml - so a judge can run the entire stack with a single command. DrivePulse ships two services - (FastAPI backend + React frontend) wired together behind Nginx. + Infrastructure Note: DriverIntel consists of two split services: FastAPI Python Backend + Node/React Vite Frontend. They communicate natively over REST endpoints.

Containers

    -
  • Backend container: Python 3.11 + FastAPI. Runs uvicorn main:app inside the backend/ folder so imports like from utils... and from data... match local dev. Exposes 8000 with all /api/* routes.
  • -
  • Frontend container: Builds the React SPA with Node + Vite, then serves the static dist/ bundle via Nginx on port 80. Nginx proxies any request to /api/ to the backend service.
  • -
  • Compose orchestration: docker-compose.yml in the repo root builds both images, creates a shared network, and publishes: -
      -
    • http://localhost:5173 โ†’ frontend (Nginx)
    • -
    • http://localhost:8000 โ†’ backend (FastAPI, e.g. /api/health)
    • -
    -
  • +
  • Backend container: Python 3.11 + FastAPI. Runs uvicorn main:app inside the backend/ folder to execute our ML + REST models. Exposes port 8000.
  • +
  • Frontend container: Builds the React SPA with Node + Vite, compiles Tailwind definitions, and serves the static dist/ bundle via a lightweight internal proxy router.
  • +
  • Single Orchestration: Complete configuration exists in docker-compose.yml. Running docker compose up --build constructs the necessary network bridges locally for the frontend to hit /api properly.
-

Judge Runbook

+

Testing Runbook

    -
  1. Prerequisite: Install Docker Desktop and ensure it is running.
  2. -
  3. Clone repo: git clone ... && cd Driver-Pulse
  4. -
  5. One command: - docker compose up --build from the repo root (Driver-Pulse/).
  6. -
  7. Open app: visit http://localhost:5173 in the browser - (no manual dependency installation required).
  8. +
  9. Prerequisite: Start Docker Desktop.
  10. +
  11. Launch locally: git clone ... && cd Driver-Pulse (or your repository folder).
  12. +
  13. Spin up execution: docker compose up --build.
  14. +
  15. Validate app: Open http://localhost:5173 in the browser to interact via demo telemetry accounts.
- Judge credentials: we provide a pre-populated demo account.
- Username: judge@uber.com ยท Password: hackathon2026. + Demo Credentials: We provide structured demo telemetry data via sample accounts.
+ Username: demo@driveintel.com ยท Password: demo2026.
+ +
+

04 Risk Maps & Visualisations

+

Visual layout functionality of complex geo-spatial components.

+ +

Dynamic Trip Map Segmenting

+
    +
  • The core TripMap.jsx component takes real coordinate polyline segments and calculates spatial risk.
  • +
  • Coloring Logic: Calm baseline data outputs partially transparent routes. If an event timestamp triggers near a location chunk, the segment opacity scales up and colors (Amber/Green/Red) directly depending on event severity.
  • +
  • Rich Modals: Clicking event pins queries the React context layout for AI Assistant XAI explanations and model parameters without page routing.
  • +
+ +

Risk Zones Prediction Map

+
    +
  • Standalone Leaflet engine using mock overlay heat-circles to present future-state infrastructure of geographical "hazard clusters" identified by the application.
  • +
+
+
- + diff --git a/docs/architecture_image.png b/docs/architecture_image.png index c1bf0ab..8f1642f 100644 Binary files a/docs/architecture_image.png and b/docs/architecture_image.png differ diff --git a/docs/design.html b/docs/design.html index 7338047..f046998 100644 --- a/docs/design.html +++ b/docs/design.html @@ -3,75 +3,90 @@ - DrivePulse โ€” Design Document + DriverIntel โ€” Design Document
-

๐Ÿš— DrivePulse

+

๐Ÿš— DriverIntel

Design Document

-
UBER SHE++ HACKATHON 2026
-
MerinRishitLavisha
+
Advanced Driver Analytics
@@ -83,44 +98,47 @@

01 Product Vision

User Persona

- Full-time ride-hailing driver in an Indian metro city (Bangalore in our demo). - Drives 8โ€“10 hours daily. Cares about two things: staying safe on chaotic roads and - hitting a daily earnings target. Not tech-savvy โ€” needs information delivered at a glance, - not buried in charts. + Full-time ride-hailing driver in a major metro city. Drives 8โ€“10 hours daily. Cares about two things: staying safe on chaotic roads and + hitting daily performance goals. Not deeply tech-savvy โ€” needs information delivered at a glance, + not buried in heavy statistics.

Core Value Proposition

- DrivePulse transforms raw trip signals โ€” accelerometer, speed, audio dB โ€” into two actionable insights: + DriverIntel transforms raw trip signals โ€” accelerometer, spatial GPS, audio dB โ€” into highly actionable insights:

    -
  1. Safety alerts โ€” Detects dangerous situations (hard braking + loud cabin, escalating conflicts) in real-time and tells the driver why each event was flagged.
  2. -
  3. Earnings forecasting โ€” Predicts earnings velocity (โ‚น/hr), shows whether the driver is on track to hit their daily target, and estimates time-to-goal.
  4. +
  5. Safety & Coaching alerts โ€” Detects potentially dangerous situations via Multi-factor ML (hard braking, rough maneuvering, loud cabin) and provides instant explainable tips via AI.
  6. +
  7. Predictive Pathing โ€” Forecasts performance and guides towards goals efficiently with dynamic visual risk mapping.

The "Glanceable" Test

- A driver can't read a dense dashboard while navigating traffic. Every screen in DrivePulse is designed to pass the 2-second glance test: + A driver can't read a dense dashboard while navigating traffic. Every screen in DriverIntel is designed to pass the 2-second glance test:

+ -
- Design principle: The driver should never have to interpret raw numbers. - Every metric is translated into a status (ahead / on_track / at_risk), a colour (green / yellow / red), - or a plain-language message. Detailed signal charts and explainability modals exist for the - Trip Detail page โ€” but they're opt-in, not the default view. -
+ +
+

02 Overall Architecture

+

End-to-End Data Flow from Edge to Cloud Insights

+ + + DriverIntel Data Flow Diagram + +

+ The system is split into two massive segments. Edge processing runs live data locally to guarantee zero latency and complete offline persistence for immediate danger alerts. Server API routing manages batch processing overhead and syncs AI interactions where robust NLP computation is requested. +

- +
-

02 Stress Detection Algorithm

+

03 Stress Detection ML Algorithm

Lightweight signal processing, sensor fusion, and false-positive reduction.

Pipeline

@@ -129,193 +147,78 @@

Pipeline

HALDevice Norm
โ†’
30s Window~12 features
โ†’
Z-ScoreBaseline ฮผ/ฯƒ
โ†’
-
RF Classifyโ†’ 7 classes
โ†’
-
Platt Calโ†’ true prob
+
RF Classifyโ†’ 7 events
โ†’
+
Edge Alertโ†’ driver

Cleaning Noisy Motion Data (HAL)

-

Phone sensors are noisy and device-dependent. Our Hardware Abstraction Layer runs a two-phase calibration:

- -

After HAL, accelerometer output = net motion above road vibration, audio = net cabin noise above ambient. Device-agnostic.

- -

Interpreting Audio Intensity

-

Audio features are acoustic aggregates only โ€” no raw audio stored (privacy by design). Key features per 30s window:

- -

The insight: arguments have irregular cadence + sustained loudness, while music has regular cadence + steady levels. These two features alone separate ARGUMENT from MUSIC_OR_CALL well.

- -

Multi-Sensor Fusion

-

Dangerous situations are rarely single-sensor. The key fusion features:

+

Phone sensors are noisy and device-dependent. Our Hardware Abstraction Layer runs calibration:

-

Reducing False Positives

-
    -
  1. Platt calibration: Sigmoid recalibration so 85% confidence โ‰ˆ 85% true probability. Alerts only on HIGH (โ‰ฅ75%).
  2. -
  3. Confidence gating: If top-class confidence <50%, system defaults to NORMAL โ€” no alert.
  4. -
  5. Class weighting: CONFLICT and ESCALATING weighted 3ร— during training (favour recall on dangerous events); Platt step corrects the resulting overconfidence.
  6. -
  7. Rule-based fallback: If model files are missing, simple thresholds (motion >3.5g + audio >80 dB โ†’ CONFLICT) ensure the app never crashes.
  8. -
+

Data Privacy

+

Audio features are acoustic statistical aggregates only โ€” no raw voice audio stored or transmitted to the backend (privacy by design). The backend parses numeric severity parameters alone.

-

Output

-

Per 30s window: situation class (7 classes), calibrated confidence (HIGH / MEDIUM / LOW), top feature deviations (for explainability), safety flag, <1ms inference on CPU.

+

Output & Explainability

+

Engine spits out confidence intervals. When events occur, feature weights are analyzed to determine the exact cause (e.g. "You were braking too heavily") which drives the AI Safety Copilot.

- +
-

03 Earnings Velocity Algorithm

-

Current speed, forecasting, and cold-start handling.

- -

Pipeline

-
-
Driver Statetrips, hours, โ‚น
โ†’
-
Feature Eng14 features
โ†’
-
RF Regress300 trees
โ†’
-
โ‚น/hr + Status+ probability
-
- -

Current Earnings Speed

-

Earnings velocity = cumulative earnings รท elapsed hours (โ‚น/hr). Required velocity = remaining earnings รท remaining hours. The gap between the two gives an instant "am I on track?" signal.

- -

Feature Engineering (14 features)

-
- - - - - -
GroupFeaturesWhy
Currentcurrent_velocity, elapsed_hours, trips_completed, trip_rateHow is the driver doing right now?
Contexthour_of_day, is_morning/lunch/evening_rushDemand varies by time of day
Historyvelocity_last_1/2/3, rolling_velocity_3/5Recent trend (momentum)
Goalgoal_pressure (target โˆ’ current velocity)How urgently driver needs to speed up
- -

Forecasting

-

RF regressor predicts next-period velocity. From that we derive:

- - -

Handling Cold Start

-

First 15 min of a shift โ€” no velocity lags, unstable trip rate, no rolling averages.

- - -
- Edge case: A driver with a โ‚น5,000 target and 2 hours left sees required = โ‚น2,500/hr โ€” clearly unreachable. - The model predicts honestly; the dashboard shows ๐Ÿ”ด at_risk. We don't hide bad news. -
+

04 Driver Safety Goals Forecaster

+

Forecasting event tracking and goal resolution.

+ +

Users establish custom performance goals directly targeting weak habits identified by the AI. Trend line analysis determines if the driver is successfully migrating their driving habits towards the stated objective (e.g. fewer deep acceleration events). The ML trends calculate rolling regression to map success probability.

- +
-

04 Execution Strategy

-

MVP scope, phased build, and the cut line.

- -

MVP Scope

-
- - - - - - -
LayerWhat's included
ML โ€” StressLightweight RF classifier, ~12 key features, 7 classes, Platt calibration, HAL, rule-based fallback
ML โ€” EarningsRF regressor, 14 features, velocity prediction, 5 derived goal metrics
BackendFastAPI (25 endpoints), in-memory store, batch processor, CSV import, auth
FrontendReact SPA (8 pages, 16 components), maps, charts, explainability modals
Judge toolsPredict page (single-row testing), Batch Upload (CSV inference + charts)
- -

Phased Build

-
    -
  1. Data & Models โ€” Feature engineering, train both RF models, validate with cross-validation.
  2. -
  3. Backend API โ€” FastAPI with core endpoints, in-memory data store, batch inference.
  4. -
  5. Frontend Core โ€” Dashboard, Trips, Trip Detail with map + charts, auth flow.
  6. -
  7. Polish & Judge Tools โ€” Predict, Batch Upload, explainability, Trends, Goals.
  8. -
  9. Docs & Deploy โ€” Design doc, architecture diagram, README, deployment.
  10. -
+

05 Execution Strategy

+

MVP scope and development milestones.

-

The Cut Line

+

Tech Stack Core

-

What we cut:

+

Frontend (Local Web/App)

    -
  • Real-time phone sensor streaming (simulated with synthetic data)
  • -
  • Persistent database (in-memory = zero-setup for judges)
  • -
  • Push notifications / WebSockets
  • -
  • Model retraining from feedback
  • -
  • Payment integration / real fare calculation
  • +
  • React 18 & Vite
  • +
  • Tailwind CSS (Glassmorphic implementation)
  • +
  • Recharts (Dashboard components)
  • +
  • Leaflet API (Risk Mapping)
-

Why:

+

Backend (Cloud Sync API)

    -
  • Each adds setup complexity without demonstrating core algorithm thinking
  • -
  • Architecture supports a DB โ€” we just don't require one to run
  • -
  • Feedback collection is built; retraining is a production concern
  • -
  • Time focused on model quality + explainability + UX
  • +
  • Python 3.11 & FastAPI
  • +
  • Gemini LLM Toolkit
  • +
  • Random Forest Inference CLI
  • +
  • Batch processing hooks
- -

Key Trade-offs

-
- - - - -
ChoiceGainedGave Up
RandomForest over deep learningLightweight, interpretable, CPU-only, <1ms inferencePotentially lower accuracy on complex patterns
In-memory store over DBZero setup, instant startupNo persistence across restarts
Synthetic sensor dataFull control over class balanceMay not generalise to real sensors
- -
-

05 Judge Experience & Docker

-

How we designed the repo and Docker setup so judges can run DrivePulse in a few minutes.

+ +
+

06 Deployment & Docker Setup

+

Zero-setup runtime orchestration.

-

Zero-setup runtime

-

To avoid asking judges to install Python, Node, or ML libraries locally, we ship a fully containerised stack:

-
    -
  • Backend: Dockerfile.backend builds a Python 3.11 image, installs all ML and FastAPI dependencies from the repo's requirements.txt files, and starts uvicorn main:app from backend/.
  • -
  • Frontend: Dockerfile.frontend builds the React + Vite SPA, then serves it via Nginx, which also proxies /api/* to the backend service.
  • -
  • Compose: docker-compose.yml at the root orchestrates both services and exposes: -
      -
    • http://localhost:5173 โ†’ Nginx + React SPA
    • -
    • http://localhost:8000/api/health โ†’ backend health check
    • -
    -
  • -
- -

Judge run instructions

-

We repeat the exact steps (as required by the hackathon) in the root README.md and docs:

+

The entire platform operates via containerised stacks to run concurrently without complex dependency resolution.

+
    -
  1. Install Docker Desktop and ensure it is running.
  2. -
  3. git clone ... && cd Driver-Pulse
  4. -
  5. From the repo root run: docker compose up --build
  6. -
  7. Visit http://localhost:5173 to use the app; optional backend health at http://localhost:8000/api/health.
  8. +
  9. Install Docker Desktop.
  10. +
  11. git clone the repository.
  12. +
  13. From root run: docker compose up --build
  14. +
  15. Navigate to http://localhost:5173 to explore the live DriverIntel dashboard.
-
- Judge login: we provide a pre-configured demo account so judges land in a realistic dashboard immediately.
- Username: judge@uber.com ยท Password: hackathon2026. -
- -
- This approach satisfies the hackathon's Docker criterion: a working Dockerfile and docker-compose.yml - at the repo root, with a single docker compose up --build command to start the entire application. -
- + diff --git a/drivepulse_stress_model/README.md b/driveintel_stress_model/README.md similarity index 98% rename from drivepulse_stress_model/README.md rename to driveintel_stress_model/README.md index bfe161c..50de27d 100644 --- a/drivepulse_stress_model/README.md +++ b/driveintel_stress_model/README.md @@ -1,4 +1,4 @@ -# DrivePulse โ€” Stress Detection Model +# DriveIntel โ€” Stress Detection Model Edge-computed driver stress detection. No audio recorded. No cloud inference. Classifies 30-second sensor windows into 7 situation types. @@ -11,7 +11,7 @@ Classifies 30-second sensor windows into 7 situation types. ```bash # 1. Clone or unzip the project -cd drivepulse_stress_model +cd driveintel_stress_model # 2. Create a virtual environment (recommended) python -m venv venv @@ -100,7 +100,7 @@ The synthetic test set is a clean lower bound, not a production estimate. ## Project structure ``` -drivepulse_stress_model/ +driveintel_stress_model/ โ”‚ โ”œโ”€โ”€ run.py โ† entry point โ”œโ”€โ”€ requirements.txt diff --git a/drivepulse_stress_model/calibration/device_profile.json b/driveintel_stress_model/calibration/device_profile.json similarity index 100% rename from drivepulse_stress_model/calibration/device_profile.json rename to driveintel_stress_model/calibration/device_profile.json diff --git a/drivepulse_stress_model/data/synthetic_windows.csv b/driveintel_stress_model/data/synthetic_windows.csv similarity index 100% rename from drivepulse_stress_model/data/synthetic_windows.csv rename to driveintel_stress_model/data/synthetic_windows.csv diff --git a/drivepulse_stress_model/model/baseline_mean.npy b/driveintel_stress_model/model/baseline_mean.npy similarity index 100% rename from drivepulse_stress_model/model/baseline_mean.npy rename to driveintel_stress_model/model/baseline_mean.npy diff --git a/drivepulse_stress_model/model/baseline_std.npy b/driveintel_stress_model/model/baseline_std.npy similarity index 100% rename from drivepulse_stress_model/model/baseline_std.npy rename to driveintel_stress_model/model/baseline_std.npy diff --git a/drivepulse_stress_model/model/feature_contract.json b/driveintel_stress_model/model/feature_contract.json similarity index 100% rename from drivepulse_stress_model/model/feature_contract.json rename to driveintel_stress_model/model/feature_contract.json diff --git a/driveintel_stress_model/requirements.txt b/driveintel_stress_model/requirements.txt new file mode 100644 index 0000000..2a9510f --- /dev/null +++ b/driveintel_stress_model/requirements.txt @@ -0,0 +1,9 @@ +pandas>=2.0.0 +numpy>=1.24.0 +scikit-learn>=1.3.0 +joblib>=1.3.0 +fastapi==0.104.1 +uvicorn==0.24.0 +python-multipart==0.0.6 +pydantic==2.5.0 +pydantic-settings==2.1.0 \ No newline at end of file diff --git a/drivepulse_stress_model/run.py b/driveintel_stress_model/run.py similarity index 95% rename from drivepulse_stress_model/run.py rename to driveintel_stress_model/run.py index 16450e9..6994713 100644 --- a/drivepulse_stress_model/run.py +++ b/driveintel_stress_model/run.py @@ -1,5 +1,5 @@ """ -run.py โ€” DrivePulse Stress Detection +run.py โ€” DriveIntel Stress Detection Single entry point. Run from the project root directory. Usage: @@ -81,7 +81,7 @@ def step_demo(): def main(): - parser = argparse.ArgumentParser(description="DrivePulse Stress Detection") + parser = argparse.ArgumentParser(description="DriveIntel Stress Detection") parser.add_argument("--generate", action="store_true", help="Generate synthetic data only") parser.add_argument("--calibrate", action="store_true", help="Run HAL calibration demo only") parser.add_argument("--train", action="store_true", help="Train model only") @@ -101,7 +101,7 @@ def main(): else: # Full pipeline print("=" * 50) - print("DrivePulse โ€” Full Pipeline") + print("DriveIntel โ€” Full Pipeline") print("=" * 50) step_generate() step_calibrate() diff --git a/drivepulse_stress_model/src/generate_data.py b/driveintel_stress_model/src/generate_data.py similarity index 100% rename from drivepulse_stress_model/src/generate_data.py rename to driveintel_stress_model/src/generate_data.py diff --git a/drivepulse_stress_model/src/hal.py b/driveintel_stress_model/src/hal.py similarity index 100% rename from drivepulse_stress_model/src/hal.py rename to driveintel_stress_model/src/hal.py diff --git a/drivepulse_stress_model/src/inference.py b/driveintel_stress_model/src/inference.py similarity index 100% rename from drivepulse_stress_model/src/inference.py rename to driveintel_stress_model/src/inference.py diff --git a/drivepulse_stress_model/src/train.py b/driveintel_stress_model/src/train.py similarity index 99% rename from drivepulse_stress_model/src/train.py rename to driveintel_stress_model/src/train.py index 84e9f36..f342f8c 100644 --- a/drivepulse_stress_model/src/train.py +++ b/driveintel_stress_model/src/train.py @@ -202,7 +202,7 @@ def export(clf, cal, mean, std): def run(): print("=" * 60) - print("DrivePulse โ€” Stress Detection Training") + print("DriveIntel โ€” Stress Detection Training") print("=" * 60 + "\n") X, y = load_data() diff --git a/drivepulse_stress_model/model/calibrated_model.pkl b/drivepulse_stress_model/model/calibrated_model.pkl deleted file mode 100644 index b4949b4..0000000 Binary files a/drivepulse_stress_model/model/calibrated_model.pkl and /dev/null differ diff --git a/drivepulse_stress_model/model/rf_model.pkl b/drivepulse_stress_model/model/rf_model.pkl deleted file mode 100644 index 6b7350d..0000000 Binary files a/drivepulse_stress_model/model/rf_model.pkl and /dev/null differ diff --git a/drivepulse_stress_model/requirements.txt b/drivepulse_stress_model/requirements.txt deleted file mode 100644 index 1bedc27..0000000 --- a/drivepulse_stress_model/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -pandas>=2.0.0 -numpy>=1.24.0 -scikit-learn>=1.3.0 -joblib>=1.3.0 diff --git a/drivepulse_stress_model/src/__pycache__/generate_data.cpython-313.pyc b/drivepulse_stress_model/src/__pycache__/generate_data.cpython-313.pyc deleted file mode 100644 index cd9744e..0000000 Binary files a/drivepulse_stress_model/src/__pycache__/generate_data.cpython-313.pyc and /dev/null differ diff --git a/drivepulse_stress_model/src/__pycache__/hal.cpython-313.pyc b/drivepulse_stress_model/src/__pycache__/hal.cpython-313.pyc deleted file mode 100644 index bd63e0e..0000000 Binary files a/drivepulse_stress_model/src/__pycache__/hal.cpython-313.pyc and /dev/null differ diff --git a/drivepulse_stress_model/src/__pycache__/inference.cpython-313.pyc b/drivepulse_stress_model/src/__pycache__/inference.cpython-313.pyc deleted file mode 100644 index c251800..0000000 Binary files a/drivepulse_stress_model/src/__pycache__/inference.cpython-313.pyc and /dev/null differ diff --git a/drivepulse_stress_model/src/__pycache__/train.cpython-313.pyc b/drivepulse_stress_model/src/__pycache__/train.cpython-313.pyc deleted file mode 100644 index 348212a..0000000 Binary files a/drivepulse_stress_model/src/__pycache__/train.cpython-313.pyc and /dev/null differ diff --git a/frontend/.env.production b/frontend/.env.production new file mode 100644 index 0000000..c5c3f48 --- /dev/null +++ b/frontend/.env.production @@ -0,0 +1 @@ +VITE_API_URL=https://your-vercel-deployment.vercel.app \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html index 011ae1e..f03963d 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -3,15 +3,18 @@ - DrivePulse โ€” Driver Wellness & Earnings + DriveIntel โ€” Driver Safety & Behavior Analytics + + + - +
diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 302a2bd..5dbf2bc 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,11 +1,11 @@ { - "name": "drivepulse-frontend", + "name": "driveintel-frontend", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "drivepulse-frontend", + "name": "driveintel-frontend", "version": "1.0.0", "dependencies": { "date-fns": "^3.2.0", diff --git a/frontend/package.json b/frontend/package.json index 0bd8f65..dab185c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,5 +1,5 @@ { - "name": "drivepulse-frontend", + "name": "driveintel-frontend", "private": true, "version": "1.0.0", "type": "module", diff --git a/frontend/src/__tests__/EarningsProgress.test.jsx b/frontend/src/__tests__/EarningsProgress.test.jsx deleted file mode 100644 index cce50bd..0000000 --- a/frontend/src/__tests__/EarningsProgress.test.jsx +++ /dev/null @@ -1,32 +0,0 @@ -// NOTE: Illustrative test only โ€“ runner not wired. -// Shows how EarningsProgress could be tested with a real test setup. - -import EarningsProgress from '../components/EarningsProgress' - -const mockGoals = { - daily_target: 1800, - current_earnings: 900, - current_velocity: 200, - required_velocity: 225, - goal_probability: 0.75, - current_hours: 4.5, - target_hours: 10, - trips_completed: 6, - forecast_status: 'on_track', -} - -// Pseudo-test demonstrating expected derived values. -function exampleUsage() { - const pct = Math.round((mockGoals.current_earnings / mockGoals.daily_target) * 100) - const remaining = mockGoals.daily_target - mockGoals.current_earnings - - // In a real test you might assert: - // expect(screen.getByText(`โ‚น${mockGoals.current_earnings.toLocaleString()}`)).toBeInTheDocument() - // expect(screen.getByText(`${pct}% achieved`)).toBeInTheDocument() - // expect(screen.getByText(`โ‚น${remaining.toLocaleString()} remaining`)).toBeInTheDocument() - - return { pct, remaining } -} - -export { EarningsProgress, mockGoals, exampleUsage } - diff --git a/frontend/src/api/client.js b/frontend/src/api/client.js index 42d484e..e675e22 100644 --- a/frontend/src/api/client.js +++ b/frontend/src/api/client.js @@ -1,5 +1,5 @@ -// Use full backend URL from env, or fallback to /api for local dev -const BASE = '/api'; +// Relative /api for local dev + Docker; set VITE_API_BASE on Vercel (e.g. https://api.example.com/api) +const BASE = import.meta.env.VITE_API_BASE || '/api'; // Single place to plug in auth headers, retries, error normalisation, etc. async function request(path, options = {}) { diff --git a/frontend/src/components/AICopilot.jsx b/frontend/src/components/AICopilot.jsx index 23722de..1c7529d 100644 --- a/frontend/src/components/AICopilot.jsx +++ b/frontend/src/components/AICopilot.jsx @@ -34,7 +34,7 @@ const AICopilot = () => { const [messages, setMessages] = useState([ { role: 'ai', - text: "Hey! I'm your DrivePulse Co-pilot. How can I help you today?" + text: "Hey! I'm your DriveIntel Safety Assistant. How can I help you stay safe today?" } ]); const [isLoading, setIsLoading] = useState(false); @@ -78,25 +78,29 @@ const AICopilot = () => { return (
{isOpen && ( -
-
-
-
-

DrivePulse Co-pilot

+
+
+
+
+
+
+

Safety Copilot

+

Online & analyzing

+
-
-
+
{messages.map((m, i) => (
{/* USE THE NEW HELPER HERE */} @@ -104,17 +108,17 @@ const AICopilot = () => {
))} {isLoading && ( -
+
- Co-pilot is calculating... + Copilot is typing...
)}
-
+
setInput(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && sendMessage()} @@ -122,7 +126,7 @@ const AICopilot = () => { @@ -132,9 +136,9 @@ const AICopilot = () => {
); diff --git a/frontend/src/components/ConfidenceBadge.jsx b/frontend/src/components/ConfidenceBadge.jsx index 9fe323c..5b4b8cd 100644 --- a/frontend/src/components/ConfidenceBadge.jsx +++ b/frontend/src/components/ConfidenceBadge.jsx @@ -1,15 +1,15 @@ const levelConfig = { - low: { bg: 'bg-green-100', text: 'text-green-800', label: 'Low' }, - medium: { bg: 'bg-yellow-100', text: 'text-yellow-800', label: 'Med' }, - high: { bg: 'bg-red-100', text: 'text-red-800', label: 'High' }, + low: { bg: 'bg-emerald-500/10 border-emerald-500/20', text: 'text-emerald-400', label: 'Low' }, + medium: { bg: 'bg-amber-500/10 border-amber-500/20', text: 'text-amber-400', label: 'Med' }, + high: { bg: 'bg-rose-500/10 border-rose-500/20', text: 'text-rose-400', label: 'High' }, } export default function ConfidenceBadge({ level, score }) { const cfg = levelConfig[level] || levelConfig.low return ( - + {cfg.label} - {score !== undefined && {Math.round(score * 100)}%} + {score !== undefined && {Math.round(score * 100)}%} ) } diff --git a/frontend/src/components/EarningsProgress.jsx b/frontend/src/components/EarningsProgress.jsx deleted file mode 100644 index 2b05641..0000000 --- a/frontend/src/components/EarningsProgress.jsx +++ /dev/null @@ -1,104 +0,0 @@ -export default function EarningsProgress({ goals }) { - if (!goals) return null - - const currentEarnings = Number(goals.current_earnings || 0) - const dailyTarget = Number(goals.daily_target || 0) - const safeTarget = dailyTarget > 0 ? dailyTarget : 0 - const pct = safeTarget > 0 - ? Math.min(100, Math.round((currentEarnings / safeTarget) * 100)) - : 0 - - const statusColor = { - ahead: 'text-uber-green', - on_track: 'text-uber-blue', - at_risk: 'text-uber-red', - }[goals.forecast_status] || 'text-uber-gray-500' - - const prettyStatus = - typeof goals.forecast_status === 'string' - ? goals.forecast_status.replace('_', ' ') - : 'on track' - - return ( -
-
-

Daily Earnings Target

- - {goals.forecast_status?.replace('_', ' ')} - -
- -
- โ‚น{currentEarnings.toLocaleString()} - / โ‚น{safeTarget.toLocaleString()} -
- - {/* Progress bar */} -
-
-
-
- {pct}% achieved - โ‚น{Math.max(0, safeTarget - currentEarnings).toLocaleString()} remaining -
- - {/* Extra stats */} -
-
-

โ‚น{goals.current_velocity}

-

Current โ‚น/hr

-
-
-

โ‚น{goals.required_velocity}

-

Required โ‚น/hr

-
-
-

- {Number.isFinite(goals.goal_probability) - ? Math.round(goals.goal_probability * 100) - : 0} - % -

-

Probability

-
-
- - {/* Details grid */} -
-
-

Remaining

-

โ‚น{Math.max(0, safeTarget - currentEarnings).toLocaleString()}

-

to reach target

-
-
-

Time Worked

-

{goals.current_hours}h

-

of {goals.target_hours}h target

-
-
-

Trips Today

-

{goals.trips_completed}

-

completed

-
-
-

Status

-

- {prettyStatus.charAt(0).toUpperCase() + prettyStatus.slice(1)} -

-

today's pace

-
-
-
- ) -} diff --git a/frontend/src/components/EventCard.jsx b/frontend/src/components/EventCard.jsx index be8cab2..ad07136 100644 --- a/frontend/src/components/EventCard.jsx +++ b/frontend/src/components/EventCard.jsx @@ -8,10 +8,10 @@ export default function EventCard({ event, onJumpTo, onFeedback }) { const [showExplain, setShowExplain] = useState(false) const severityColor = { - low: 'border-l-uber-green', - medium: 'border-l-uber-yellow', - high: 'border-l-uber-red', - }[event.severity] || 'border-l-uber-gray-300' + low: 'border-l-emerald-500 shadow-[0_4px_20px_rgba(16,185,129,0.1)]', + medium: 'border-l-amber-500 shadow-[0_4px_20px_rgba(245,158,11,0.1)]', + high: 'border-l-rose-500 shadow-[0_4px_20px_rgba(244,63,94,0.15)]', + }[event.severity] || 'border-l-slate-700' const time = event.timestamp ? new Date(event.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }) @@ -19,24 +19,25 @@ export default function EventCard({ event, onJumpTo, onFeedback }) { return ( <> -
-
+
+
+
- {event.emoji} - {event.label.replace(/_/g, ' ')} + {event.emoji} + {event.label.replace(/_/g, ' ')}
-

{time}

+

{time}

{event.explain?.summary && ( -

{event.explain.summary}

+

{event.explain.summary}

)}
-
+
-
+
e.stopPropagation()} > {/* Header */} -
+
-

Why This Happened

-

- {event.emoji} {event.label.replace(/_/g, ' ')} +

Why This Happened

+

+ {event.emoji} {event.label.replace(/_/g, ' ')}

-
{/* Top 3 feature contributions */} -
-

Top Feature Contributions

+
+

Top Feature Contributions

{explain.top_features?.map((f, i) => { const pct = Math.round(f.contribution * 100) - const barColor = i === 0 ? 'bg-uber-red' : i === 1 ? 'bg-uber-orange' : 'bg-uber-yellow' + const barColor = i === 0 ? 'bg-rose-500 shadow-[0_0_8px_rgba(244,63,94,0.6)]' : i === 1 ? 'bg-amber-500 shadow-[0_0_8px_rgba(245,158,11,0.6)]' : 'bg-emerald-500 shadow-[0_0_8px_rgba(16,185,129,0.6)]' return (
-
- - {f.feature.replace(/_/g, ' ')} {f.direction} +
+ + {f.feature.replace(/_/g, ' ')} {f.direction} - {pct}% + {pct}%
-
+
@@ -48,14 +48,14 @@ export default function ExplainModal({ event, onClose }) {
{/* Model inputs */} -
-

Model Inputs (snapshot)

-
+
+

Model Inputs (snapshot)

+
{explain.model_inputs && Object.entries(explain.model_inputs).map(([k, v]) => ( -
- {k.replace(/_/g, ' ')} - {v} +
+ {k.replace(/_/g, ' ')} + {v}
))}
@@ -63,8 +63,8 @@ export default function ExplainModal({ event, onClose }) { {/* Summary */} {explain.summary && ( -
-

{explain.summary}

+
+

"{explain.summary}"

)}
diff --git a/frontend/src/components/FeedbackButtons.jsx b/frontend/src/components/FeedbackButtons.jsx index d705f50..b614bcf 100644 --- a/frontend/src/components/FeedbackButtons.jsx +++ b/frontend/src/components/FeedbackButtons.jsx @@ -5,7 +5,7 @@ import { api } from '../api/client' const options = [ { key: 'correct', label: 'Correct', icon: ThumbsUp, color: 'text-uber-green hover:bg-green-50' }, { key: 'incorrect', label: 'Incorrect', icon: ThumbsDown, color: 'text-uber-red hover:bg-red-50' }, - { key: 'not_relevant', label: 'Not Relevant', icon: MinusCircle, color: 'text-uber-gray-500 hover:bg-uber-gray-100' }, + { key: 'not_relevant', label: 'Not Relevant', icon: MinusCircle, color: 'text-slate-500 hover:bg-slate-800' }, ] export default function FeedbackButtons({ eventId, current, onFeedback }) { @@ -28,7 +28,7 @@ export default function FeedbackButtons({ eventId, current, onFeedback }) { return (
- Feedback: + Feedback: {options.map(({ key, label, icon: Icon, color }) => ( +
+
+
+

Quick Start

+

Explore a Sample Trip

+

+ See stress detection, earnings tracking, and event explainability in action. +

+ +
) } diff --git a/frontend/src/components/Sidebar.jsx b/frontend/src/components/Sidebar.jsx index 83b3340..cd0336a 100644 --- a/frontend/src/components/Sidebar.jsx +++ b/frontend/src/components/Sidebar.jsx @@ -12,36 +12,36 @@ const links = [ export default function Sidebar({ user, onLogout }) { return ( -