Files
MobilityOps/backend/app/main.py
T
NuklearRabbit b511ba2dbc M5: implement RAGcore knowledge integration
KnowledgeProvider protocol with a deterministic TF-IDF-weighted extractive demo provider (never generative, always cites real excerpts) and a RAGcore HTTP adapter that degrades cleanly to unavailable. Knowledge nav + chat-style Q&A UI with source cards and honest grounded/insufficient/unavailable states. 57 backend tests passing, ruff clean. Fixed a real relevance bug (generic terms like "vehicle" crowding out distinctive matches) via IDF weighting, found by testing the actual S6 scenario. Verified end-to-end in the browser: grounded damage question cites both expected procedures; unrelated question honestly returns insufficient evidence with no fabrication.
2026-08-01 22:57:06 +02:00

89 lines
2.3 KiB
Python

import uuid
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from app.api.routers import (
audit,
bookings,
dashboard,
data_quality,
demo,
integrations,
knowledge,
vehicles,
workflows,
)
from app.core.config import get_settings
from app.core.errors import AppError, error_body
from app.services.dispatcher import start_background_dispatcher, stop_background_dispatcher
settings = get_settings()
@asynccontextmanager
async def lifespan(_app: FastAPI):
start_background_dispatcher()
yield
stop_background_dispatcher()
app = FastAPI(title="MobilityOps API", version="0.1.0", lifespan=lifespan)
app.add_middleware(
CORSMiddleware,
allow_origins=[o.strip() for o in settings.cors_allow_origins.split(",")],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.exception_handler(AppError)
def handle_app_error(_request: Request, exc: AppError) -> JSONResponse:
return JSONResponse(
status_code=exc.status_code,
content=error_body(exc.code, exc.message, exc.correlation_id, exc.details),
)
@app.exception_handler(HTTPException)
def handle_http_exception(_request: Request, exc: HTTPException) -> JSONResponse:
return JSONResponse(
status_code=exc.status_code,
content=error_body(
code=str(exc.status_code),
message=str(exc.detail),
correlation_id=str(uuid.uuid4()),
details={},
),
)
@app.get("/health")
def health() -> dict[str, str]:
return {"status": "ok", "service": "mobilityops-api"}
@app.get("/api/v1/system/status")
def system_status() -> dict[str, object]:
return {
"service": "mobilityops-api",
"environment": settings.mobilityops_env,
"demo_mode": settings.mobilityops_demo_mode,
"knowledge_provider": settings.knowledge_provider,
}
app.include_router(demo.router)
app.include_router(dashboard.router)
app.include_router(vehicles.router)
app.include_router(bookings.router)
app.include_router(audit.router)
app.include_router(data_quality.router)
app.include_router(workflows.router)
app.include_router(integrations.router)
app.include_router(knowledge.router)