взаимодействие сайта с FileAudioAPI
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
"""
|
||||
API endpoints для обслуживания аудиофайлов
|
||||
"""
|
||||
from fastapi import APIRouter, HTTPException, Depends
|
||||
from fastapi.responses import FileResponse, StreamingResponse
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import Optional
|
||||
import os
|
||||
import logging
|
||||
|
||||
from apiApp.database import get_db
|
||||
from apiApp.database.Audio import Audio
|
||||
from apiApp.config import AUDIOFILES_PATH
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
audio_files_router = APIRouter()
|
||||
|
||||
|
||||
@audio_files_router.get("/audio/{filename}")
|
||||
async def get_audio_file(filename: str):
|
||||
"""
|
||||
Возвращает аудиофайл для стриминга/воспроизведения
|
||||
|
||||
Args:
|
||||
filename: Имя аудиофайла (например, "in-xxx.wav")
|
||||
|
||||
Returns:
|
||||
StreamingResponse с аудиофайлом
|
||||
"""
|
||||
try:
|
||||
# Проверяем расширение файла
|
||||
allowed_extensions = ['.wav', '.mp3', '.ogg', '.m4a', '.flac']
|
||||
if not any(filename.lower().endswith(ext) for ext in allowed_extensions):
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f'Неподдерживаемый формат файла. Разрешены: {", ".join(allowed_extensions)}'
|
||||
)
|
||||
|
||||
# Формируем путь к файлу
|
||||
file_path = os.path.join(AUDIOFILES_PATH, filename)
|
||||
|
||||
# Проверяем существование файла
|
||||
if not os.path.exists(file_path):
|
||||
logger.warning(f"⚠️ Файл не найден: {file_path}")
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f'Файл {filename} не найден'
|
||||
)
|
||||
|
||||
logger.info(f"🎵 Отдача аудио: {filename}")
|
||||
|
||||
# Определяем MIME тип
|
||||
import mimetypes
|
||||
mime_type, _ = mimetypes.guess_type(file_path)
|
||||
if mime_type is None:
|
||||
mime_type = 'audio/wav'
|
||||
|
||||
# Возвращаем файл как поток
|
||||
def iterfile():
|
||||
with open(file_path, 'rb') as f:
|
||||
data = f.read(8192)
|
||||
while data:
|
||||
yield data
|
||||
data = f.read(8192)
|
||||
|
||||
return StreamingResponse(
|
||||
iterfile(),
|
||||
media_type=mime_type,
|
||||
headers={
|
||||
'Content-Disposition': f'inline; filename="{filename}"',
|
||||
'Accept-Ranges': 'bytes'
|
||||
}
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Ошибка при отдаче аудио: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f'Ошибка при отдаче файла: {str(e)}'
|
||||
)
|
||||
|
||||
|
||||
@audio_files_router.get("/audio/{filename}/info")
|
||||
async def get_audio_info(filename: str, db: Session = Depends(get_db)):
|
||||
"""
|
||||
Возвращает информацию об аудиофайле
|
||||
|
||||
Args:
|
||||
filename: Имя аудиофайла
|
||||
|
||||
Returns:
|
||||
JSON с информацией о файле
|
||||
"""
|
||||
try:
|
||||
# Ищем информацию в БД
|
||||
audio = db.query(Audio).filter(Audio.filename == filename).first()
|
||||
|
||||
if not audio:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f'Файл {filename} не найден в БД'
|
||||
)
|
||||
|
||||
# Проверяем существование файла
|
||||
file_path = os.path.join(AUDIOFILES_PATH, filename)
|
||||
if not os.path.exists(file_path):
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f'Файл {filename} не найден на диске'
|
||||
)
|
||||
|
||||
# Получаем размер файла
|
||||
file_size = os.path.getsize(file_path)
|
||||
|
||||
# Определяем длительность (приблизительно)
|
||||
# В идеале использовать библиотеку типа mutagen или soundfile
|
||||
duration = None
|
||||
try:
|
||||
import wave
|
||||
with wave.open(file_path, 'r') as wav_file:
|
||||
frames = wav_file.getnframes()
|
||||
rate = wav_file.getframerate()
|
||||
duration = frames / float(rate) if rate > 0 else 0
|
||||
except:
|
||||
pass
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"filename": filename,
|
||||
"file_size_bytes": file_size,
|
||||
"duration_seconds": duration,
|
||||
"created_at": audio.index_date.isoformat() if audio.index_date else None,
|
||||
"audio_id": str(audio.id)
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Ошибка при получении информации: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=str(e)
|
||||
)
|
||||
|
||||
|
||||
@audio_files_router.get("/audio/list")
|
||||
async def list_audio_files(
|
||||
db: Session = Depends(get_db),
|
||||
limit: int = 100,
|
||||
offset: int = 0
|
||||
):
|
||||
"""
|
||||
Возвращает список аудиофайлов
|
||||
|
||||
Query Parameters:
|
||||
limit: Максимальное количество файлов (default: 100)
|
||||
offset: Смещение для пагинации (default: 0)
|
||||
|
||||
Returns:
|
||||
JSON со списком файлов
|
||||
"""
|
||||
try:
|
||||
# Получаем список файлов из БД
|
||||
query = db.query(Audio).order_by(Audio.index_date.desc())
|
||||
|
||||
total = query.count()
|
||||
audio_files = query.offset(offset).limit(limit).all()
|
||||
|
||||
files_info = []
|
||||
for audio in audio_files:
|
||||
file_path = os.path.join(AUDIOFILES_PATH, audio.filename)
|
||||
exists = os.path.exists(file_path)
|
||||
|
||||
files_info.append({
|
||||
"filename": audio.filename,
|
||||
"file_size": audio.file_size,
|
||||
"created_at": audio.index_date.isoformat() if audio.index_date else None,
|
||||
"exists": exists,
|
||||
"audio_id": str(audio.id)
|
||||
})
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"total": total,
|
||||
"count": len(files_info),
|
||||
"files": files_info
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Ошибка при получении списка файлов: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=str(e)
|
||||
)
|
||||
|
||||
|
||||
@audio_files_router.get("/audio/{filename}/download")
|
||||
async def download_audio_file(filename: str):
|
||||
"""
|
||||
Возвращает аудиофайл для скачивания
|
||||
|
||||
Args:
|
||||
filename: Имя аудиофайла
|
||||
|
||||
Returns:
|
||||
FileResponse для скачивания
|
||||
"""
|
||||
try:
|
||||
# Формируем путь к файлу
|
||||
file_path = os.path.join(AUDIOFILES_PATH, filename)
|
||||
|
||||
# Проверяем существование файла
|
||||
if not os.path.exists(file_path):
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f'Файл {filename} не найден'
|
||||
)
|
||||
|
||||
logger.info(f"📥 Скачивание аудио: {filename}")
|
||||
|
||||
return FileResponse(
|
||||
path=file_path,
|
||||
media_type='audio/wav',
|
||||
filename=filename
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Ошибка при скачивании: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=str(e)
|
||||
)
|
||||
@@ -9,6 +9,7 @@ from apiApp.config import APP_TITLE, APP_VERSION, API_V1_PREFIX, UPLOAD_FOLDER,
|
||||
from apiApp.database import engine, Base
|
||||
from apiApp.routers import audio_router, recognition_router
|
||||
from apiApp.routers.ai_conclusion_router import ai_conclusion_router
|
||||
from apiApp.routers.audio_files_router import audio_files_router
|
||||
|
||||
# Настройка логирования
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
@@ -58,6 +59,7 @@ async def startup_event():
|
||||
app.include_router(audio_router, prefix=API_V1_PREFIX, tags=["audio"])
|
||||
app.include_router(recognition_router, prefix=API_V1_PREFIX, tags=["recognition"])
|
||||
app.include_router(ai_conclusion_router, prefix=API_V1_PREFIX, tags=["ai_conclusion"])
|
||||
app.include_router(audio_files_router, prefix=API_V1_PREFIX, tags=["audio_files"])
|
||||
|
||||
# Статические файлы (для загрузки аудио)
|
||||
app.mount("/uploads", StaticFiles(directory=str(UPLOAD_FOLDER)), name="uploads")
|
||||
|
||||
Reference in New Issue
Block a user