1- from fastapi import FastAPI , HTTPException
1+ from fastapi import FastAPI , HTTPException , Depends
22from pydantic import BaseModel
33from src .services .chroma import ChromaService
4- from src .pipeline .ingestion import IngestionWorkflow
54from src .pipeline .retrieval import RetrievalWorkflow
65from src .config .settings import settings
76from src .utils .logger import logger
7+ from src .db .session import SessionLocal , get_db
8+ from src .models .db import IngestionJob
9+ from src .worker import queue
810import os
911from contextlib import asynccontextmanager
12+ from sqlalchemy .orm import Session
1013
1114# Global variables for chroma service and workflow
1215chroma_service = None
@@ -17,19 +20,13 @@ async def lifespan(app: FastAPI):
1720 global chroma_service , retrieval_wf
1821
1922 try :
20- ingestion_wf = IngestionWorkflow ()
21-
22- if os .path .exists (settings .data_dir ) and os .listdir (settings .data_dir ):
23- logger .info (f"Initializing ingestion from { settings .data_dir } ..." )
24- # ingestion_wf.run returns chroma_service (StopEvent result)
25- chroma_service = await ingestion_wf .run (input_dir = settings .data_dir )
26- retrieval_wf = RetrievalWorkflow (chroma_service = chroma_service )
27- logger .info ("API Startup: Ingestion complete and Chroma Cloud index ready." )
28- else :
29- logger .warning (f"Data directory '{ settings .data_dir } ' is empty or missing. API in degraded mode." )
23+ # Initialize search infrastructure on startup
24+ chroma_service = ChromaService ()
25+ retrieval_wf = RetrievalWorkflow (chroma_service = chroma_service )
26+ logger .info ("API Startup: Chroma Cloud retrieval ready." )
3027 except Exception as e :
3128 logger .error (f"Startup failed: { e } " )
32- logger .warning ("API starting in degraded mode due to infrastructure or ingestion error." )
29+ logger .warning ("API starting in degraded mode due to infrastructure error." )
3330
3431 yield
3532
@@ -42,9 +39,48 @@ class QueryResponse(BaseModel):
4239 answer : str
4340 from_cache : bool
4441
42+ class IngestResponse (BaseModel ):
43+ job_id : str
44+
45+ class JobStatusResponse (BaseModel ):
46+ id : str
47+ status : str
48+
4549@app .get ("/health" )
4650async def health ():
47- return {"status" : "ok" , "index_ready" : chroma_service is not None }
51+ return {"status" : "ok" , "retrieval_ready" : retrieval_wf is not None }
52+
53+ @app .post ("/ingest" , response_model = IngestResponse , status_code = 202 )
54+ async def ingest_docs (db : Session = Depends (get_db )):
55+ """
56+ Trigger document ingestion as a background job.
57+ """
58+ try :
59+ # Create a job record in Postgres
60+ job = IngestionJob (status = "PENDING" )
61+ db .add (job )
62+ db .commit ()
63+ db .refresh (job )
64+
65+ # Enqueue the background task
66+ queue .enqueue ("src.jobs.ingestion.process_ingestion" , str (job .id ))
67+
68+ logger .info (f"Ingestion job { job .id } enqueued." )
69+ return IngestResponse (job_id = str (job .id ))
70+ except Exception as e :
71+ logger .error (f"Failed to enqueue ingestion job: { e } " )
72+ raise HTTPException (status_code = 500 , detail = "Failed to trigger ingestion." )
73+
74+ @app .get ("/jobs/{job_id}" , response_model = JobStatusResponse )
75+ async def get_job_status (job_id : str , db : Session = Depends (get_db )):
76+ """
77+ Check the status of an ingestion job.
78+ """
79+ job = db .query (IngestionJob ).filter (IngestionJob .id == job_id ).first ()
80+ if not job :
81+ raise HTTPException (status_code = 404 , detail = "Job not found." )
82+
83+ return JobStatusResponse (id = str (job .id ), status = job .status )
4884
4985@app .post ("/query" , response_model = QueryResponse )
5086async def query_docs (request : QueryRequest ):
0 commit comments