загрузка и распознвание внешний файлов
This commit is contained in:
@@ -14,6 +14,7 @@ class Audio(Base):
|
|||||||
file_path = Column(Text)
|
file_path = Column(Text)
|
||||||
duration = Column(Float)
|
duration = Column(Float)
|
||||||
file_size = Column(Integer)
|
file_size = Column(Integer)
|
||||||
|
sourse = Column(Text, default="internal")
|
||||||
|
|
||||||
ai_conclusion = relationship("AiConclusion", back_populates="audio", cascade="all, delete-orphan")
|
ai_conclusion = relationship("AiConclusion", back_populates="audio", cascade="all, delete-orphan")
|
||||||
|
|
||||||
@@ -24,5 +25,6 @@ class Audio(Base):
|
|||||||
"index_date": self.index_date.isoformat() if self.index_date else None,
|
"index_date": self.index_date.isoformat() if self.index_date else None,
|
||||||
"file_path": self.file_path,
|
"file_path": self.file_path,
|
||||||
"duration": self.duration,
|
"duration": self.duration,
|
||||||
"file_size": self.file_size
|
"file_size": self.file_size,
|
||||||
|
"sourse": self.sourse
|
||||||
}
|
}
|
||||||
@@ -16,6 +16,31 @@ from apiApp.config import WEBHOOK_ENDPOINT, WEBHOOK_API_KEY
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
ai_conclusion_router = APIRouter()
|
ai_conclusion_router = APIRouter()
|
||||||
|
|
||||||
|
def _send_callback(callback_url: str, audio: Audio, conclusion_data: Dict[str, Any]) -> None:
|
||||||
|
"""Отправляем результат клиенту по callback_url (не храним в БД)."""
|
||||||
|
try:
|
||||||
|
callback_url = (callback_url or "").strip()
|
||||||
|
if not callback_url:
|
||||||
|
return
|
||||||
|
if not callback_url.startswith(("http://", "https://")):
|
||||||
|
logger.warning(f"⚠️ Некорректный callback_url для {audio.filename}: {callback_url}")
|
||||||
|
return
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"audio_id": str(audio.id),
|
||||||
|
"filename": audio.filename,
|
||||||
|
"result": conclusion_data
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = requests.post(callback_url, json=payload, timeout=30)
|
||||||
|
if 200 <= resp.status_code < 300:
|
||||||
|
logger.info(f"✅ Callback успешно отправлен для {audio.filename}")
|
||||||
|
else:
|
||||||
|
logger.warning(f"⚠️ Callback вернул статус {resp.status_code} для {audio.filename}")
|
||||||
|
logger.warning(f"Response: {resp.text}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Ошибка при отправке callback для {audio.filename}: {e}")
|
||||||
|
|
||||||
|
|
||||||
class AiConclusionRequest(BaseModel):
|
class AiConclusionRequest(BaseModel):
|
||||||
"""Модель запроса для сохранения AI заключения"""
|
"""Модель запроса для сохранения AI заключения"""
|
||||||
@@ -25,6 +50,7 @@ class AiConclusionRequest(BaseModel):
|
|||||||
analysis: Dict[str, Any]
|
analysis: Dict[str, Any]
|
||||||
segments: Optional[List[Dict[str, Any]]] = []
|
segments: Optional[List[Dict[str, Any]]] = []
|
||||||
processing_time_seconds: Optional[float] = 0
|
processing_time_seconds: Optional[float] = 0
|
||||||
|
callback_url: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
class AiConclusionResponse(BaseModel):
|
class AiConclusionResponse(BaseModel):
|
||||||
@@ -93,6 +119,10 @@ async def save_ai_conclusion(request: AiConclusionRequest, db: Session = Depends
|
|||||||
db.commit()
|
db.commit()
|
||||||
logger.info(f"✅ Заключение сохранено для {request.filename}")
|
logger.info(f"✅ Заключение сохранено для {request.filename}")
|
||||||
|
|
||||||
|
# Для внешних файлов — отправляем результат клиенту из FileAudioAPI
|
||||||
|
if (audio.sourse or "").lower() == "external" and request.callback_url:
|
||||||
|
_send_callback(request.callback_url, audio, conclusion_data)
|
||||||
|
|
||||||
# Отправляем webhook в Calls_WEB_Client_main для анализа
|
# Отправляем webhook в Calls_WEB_Client_main для анализа
|
||||||
try:
|
try:
|
||||||
logger.info(f"📤 Отправка webhook в Calls_WEB_Client_main для {request.filename}")
|
logger.info(f"📤 Отправка webhook в Calls_WEB_Client_main для {request.filename}")
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ def query_audio_without_conclusion(db, limit=None):
|
|||||||
|
|
||||||
query = db.query(Audio).filter(
|
query = db.query(Audio).filter(
|
||||||
~subquery
|
~subquery
|
||||||
|
).filter(
|
||||||
|
Audio.sourse == "internal"
|
||||||
).order_by(Audio.index_date.asc())
|
).order_by(Audio.index_date.asc())
|
||||||
|
|
||||||
if limit:
|
if limit:
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
from fastapi import APIRouter, Depends, HTTPException, UploadFile, File as FastAPIFile, status
|
||||||
|
from apiApp.database import get_db
|
||||||
|
from fastapi.responses import FileResponse
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
import os, uuid
|
||||||
|
from apiApp.config import UPLOAD_FOLDER, ALLOWED_AUDIO_EXTENSIONS, MAX_UPLOAD_SIZE
|
||||||
|
import aiofiles
|
||||||
|
|
||||||
|
from apiApp.schemas import (
|
||||||
|
AudioCreate,
|
||||||
|
AudioResponse,
|
||||||
|
AudioListResponse,
|
||||||
|
MessageResponse
|
||||||
|
)
|
||||||
|
from apiApp.services import AudioCRUD
|
||||||
|
|
||||||
|
router = APIRouter(
|
||||||
|
prefix="/external_audio",
|
||||||
|
tags=["Внешние аудиофайлы"]
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.post("/upload")
|
||||||
|
async def upload_external_audio(
|
||||||
|
file: UploadFile = FastAPIFile(...),
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Загрузка внешнего аудиофайла на сервер
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Проверка расширения файла
|
||||||
|
file_ext = os.path.splitext(file.filename)[1].lower()
|
||||||
|
if file_ext not in ALLOWED_AUDIO_EXTENSIONS:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||||
|
detail=f"File extension not allowed. Allowed: {', '.join(ALLOWED_AUDIO_EXTENSIONS)}"
|
||||||
|
)
|
||||||
|
content = await file.read()
|
||||||
|
# Проверка размера файла
|
||||||
|
if len(content) > MAX_UPLOAD_SIZE:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
|
||||||
|
detail=f"File too large. Maximum size: {MAX_UPLOAD_SIZE / (1024*1024)}MB"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Сохранение файла
|
||||||
|
file_path = UPLOAD_FOLDER / f"{uuid.uuid4()}{file_ext}"
|
||||||
|
try:
|
||||||
|
async with aiofiles.open(file_path, 'wb') as f:
|
||||||
|
await f.write(content)
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail=f"Error saving file: {str(e)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Создание записи в БД
|
||||||
|
try:
|
||||||
|
audio_data = AudioCreate(filename=file.filename)
|
||||||
|
audio = AudioCRUD.create(
|
||||||
|
db=db,
|
||||||
|
audio_data=audio_data,
|
||||||
|
file_path=str(file_path),
|
||||||
|
file_size=len(content),
|
||||||
|
sourse="external"
|
||||||
|
)
|
||||||
|
return audio
|
||||||
|
except Exception as e:
|
||||||
|
# Удаление файла при ошибке записи в БД
|
||||||
|
if os.path.exists(file_path):
|
||||||
|
os.remove(file_path)
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail=f"Error creating database record: {str(e)}"
|
||||||
|
)
|
||||||
|
return {"message": "External audio uploaded successfully"}
|
||||||
|
|
||||||
|
def send_to_recognition(file_path: str):
|
||||||
|
"""
|
||||||
|
Отправка аудиофайла на распознавание
|
||||||
|
"""
|
||||||
@@ -26,13 +26,20 @@ class AudioCRUD:
|
|||||||
return db.query(Audio).filter(Audio.filename == filename).first()
|
return db.query(Audio).filter(Audio.filename == filename).first()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create(db: Session, audio_data: AudioCreate, file_path: str, file_size: int = None) -> Audio:
|
def create(
|
||||||
|
db: Session,
|
||||||
|
audio_data: AudioCreate,
|
||||||
|
file_path: str,
|
||||||
|
file_size: int = None,
|
||||||
|
sourse: str = "internal"
|
||||||
|
) -> Audio:
|
||||||
"""Создать новую запись аудиофайла"""
|
"""Создать новую запись аудиофайла"""
|
||||||
db_audio = Audio(
|
db_audio = Audio(
|
||||||
filename=audio_data.filename,
|
filename=audio_data.filename,
|
||||||
file_path=file_path,
|
file_path=file_path,
|
||||||
index_date=datetime.datetime.utcnow(),
|
index_date=datetime.datetime.utcnow(),
|
||||||
file_size=file_size
|
file_size=file_size,
|
||||||
|
sourse=sourse
|
||||||
)
|
)
|
||||||
db.add(db_audio)
|
db.add(db_audio)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|||||||
Reference in New Issue
Block a user