import logging from contextlib import asynccontextmanager from pathlib import Path from fastapi import FastAPI from fastapi.responses import FileResponse, JSONResponse from fastapi.staticfiles import StaticFiles from starlette.types import Scope from app.api.jobs import router as jobs_router from app.core.config import settings from app.core.db import init_db from app.core.mac_client import MacClient class NoCacheStaticFiles(StaticFiles): """StaticFiles, die Browser zu Revalidierung zwingen (verhindert hängende Caches nach Deploy).""" async def get_response(self, path: str, scope: Scope): response = await super().get_response(path, scope) response.headers["Cache-Control"] = "no-cache, must-revalidate" return response logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s") log = logging.getLogger("voice-agent") @asynccontextmanager async def lifespan(app: FastAPI): init_db() log.info("DB initialized at %s", settings.db_url) log.info("Upload dir: %s", settings.upload_dir) log.info("Result dir: %s", settings.result_dir) log.info("Mac API: %s", settings.mac_api_url) yield app = FastAPI(title=settings.app_name, lifespan=lifespan) app.include_router(jobs_router) STATIC_DIR = Path(__file__).resolve().parent / "static" app.mount("/static", NoCacheStaticFiles(directory=STATIC_DIR), name="static") @app.get("/") def index(): return FileResponse(STATIC_DIR / "index.html", headers={"Cache-Control": "no-cache, must-revalidate"}) @app.get("/health") def health(): return {"status": "ok", "service": settings.app_name} @app.get("/api/mac/health") async def mac_health(): try: data = await MacClient().health() return {"reachable": True, "mac": data} except Exception as e: # noqa: BLE001 return JSONResponse(status_code=502, content={"reachable": False, "error": str(e)})