from __future__ import annotations import asyncio import logging import sys from contextlib import asynccontextmanager from pathlib import Path from fastapi import ( FastAPI, Request, ) from fastapi.middleware.cors import ( CORSMiddleware, ) PROJECT_ROOT = Path(__file__).resolve().parents[1] if str(PROJECT_ROOT) not in sys.path: sys.path.insert( 0, str(PROJECT_ROOT), ) from app.routes import router from app.security import ( validate_security_configuration, ) from scripts.embedding_utils import embed_query logger = logging.getLogger(__name__) OPENWEBUI_ORIGIN = ( "https://ui.tukekemt.xyz" ) @asynccontextmanager async def lifespan( _: FastAPI, ): validate_security_configuration() try: await asyncio.to_thread( embed_query, "warmup", ) except Exception: logger.exception( "Predhriatie embedding modelu " "zlyhalo. API pokračuje bez " "úspešného warm-upu." ) yield app = FastAPI( title="ZP Agent API", description=( "RAG API pre vyhľadávanie " "a získavanie informácií " "z repozitára záverečných prác " "ZP Wiki." ), version="0.9.0", lifespan=lifespan, # Interaktívne Swagger/ReDoc rozhrania # nepotrebujeme vystavovať. # /openapi.json zostáva dostupné, # pretože ho používa OpenWebUI. docs_url=None, redoc_url=None, ) app.add_middleware( CORSMiddleware, allow_origins=[ OPENWEBUI_ORIGIN, ], allow_credentials=True, allow_methods=[ "GET", "POST", "OPTIONS", ], allow_headers=[ "Authorization", "Content-Type", "X-API-Key", ], allow_private_network=True, ) @app.middleware( "http" ) async def add_security_headers( request: Request, call_next, ): response = await call_next( request ) # API odpovede obsahujú retrieval kontext, # preto ich nechceme ukladať do cache. response.headers[ "Cache-Control" ] = "no-store" response.headers[ "X-Content-Type-Options" ] = "nosniff" response.headers[ "Referrer-Policy" ] = "no-referrer" response.headers[ "X-Frame-Options" ] = "DENY" return response app.include_router( router )