@ -1,19 +1,20 @@
from fastapi import APIRouter , Depends , HTTPException , UploadFile , File as FastAPIFile , status
from fastapi import APIRouter , Depends , HTTPException , UploadFile , File as FastAPIFile , Form , status
from apiApp . database import get_db
from apiApp . database import get_db
from fastapi . responses import FileResponse
from fastapi . responses import FileResponse
from sqlalchemy . orm import Session
from sqlalchemy . orm import Session
import os , uuid
import os , uuid
from apiApp . config import UPLOAD_FOLDER , ALLOWED_AUDIO_EXTENSIONS , MAX_UPLOAD_SIZE
import logging
from pathlib import Path
import requests
from apiApp . config import ALLOWED_AUDIO_EXTENSIONS , MAX_UPLOAD_SIZE , AUDIOFILES_PATH , GIGAAM_API_URL
import aiofiles
import aiofiles
from apiApp . schemas import (
from apiApp . schemas import AudioCreate
AudioCreate ,
AudioResponse ,
AudioListResponse ,
MessageResponse
)
from apiApp . services import AudioCRUD
from apiApp . services import AudioCRUD
logger = logging . getLogger ( __name__ )
router = APIRouter (
router = APIRouter (
prefix = " /external_audio " ,
prefix = " /external_audio " ,
tags = [ " Внешние аудиофайлы " ]
tags = [ " Внешние аудиофайлы " ]
@ -22,10 +23,12 @@ router = APIRouter(
@router . post ( " /upload " )
@router . post ( " /upload " )
async def upload_external_audio (
async def upload_external_audio (
file : UploadFile = FastAPIFile ( . . . ) ,
file : UploadFile = FastAPIFile ( . . . ) ,
callback_url : str = Form ( . . . , description = " URL для отправки результата распознавания (FileAudioAPI вызовет GigaAM и затем отправит результат на этот URL) " ) ,
db : Session = Depends ( get_db )
db : Session = Depends ( get_db )
) :
) :
"""
"""
Загрузка внешнего аудиофайла на сервер
Загрузка внешнего аудиофайла . Файл сохраняется в общей папке , после чего
автоматически отправляется на распознавание в GigaAM . Результат придёт на callback_url .
"""
"""
# Проверка расширения файла
# Проверка расширения файла
@ -43,8 +46,11 @@ async def upload_external_audio(
detail = f " File too large. Maximum size: { MAX_UPLOAD_SIZE / ( 1024 * 1024 ) } MB "
detail = f " File too large. Maximum size: { MAX_UPLOAD_SIZE / ( 1024 * 1024 ) } MB "
)
)
# Сохранение файла
# Сохранение в общей папке под именем uuid+ext; это же имя передаём в GigaAM
file_path = UPLOAD_FOLDER / f " { uuid . uuid4 ( ) } { file_ext } "
safe_name = f " { uuid . uuid4 ( ) } { file_ext } "
upload_dir = Path ( AUDIOFILES_PATH ) if isinstance ( AUDIOFILES_PATH , str ) else AUDIOFILES_PATH
upload_dir . mkdir ( parents = True , exist_ok = True )
file_path = upload_dir / safe_name
try :
try :
async with aiofiles . open ( file_path , ' wb ' ) as f :
async with aiofiles . open ( file_path , ' wb ' ) as f :
await f . write ( content )
await f . write ( content )
@ -54,9 +60,9 @@ async def upload_external_audio(
detail = f " Error saving file: { str ( e ) } "
detail = f " Error saving file: { str ( e ) } "
)
)
# Создание записи в БД
# Создание записи в БД (filename = имя файла на диске, его же передаём в GigaAM)
try :
try :
audio_data = AudioCreate ( filename = file . fil ename )
audio_data = AudioCreate ( filename = sa fe_ name)
audio = AudioCRUD . create (
audio = AudioCRUD . create (
db = db ,
db = db ,
audio_data = audio_data ,
audio_data = audio_data ,
@ -64,18 +70,56 @@ async def upload_external_audio(
file_size = len ( content ) ,
file_size = len ( content ) ,
sourse = " external "
sourse = " external "
)
)
return audio
except Exception as e :
except Exception as e :
# Удаление файла при ошибке записи в БД
if os . path . exists ( file_path ) :
if os . path . exists ( file_path ) :
os . remove ( file_path )
os . remove ( file_path )
raise HTTPException (
raise HTTPException (
status_code = status . HTTP_500_INTERNAL_SERVER_ERROR ,
status_code = status . HTTP_500_INTERNAL_SERVER_ERROR ,
detail = f " Error creating database record: { str ( e ) } "
detail = f " Error creating database record: { str ( e ) } "
)
)
return { " message " : " External audio uploaded successfully " }
def send_to_recognition ( file_path : str ) :
# Запрос на распознавание в GigaAM (файл уже в общей папке по имени safe_name)
task_id , recognition_error = send_to_recognition ( filename = safe_name , callback_url = callback_url . strip ( ) )
# Ответ: запись аудио + данные по постановке в очередь распознавания
result = {
" id " : str ( audio . id ) ,
" filename " : audio . filename ,
" index_date " : audio . index_date . isoformat ( ) if audio . index_date else None ,
" file_path " : audio . file_path ,
" file_size " : audio . file_size ,
" sourse " : audio . sourse ,
}
if task_id :
result [ " recognition_task_id " ] = task_id
result [ " recognition_status_url " ] = f " { GIGAAM_API_URL . rstrip ( ' / ' ) } /api/call/task/ { task_id } "
if recognition_error :
result [ " recognition_error " ] = recognition_error
return result
def send_to_recognition ( filename : str , callback_url : str ) - > tuple :
"""
"""
Отправка аудиофайла на распознавание
Отправка аудиофайла на распознавание в GigaAM .
"""
Файл должен уже лежать в общей папке под именем filename .
Returns :
( task_id или None , recognition_error или None )
"""
try :
gigaam_url = f " { GIGAAM_API_URL . rstrip ( ' / ' ) } /api/call/external/process "
resp = requests . post (
gigaam_url ,
json = { " filename " : filename , " callback_url " : callback_url } ,
timeout = 15 ,
)
if resp . status_code == 202 :
data = resp . json ( )
task_id = data . get ( " task_id " )
logger . info ( f " ✅ Внешний файл { filename } поставлен в очередь GigaAM, task_id= { task_id } " )
return ( task_id , None )
recognition_error = resp . text or f " HTTP { resp . status_code } "
logger . warning ( f " ⚠️ GigaAM не принял задачу { filename } : { recognition_error } " )
return ( None , recognition_error )
except requests . exceptions . RequestException as e :
logger . warning ( f " ⚠️ Ошибка вызова GigaAM для { filename } : { e } " )
return ( None , str ( e ) )