FairRelay / brain /app /api /consolidation.py
MouleeswaranM's picture
Upload folder using huggingface_hub
fcf8749 verified
raw
history blame
3.8 kB
"""
API endpoints for AI Load Consolidation.
POST /consolidate β€” Run consolidation (LangGraph multi-agent pipeline)
POST /consolidate/sync β€” Run consolidation (synchronous fallback)
POST /consolidate/simulate β€” Compare multiple scenarios
"""
from typing import List
from uuid import uuid4
from fastapi import APIRouter, HTTPException
from app.schemas.consolidation import (
ConsolidationRequest,
SimulationRequest,
ConsolidationResult,
)
from app.services.consolidation_engine import run_consolidation_pipeline
router = APIRouter(prefix="/consolidate", tags=["Consolidation"])
@router.post("", response_model=ConsolidationResult)
async def consolidate(req: ConsolidationRequest):
"""
Run AI Load Consolidation through the 5-agent LangGraph pipeline.
Agents executed in order:
1. GeoClusteringAgent β€” geographic proximity clustering
2. TimeWindowAgent β€” time-window compatibility filtering
3. CapacityOptimizationAgent β€” FFD bin-packing
4. ScoringConfidenceAgent β€” AI confidence + optimization score
5. ContinuousLearningAgent β€” actionable insights
"""
if not req.shipments:
raise HTTPException(400, "shipments array must not be empty")
if not req.trucks:
raise HTTPException(400, "trucks array must not be empty")
shipments = [s.model_dump() for s in req.shipments]
trucks = [t.model_dump() for t in req.trucks]
options = req.options.model_dump()
try:
from app.services.consolidation_workflow import invoke_consolidation_workflow
result = await invoke_consolidation_workflow(
shipments=shipments,
trucks=trucks,
options=options,
thread_id=str(uuid4()),
)
except Exception as e:
# Fallback to synchronous pipeline if LangGraph fails
print(f"LangGraph consolidation failed ({e}), using sync pipeline")
result = run_consolidation_pipeline(shipments, trucks, options)
return ConsolidationResult(**result)
@router.post("/sync", response_model=ConsolidationResult)
async def consolidate_sync(req: ConsolidationRequest):
"""
Run consolidation using the synchronous multi-agent pipeline (no LangGraph).
Useful for environments without LangGraph installed.
"""
if not req.shipments:
raise HTTPException(400, "shipments array must not be empty")
if not req.trucks:
raise HTTPException(400, "trucks array must not be empty")
shipments = [s.model_dump() for s in req.shipments]
trucks = [t.model_dump() for t in req.trucks]
options = req.options.model_dump()
result = run_consolidation_pipeline(shipments, trucks, options)
return ConsolidationResult(**result)
@router.post("/simulate")
async def simulate_scenarios(req: SimulationRequest):
"""
Compare multiple consolidation strategies side-by-side.
Returns results for each scenario and a recommendation.
"""
if not req.shipments or not req.trucks:
raise HTTPException(400, "shipments and trucks arrays required")
if not req.scenarios:
raise HTTPException(400, "at least one scenario required")
shipments = [s.model_dump() for s in req.shipments]
trucks = [t.model_dump() for t in req.trucks]
results = []
for sc in req.scenarios:
opts = {
"maxGroupRadiusKm": sc.maxGroupRadiusKm,
"timeWindowToleranceMinutes": sc.timeWindowToleranceMinutes,
"scenarioName": sc.name,
}
r = run_consolidation_pipeline(shipments, trucks, opts)
results.append({"name": sc.name, **r})
best = max(results, key=lambda r: r["metrics"]["optimizationScore"])
return {
"scenarios": results,
"recommendation": best["name"],
}