FairRelay / brain /README.md
MouleeswaranM's picture
Upload folder using huggingface_hub
fcf8749 verified

🚚 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

# 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

# Copy example environment file
cp .env.example .env

# Edit .env with your configuration

Essential environment variables:

# 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

# Create PostgreSQL database
createdb fair_dispatch

# Run migrations
alembic upgrade head

4. Start the Server

# Development server with hot reload
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

5. Access the System

πŸ“Š Visualization Dashboard

The system includes a real-time Streamlit dashboard for monitoring allocations:

# 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

{
  "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

{
  "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

# 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

# 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

# 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

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 file for details.


Built with ❀️ for fairer logistics