Spaces:
Running
Running
| """ | |
| FastAPI backend for the RAG pipeline. | |
| Requirements: | |
| pip install fastapi uvicorn[standard] | |
| Run with: | |
| uvicorn api:app --host 0.0.0.0 --port 8000 | |
| Then: | |
| curl -X POST http://localhost:8000/query \\ | |
| -H "Content-Type: application/json" \\ | |
| -d '{"query": "What is hallucination and cause?"}' | |
| The index (documents + FAISS + LLM + compressor) is built ONCE at | |
| startup via the "startup" event below, not per-request — pipeline_service | |
| caches it in module-level globals after the first _get_index() call, so | |
| every request after startup reuses it. | |
| """ | |
| from fastapi import FastAPI, HTTPException | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from pydantic import BaseModel, Field | |
| from pipeline_service import answer_query, _get_index | |
| app = FastAPI(title="Hybrid RAG API", version="1.0") | |
| # Adjust or remove this for production — wide open here for local dev | |
| # so a browser-based frontend on a different port can call the API. | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| class QueryRequest(BaseModel): | |
| query: str = Field(..., min_length=1, description="The user's question") | |
| class SourceInfo(BaseModel): | |
| source: str | None = None | |
| section: str | None = None | |
| page: int | None = None | |
| rerank_score: float | None = None | |
| class QueryResponse(BaseModel): | |
| query: str | |
| route: str | |
| answer: str | |
| cited_answer: str | |
| passed: bool | |
| decision: str | |
| attempts: int | |
| metrics: dict | |
| checks: dict | |
| sources: list[SourceInfo] | |
| citations: list | |
| hallucination_report: dict | |
| verification_report: dict | |
| def startup_event(): | |
| """ | |
| Build the index once when the server process starts, so the first | |
| real request doesn't pay for document loading + FAISS indexing + | |
| model loading. Subsequent requests reuse the cached index. | |
| """ | |
| _get_index() | |
| def health(): | |
| return {"status": "ok"} | |
| def query(request: QueryRequest): | |
| try: | |
| result = answer_query(request.query) | |
| except Exception as exc: | |
| raise HTTPException(status_code=500, detail=str(exc)) | |
| return result | |