Files
whisper-api-server/app/audio/sources.py
T
Serge ZaigraeffandClaude Opus 4.6 2e2bad8255 Simplify architecture: remove overengineering, flatten structure
- Remove dead code: cache.py, context_managers.py, decorators.py, flask-limiter
- Replace AudioSource ABC + FakeFile (5 classes) with 4 plain functions
- Replace TempFileManager class with create_temp_file/cleanup_temp_files functions
- Simplify RequestLogger from 233 to 65 lines, remove file reading side-effect
- Convert HistoryLogger and AudioUtils classes to module-level functions
- Remove unused speed_up_audio and audio_speed_factor config
- Flatten single-file directories: shared/, api/, storage/, validation/, async_tasks/, logging/
- Merge logging config + request_logger into single infrastructure/log.py
- Fix request_logging config key (was request_logger)
- Trim CLAUDE.md to high-level only

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 05:28:34 +03:00

137 lines
4.7 KiB
Python

"""
Модуль sources.py содержит функции для получения аудиофайлов
из различных источников (загруженные файлы, URL, base64, локальные файлы).
"""
import os
import uuid
import tempfile
import base64
import requests
from typing import Tuple, Optional
import logging
logger = logging.getLogger('app.audio_sources')
def _check_size(size_bytes: int, max_size_mb: int) -> Optional[str]:
"""Проверяет размер файла. Возвращает сообщение об ошибке или None."""
if size_bytes > max_size_mb * 1024 * 1024:
return f"File exceeds maximum size of {max_size_mb}MB"
return None
def _make_temp_path(suffix: str = ".wav") -> str:
"""Создаёт путь для временного файла."""
temp_dir = tempfile.mkdtemp()
return os.path.join(temp_dir, f"{uuid.uuid4()}{suffix}")
def get_uploaded_file(request_files, max_file_size_mb: int = 100) -> Tuple[Optional[str], Optional[str], Optional[str]]:
"""
Получает аудиофайл из загруженных файлов Flask.
Returns:
Кортеж (путь к temp-файлу, имя файла, сообщение об ошибке).
"""
if 'file' not in request_files:
return None, None, "No file part"
file = request_files['file']
if file.filename == '':
return None, None, "No selected file"
# Проверка размера
file.seek(0, os.SEEK_END)
size = file.tell()
file.seek(0)
error = _check_size(size, max_file_size_mb)
if error:
return None, None, error
# Сохраняем во временный файл
temp_path = _make_temp_path()
file.save(temp_path)
return temp_path, file.filename, None
def get_url_file(url: str, max_file_size_mb: int = 100) -> Tuple[Optional[str], Optional[str], Optional[str]]:
"""
Получает аудиофайл по URL.
Returns:
Кортеж (путь к temp-файлу, имя файла, сообщение об ошибке).
"""
try:
response = requests.get(url, stream=True)
response.raise_for_status()
# Проверка размера по Content-Length
content_length = response.headers.get('Content-Length')
if content_length:
error = _check_size(int(content_length), max_file_size_mb)
if error:
return None, None, error
temp_path = _make_temp_path()
with open(temp_path, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
return temp_path, os.path.basename(temp_path), None
except Exception as e:
logger.error(f"Ошибка при получении файла по URL {url}: {e}")
return None, None, f"Error retrieving file from URL: {str(e)}"
def get_base64_file(base64_data: str, max_file_size_mb: int = 100) -> Tuple[Optional[str], Optional[str], Optional[str]]:
"""
Получает аудиофайл из base64 данных.
Returns:
Кортеж (путь к temp-файлу, имя файла, сообщение об ошибке).
"""
try:
audio_data = base64.b64decode(base64_data)
error = _check_size(len(audio_data), max_file_size_mb)
if error:
return None, None, error
temp_path = _make_temp_path()
with open(temp_path, 'wb') as f:
f.write(audio_data)
return temp_path, os.path.basename(temp_path), None
except Exception as e:
logger.error(f"Ошибка при декодировании base64 данных: {e}")
return None, None, f"Error decoding base64 data: {str(e)}"
def get_local_file(file_path: str, max_file_size_mb: int = 100) -> Tuple[Optional[str], Optional[str], Optional[str]]:
"""
Получает локальный аудиофайл.
Returns:
Кортеж (путь к файлу, имя файла, сообщение об ошибке).
Примечание: возвращает оригинальный путь, не копирует файл.
"""
if not os.path.exists(file_path):
return None, None, f"File not found: {file_path}"
try:
error = _check_size(os.path.getsize(file_path), max_file_size_mb)
if error:
return None, None, error
return file_path, os.path.basename(file_path), None
except Exception as e:
logger.error(f"Ошибка при открытии локального файла {file_path}: {e}")
return None, None, f"Error opening local file: {str(e)}"