Update photo_bot/handlers.py: AI photo verification instead of preview
This commit is contained in:
+26
-38
@@ -1,4 +1,3 @@
|
|||||||
# /opt/trueconf_bot/photo_bot/handlers.py
|
|
||||||
import os
|
import os
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
@@ -15,11 +14,11 @@ from trueconf.types import FSInputFile
|
|||||||
import config.config as config
|
import config.config as config
|
||||||
from utils import states
|
from utils import states
|
||||||
from utils.menu import MENU_TEXT
|
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 (
|
from utils.texts import (
|
||||||
EMOJI_DIGITS,
|
EMOJI_DIGITS,
|
||||||
PHOTO_MAIN_MENU_TEXT,
|
PHOTO_MAIN_MENU_TEXT,
|
||||||
system_error_text,
|
PHOTO_UNKNOWN_CMD_TEXT,
|
||||||
photo_error_handling,
|
photo_error_handling,
|
||||||
PHOTO_UPLOADING_TEXT,
|
PHOTO_UPLOADING_TEXT,
|
||||||
photo_success_sent,
|
photo_success_sent,
|
||||||
@@ -48,7 +47,7 @@ def log_and_notify_photo_error(user_id: str, action: str, error_details: str):
|
|||||||
"""Записывает системную ошибку в лог-файл и отправляет email-алерт администраторам"""
|
"""Записывает системную ошибку в лог-файл и отправляет email-алерт администраторам"""
|
||||||
global last_email_time
|
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)
|
os.makedirs(log_dir, exist_ok=True)
|
||||||
log_file = os.path.join(log_dir, "photo_errors.log")
|
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):
|
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 asyncio.to_thread(log_and_notify_photo_error, user_id, action, error_details)
|
||||||
|
|
||||||
await msg.answer(photo_error_handling(), parse_mode="html")
|
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)
|
response = await client.post(config.TRASH_API_URL, files=files)
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
# ФИКСАЦИЯ СТАТИСТИКИ: Успешная выгрузка фото на утверждение
|
|
||||||
log_menu_stats(user_id, "Photo Bot", "Отправка фото на утверждение")
|
log_menu_stats(user_id, "Photo Bot", "Отправка фото на утверждение")
|
||||||
await msg.answer(photo_success_sent(), parse_mode="html")
|
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")
|
await msg.answer(photo_cancel_text(), parse_mode="html")
|
||||||
return
|
return
|
||||||
|
|
||||||
# --- ИСПРАВЛЕНО: Защита от мусорного ввода при висящем превью ---
|
|
||||||
else:
|
else:
|
||||||
await msg.answer(system_error_text(EMOJI_DIGITS), parse_mode="html")
|
await msg.answer(PHOTO_UNKNOWN_CMD_TEXT, parse_mode="html")
|
||||||
return
|
return
|
||||||
|
|
||||||
# --- ПРИЕМ НОВОГО ФОТО ---
|
# --- ПРИЕМ НОВОГО ФОТО (ТЕСТОВЫЙ РЕЖИМ: ТОЛЬКО ИИ) ---
|
||||||
if is_attachment:
|
if is_attachment:
|
||||||
file_id = getattr(msg.content, "file_id", None)
|
file_id = getattr(msg.content, "file_id", None)
|
||||||
ready_path = f"/tmp/{user_login}.bmp"
|
raw_data = None
|
||||||
raw_path = None
|
|
||||||
|
|
||||||
await msg.answer(PHOTO_PROCESSING_TEXT, parse_mode="html")
|
await msg.answer("🤖 <i>Отправка фото на проверку в ИИ (srvkem-ii-03:8083)...</i>", parse_mode="html")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
downloaded_file = await states.tc_bot.download_file_by_id(file_id)
|
downloaded_file = await states.tc_bot.download_file_by_id(file_id)
|
||||||
raw_path = downloaded_file
|
raw_data = downloaded_file
|
||||||
result = await asyncio.to_thread(prepare_ad_photo, raw_path, ready_path, 96)
|
|
||||||
|
|
||||||
if result["success"]:
|
# Отправляем фото напрямую в ИИ Gemma 12B Vision
|
||||||
# ФИКСАЦИЯ СТАТИСТИКИ: Факт успешной загрузки и обработки нового фото
|
ai_result = await verify_photo_with_ai(raw_data)
|
||||||
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)
|
|
||||||
|
|
||||||
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(
|
await msg.answer(
|
||||||
photo_preview_ready(),
|
f"❌ <b>[ИИ Отклонил]</b>\n\n<b>Причина:</b> {reason}",
|
||||||
parse_mode="html"
|
parse_mode="html"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
error_text = result.get('error', 'Не удалось обработать фото.')
|
|
||||||
await msg.answer(
|
await msg.answer(
|
||||||
photo_error_processing(error_text),
|
f"✅ <b>[ИИ Одобрил]</b>\n\n<b>Вердикт:</b> Фотография полностью соответствует требованиям.",
|
||||||
parse_mode="html"
|
parse_mode="html"
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
logger.exception(f"Ошибка при передаче фото в ИИ: {e}")
|
||||||
await handle_photo_error(msg, user_id, "Скачивание и обработка файла", str(e))
|
await handle_photo_error(msg, user_id, "Скачивание и обработка файла", str(e))
|
||||||
finally:
|
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:
|
try:
|
||||||
os.remove(raw_path)
|
os.remove(raw_data)
|
||||||
except Exception as cleanup_err:
|
except Exception:
|
||||||
await asyncio.to_thread(log_and_notify_photo_error, user_id, "Очистка временных файлов", str(cleanup_err))
|
pass
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user