""" DungeonMaster AI - Voice Integration Exceptions Custom exception hierarchy for clear error handling in voice synthesis operations. """ from __future__ import annotations class VoiceIntegrationError(Exception): """Base exception for all voice integration errors.""" def __init__(self, message: str = "A voice integration error occurred") -> None: self.message = message super().__init__(self.message) class VoiceAPIError(VoiceIntegrationError): """Raised when ElevenLabs API returns an error.""" def __init__( self, message: str = "ElevenLabs API error", status_code: int | None = None, ) -> None: self.status_code = status_code if status_code: message = f"{message} (HTTP {status_code})" super().__init__(message) class VoiceRateLimitError(VoiceAPIError): """Raised when rate limit is exceeded (HTTP 429).""" def __init__( self, message: str = "Rate limit exceeded", retry_after_seconds: float | None = None, ) -> None: self.retry_after_seconds = retry_after_seconds if retry_after_seconds: message = f"{message}. Retry after {retry_after_seconds:.1f}s" super().__init__(message, status_code=429) class VoiceQuotaExhaustedError(VoiceAPIError): """Raised when monthly quota is exhausted.""" def __init__( self, message: str = "Monthly voice quota exhausted", quota_reset_date: str | None = None, ) -> None: self.quota_reset_date = quota_reset_date if quota_reset_date: message = f"{message}. Resets on {quota_reset_date}" super().__init__(message, status_code=402) class VoiceAuthenticationError(VoiceAPIError): """Raised when API key is invalid or expired (HTTP 401).""" def __init__(self, message: str = "Invalid or expired ElevenLabs API key") -> None: super().__init__(message, status_code=401) class VoiceUnavailableError(VoiceIntegrationError): """Raised when voice service is unavailable after retries.""" def __init__( self, message: str = "Voice service is currently unavailable", reason: str | None = None, ) -> None: self.reason = reason if reason: message = f"{message}: {reason}" super().__init__(message) class VoiceCircuitBreakerOpenError(VoiceIntegrationError): """Raised when circuit breaker is open and rejecting requests.""" def __init__( self, message: str = "Circuit breaker is open - too many recent failures", retry_after_seconds: float | None = None, ) -> None: self.retry_after_seconds = retry_after_seconds if retry_after_seconds: message = f"{message}. Retry after {retry_after_seconds:.1f}s" super().__init__(message) class VoiceNotFoundError(VoiceIntegrationError): """Raised when requested voice ID doesn't exist.""" def __init__(self, voice_id: str) -> None: self.voice_id = voice_id super().__init__(f"Voice not found: {voice_id}") class VoiceSynthesisError(VoiceIntegrationError): """Raised when synthesis fails for the given text.""" def __init__( self, message: str = "Voice synthesis failed", text_preview: str | None = None, ) -> None: self.text_preview = text_preview if text_preview: preview = text_preview[:50] + "..." if len(text_preview) > 50 else text_preview message = f"{message} for text: '{preview}'" super().__init__(message) class VoiceConfigurationError(VoiceIntegrationError): """Raised when voice settings are misconfigured.""" def __init__(self, message: str = "Voice configuration error") -> None: super().__init__(message)