🚚 Fair Dispatch System

Single‑API Fair Routing Β· Angelic Fairness Engine Β· Live Agent Visualization

Quick Start β€’ Features β€’ Architecture β€’ API Reference β€’ Dashboard

--- 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. ---

Built with ❀️ for fairer logistics