fix checker
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
"""
|
||||
Класс для проверки файлов без AI заключения и отправки на распознавание
|
||||
Исправленная версия recognition_checker.py
|
||||
Избегает detached instance error путём использования словарей вместо SQLAlchemy объектов
|
||||
"""
|
||||
|
||||
import requests
|
||||
from sqlalchemy import inspect
|
||||
from typing import List, Optional
|
||||
from typing import List, Optional, Dict, Any
|
||||
import logging
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
import threading
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
from autoLoader.database import get_db_session, Audio, AiConclusion
|
||||
from autoLoader.config import GIGAAM_API_URL
|
||||
@@ -67,7 +69,7 @@ class RecognitionChecker:
|
||||
|
||||
return True
|
||||
|
||||
def get_files_without_conclusion(self, limit: Optional[int] = None) -> List[Audio]:
|
||||
def get_files_without_conclusion(self, limit: Optional[int] = None) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Находит все файлы, у которых нет AI заключения
|
||||
|
||||
@@ -75,7 +77,7 @@ class RecognitionChecker:
|
||||
limit: Ограничение количества файлов (None = все)
|
||||
|
||||
Returns:
|
||||
Список объектов Audio без заключения
|
||||
Список словарей с информацией о файлах (избегаем detached instance)
|
||||
"""
|
||||
if not self.check_database():
|
||||
logger.error("❌ База данных не готова")
|
||||
@@ -97,40 +99,52 @@ class RecognitionChecker:
|
||||
|
||||
# Находим все audio, у которых нет заключения
|
||||
if conclusion_ids:
|
||||
files_without_conclusion = db.query(Audio).filter(
|
||||
audio_objects = db.query(Audio).filter(
|
||||
~Audio.id.in_(conclusion_ids)
|
||||
).all()
|
||||
else:
|
||||
# Если заключений нет вообще - все файлы без заключения
|
||||
files_without_conclusion = db.query(Audio).all()
|
||||
audio_objects = db.query(Audio).all()
|
||||
|
||||
logger.info(f"📊 Найдено файлов без заключения: {len(files_without_conclusion)}")
|
||||
# Конвертируем в словари внутри сессии БД
|
||||
files_data = []
|
||||
for audio in audio_objects:
|
||||
files_data.append({
|
||||
'id': str(audio.id),
|
||||
'filename': audio.filename,
|
||||
'file_size': audio.file_size,
|
||||
'index_date': audio.index_date.isoformat() if audio.index_date else None
|
||||
})
|
||||
|
||||
logger.info(f"📊 Найдено файлов без заключения: {len(files_data)}")
|
||||
|
||||
if limit:
|
||||
return files_without_conclusion[:limit]
|
||||
return files_data[:limit]
|
||||
|
||||
return files_without_conclusion
|
||||
return files_data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Ошибка при поиске файлов: {e}")
|
||||
return []
|
||||
|
||||
def send_to_recognition(self, audio: Audio) -> bool:
|
||||
def send_to_recognition(self, audio_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
Отправляет файл на распознавание в GigaAM API
|
||||
|
||||
Args:
|
||||
audio: Объект Audio для распознавания
|
||||
audio_data: Словарь с данными об аудио файле
|
||||
|
||||
Returns:
|
||||
True если успешно отправлен, иначе False
|
||||
"""
|
||||
filename = audio_data.get('filename')
|
||||
|
||||
payload = {
|
||||
"filename": audio.filename
|
||||
"filename": filename
|
||||
}
|
||||
|
||||
try:
|
||||
logger.info(f"📤 [Thread-{threading.current_thread().name}] Отправка файла {audio.filename} на распознавание...")
|
||||
logger.info(f"📤 [Thread-{threading.current_thread().name}] Отправка файла {filename} на распознавание...")
|
||||
|
||||
response = requests.post(
|
||||
self.api_url,
|
||||
@@ -139,7 +153,7 @@ class RecognitionChecker:
|
||||
)
|
||||
|
||||
if response.status_code == 200 or response.status_code == 202:
|
||||
logger.info(f"✅ [Thread-{threading.current_thread().name}] Файл {audio.filename} успешно отправлен")
|
||||
logger.info(f"✅ [Thread-{threading.current_thread().name}] Файл {filename} успешно отправлен")
|
||||
|
||||
# Thread-safe обновление счётчиков
|
||||
with self._lock:
|
||||
@@ -156,7 +170,7 @@ class RecognitionChecker:
|
||||
return False
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
logger.error(f"❌ [Thread-{threading.current_thread().name}] Таймаут при отправке файла {audio.filename}")
|
||||
logger.error(f"❌ [Thread-{threading.current_thread().name}] Таймаут при отправке файла {filename}")
|
||||
|
||||
with self._lock:
|
||||
self._failed_count += 1
|
||||
@@ -170,19 +184,19 @@ class RecognitionChecker:
|
||||
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"❌ [Thread-{threading.current_thread().name}] Ошибка при отправке {audio.filename}: {e}")
|
||||
logger.error(f"❌ [Thread-{threading.current_thread().name}] Ошибка при отправке {filename}: {e}")
|
||||
|
||||
with self._lock:
|
||||
self._failed_count += 1
|
||||
|
||||
return False
|
||||
|
||||
def send_to_recognition_parallel(self, audio_list: List[Audio]) -> dict:
|
||||
def send_to_recognition_parallel(self, audio_list: List[Dict[str, Any]]) -> Dict[str, Any]:
|
||||
"""
|
||||
Отправляет несколько файлов на распознавание параллельно
|
||||
|
||||
Args:
|
||||
audio_list: Список объектов Audio для распознавания
|
||||
audio_list: Список словарей с данными об аудио файлах
|
||||
|
||||
Returns:
|
||||
Словарь с результатами отправки
|
||||
@@ -226,19 +240,19 @@ class RecognitionChecker:
|
||||
success = future.result()
|
||||
|
||||
result = {
|
||||
"filename": audio.filename,
|
||||
"audio_id": str(audio.id),
|
||||
"filename": audio.get('filename'),
|
||||
"audio_id": audio.get('id'),
|
||||
"success": success
|
||||
}
|
||||
|
||||
results["files"].append(result)
|
||||
|
||||
except Exception as exc:
|
||||
logger.error(f"❌ Файл {audio.filename} сгенерировал исключение: {exc}")
|
||||
logger.error(f"❌ Файл {audio.get('filename')} сгенерировал исключение: {exc}")
|
||||
|
||||
result = {
|
||||
"filename": audio.filename,
|
||||
"audio_id": str(audio.id),
|
||||
"filename": audio.get('filename'),
|
||||
"audio_id": audio.get('id'),
|
||||
"success": False,
|
||||
"error": str(exc)
|
||||
}
|
||||
@@ -257,7 +271,7 @@ class RecognitionChecker:
|
||||
|
||||
return results
|
||||
|
||||
def process_all_pending(self, limit: Optional[int] = None, parallel: bool = True) -> dict:
|
||||
def process_all_pending(self, limit: Optional[int] = None, parallel: bool = True) -> Dict[str, Any]:
|
||||
"""
|
||||
Находит и отправляет все файлы без заключения на распознавание
|
||||
|
||||
@@ -298,8 +312,8 @@ class RecognitionChecker:
|
||||
success = self.send_to_recognition(audio)
|
||||
|
||||
result = {
|
||||
"filename": audio.filename,
|
||||
"audio_id": str(audio.id),
|
||||
"filename": audio.get('filename'),
|
||||
"audio_id": audio.get('id'),
|
||||
"success": success
|
||||
}
|
||||
|
||||
@@ -347,7 +361,7 @@ class RecognitionChecker:
|
||||
|
||||
|
||||
# Удобная функция для запуска из командной строки
|
||||
def process_pending_files(api_url: Optional[str] = None, limit: Optional[int] = None):
|
||||
def process_pending_files(api_url: Optional[str] = None, limit: Optional[int] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Обрабатывает все файлы без заключения
|
||||
|
||||
@@ -372,18 +386,3 @@ def process_pending_files(api_url: Optional[str] = None, limit: Optional[int] =
|
||||
|
||||
# Обрабатываем файлы
|
||||
return checker.process_all_pending(limit)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Пример использования
|
||||
import sys
|
||||
|
||||
api_url = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:5001/api/call/process"
|
||||
limit = int(sys.argv[2]) if len(sys.argv) > 2 else None
|
||||
|
||||
results = process_pending_files(api_url, limit)
|
||||
|
||||
print(f"\n📊 Результаты:")
|
||||
print(f"Всего: {results['total']}")
|
||||
print(f"Отправлено: {results['sent']}")
|
||||
print(f"Ошибок: {results['failed']}")
|
||||
|
||||
Reference in New Issue
Block a user