handlers.py: проверка статуса модерации при входе и перед отправкой
This commit is contained in:
+62
-20
@@ -109,6 +109,27 @@ async def handle_photo_error(msg: Message, user_id: str, action: str, error_deta
|
||||
await msg.answer(photo_error_handling(), parse_mode="html")
|
||||
|
||||
|
||||
async def check_moderation_status(user_id: str) -> dict:
|
||||
"""Проверяет текущий статус модерации пользователя через API"""
|
||||
from photo_bot.photo_processor import API_URL, API_KEY
|
||||
import requests
|
||||
|
||||
status_url = API_URL.replace("/upload/", "/status/")
|
||||
try:
|
||||
response = requests.get(
|
||||
status_url,
|
||||
params={"user_id": user_id},
|
||||
headers={"X-API-Key": API_KEY},
|
||||
timeout=15,
|
||||
verify=False
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка проверки статуса модерации: {e}")
|
||||
return {"status": "error", "reason": str(e)}
|
||||
|
||||
|
||||
# =========================================================
|
||||
# ОСНОВНОЙ ОБРАБОТЧИК
|
||||
# =========================================================
|
||||
@@ -149,12 +170,28 @@ async def photo_module_handler(msg: Message):
|
||||
await msg.answer(MENU_TEXT, parse_mode="html")
|
||||
return
|
||||
|
||||
# --- ПЕРВАЯ ПРОВЕРКА: если нет фото в pending_photos, проверяем статус модерации ---
|
||||
if user_id not in pending_photos and not is_attachment:
|
||||
status = await check_moderation_status(user_id)
|
||||
if status.get("status") == "ok" and status.get("moderation_status") == "pending":
|
||||
photo_id = status.get("photo_id", "???")
|
||||
await msg.answer(
|
||||
f"⏳ <b>У вас уже есть фото на модерации (ID: {photo_id}).</b>\n\n"
|
||||
f"Ожидайте решения модератора.\n\n"
|
||||
f"{EMOJI_DIGITS['0']} — В главное меню",
|
||||
parse_mode="html"
|
||||
)
|
||||
return
|
||||
elif status.get("status") != "ok":
|
||||
# Ошибка проверки — не блокируем, просто логируем
|
||||
logger.warning(f"Не удалось проверить статус модерации для {user_id}: {status.get('reason')}")
|
||||
|
||||
# --- ПОДТВЕРЖДЕНИЕ ОТПРАВКИ (Кнопка 1) ---
|
||||
if not is_attachment and user_id in pending_photos:
|
||||
if cmd == "1":
|
||||
photo_data = pending_photos[user_id]
|
||||
original_path = photo_data['path']
|
||||
|
||||
|
||||
await msg.answer(PHOTO_AI_PROCESSING_TEXT, parse_mode="html")
|
||||
|
||||
try:
|
||||
@@ -162,7 +199,7 @@ async def photo_module_handler(msg: Message):
|
||||
result = await asyncio.to_thread(
|
||||
prepare_ad_photo, original_path, user_login
|
||||
)
|
||||
|
||||
|
||||
if result["success"]:
|
||||
verdict = result.get("verdict")
|
||||
if verdict == "published":
|
||||
@@ -175,11 +212,16 @@ async def photo_module_handler(msg: Message):
|
||||
msg_text = result.get("message", "Фото обработано")
|
||||
await msg.answer(f"✅ {msg_text}", parse_mode="html")
|
||||
else:
|
||||
# Любая ошибка API — системная заглушка
|
||||
await msg.answer(photo_error_handling(), parse_mode="html")
|
||||
error_msg = result.get("error", "Неизвестная ошибка")
|
||||
# Если фото уже на модерации — показываем конкретное сообщение
|
||||
if "уже есть фото на модерации" in error_msg:
|
||||
log_menu_stats(user_id, "Photo Bot", "Попытка повторной загрузки на модерации")
|
||||
await msg.answer(photo_error_already_pending(), parse_mode="html")
|
||||
else:
|
||||
await msg.answer(photo_error_handling(), parse_mode="html")
|
||||
except Exception as e:
|
||||
await handle_photo_error(msg, user_id, "Отправка фото через API", str(e))
|
||||
|
||||
|
||||
# Убираем за собой
|
||||
if os.path.exists(original_path):
|
||||
os.remove(original_path)
|
||||
@@ -188,7 +230,7 @@ async def photo_module_handler(msg: Message):
|
||||
states.clear_state(user_id)
|
||||
if user_id in pending_photos:
|
||||
del pending_photos[user_id]
|
||||
|
||||
|
||||
return
|
||||
|
||||
# --- ОТМЕНА ФОТО (Кнопка 2) ---
|
||||
@@ -220,7 +262,7 @@ async def photo_module_handler(msg: Message):
|
||||
try:
|
||||
downloaded_file = await states.tc_bot.download_file_by_id(file_id)
|
||||
logger.info(f"Скачан файл для {user_login}: type={type(downloaded_file)}, len={len(downloaded_file) if isinstance(downloaded_file, (bytes, str)) else 'N/A'}")
|
||||
|
||||
|
||||
# Скачиваем в байты напрямую
|
||||
if isinstance(downloaded_file, bytes):
|
||||
raw_bytes = downloaded_file
|
||||
@@ -235,13 +277,13 @@ async def photo_module_handler(msg: Message):
|
||||
raw_bytes = f.read()
|
||||
else:
|
||||
raise Exception(f"Не удалось получить байты файла: {type(downloaded_file)}")
|
||||
|
||||
|
||||
logger.info(f"Прочитано {len(raw_bytes)} байт для {user_login}")
|
||||
|
||||
|
||||
# Ищем лицо и получаем координаты
|
||||
coords = await asyncio.to_thread(get_crop_coordinates, raw_bytes)
|
||||
logger.info(f"get_crop_coordinates вернул: {coords} для {user_login}")
|
||||
|
||||
|
||||
if not coords:
|
||||
await msg.answer(
|
||||
"❌ Лицо не найдено. Пожалуйста, сделайте фото анфас при хорошем освещении.\n\n"
|
||||
@@ -249,7 +291,7 @@ async def photo_module_handler(msg: Message):
|
||||
parse_mode="html"
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
# Генерируем превью
|
||||
try:
|
||||
from PIL import Image
|
||||
@@ -257,40 +299,40 @@ async def photo_module_handler(msg: Message):
|
||||
img = Image.open(io.BytesIO(raw_bytes))
|
||||
if img.mode != 'RGB':
|
||||
img = img.convert('RGB')
|
||||
|
||||
|
||||
x1, y1, x2, y2 = coords
|
||||
cropped = img.crop((x1, y1, x2, y2))
|
||||
|
||||
|
||||
# Ресайз до квадрата
|
||||
side = min(cropped.size[0], cropped.size[1])
|
||||
left = (cropped.size[0] - side) // 2
|
||||
top = (cropped.size[1] - side) // 2
|
||||
cropped = cropped.crop((left, top, left + side, top + side))
|
||||
|
||||
|
||||
preview = cropped.resize((400, 400), Image.Resampling.LANCZOS)
|
||||
|
||||
|
||||
preview_path = f"/tmp/prev_{user_login}.jpg"
|
||||
preview.save(preview_path, format="JPEG", quality=85)
|
||||
|
||||
|
||||
preview_doc = FSInputFile(preview_path, filename="preview.jpg")
|
||||
await msg.answer_photo(preview_doc, preview_doc)
|
||||
except Exception as lib_err:
|
||||
await asyncio.to_thread(log_and_notify_photo_error, user_id, "Генерация превью", str(lib_err))
|
||||
raise Exception("Ошибка генерации превью")
|
||||
|
||||
|
||||
# Сохраняем оригинал и координаты
|
||||
original_path = f"/tmp/orig_{user_login}.jpg"
|
||||
with open(original_path, 'wb') as f:
|
||||
f.write(raw_bytes)
|
||||
|
||||
|
||||
pending_photos[user_id] = {
|
||||
'path': original_path,
|
||||
'coords': coords,
|
||||
'preview_path': preview_path
|
||||
}
|
||||
|
||||
|
||||
log_menu_stats(user_id, "Photo Bot", "Загрузка и обработка нового фото")
|
||||
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
await msg.answer(
|
||||
photo_preview_ready(),
|
||||
|
||||
Reference in New Issue
Block a user