diff --git a/photo_bot/handlers.py b/photo_bot/handlers.py index c5b15c0..eaa72b0 100644 --- a/photo_bot/handlers.py +++ b/photo_bot/handlers.py @@ -1,4 +1,3 @@ -# /opt/trueconf_bot/photo_bot/handlers.py import os import asyncio import logging @@ -15,11 +14,11 @@ from trueconf.types import FSInputFile import config.config as config from utils import states from utils.menu import MENU_TEXT -from photo_bot.photo_processor import prepare_ad_photo +from photo_bot.photo_ai_checker import verify_photo_with_ai from utils.texts import ( EMOJI_DIGITS, PHOTO_MAIN_MENU_TEXT, - system_error_text, + PHOTO_UNKNOWN_CMD_TEXT, photo_error_handling, PHOTO_UPLOADING_TEXT, photo_success_sent, @@ -48,7 +47,7 @@ def log_and_notify_photo_error(user_id: str, action: str, error_details: str): """Записывает системную ошибку в лог-файл и отправляет email-алерт администраторам""" global last_email_time - log_dir = os.path.dirname(os.path.abspath(__file__)) + log_dir = "/opt/trueconf_bot/photo_bot/logs" os.makedirs(log_dir, exist_ok=True) log_file = os.path.join(log_dir, "photo_errors.log") @@ -102,7 +101,6 @@ def log_and_notify_photo_error(user_id: str, action: str, error_details: str): async def handle_photo_error(msg: Message, user_id: str, action: str, error_details: str): """Вызывает системное логирование и выдает заглушку пользователю""" await asyncio.to_thread(log_and_notify_photo_error, user_id, action, error_details) - await msg.answer(photo_error_handling(), parse_mode="html") @@ -158,7 +156,6 @@ async def photo_module_handler(msg: Message): response = await client.post(config.TRASH_API_URL, files=files) if response.status_code == 200: - # ФИКСАЦИЯ СТАТИСТИКИ: Успешная выгрузка фото на утверждение log_menu_stats(user_id, "Photo Bot", "Отправка фото на утверждение") await msg.answer(photo_success_sent(), parse_mode="html") @@ -186,58 +183,49 @@ async def photo_module_handler(msg: Message): await msg.answer(photo_cancel_text(), parse_mode="html") return - # --- ИСПРАВЛЕНО: Защита от мусорного ввода при висящем превью --- else: - await msg.answer(system_error_text(EMOJI_DIGITS), parse_mode="html") + await msg.answer(PHOTO_UNKNOWN_CMD_TEXT, parse_mode="html") return - # --- ПРИЕМ НОВОГО ФОТО --- + # --- ПРИЕМ НОВОГО ФОТО (ТЕСТОВЫЙ РЕЖИМ: ТОЛЬКО ИИ) --- if is_attachment: file_id = getattr(msg.content, "file_id", None) - ready_path = f"/tmp/{user_login}.bmp" - raw_path = None + raw_data = None - await msg.answer(PHOTO_PROCESSING_TEXT, parse_mode="html") + await msg.answer("🤖 Отправка фото на проверку в ИИ (srvkem-ii-03:8083)...", parse_mode="html") try: downloaded_file = await states.tc_bot.download_file_by_id(file_id) - raw_path = downloaded_file - result = await asyncio.to_thread(prepare_ad_photo, raw_path, ready_path, 96) + raw_data = downloaded_file - if result["success"]: - # ФИКСАЦИЯ СТАТИСТИКИ: Факт успешной загрузки и обработки нового фото - log_menu_stats(user_id, "Photo Bot", "Загрузка и конвертация нового фото") - pending_photos[user_id] = ready_path - preview_path = f"/tmp/prev_{user_login}.jpg" - try: - Image.open(ready_path).save(preview_path, format="JPEG") - p_main = FSInputFile(preview_path, filename="preview.jpg") - p_thumb = FSInputFile(preview_path, filename="preview_thumb.jpg") - await msg.answer_photo(p_main, p_thumb) - except Exception as lib_err: - await asyncio.to_thread(log_and_notify_photo_error, user_id, "Генерация превью", str(lib_err)) - finally: - if os.path.exists(preview_path): - os.remove(preview_path) + # Отправляем фото напрямую в ИИ Gemma 12B Vision + ai_result = await verify_photo_with_ai(raw_data) - await asyncio.sleep(0.5) + # 🛡️ Защита от неожиданного формата (гарантирует отсутствие NameError) + if not isinstance(ai_result, dict): + ai_result = {"is_valid": False, "reason": "Некорректный формат ответа от ИИ."} + + is_valid = ai_result.get("is_valid", False) + reason = ai_result.get("reason", "Нет ответа от модели.") + + if not is_valid: await msg.answer( - photo_preview_ready(), + f"❌ [ИИ Отклонил]\n\nПричина: {reason}", parse_mode="html" ) else: - error_text = result.get('error', 'Не удалось обработать фото.') await msg.answer( - photo_error_processing(error_text), + f"✅ [ИИ Одобрил]\n\nВердикт: Фотография полностью соответствует требованиям.", parse_mode="html" ) + except Exception as e: + logger.exception(f"Ошибка при передаче фото в ИИ: {e}") await handle_photo_error(msg, user_id, "Скачивание и обработка файла", str(e)) finally: - if raw_path and os.path.exists(raw_path): + if raw_data and isinstance(raw_data, str) and os.path.exists(raw_data): try: - os.remove(raw_path) - except Exception as cleanup_err: - await asyncio.to_thread(log_and_notify_photo_error, user_id, "Очистка временных файлов", str(cleanup_err)) + os.remove(raw_data) + except Exception: + pass return -