| <p align="center"> |
| <h1 align="center">π Fair Dispatch System</h1> |
| <p align="center"> |
| <strong>SingleβAPI Fair Routing Β· Angelic Fairness Engine Β· Live Agent Visualization</strong> |
| </p> |
| <p align="center"> |
| <a href="#-quick-start">Quick Start</a> β’ |
| <a href="#-features">Features</a> β’ |
| <a href="#-architecture">Architecture</a> β’ |
| <a href="#-api-reference">API Reference</a> β’ |
| <a href="#-visualization-dashboard">Dashboard</a> |
| </p> |
| </p> |
| |
| --- |
|
|
| Fair Dispatch is an AIβassisted, **fairnessβaware route allocation engine** designed as a single seamless API that any logistics stack can plug into. |
|
|
| **You send today's drivers and packages as JSON. The system does everything else:** |
| - π¦ Clustering packages into optimal routes |
| - βοΈ Calculating effort scores and fairness metrics |
| - π£οΈ Planning routes with EV-aware optimization |
| - π€ Balancing workload across drivers |
| - π€ AI-powered driver negotiation and explanation |
| - π Learning from feedback to improve over time |
|
|
| ...and streams the whole multiβagent process into a **live visualization**. |
|
|
| ## β¨ Features |
|
|
| | Feature | Description | |
| |---------|-------------| |
| | **π― Single API Endpoint** | One POST to `/api/v1/langgraph/allocate` handles everything | |
| | **π€ 5+ Specialized AI Agents** | LangGraph-orchestrated multi-agent workflow | |
| | **βοΈ Fairness-First Design** | Gini index, individual fairness scores, and equity metrics | |
| | **π£οΈ Natural Language Explanations** | Gemini-powered driver-friendly route explanations | |
| | **π Live Agent Visualization** | Real-time Streamlit dashboard showing agent workflow | |
| | **π Continuous Learning** | Feedback loop improves allocations over time | |
| | **β‘ EV-Aware Routing** | Battery constraints and charging station integration | |
| | **π Full Audit Trail** | Complete decision logging for transparency | |
|
|
| ## ποΈ Architecture |
|
|
| ### Multi-Agent Workflow (LangGraph) |
|
|
| ``` |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| β FAIR DISPATCH WORKFLOW β |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| β |
| βΌ |
| βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ |
| β π§ Initialize β β β π¦ Clustering β β β πͺ ML Effort β |
| β Node β β Agent β β Agent β |
| βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ |
| β |
| βΌ |
| βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ |
| β β‘ EV Recovery β β β βοΈ Fairness β β β π£οΈ Route β |
| β Node β β Manager β β Planner β |
| βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ |
| β β |
| βΌ βΌ (if unfair) |
| βββββββββββββββββββ βββββββββββββββββββ |
| β π€ Driver β β π Reoptimize β |
| β Liaison β β Loop β |
| βββββββββββββββββββ βββββββββββββββββββ |
| β |
| βΌ |
| βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ |
| β π Learning β β β π£οΈ LLM β β β β
Finalize β |
| β Agent β β Explain β β Node β |
| βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ |
| ``` |
|
|
| ### Agent Descriptions |
|
|
| | Agent | Purpose | Key Outputs | |
| |-------|---------|-------------| |
| | **Initialize Node** | Sets up allocation state, validates inputs | Validated driver/package data | |
| | **Clustering Agent** | Groups packages using K-Means by geography | Route clusters with centroids | |
| | **ML Effort Agent** | Builds effort matrix for all driver-route pairs | Effort scores, XGBoost predictions | |
| | **Route Planner Agent** | Solves optimal assignment (Hungarian algorithm) | Driver-route assignments | |
| | **Fairness Manager** | Evaluates Gini index, std dev, thresholds | ACCEPT or REOPTIMIZE decision | |
| | **EV Recovery Node** | Handles EV battery constraints | Charging station insertions | |
| | **Driver Liaison Agent** | Handles driver negotiations/appeals | Appeal resolutions | |
| | **Learning Agent** | Updates models from feedback | Improved future allocations | |
| | **LLM Explain Node** | Generates natural language explanations | Human-readable route descriptions | |
|
|
| ## π Quick Start |
|
|
| ### Prerequisites |
|
|
| - **Python 3.11+** |
| - **PostgreSQL 14+** (or SQLite for development) |
| - **Git** |
|
|
| ### 1. Clone & Setup |
|
|
| ```bash |
| # Clone the repository |
| git clone https://github.com/your-org/fair-dispatch-system.git |
| cd fair-dispatch-system |
| |
| # Create virtual environment |
| python -m venv venv |
| |
| # Activate virtual environment |
| # Windows: |
| venv\Scripts\activate |
| # Linux/macOS: |
| source venv/bin/activate |
| |
| # Install dependencies |
| pip install -r requirements.txt |
| ``` |
|
|
| ### 2. Configure Environment |
|
|
| ```bash |
| # Copy example environment file |
| cp .env.example .env |
| |
| # Edit .env with your configuration |
| ``` |
|
|
| **Essential environment variables:** |
|
|
| ```env |
| # Database (PostgreSQL recommended for production) |
| DATABASE_URL=postgresql+asyncpg://postgres:password@localhost:5432/fair_dispatch |
| |
| # Application |
| APP_ENV=development |
| DEBUG=true |
| |
| # Optional: Gemini API for AI explanations |
| GOOGLE_API_KEY=your-gemini-api-key |
| |
| # Optional: LangSmith tracing |
| LANGCHAIN_TRACING_V2=true |
| LANGCHAIN_API_KEY=your-langsmith-key |
| ``` |
|
|
| ### 3. Setup Database |
|
|
| ```bash |
| # Create PostgreSQL database |
| createdb fair_dispatch |
| |
| # Run migrations |
| alembic upgrade head |
| ``` |
|
|
| ### 4. Start the Server |
|
|
| ```bash |
| # Development server with hot reload |
| uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 |
| ``` |
|
|
| ### 5. Access the System |
|
|
| | Endpoint | URL | |
| |----------|-----| |
| | **API Documentation** | http://localhost:8000/docs | |
| | **ReDoc** | http://localhost:8000/redoc | |
| | **Demo Page** | http://localhost:8000/demo/allocate | |
| | **Admin Dashboard** | http://localhost:8000/admin | |
|
|
| ## π Visualization Dashboard |
|
|
| The system includes a **real-time Streamlit dashboard** for monitoring allocations: |
|
|
| ```bash |
| # Navigate to dashboard directory |
| cd supply_chain_dashboard |
| |
| # Install dashboard dependencies |
| pip install -r requirements.txt |
| |
| # Run the dashboard |
| streamlit run dashboard.py |
| ``` |
|
|
| **Dashboard Features:** |
| - πΊοΈ **Live Map Visualization** - See routes on an interactive map |
| - π **Fairness Metrics** - Real-time Gini index and equity scores |
| - π€ **Agent Activity Feed** - Watch agents work in real-time |
| - π **Analytics Charts** - Workload distribution and trends |
|
|
| ## π‘ API Reference |
|
|
| ### Primary Endpoint: Allocate Routes |
|
|
| **`POST /api/v1/langgraph/allocate`** |
|
|
| This single endpoint handles the complete allocation workflow. |
|
|
| #### Request |
|
|
| ```json |
| { |
| "date": "2026-02-10", |
| "warehouse": { |
| "lat": 12.9716, |
| "lng": 77.5946 |
| }, |
| "packages": [ |
| { |
| "id": "pkg_001", |
| "weight_kg": 2.5, |
| "fragility_level": 3, |
| "address": "123 Main St, Bangalore", |
| "latitude": 12.97, |
| "longitude": 77.60, |
| "priority": "NORMAL" |
| }, |
| { |
| "id": "pkg_002", |
| "weight_kg": 1.0, |
| "fragility_level": 1, |
| "address": "456 Oak Ave, Bangalore", |
| "latitude": 12.98, |
| "longitude": 77.61, |
| "priority": "HIGH" |
| } |
| ], |
| "drivers": [ |
| { |
| "id": "driver_001", |
| "name": "Raju", |
| "vehicle_capacity_kg": 150, |
| "preferred_language": "en", |
| "vehicle_type": "PETROL" |
| }, |
| { |
| "id": "driver_002", |
| "name": "Kumar", |
| "vehicle_capacity_kg": 200, |
| "preferred_language": "ta", |
| "vehicle_type": "EV", |
| "ev_range_km": 120 |
| } |
| ] |
| } |
| ``` |
|
|
| #### Response |
|
|
| ```json |
| { |
| "allocation_run_id": "550e8400-e29b-41d4-a716-446655440000", |
| "date": "2026-02-10", |
| "status": "SUCCESS", |
| "global_fairness": { |
| "avg_workload": 63.2, |
| "std_dev": 5.4, |
| "gini_index": 0.12, |
| "max_gap": 8.3 |
| }, |
| "assignments": [ |
| { |
| "driver_id": "driver_001", |
| "driver_name": "Raju", |
| "route_id": "route_uuid", |
| "workload_score": 65.3, |
| "fairness_score": 0.92, |
| "route_summary": { |
| "num_packages": 22, |
| "total_weight_kg": 48.5, |
| "num_stops": 14, |
| "estimated_time_minutes": 145 |
| }, |
| "explanation": "Your route covers the Koramangala area with 22 packages, mostly residential. Expected completion time is around 2.5 hours with moderate traffic." |
| } |
| ], |
| "agent_events": [ |
| { |
| "agent": "clustering_agent", |
| "status": "completed", |
| "message": "Created 5 route clusters" |
| }, |
| { |
| "agent": "fairness_manager", |
| "status": "completed", |
| "message": "Allocation ACCEPTED (Gini: 0.12)" |
| } |
| ] |
| } |
| ``` |
|
|
| ### Additional Endpoints |
|
|
| | Method | Endpoint | Description | |
| |--------|----------|-------------| |
| | `GET` | `/api/v1/drivers/{id}` | Get driver details and stats | |
| | `GET` | `/api/v1/routes/{id}` | Get route details and packages | |
| | `POST` | `/api/v1/feedback` | Submit driver feedback | |
| | `GET` | `/api/v1/admin/dashboard` | Admin dashboard data | |
| | `GET` | `/api/v1/runs` | List allocation runs | |
| | `GET` | `/api/v1/runs/{id}/events` | Get agent events for a run | |
|
|
| ## π§ͺ Testing |
|
|
| ```bash |
| # Run all tests |
| make test |
| |
| # Run with coverage |
| make test-cov |
| |
| # Run specific test file |
| pytest tests/test_allocation.py -v |
| |
| # Run E2E tests only |
| make test-e2e |
| |
| # Run tests in parallel (faster) |
| pytest tests/ -n auto |
| ``` |
|
|
| ## βοΈ Configuration |
|
|
| ### Environment Variables |
|
|
| | Variable | Default | Description | |
| |----------|---------|-------------| |
| | `DATABASE_URL` | - | PostgreSQL connection string | |
| | `DEBUG` | `true` | Enable debug mode | |
| | `GOOGLE_API_KEY` | - | Gemini API key for explanations | |
| | `LANGCHAIN_TRACING_V2` | `false` | Enable LangSmith tracing | |
| | `LANGCHAIN_API_KEY` | - | LangSmith API key | |
|
|
| ### Workload Score Weights |
|
|
| | Variable | Default | Description | |
| |----------|---------|-------------| |
| | `WORKLOAD_WEIGHT_A` | `1.0` | Weight for num_packages | |
| | `WORKLOAD_WEIGHT_B` | `0.5` | Weight for total_weight_kg | |
| | `WORKLOAD_WEIGHT_C` | `10.0` | Weight for route_difficulty_score | |
| | `WORKLOAD_WEIGHT_D` | `0.2` | Weight for estimated_time_minutes | |
| |
| ### Fairness Thresholds |
| |
| | Variable | Default | Description | |
| |----------|---------|-------------| |
| | `TARGET_PACKAGES_PER_ROUTE` | `20` | Target packages per cluster | |
| | `GINI_THRESHOLD` | `0.25` | Max acceptable Gini index | |
| | `STD_DEV_THRESHOLD` | `15.0` | Max acceptable standard deviation | |
|
|
| ## π Algorithms |
|
|
| ### Workload Score Formula |
|
|
| ``` |
| workload_score = a Γ num_packages |
| + b Γ total_weight_kg |
| + c Γ route_difficulty_score |
| + d Γ estimated_time_minutes |
| ``` |
|
|
| ### Gini Index |
|
|
| Measures inequality in workload distribution (0 = perfect equality, 1 = maximum inequality): |
|
|
| ``` |
| G = (2 Γ Ξ£(i Γ x_i)) / (n Γ Ξ£x_i) - (n + 1) / n |
| ``` |
|
|
| ### Individual Fairness Score |
|
|
| Per-driver fairness relative to average: |
|
|
| ``` |
| fairness_score = 1 - |workload - avg_workload| / max(avg_workload, 1) |
| ``` |
|
|
| ## π Project Structure |
|
|
| ``` |
| fair-dispatch-system/ |
| βββ π alembic/ # Database migrations |
| β βββ versions/ # Migration files |
| βββ π app/ |
| β βββ π api/ # FastAPI routers |
| β β βββ allocation.py # POST /allocate (basic) |
| β β βββ allocation_langgraph.py # POST /langgraph/allocate |
| β β βββ admin.py # Admin endpoints |
| β β βββ drivers.py # Driver endpoints |
| β β βββ feedback.py # Feedback endpoints |
| β β βββ routes.py # Route endpoints |
| β βββ π models/ # SQLAlchemy models |
| β β βββ driver.py |
| β β βββ package.py |
| β β βββ route.py |
| β β βββ assignment.py |
| β βββ π schemas/ # Pydantic DTOs |
| β βββ π services/ # Business logic |
| β β βββ langgraph_workflow.py # Agent orchestration |
| β β βββ langgraph_nodes.py # Individual agents |
| β β βββ ml_effort_agent.py # ML scoring |
| β β βββ fairness_manager_agent.py |
| β β βββ route_planner_agent.py |
| β β βββ driver_liaison_agent.py |
| β β βββ learning_agent.py |
| β β βββ gemini_explain_node.py |
| β β βββ ... |
| β βββ config.py # Settings |
| β βββ database.py # DB connection |
| β βββ main.py # FastAPI app |
| βββ π frontend/ # Static frontend files |
| β βββ index.html # Demo UI |
| β βββ visualization.html # Live visualization |
| βββ π supply_chain_dashboard/ # Streamlit dashboard |
| β βββ dashboard.py |
| β βββ api_client.py |
| βββ π tests/ # Test suite |
| βββ .env.example |
| βββ requirements.txt |
| βββ Makefile |
| βββ README.md |
| ``` |
|
|
| ## π§ Development |
|
|
| ### Running in Development Mode |
|
|
| ```bash |
| # Start with auto-reload |
| uvicorn app.main:app --reload |
| |
| # Start with custom port |
| uvicorn app.main:app --reload --port 3000 |
| |
| # Start with debug logging |
| DEBUG=true uvicorn app.main:app --reload |
| ``` |
|
|
| ### Database Migrations |
|
|
| ```bash |
| # Create new migration |
| alembic revision --autogenerate -m "Add new table" |
| |
| # Apply migrations |
| alembic upgrade head |
| |
| # Rollback one version |
| alembic downgrade -1 |
| |
| # View migration history |
| alembic history |
| ``` |
|
|
| ### Makefile Commands |
|
|
| ```bash |
| make test # Run all tests |
| make test-cov # Run with coverage |
| make test-e2e # Run E2E tests |
| make test-parallel # Run tests in parallel |
| make lint # Run linting |
| make format # Format code |
| make ci # Full CI pipeline |
| ``` |
|
|
| ## π€ Contributing |
|
|
| 1. Fork the repository |
| 2. Create your feature branch (`git checkout -b feature/amazing-feature`) |
| 3. Commit your changes (`git commit -m 'Add amazing feature'`) |
| 4. Push to the branch (`git push origin feature/amazing-feature`) |
| 5. Open a Pull Request |
|
|
| ## π License |
|
|
| This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. |
|
|
| --- |
|
|
| <p align="center"> |
| Built with β€οΈ for fairer logistics |
| </p> |
|
|