""" Custom exceptions for the Document Translation API """ from typing import Any, Dict, Optional class TranslationError(Exception): """ Base exception for translation errors. Includes an error code and optional details for structured JSON responses. """ def __init__( self, message: str, code: str = "TRANSLATION_ERROR", details: Optional[Dict[str, Any]] = None, ): self.message = message self.code = code self.details = details or {} super().__init__(message) class UnsupportedFileTypeError(TranslationError): """Raised when an unsupported file type is provided""" def __init__( self, message: str = "Format de fichier non supporté.", details: Optional[Dict[str, Any]] = None, ): super().__init__(message, code="INVALID_FORMAT", details=details) class FileSizeLimitExceededError(TranslationError): """Raised when a file exceeds the size limit""" def __init__( self, message: str = "Fichier trop volumineux.", details: Optional[Dict[str, Any]] = None, ): super().__init__(message, code="FILE_TOO_LARGE", details=details) class LanguageNotSupportedError(TranslationError): """Raised when a language code is not supported""" def __init__( self, message: str = "Langue non supportée.", details: Optional[Dict[str, Any]] = None, ): super().__init__(message, code="INVALID_FORMAT", details=details) class DocumentProcessingError(TranslationError): """Raised when there's an error processing the document""" def __init__( self, message: str = "Erreur lors du traitement du document.", details: Optional[Dict[str, Any]] = None, ): super().__init__(message, code="INTERNAL_ERROR", details=details) class TranslationProviderError(TranslationError): """Raised when a translation provider returns a structured error.""" def __init__( self, error_code: str, message: str, details: Optional[Dict[str, Any]] = None ): super().__init__(message, code=error_code, details=details) class GlossaryNotFoundError(TranslationError): """Raised when a glossary is not found or doesn't belong to the user. Story 3.10: Glossaires - Application lors Traduction LLM """ def __init__( self, message: str = "Glossaire introuvable ou vous n'avez pas accès à cette ressource.", details: Optional[Dict[str, Any]] = None, ): super().__init__(message, code="GLOSSARY_NOT_FOUND", details=details) class PromptNotFoundError(TranslationError): """Raised when a prompt is not found or doesn't belong to the user. Story 3.12: Custom Prompts - Application lors Traduction LLM """ def __init__( self, message: str = "Prompt introuvable ou vous n'avez pas accès à cette ressource.", details: Optional[Dict[str, Any]] = None, ): super().__init__(message, code="PROMPT_NOT_FOUND", details=details) # Map provider error codes to HTTP status (Story 2.2, 2.3, 2.6) _PROVIDER_ERROR_HTTP_STATUS = { "GOOGLE_QUOTA_EXCEEDED": 429, "GOOGLE_INVALID_KEY": 401, "GOOGLE_NETWORK_ERROR": 502, "GOOGLE_UNSUPPORTED_LANGUAGE": 400, "GOOGLE_TEXT_TOO_LONG": 413, "DEEPL_QUOTA_EXCEEDED": 429, "DEEPL_INVALID_KEY": 401, "DEEPL_NETWORK_ERROR": 502, "DEEPL_UNSUPPORTED_LANGUAGE": 400, "DEEPL_TEXT_TOO_LONG": 413, "ALL_PROVIDERS_FAILED": 502, } def handle_translation_error(error: TranslationError) -> tuple[dict, int]: """ Handle a translation error and return a tuple of (response_body, status_code). Args: error: The TranslationError to handle Returns: Tuple of (error response dict, HTTP status code) """ status_code = _PROVIDER_ERROR_HTTP_STATUS.get(error.code, 400) response = { "error": error.code, "message": error.message, "details": error.details if error.details else {}, } return response, status_code