diff --git a/photo_bot/ai_validator.py b/photo_bot/ai_validator.py
index 6a8c798..a1c1cda 100644
--- a/photo_bot/ai_validator.py
+++ b/photo_bot/ai_validator.py
@@ -21,32 +21,33 @@ def _build_prompt() -> str:
"""Промпт проверки фото (без подсказки MediaPipe — в тест-моде геометрия не считается)."""
cv_hint = 'ℹ️ ПОДСКАЗКА ОТ ALGORITHM: Геометрическая проверка в тестовом режиме не выполняется, проверяй визуально.'
- return ('''Ты — автоматический эксперт пропускной системы. Проверь фотографию сотрудника на соответствие регламенту.
+ return ('''Ты — строгий инспектор пропускной системы. Проверь фотографию сотрудника на соответствие регламенту.
%s
ЗАПРЕЩЕНО выводить внутренние рассуждения и теги размышлений. Сразу пиши финальный ответ.
-БЛОК 0. КРИТИЧЕСКИЕ СТОП-ФАКТОРЫ:
-1. Не реальное фото: ИИ-генерация, 3D-арт, цифровой рисунок, мультфильм, стилизованный портрет, сильная обработка фильтрами.
-2. Графика и текст: Любые надписи, водяные знаки, рамки, декоративный фон с буквами, графическими элементами, коллажи.
-3. Костюмы и атрибуты: Исторические костюмы, короны, маски, каски (кроме строительных).
-4. Посторонние предметы: Оружие, предметы перед лицом.
-5. Неправильный ракурс и взгляд: Строгий боковой профиль, затылок, человек смотрит совсем в сторону.
-6. Гримасы и мимика: Гримасы, смешные рожи, высунутый язык, вытянутые щёки, скривленные губы, смех/улыбка с закрытым ртом, любой невынужденный и неспокойный вид. Выражение лица должно быть нейтральным или слегка спокойным.
+ПРЯМО СЕЙЧАС ВНИМАТЕЛЬНО РАССМОТРИ ФОТО И ПОСЛЕДОВАТЕЛЬНО ЗАФИКСИРУЙ:
+A) РЕАЛЬНОСТЬ: это живое фото, а не ИИ-генерация, рисунок, 3D, мультфильм, фильтр?
+B) ГРАФИКА: есть ли рамка, любые буквы/надписи/подписи (включая подпись с именем внизу), водяные знаки, декоративный фон с буквами, коллаж?
+C) МИМИКА: высунут ли язык? Скривлены ли губы? Есть ли гримаса, смешная рожа, щёлканье зубами, смех, скос глаз, закатанные глаза?
+D) РАКУРС: профиль, затылок, взгляд в сторону?
+E) МАСШТАБ: ниже линии груди видны ли живот, талия, подмышки?
-БЛОК 1. МАСШТАБ И КАДРИРОВАНИЕ:
-- подбородок НИЖЕ середины кадра → тест пройден.
-- «Не прошел», если видны талия, живот, подмышки, одежда ниже линии груди.
+ПРАВИЛО ОТКАЗА: если по любому пункту A–E есть хоть малейшее отклонение — вердикт «Не прошел».
+Смех, ржа, рожи, высунутый язык, скривлённые губы — фото НЕ ПРОХОДИТ, даже если лицо анфас и хорошо освещено.
+Рамка или буквы/подпись на фоне или по краю кадра — фото НЕ ПРОХОДИТ.
ИТОГОВЫЙ ВЕРДИКТ:
-- «Прошел» — нормальные портретные фотографии.
-- «Не прошел» — только явные нарушения.
-- «На модерацию» — если фото качественное, но масштаб на грани.
+- «Прошел» — только если все пункты A–E идеальны: нейтральное спокойное лицо, чистый кадр без рамки и букв.
+- «Не прошел» — любое отклонение, описанное выше.
+- «На модерацию» — только если фото реальное и лицо нейтральное, но масштаб или ракурс на грани нормы.
-ФОРМАТ ОТВЕТА — СТРОГО 2 строки:
+ФОРМАТ ОТВЕТА — СТРОГО 4 строки, без других слов:
+Мимика: <нейтрально / высунут язык / гримаса / скривленная улыбка / смех — что именно видно>
+Графика: <нет / рамка / буквы / подпись / коллаж — что именно видно>
Вердикт: [Прошел / Не прошел / На модерацию]
-Причина: [1–2 предложения с указанием конкретной причины]
+Причина: [1–2 предложения с указанием конкретного пункта A–E]
''') % cv_hint
@@ -99,15 +100,22 @@ def validate_photo_with_ai(file_bytes: bytes) -> dict:
verdict = 'Не прошел'
reason = ''
+ mimi = ''
+ grafika = ''
for line in clean_ans.splitlines():
- if line.strip().lower().startswith('причина:'):
+ ls = line.strip().lower()
+ if ls.startswith('причина:'):
reason = line.split(':', 1)[1].strip()
- break
+ elif ls.startswith('мимика:'):
+ mimi = line.split(':', 1)[1].strip()
+ elif ls.startswith('графика:'):
+ grafika = line.split(':', 1)[1].strip()
if not reason:
reason = clean_ans.replace('\n', ' ').strip()
- logger.info(f"[TEST MODE] ИИ-вердикт: {verdict} | {reason}")
- return {'ok': True, 'verdict': verdict, 'reason': reason, 'error': ''}
+ logger.info(f"[TEST MODE] ИИ-вердикт: {verdict} | мимика={mimi} | графика={grafika} | {reason}")
+ return {'ok': True, 'verdict': verdict, 'reason': reason, 'error': '',
+ 'mimi': mimi, 'grafika': grafika}
except Exception as e:
logger.error(f"[TEST MODE] Ошибка обращения к ИИ: {e}")
diff --git a/photo_bot/handlers.py b/photo_bot/handlers.py
index b5c2498..77f9094 100644
--- a/photo_bot/handlers.py
+++ b/photo_bot/handlers.py
@@ -220,10 +220,12 @@ async def photo_module_handler(msg: Message):
verdict = ai_res['verdict']
reason = ai_res['reason'] or 'Причина не указана.'
+ mimi = ai_res.get('mimi', '')
+ grafika = ai_res.get('grafika', '')
log_menu_stats(user_id, "Photo Bot (TEST)", f"ИИ-вердикт: {verdict}")
# Фото остаётся в pending — можно повторить проверку другим фото (кнопка 2)
- await msg.answer(photo_test_result(verdict, reason), parse_mode="html")
+ await msg.answer(photo_test_result(verdict, reason, mimi, grafika), parse_mode="html")
return
elif cmd == "2":
@@ -314,8 +316,7 @@ async def photo_module_handler(msg: Message):
file_id = getattr(msg.content, "file_id", None)
raw_bytes = None
- face_text = PHOTO_TEST_RECEIVING_TEXT if config.PHOTO_TEST_MODE else PHOTO_PROCESSING_FACE_TEXT
- await msg.answer(face_text, parse_mode="html")
+ await msg.answer(PHOTO_PROCESSING_FACE_TEXT, parse_mode="html")
try:
downloaded_file = await states.tc_bot.download_file_by_id(file_id)
diff --git a/utils/texts.py b/utils/texts.py
index 1e36897..1615f75 100644
--- a/utils/texts.py
+++ b/utils/texts.py
@@ -269,16 +269,27 @@ def _photo_test_ai_checking(emojis: dict) -> str:
def _photo_test_receiving(emojis: dict) -> str:
return "🧪 Ищу лицо на фото (тестовый режим), пожалуйста, подождите..."
-def _photo_test_result(verdict: str, reason: str, emojis: dict) -> str:
+def _photo_test_result(verdict: str, reason: str, mimi: str = '', grafika: str = '', emojis: dict = None) -> str:
+ emojis = emojis or {}
icons = {"Прошел": "✅", "Не прошел": "❌", "На модерацию": "⏳"}
icon = icons.get(verdict, "ℹ️")
+ lines = []
+ if mimi:
+ lines.append(f"🙂 Мимика: {mimi}")
+ if grafika:
+ lines.append(f"🖼 Графика: {grafika}")
+ if lines:
+ detail = "\n".join(lines) + "\n\n"
+ else:
+ detail = ""
return (
f"🧪 Тестовый режим: вердикт ИИ\n\n"
f"{icon} Вердикт: {verdict}\n"
+ f"{detail}"
f"📝 Причина: {reason}\n\n"
f"⚠️ Тестовый режим: фото не публиковалось и никуда не отправлялось.\n\n"
- f"{emojis['2']} — Загрузить другое фото\n"
- f"{emojis['0']} — В главное меню"
+ f"{emojis.get('2', '2')} — Загрузить другое фото\n"
+ f"{emojis.get('0', '0')} — В главное меню"
)
def _photo_test_ai_error(emojis: dict) -> str:
@@ -362,8 +373,8 @@ PHOTO_TEST_PREVIEW_TEXT = _photo_test_preview(EMOJI_DIGITS)
PHOTO_TEST_AI_CHECKING_TEXT = _photo_test_ai_checking(EMOJI_DIGITS)
PHOTO_TEST_RECEIVING_TEXT = _photo_test_receiving(EMOJI_DIGITS)
-def photo_test_result(verdict: str, reason: str) -> str:
- return _photo_test_result(verdict, reason, EMOJI_DIGITS)
+def photo_test_result(verdict: str, reason: str, mimi: str = '', grafika: str = '') -> str:
+ return _photo_test_result(verdict, reason, mimi, grafika, EMOJI_DIGITS)
def photo_test_ai_error() -> str:
return _photo_test_ai_error(EMOJI_DIGITS)