Spaces:
Build error
Build error
"""Error message mapping for user-friendly error handling.""" | |
import logging | |
from typing import Dict, Optional, Any | |
from enum import Enum | |
from ...domain.exceptions import ( | |
DomainException, | |
InvalidAudioFormatException, | |
InvalidTextContentException, | |
TranslationFailedException, | |
SpeechRecognitionException, | |
SpeechSynthesisException, | |
InvalidVoiceSettingsException, | |
AudioProcessingException | |
) | |
logger = logging.getLogger(__name__) | |
class ErrorSeverity(Enum): | |
"""Error severity levels.""" | |
LOW = "low" | |
MEDIUM = "medium" | |
HIGH = "high" | |
CRITICAL = "critical" | |
class ErrorCategory(Enum): | |
"""Error categories for classification.""" | |
VALIDATION = "validation" | |
PROCESSING = "processing" | |
SYSTEM = "system" | |
EXTERNAL = "external" | |
CONFIGURATION = "configuration" | |
class ErrorMapping: | |
"""Error mapping configuration.""" | |
def __init__(self, user_message: str, error_code: str, | |
severity: ErrorSeverity, category: ErrorCategory, | |
recovery_suggestions: Optional[list] = None, | |
technical_details: Optional[str] = None): | |
self.user_message = user_message | |
self.error_code = error_code | |
self.severity = severity | |
self.category = category | |
self.recovery_suggestions = recovery_suggestions or [] | |
self.technical_details = technical_details | |
class ErrorMapper: | |
"""Maps domain exceptions to user-friendly error messages.""" | |
def __init__(self): | |
"""Initialize error mapper with predefined mappings.""" | |
self._mappings: Dict[type, ErrorMapping] = { | |
# Audio format errors | |
InvalidAudioFormatException: ErrorMapping( | |
user_message="The uploaded audio file format is not supported. Please use WAV, MP3, FLAC, or OGG format.", | |
error_code="INVALID_AUDIO_FORMAT", | |
severity=ErrorSeverity.MEDIUM, | |
category=ErrorCategory.VALIDATION, | |
recovery_suggestions=[ | |
"Convert your audio file to a supported format (WAV, MP3, FLAC, or OGG)", | |
"Check that your file is not corrupted", | |
"Ensure the file has a proper audio extension" | |
] | |
), | |
# Text content errors | |
InvalidTextContentException: ErrorMapping( | |
user_message="The text content is invalid or too long. Please check your input.", | |
error_code="INVALID_TEXT_CONTENT", | |
severity=ErrorSeverity.MEDIUM, | |
category=ErrorCategory.VALIDATION, | |
recovery_suggestions=[ | |
"Ensure text is not empty", | |
"Check that text length is within limits (max 10,000 characters)", | |
"Verify text encoding is valid" | |
] | |
), | |
# Translation errors | |
TranslationFailedException: ErrorMapping( | |
user_message="Translation failed. This might be due to unsupported language pairs or service issues.", | |
error_code="TRANSLATION_FAILED", | |
severity=ErrorSeverity.HIGH, | |
category=ErrorCategory.PROCESSING, | |
recovery_suggestions=[ | |
"Try a different target language", | |
"Check if the source language is correctly detected", | |
"Retry the operation after a few moments", | |
"Ensure the text is in a supported language" | |
] | |
), | |
# Speech recognition errors | |
SpeechRecognitionException: ErrorMapping( | |
user_message="Speech recognition failed. The audio might be unclear or in an unsupported language.", | |
error_code="SPEECH_RECOGNITION_FAILED", | |
severity=ErrorSeverity.HIGH, | |
category=ErrorCategory.PROCESSING, | |
recovery_suggestions=[ | |
"Ensure audio quality is good (clear speech, minimal background noise)", | |
"Try a different speech recognition model", | |
"Check that the audio contains speech in a supported language", | |
"Verify audio file is not corrupted" | |
] | |
), | |
# Speech synthesis errors | |
SpeechSynthesisException: ErrorMapping( | |
user_message="Text-to-speech generation failed. This might be due to voice availability or text issues.", | |
error_code="SPEECH_SYNTHESIS_FAILED", | |
severity=ErrorSeverity.HIGH, | |
category=ErrorCategory.PROCESSING, | |
recovery_suggestions=[ | |
"Try a different voice", | |
"Check if the text contains unsupported characters", | |
"Reduce text length if it's very long", | |
"Retry with a different TTS provider" | |
] | |
), | |
# Voice settings errors | |
InvalidVoiceSettingsException: ErrorMapping( | |
user_message="Voice settings are invalid. Please check speed, voice selection, and language settings.", | |
error_code="INVALID_VOICE_SETTINGS", | |
severity=ErrorSeverity.MEDIUM, | |
category=ErrorCategory.VALIDATION, | |
recovery_suggestions=[ | |
"Ensure speed is between 0.5 and 2.0", | |
"Select a valid voice from the available options", | |
"Check that the language is supported", | |
"Verify voice is available for the selected language" | |
] | |
), | |
# General audio processing errors | |
AudioProcessingException: ErrorMapping( | |
user_message="Audio processing failed. There was an issue processing your audio file.", | |
error_code="AUDIO_FORMAT_ERROR", # Use existing valid error code | |
severity=ErrorSeverity.HIGH, | |
category=ErrorCategory.PROCESSING, | |
recovery_suggestions=[ | |
"Check that your audio file is valid and not corrupted", | |
"Try uploading a different audio file", | |
"Ensure file size is within limits", | |
"Retry the operation" | |
] | |
), | |
# Validation errors | |
ValueError: ErrorMapping( | |
user_message="Invalid input provided. Please check your request parameters.", | |
error_code="VALIDATION_ERROR", | |
severity=ErrorSeverity.MEDIUM, | |
category=ErrorCategory.VALIDATION, | |
recovery_suggestions=[ | |
"Check all required fields are provided", | |
"Verify parameter values are within valid ranges", | |
"Ensure file formats are supported" | |
] | |
), | |
# File size errors | |
PermissionError: ErrorMapping( | |
user_message="Permission denied. Unable to access required files or directories.", | |
error_code="PERMISSION_ERROR", | |
severity=ErrorSeverity.HIGH, | |
category=ErrorCategory.SYSTEM, | |
recovery_suggestions=[ | |
"Check file permissions", | |
"Ensure temporary directory is writable", | |
"Contact system administrator if issue persists" | |
] | |
), | |
# Memory errors | |
MemoryError: ErrorMapping( | |
user_message="Insufficient memory to process the request. Try with a smaller file.", | |
error_code="MEMORY_ERROR", | |
severity=ErrorSeverity.HIGH, | |
category=ErrorCategory.SYSTEM, | |
recovery_suggestions=[ | |
"Use a smaller audio file", | |
"Try processing shorter audio segments", | |
"Retry the operation later" | |
] | |
), | |
# Timeout errors | |
TimeoutError: ErrorMapping( | |
user_message="Processing timed out. The operation took too long to complete.", | |
error_code="TIMEOUT_ERROR", | |
severity=ErrorSeverity.HIGH, | |
category=ErrorCategory.SYSTEM, | |
recovery_suggestions=[ | |
"Try with a shorter audio file", | |
"Retry the operation", | |
"Check system load and try again later" | |
] | |
), | |
# Type errors | |
TypeError: ErrorMapping( | |
user_message="Invalid data type provided. This is likely a configuration or implementation issue.", | |
error_code="TYPE_ERROR", | |
severity=ErrorSeverity.HIGH, | |
category=ErrorCategory.SYSTEM, | |
recovery_suggestions=[ | |
"Retry the operation", | |
"Try a different voice or model", | |
"Contact support if the issue persists" | |
] | |
) | |
} | |
# Default mapping for unknown errors | |
self._default_mapping = ErrorMapping( | |
user_message="An unexpected error occurred. Please try again or contact support.", | |
error_code="UNKNOWN_ERROR", | |
severity=ErrorSeverity.CRITICAL, | |
category=ErrorCategory.SYSTEM, | |
recovery_suggestions=[ | |
"Retry the operation", | |
"Check your input parameters", | |
"Contact support if the issue persists" | |
] | |
) | |
def map_exception(self, exception: Exception, context: Optional[Dict[str, Any]] = None) -> ErrorMapping: | |
""" | |
Map an exception to user-friendly error information. | |
Args: | |
exception: The exception to map | |
context: Optional context information | |
Returns: | |
ErrorMapping: Mapped error information | |
""" | |
try: | |
# Get mapping for exception type | |
mapping = self._mappings.get(type(exception)) | |
if mapping is None: | |
# Try parent classes for domain exceptions | |
for exc_type in type(exception).__mro__: | |
if exc_type in self._mappings: | |
mapping = self._mappings[exc_type] | |
break | |
if mapping is None: | |
# Use default mapping | |
mapping = self._default_mapping | |
logger.warning(f"No mapping found for exception type: {type(exception).__name__}") | |
# Add context-specific information if available | |
if context: | |
mapping = self._enhance_mapping_with_context(mapping, exception, context) | |
logger.info(f"Mapped {type(exception).__name__} to {mapping.error_code}") | |
return mapping | |
except Exception as e: | |
logger.error(f"Error mapping exception {type(exception).__name__}: {e}") | |
return self._default_mapping | |
def _enhance_mapping_with_context(self, mapping: ErrorMapping, exception: Exception, | |
context: Dict[str, Any]) -> ErrorMapping: | |
""" | |
Enhance error mapping with context-specific information. | |
Args: | |
mapping: Base error mapping | |
exception: Original exception | |
context: Context information | |
Returns: | |
ErrorMapping: Enhanced error mapping | |
""" | |
try: | |
# Create a copy of the mapping to avoid modifying the original | |
enhanced_mapping = ErrorMapping( | |
user_message=mapping.user_message, | |
error_code=mapping.error_code, | |
severity=mapping.severity, | |
category=mapping.category, | |
recovery_suggestions=mapping.recovery_suggestions.copy(), | |
technical_details=mapping.technical_details | |
) | |
# Add context-specific enhancements | |
if 'file_name' in context: | |
enhanced_mapping.user_message += f" (File: {context['file_name']})" | |
if 'operation' in context: | |
enhanced_mapping.technical_details = f"Failed during {context['operation']}: {str(exception)}" | |
if 'correlation_id' in context: | |
enhanced_mapping.technical_details = ( | |
f"{enhanced_mapping.technical_details or str(exception)} " | |
f"[ID: {context['correlation_id']}]" | |
) | |
# Add provider-specific suggestions | |
if 'provider' in context: | |
provider = context['provider'] | |
if isinstance(exception, (SpeechRecognitionException, SpeechSynthesisException, TranslationFailedException)): | |
enhanced_mapping.recovery_suggestions.append(f"Try switching from {provider} to an alternative provider") | |
# Add file size specific suggestions | |
if 'file_size' in context and context['file_size'] > 50 * 1024 * 1024: # 50MB | |
enhanced_mapping.recovery_suggestions.insert(0, "Try with a smaller file (under 50MB)") | |
return enhanced_mapping | |
except Exception as e: | |
logger.error(f"Error enhancing mapping with context: {e}") | |
return mapping | |
def get_error_code_from_exception(self, exception: Exception) -> str: | |
""" | |
Get error code from exception. | |
Args: | |
exception: Exception to get code for | |
Returns: | |
str: Error code | |
""" | |
mapping = self.map_exception(exception) | |
return mapping.error_code | |
def get_user_message_from_exception(self, exception: Exception, | |
context: Optional[Dict[str, Any]] = None) -> str: | |
""" | |
Get user-friendly message from exception. | |
Args: | |
exception: Exception to get message for | |
context: Optional context information | |
Returns: | |
str: User-friendly error message | |
""" | |
mapping = self.map_exception(exception, context) | |
return mapping.user_message | |
def get_recovery_suggestions(self, exception: Exception, | |
context: Optional[Dict[str, Any]] = None) -> list: | |
""" | |
Get recovery suggestions for an exception. | |
Args: | |
exception: Exception to get suggestions for | |
context: Optional context information | |
Returns: | |
list: List of recovery suggestions | |
""" | |
mapping = self.map_exception(exception, context) | |
return mapping.recovery_suggestions | |
def add_custom_mapping(self, exception_type: type, mapping: ErrorMapping) -> None: | |
""" | |
Add a custom error mapping. | |
Args: | |
exception_type: Exception type to map | |
mapping: Error mapping configuration | |
""" | |
self._mappings[exception_type] = mapping | |
logger.info(f"Added custom mapping for {exception_type.__name__}") | |
def get_all_error_codes(self) -> list: | |
""" | |
Get all available error codes. | |
Returns: | |
list: List of all error codes | |
""" | |
codes = [mapping.error_code for mapping in self._mappings.values()] | |
codes.append(self._default_mapping.error_code) | |
return list(set(codes)) |