|
1 | 1 | from fastapi import FastAPI, Request, Form |
2 | | -from fastapi.responses import HTMLResponse |
| 2 | +from fastapi.responses import HTMLResponse, JSONResponse |
3 | 3 | from fastapi.staticfiles import StaticFiles |
4 | 4 | from fastapi.templating import Jinja2Templates |
5 | 5 | from project.pipeline.agents import AgentWorkflow |
6 | 6 | from project.logger.logging import get_logger |
7 | 7 | import uvicorn |
| 8 | +import asyncio |
| 9 | +from contextlib import asynccontextmanager |
8 | 10 |
|
9 | 11 | logger = get_logger(__name__) |
10 | 12 |
|
11 | | -app = FastAPI(title="Learn with Transformers") |
| 13 | +# Global initialization state |
| 14 | +agent = None |
| 15 | +initialization_complete = False |
| 16 | +initialization_error = None |
| 17 | + |
| 18 | + |
| 19 | +async def initialize_rag_pipeline(): |
| 20 | + """Background task to initialize RAG pipeline""" |
| 21 | + global agent, initialization_complete, initialization_error |
| 22 | + try: |
| 23 | + logger.info("Initializing RAG pipeline in background...") |
| 24 | + agent = AgentWorkflow() |
| 25 | + agent.setup(use_attention_paper=True) |
| 26 | + initialization_complete = True |
| 27 | + logger.info("RAG pipeline ready") |
| 28 | + except Exception as e: |
| 29 | + initialization_error = str(e) |
| 30 | + logger.error(f"Initialization failed: {e}") |
| 31 | + initialization_complete = True |
| 32 | + |
| 33 | + |
| 34 | +@asynccontextmanager |
| 35 | +async def lifespan(app: FastAPI): |
| 36 | + """App lifecycle manager - returns immediately, initializes in background""" |
| 37 | + # Startup |
| 38 | + logger.info("App starting up - launching background initialization") |
| 39 | + asyncio.create_task(initialize_rag_pipeline()) |
| 40 | + yield |
| 41 | + # Shutdown |
| 42 | + logger.info("App shutting down") |
| 43 | + |
| 44 | + |
| 45 | +app = FastAPI(title="Learn with Transformers", lifespan=lifespan) |
12 | 46 |
|
13 | 47 | app.mount("/static", StaticFiles(directory="static"), name="static") |
14 | 48 | templates = Jinja2Templates(directory="templates") |
15 | 49 |
|
16 | | -agent = None |
17 | 50 |
|
| 51 | +@app.get("/health") |
| 52 | +async def health(): |
| 53 | + """Liveness probe - returns immediately (HF Spaces requirement)""" |
| 54 | + return JSONResponse({"status": "alive"}, status_code=200) |
18 | 55 |
|
19 | | -@app.on_event("startup") |
20 | | -async def startup_event(): |
21 | | - global agent |
22 | | - logger.info("Initializing RAG pipeline...") |
23 | | - agent = AgentWorkflow() |
24 | | - agent.setup(use_attention_paper=True) |
25 | | - logger.info("RAG pipeline ready") |
| 56 | + |
| 57 | +@app.get("/ready") |
| 58 | +async def readiness(): |
| 59 | + """Readiness probe - checks if initialization complete""" |
| 60 | + if initialization_error: |
| 61 | + return JSONResponse( |
| 62 | + {"status": "failed", "error": initialization_error}, |
| 63 | + status_code=503 |
| 64 | + ) |
| 65 | + if not initialization_complete: |
| 66 | + return JSONResponse( |
| 67 | + {"status": "initializing"}, |
| 68 | + status_code=503 |
| 69 | + ) |
| 70 | + return JSONResponse({"status": "ready"}, status_code=200) |
26 | 71 |
|
27 | 72 |
|
28 | 73 | @app.get("/", response_class=HTMLResponse) |
29 | 74 | async def home(request: Request): |
| 75 | + if not initialization_complete: |
| 76 | + return templates.TemplateResponse( |
| 77 | + "index.html", |
| 78 | + {"request": request, "message": "System initializing... Please wait"} |
| 79 | + ) |
| 80 | + if initialization_error: |
| 81 | + return templates.TemplateResponse( |
| 82 | + "index.html", |
| 83 | + {"request": request, "error": f"Initialization failed: {initialization_error}"} |
| 84 | + ) |
30 | 85 | return templates.TemplateResponse("index.html", {"request": request}) |
31 | 86 |
|
32 | 87 |
|
33 | 88 | @app.post("/search", response_class=HTMLResponse) |
34 | 89 | async def search(request: Request, query: str = Form(...)): |
| 90 | + if initialization_error: |
| 91 | + return templates.TemplateResponse( |
| 92 | + "index.html", |
| 93 | + {"request": request, "error": f"System error: {initialization_error}"} |
| 94 | + ) |
| 95 | + |
| 96 | + if not initialization_complete: |
| 97 | + return templates.TemplateResponse( |
| 98 | + "index.html", |
| 99 | + {"request": request, "error": "System still initializing. Please try again in a moment"} |
| 100 | + ) |
| 101 | + |
35 | 102 | if not query.strip(): |
36 | 103 | return templates.TemplateResponse( |
37 | 104 | "index.html", |
|
0 commit comments