FairRelay / brain /README.md
MouleeswaranM's picture
Upload folder using huggingface_hub
fcf8749 verified
<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>