File size: 15,409 Bytes
6613cd9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52563c2
6613cd9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0c2d9e7
 
 
 
 
 
 
 
 
 
 
 
 
6613cd9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fdc056d
6613cd9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
"""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))