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_PROCESSING_FAILED", | |
| 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" | |
| ] | |
| ) | |
| } | |
| # 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.debug(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)) |