Spaces:
Runtime error
Runtime error
| """ | |
| api.py — FastAPI web server for YT RAG Chat. | |
| Run: python api.py (or: uvicorn api:app --host 0.0.0.0 --port 8000) | |
| Then open: http://localhost:8000 | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import uuid | |
| from contextlib import asynccontextmanager | |
| from fastapi import FastAPI, HTTPException | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.responses import FileResponse, StreamingResponse | |
| from fastapi.staticfiles import StaticFiles | |
| from pydantic import BaseModel | |
| from rag_core import RAGEngine, VideoSession | |
| # ============================================================ | |
| # App lifecycle — engine & sessions | |
| # ============================================================ | |
| engine: RAGEngine | None = None | |
| sessions: dict[str, VideoSession] = {} | |
| async def lifespan(app: FastAPI): | |
| global engine | |
| print("Loading models...") | |
| engine = RAGEngine() | |
| print("Models ready. Server up at http://localhost:8000") | |
| yield | |
| sessions.clear() | |
| app = FastAPI(title="YT RAG Chat", lifespan=lifespan) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| app.mount("/static", StaticFiles(directory="static"), name="static") | |
| # ============================================================ | |
| # Schemas | |
| # ============================================================ | |
| class ProcessRequest(BaseModel): | |
| url: str | |
| class AskRequest(BaseModel): | |
| session_id: str | |
| query: str | |
| # ============================================================ | |
| # SSE helpers | |
| # ============================================================ | |
| _SSE_HEADERS = { | |
| "Cache-Control": "no-cache", | |
| "X-Accel-Buffering": "no", | |
| "Connection": "keep-alive", | |
| } | |
| def sse(data: dict) -> str: | |
| return f"data: {json.dumps(data, ensure_ascii=False)}\n\n" | |
| # ============================================================ | |
| # Routes | |
| # ============================================================ | |
| async def root(): | |
| return FileResponse("static/index.html") | |
| async def process_video(body: ProcessRequest): | |
| session_id = str(uuid.uuid4()) | |
| def stream(): | |
| try: | |
| for event in engine.process_video(body.url): | |
| if event["type"] == "session": | |
| s = event["session"] | |
| sessions[session_id] = s | |
| yield sse({ | |
| "type": "ready", | |
| "session_id": session_id, | |
| "video_title": s.video_title, | |
| "video_id": s.video_id, | |
| "chunk_count": len(s.documents), | |
| }) | |
| else: | |
| yield sse(event) | |
| except Exception as exc: | |
| yield sse({"type": "error", "message": str(exc)}) | |
| return StreamingResponse(stream(), media_type="text/event-stream", headers=_SSE_HEADERS) | |
| async def ask(body: AskRequest): | |
| session = sessions.get(body.session_id) | |
| if not session: | |
| def not_found(): | |
| yield sse({"type": "error", "message": "Session not found. Please process a video first."}) | |
| return StreamingResponse(not_found(), media_type="text/event-stream", headers=_SSE_HEADERS) | |
| def stream(): | |
| try: | |
| for event in engine.answer_query(session, body.query): | |
| yield sse(event) | |
| except Exception as exc: | |
| yield sse({"type": "error", "message": str(exc)}) | |
| return StreamingResponse(stream(), media_type="text/event-stream", headers=_SSE_HEADERS) | |
| async def get_session_info(session_id: str): | |
| s = sessions.get(session_id) | |
| if not s: | |
| raise HTTPException(status_code=404, detail="Session not found") | |
| return {"video_id": s.video_id, "video_title": s.video_title, "chunk_count": len(s.documents)} | |
| async def delete_session(session_id: str): | |
| sessions.pop(session_id, None) | |
| return {"ok": True} | |
| if __name__ == "__main__": | |
| import os | |
| import uvicorn | |
| port = int(os.getenv("PORT", "8000")) | |
| uvicorn.run("api:app", host="0.0.0.0", port=port, reload=False) | |