office_translator/utils/file_handler.py

143 lines
3.9 KiB
Python

"""
Utility functions for file handling and validation
"""
import os
import uuid
from pathlib import Path
from typing import Optional
from fastapi import UploadFile, HTTPException
from config import config
class FileHandler:
"""Handles file operations for the translation API"""
@staticmethod
def validate_file_extension(filename: str) -> str:
"""
Validate that the file extension is supported
Args:
filename: Name of the file
Returns:
File extension (lowercase, with dot)
Raises:
HTTPException: If file extension is not supported
"""
file_extension = Path(filename).suffix.lower()
if file_extension not in config.SUPPORTED_EXTENSIONS:
raise HTTPException(
status_code=400,
detail=f"Unsupported file type. Supported types: {', '.join(config.SUPPORTED_EXTENSIONS)}"
)
return file_extension
@staticmethod
def validate_file_size(file: UploadFile) -> None:
"""
Validate that the file size is within limits
Args:
file: Uploaded file
Raises:
HTTPException: If file is too large
"""
# Get file size
file.file.seek(0, 2) # Move to end of file
file_size = file.file.tell() # Get position (file size)
file.file.seek(0) # Reset to beginning
if file_size > config.MAX_FILE_SIZE_BYTES:
raise HTTPException(
status_code=400,
detail=f"File too large. Maximum size: {config.MAX_FILE_SIZE_MB}MB"
)
@staticmethod
async def save_upload_file(file: UploadFile, destination: Path) -> Path:
"""
Save an uploaded file to disk
Args:
file: Uploaded file
destination: Path to save the file
Returns:
Path to the saved file
"""
destination.parent.mkdir(parents=True, exist_ok=True)
with open(destination, "wb") as buffer:
content = await file.read()
buffer.write(content)
return destination
@staticmethod
def generate_unique_filename(original_filename: str, prefix: str = "") -> str:
"""
Generate a unique filename to avoid collisions
Args:
original_filename: Original filename
prefix: Optional prefix for the filename
Returns:
Unique filename
"""
file_path = Path(original_filename)
unique_id = str(uuid.uuid4())[:8]
if prefix:
return f"{prefix}_{unique_id}_{file_path.stem}{file_path.suffix}"
else:
return f"{unique_id}_{file_path.stem}{file_path.suffix}"
@staticmethod
def cleanup_file(file_path: Path) -> None:
"""
Delete a file if it exists
Args:
file_path: Path to the file to delete
"""
try:
if file_path.exists():
file_path.unlink()
except Exception as e:
print(f"Error deleting file {file_path}: {e}")
@staticmethod
def get_file_info(file_path: Path) -> dict:
"""
Get information about a file
Args:
file_path: Path to the file
Returns:
Dictionary with file information
"""
if not file_path.exists():
return {}
stat = file_path.stat()
return {
"filename": file_path.name,
"size_bytes": stat.st_size,
"size_mb": round(stat.st_size / (1024 * 1024), 2),
"extension": file_path.suffix,
"created": stat.st_ctime,
"modified": stat.st_mtime
}
# Global file handler instance
file_handler = FileHandler()