"""Typované výjimky + centrální exception handlery. Platí pravidlo: žádná tichá selhání — každá chyba se loguje (bez secrets). """ from fastapi import FastAPI, Request from fastapi.responses import JSONResponse from .logging_config import get_logger log = get_logger("audio-transcription.errors") class TranscriptionError(Exception): """Základní chyba služby s HTTP status kódem.""" status_code = 500 def __init__(self, message: str, status_code: int | None = None, detail=None): super().__init__(message) self.message = message if status_code is not None: self.status_code = status_code self.detail = detail class CredentialsError(TranscriptionError): """Chybějící / neplatné přihlašovací údaje (X- hlavičky).""" status_code = 401 class BadRequestError(TranscriptionError): """Neplatný vstup (chybí audio, špatné parametry).""" status_code = 400 class UpstreamError(TranscriptionError): """Chyba při volání upstream API (Deepgram / OpenAI / stažení audia).""" status_code = 502 def register_exception_handlers(app: FastAPI) -> None: @app.exception_handler(TranscriptionError) async def _handle_transcription_error(request: Request, exc: TranscriptionError): log.warning( "%s on %s: %s", exc.__class__.__name__, request.url.path, exc.message, ) body = {"error": exc.__class__.__name__, "message": exc.message} if exc.detail is not None: body["detail"] = exc.detail return JSONResponse(status_code=exc.status_code, content=body) @app.exception_handler(Exception) async def _handle_unexpected(request: Request, exc: Exception): # Nelogujeme celý stack s možnými secrets ve vstupu; logujeme typ + zprávu. log.error( "Unhandled %s on %s: %s", exc.__class__.__name__, request.url.path, exc, ) return JSONResponse( status_code=500, content={"error": "InternalError", "message": "Neočekávaná chyba serveru."}, )