import asyncio import logging import os from contextlib import asynccontextmanager from alembic import command from alembic.config import Config as AlembicConfig from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from config import settings from services.embeddings import EmbeddingService from services.llm_client import LLMClient from services.vectorstore import VectorStoreService logger = logging.getLogger(__name__) embedding_service: EmbeddingService | None = None vectorstore_service: VectorStoreService | None = None llm_client: LLMClient | None = None def _run_migrations() -> None: """Автоматически подтягиваем схему до последней ревизии при старте.""" os.makedirs(os.path.dirname(settings.sqlite_path), exist_ok=True) cfg = AlembicConfig("alembic.ini") command.upgrade(cfg, "head") @asynccontextmanager async def lifespan(app: FastAPI): global embedding_service, vectorstore_service, llm_client logging.basicConfig(level=getattr(logging, settings.log_level.upper(), logging.INFO)) logger.info("Running DB migrations…") await asyncio.to_thread(_run_migrations) logger.info("Loading embedding model: %s", settings.embedding_model) embedding_service = EmbeddingService(settings.embedding_model) logger.info("Embedding model loaded") vectorstore_service = VectorStoreService( persist_dir=settings.chroma_persist_dir, embedding_service=embedding_service, ) logger.info("ChromaDB initialized at %s", settings.chroma_persist_dir) llm_client = LLMClient() logger.info("LLM client ready (model=%s)", llm_client.model) yield logger.info("Shutting down") app = FastAPI( title="Chat Agent for Patients — Tuning Tool", description="RAG-ядро и инструмент настройки пациентского чат-агента", version="0.1.0", lifespan=lifespan, ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) from routers import chat, documents, health, query, threads # noqa: E402 app.include_router(health.router) app.include_router(documents.router) app.include_router(query.router) app.include_router(chat.router) app.include_router(threads.router) app.mount("/", StaticFiles(directory="static", html=True), name="static")