from fastapi import FastAPI from contextlib import asynccontextmanager from typing import List # Import centralized settings and other components from app.config import settings from app.core.vector_store import FaissVectorStore from app.core.retrievers import FaissDBRetriever, Retriever from app.core.services import RAGService from app.db.session import create_db_and_tables from app.api.routes import create_api_router from app.utils import print_config @asynccontextmanager async def lifespan(app: FastAPI): """ Manages application startup and shutdown events. - On startup, it creates database tables. - On shutdown, it saves the FAISS index to disk. """ print("Application startup...") print_config(settings) create_db_and_tables() yield print("Application shutdown...") # Access the vector_store from the application state to save it if hasattr(app.state, 'vector_store'): app.state.vector_store.save_index() def create_app() -> FastAPI: """ Factory function to create and configure the FastAPI application. This encapsulates all setup logic, making the main entry point clean. """ app = FastAPI( # Use metadata from the central settings title=settings.PROJECT_NAME, version=settings.VERSION, description="A modular API to route requests to various LLMs with RAG capabilities.", lifespan=lifespan ) # --- Initialize Core Services using settings --- # Store services on the app.state object for easy access, e.g., in the lifespan manager. app.state.vector_store = FaissVectorStore( index_file_path=settings.FAISS_INDEX_PATH, dimension=settings.EMBEDDING_DIMENSION ) retrievers: List[Retriever] = [ FaissDBRetriever(vector_store=app.state.vector_store), ] rag_service = RAGService( vector_store=app.state.vector_store, retrievers=retrievers ) # Create and include the API router, injecting the service api_router = create_api_router(rag_service=rag_service) app.include_router(api_router) return app