Spaces:
Sleeping
Sleeping
File size: 3,879 Bytes
b62e029 cda6eee b62e029 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | # main.py
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.responses import RedirectResponse
from starlette.middleware.cors import CORSMiddleware
from api.v1 import search, system
from core.config import settings
from core.exceptions import setup_exception_handlers
from core.logger import setup_logger
from models.embedder import TextEmbedder
from models.reranker import TextReranker
from services.search_service import HybridSearchService
from storage.qdrant_client import QdrantStorage
from storage.sqlite_client import SQLiteStorage
logger = setup_logger("knowledge_engine")
@asynccontextmanager
async def lifespan(app: FastAPI):
"""
FastAPI Lifespan function to manage startup and shutdown events.
On startup, it initializes all necessary components (DB connections, models, services) and injects them into the app state.
On shutdown, it ensures that all resources are properly cleaned up (e.g., closing DB connections).
- This approach centralizes all initialization logic in one place, making it easier to manage dependencies and handle errors during startup.
- If any critical error occurs during startup, it logs the error and prevents the server from starting in an unstable state.
"""
logger.info("π Starting Knowledge Engine API...")
qdrant_client = None
sqlite_client = None
try:
# 1. Infrastructure Connection (Database)
qdrant_client = QdrantStorage(url=settings.QDRANT_URL, collection_name=settings.QDRANT_COLLECTION)
sqlite_client = SQLiteStorage(db_path=settings.SQLITE_PATH)
# 2. Load AI Model (Singleton)
embedder = TextEmbedder(model_name=settings.EMBEDDER_NAME, use_fp16=True)
reranker = TextReranker(model_name=settings.RERANKER_NAME)
# 3. Business Service Orchestration (Instantiate the HybridSearchService with all dependencies)
search_service = HybridSearchService(
qdrant=qdrant_client,
sqlite=sqlite_client,
embedder=embedder,
reranker=reranker
)
# 4. Injecting services into FastAPI app state for global accessibility in routers
app.state.search_service = search_service
logger.info("β
All services and models initialized successfully.")
yield # --- From this point, the server starts receiving traffic ---
except Exception as e:
logger.critical(f"β Application failed to start: {e}", exc_info=True)
raise e
finally:
logger.info("π Shutting down. Cleaning up resources...")
# Safe termination of DB connections, etc.
if qdrant_client is not None: qdrant_client.close()
if sqlite_client is not None: sqlite_client.close()
logger.info("Resources cleaned up.")
# ---------------------------
# FastAPI Instance Creation
# ---------------------------
app = FastAPI(
title="Hybrid RAG Knowledge Engine API",
description="Qdrant and BGE-M3-based high-performance hybrid search engine API",
version="0.1.0",
lifespan=lifespan
)
# CORS Setup
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Mount static files (CSS, JS, etc.) if needed (e.g., for demo pages)
# app.mount("/static", StaticFiles(directory="static"), name="static")
# ---------------------------
# Router Registration
# ---------------------------
app.include_router(system.router, prefix="/api/v1")
app.include_router(search.router, prefix="/api/v1")
@app.get("/", include_in_schema=False)
async def root():
return RedirectResponse(url="/api/v1/search/demo")
# -----------------------------------
# Register global exception handlers
# -----------------------------------
setup_exception_handlers(app) |