# app/app.py 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.faiss_store import FaissVectorStore from app.core.vector_store.embedder.factory import get_embedder_from_config from app.core.providers.factory import get_tts_provider, get_stt_provider from app.core.retrievers.faiss_db_retriever import FaissDBRetriever from app.core.retrievers.base_retriever import Retriever from app.db.session import create_db_and_tables from app.api.routes.api import create_api_router from app.utils import print_config from app.api.dependencies import ServiceContainer from app.core.services.tts import TTSService from app.core.services.stt import STTService # NEW: Added the missing import for STTService # Note: The llm_clients import and initialization are removed as they # are not used in RAGService's constructor based on your services.py # from app.core.llm_clients import DeepSeekClient, GeminiClient @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 --- # 1. Use the new, more flexible factory function to create the embedder instance # This decouples the application from a specific embedding provider. embedder = get_embedder_from_config( provider=settings.EMBEDDING_PROVIDER, dimension=settings.EMBEDDING_DIMENSION, model_name=settings.EMBEDDING_MODEL_NAME, api_key=settings.EMBEDDING_API_KEY ) # 2. Initialize the FaissVectorStore with the chosen embedder vector_store = FaissVectorStore( index_file_path=settings.FAISS_INDEX_PATH, dimension=settings.EMBEDDING_DIMENSION, embedder=embedder # Pass the instantiated embedder object, ) # CRITICAL FIX: Assign the vector_store to the app state so it can be saved on shutdown. app.state.vector_store = vector_store # 3. Create the FaissDBRetriever, regardless of the embedder type retrievers: List[Retriever] = [ FaissDBRetriever(vector_store=vector_store), ] # --- New TTS Initialization --- # 4. Get the concrete TTS provider from the factory tts_provider = get_tts_provider( provider_name=settings.TTS_PROVIDER, api_key=settings.TTS_API_KEY, voice_name=settings.TTS_VOICE_NAME ) # 5. Initialize the TTSService tts_service = TTSService(tts_provider=tts_provider) # 6. Get the concrete STT provider from the factory stt_provider = get_stt_provider( provider_name=settings.STT_PROVIDER, api_key=settings.STT_API_KEY, model_name=settings.STT_MODEL_NAME ) # 7. Initialize the STTService stt_service = STTService(stt_provider=stt_provider) # 8. Initialize the Service Container with all services # This replaces the previous, redundant initialization services = ServiceContainer( vector_store=vector_store, retrievers=retrievers, tts_service=tts_service, stt_service=stt_service # NEW: Pass the new STT service instance ) # Create and include the API router, injecting the service api_router = create_api_router(services=services) app.include_router(api_router) return app