Browse Source

add autorestart rec

dev
poturaevpetr 2 weeks ago
parent
commit
86245ce1fb
  1. 185
      apiApp/routers/audio_management_router.py

185
apiApp/routers/audio_management_router.py

@ -1,3 +1,84 @@
"""
API endpoints для управления аудиофайлами (регистрация и пакетная обработка)
Используется Calls_WEB_Client_main для оркестрации процесса распознавания
"""
from fastapi import APIRouter, HTTPException, Depends, BackgroundTasks
from sqlalchemy.orm import Session
from pydantic import BaseModel
from typing import Optional, List
import os
import logging
from datetime import datetime
from apiApp.database import get_db
from apiApp.database.Audio import Audio
from apiApp.database.AiConclusion import AiConclusion
from apiApp.config import AUDIOFILES_PATH
logger = logging.getLogger(__name__)
audio_management_router = APIRouter()
def query_audio_without_conclusion(db, limit=None):
"""
Возвращает запрос для поиска Audio без AiConclusion
Использует exists() подзапрос, так как AiConclusion - это relationship
"""
from sqlalchemy import exists
subquery = db.query(AiConclusion.audio_id).filter(
AiConclusion.audio_id == Audio.id
)
query = db.query(Audio).filter(
~exists().where(subquery.exists())
).order_by(Audio.index_date.asc())
if limit:
query = query.limit(limit)
return query
class AudioRegisterRequest(BaseModel):
"""Запрос на регистрацию аудиофайла"""
filename: str
file_path: str # Полный путь к файлу в общей папке audiofiles
class AudioProcessAllRequest(BaseModel):
"""Запрос на пакетное распознавание"""
limit: int = 100
class AudioRegisterResponse(BaseModel):
"""Ответ на регистрацию аудиофайла"""
id: str
filename: str
file_size: int
created_at: datetime
@audio_management_router.post("/audio/register", response_model=AudioRegisterResponse, status_code=201)
async def register_audio_file(
request: AudioRegisterRequest,
db: Session = Depends(get_db)
):
"""
Регистрация аудиофайла в БД (без копирования файла)
Создаёт запись в таблице Audio для файла, который уже находится
в общей папке audiofiles. НЕ копирует файл, только создаёт запись в БД.
Args:
request: {filename: "in-xxx.wav", file_path: "/app/audiofiles/in-xxx.wav"}
Returns:
201 Created + информация о созданной записи
400 Bad Request если файл уже зарегистрирован
404 Not Found если файл не существует на диске
"""
try:
filename = request.filename
file_path = request.file_path
@ -111,24 +192,13 @@ async def process_all_pending_audio(
}
"""
try:
from sqlalchemy import exists
limit = request.limit
logger.info(f"🚀 Поиск Audio без AiConclusion (limit={limit})")
# Находим все Audio без AiConclusion через подзапрос
subquery = db.query(AiConclusion.audio_id).filter(
AiConclusion.audio_id == Audio.id
)
pending_audio = db.query(Audio).filter(
~exists().where(subquery.exists())
).order_by(Audio.index_date.asc()).limit(limit).all()
total_pending = db.query(Audio).filter(
~exists().where(subquery.exists())
).count()
# Находим все Audio без AiConclusion используя вспомогательную функцию
pending_audio = query_audio_without_conclusion(db, limit).all()
total_pending = query_audio_without_conclusion(db).count()
if not pending_audio:
logger.info(" Нет файлов для распознавания")
@ -211,15 +281,7 @@ async def get_pending_audio(
Список файлов, ожидающих распознавания
"""
try:
from sqlalchemy import exists
subquery = db.query(AiConclusion.audio_id).filter(
AiConclusion.audio_id == Audio.id
)
pending_audio = db.query(Audio).filter(
~exists().where(subquery.exists())
).order_by(Audio.index_date.asc()).limit(limit).all()
pending_audio = query_audio_without_conclusion(db, limit).all()
files_info = []
for audio in pending_audio:
@ -234,9 +296,7 @@ async def get_pending_audio(
"exists_on_disk": exists
})
total_pending = db.query(Audio).filter(
~exists().where(subquery.exists())
).count()
total_pending = query_audio_without_conclusion(db).count()
return {
"total_pending": total_pending,
@ -261,19 +321,9 @@ async def get_audio_stats(db: Session = Depends(get_db)):
Статистика по Audio записям
"""
try:
from sqlalchemy import exists
total_audio = db.query(Audio).count()
subquery = db.query(AiConclusion.audio_id).filter(
AiConclusion.audio_id == Audio.id
)
with_conclusion = db.query(Audio).filter(
exists().where(subquery.exists())
).count()
without_conclusion = total_audio - with_conclusion
with_conclusion = total_audio - query_audio_without_conclusion(db).count()
without_conclusion = query_audio_without_conclusion(db).count()
# Проверяем существование файлов на диске
all_audio = db.query(Audio).all()
@ -299,62 +349,3 @@ async def get_audio_stats(db: Session = Depends(get_db)):
)
def auto_restore_on_startup(db: Session, limit: int = 100):
"""
Автоматическое восстановление распознавания при старте FileAudioAPI
Проверяет, есть ли файлы без AiConclusion, и запускает их распознавание
Args:
db: Сессия БД
limit: Максимум файлов для восстановления
"""
try:
from sqlalchemy import or_
# Проверяем, есть ли файлы без AiConclusion
pending_audio = db.query(Audio).filter(
or_(
Audio.AiConclusion == None,
Audio.AiConclusion == ''
)
).limit(limit).all()
if not pending_audio:
logger.info(" Auto-restore: нет файлов для распознавания")
return
logger.info(f"🔄 Auto-restore: найдено {len(pending_audio)} файлов без AiConclusion")
# Запускаем распознавание
started_count = 0
for audio in pending_audio:
file_path = os.path.join(AUDIOFILES_PATH, audio.filename)
if not os.path.exists(file_path):
logger.warning(f" Файл не найден: {audio.filename}")
continue
# Отправляем в GigaAM API
from apiApp.config import GIGAAM_API_URL
api_url = f"{GIGAAM_API_URL}/api/call/process"
payload = {"filename": audio.filename}
try:
import requests
response = requests.post(api_url, json=payload, timeout=5)
if response.status_code in [200, 202]:
logger.info(f"✅ Запущено распознавание: {audio.filename}")
started_count += 1
else:
logger.warning(f" Ошибка запуска {audio.filename}: {response.status_code}")
except Exception as e:
logger.error(f"❌ Ошибка при запуске {audio.filename}: {e}")
logger.info(f"🎉 Auto-restore завершено: запущено {started_count} файлов")
except Exception as e:
logger.error(f"❌ Ошибка при auto-restore: {e}")

Loading…
Cancel
Save