teachingAssistant / src /application /dtos /audio_upload_dto.py
Michael Hu
feat(logging): add detailed logging for audio upload and configuration handling
8023ba2
raw
history blame
3.72 kB
"""Audio Upload Data Transfer Object"""
from dataclasses import dataclass
from typing import Optional
import mimetypes
import os
@dataclass
class AudioUploadDto:
"""DTO for file upload data
Handles audio file upload information including filename,
content, and content type validation.
"""
filename: str
content: bytes
content_type: str
size: Optional[int] = None
def __post_init__(self):
"""Validate the DTO after initialization"""
# Add logging for debugging mp3 validation issues
import logging
logger = logging.getLogger(__name__)
logger.info(f"Validating AudioUploadDto - Filename: {self.filename}")
logger.info(f"Content-Type: {self.content_type}")
logger.info(f"File size: {len(self.content)} bytes")
# Check file extension and MIME type mapping
_, ext = os.path.splitext(self.filename.lower())
logger.info(f"File extension: {ext}")
content_type_map = {
'.wav': 'audio/wav',
'.mp3': 'audio/mpeg',
'.m4a': 'audio/mp4',
'.flac': 'audio/flac',
'.ogg': 'audio/ogg'
}
expected_content_type = content_type_map.get(ext)
logger.info(f"Expected content type for {ext}: {expected_content_type}")
logger.info(f"Actual content type: {self.content_type}")
# Check mimetypes.guess_type result
guessed_type = mimetypes.guess_type(self.filename)[0]
logger.info(f"mimetypes.guess_type result: {guessed_type}")
self._validate()
if self.size is None:
self.size = len(self.content)
def _validate(self):
"""Validate audio upload data"""
if not self.filename:
raise ValueError("Filename cannot be empty")
if not self.content:
raise ValueError("Audio content cannot be empty")
if not self.content_type:
raise ValueError("Content type cannot be empty")
# Validate file extension
_, ext = os.path.splitext(self.filename.lower())
supported_extensions = ['.wav', '.mp3', '.m4a', '.flac', '.ogg']
if ext not in supported_extensions:
raise ValueError(f"Unsupported file extension: {ext}. Supported: {supported_extensions}")
# Validate content type
expected_content_type = mimetypes.guess_type(self.filename)[0]
if expected_content_type and not self.content_type.startswith('audio/'):
raise ValueError(f"Invalid content type: {self.content_type}. Expected audio/* type")
# Validate file size (max 100MB)
max_size = 100 * 1024 * 1024 # 100MB
if len(self.content) > max_size:
raise ValueError(f"File too large: {len(self.content)} bytes. Maximum: {max_size} bytes")
# Validate minimum file size (at least 1KB)
min_size = 1024 # 1KB
if len(self.content) < min_size:
raise ValueError(f"File too small: {len(self.content)} bytes. Minimum: {min_size} bytes")
@property
def file_extension(self) -> str:
"""Get the file extension"""
return os.path.splitext(self.filename.lower())[1]
@property
def base_filename(self) -> str:
"""Get filename without extension"""
return os.path.splitext(self.filename)[0]
def to_dict(self) -> dict:
"""Convert to dictionary representation"""
return {
'filename': self.filename,
'content_type': self.content_type,
'size': self.size,
'file_extension': self.file_extension
}