DungeonMaster-AI / src /voice /exceptions.py
bhupesh-sf's picture
first commit
f8ba6bf verified
"""
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)