gateway: fix greeting UX and reduce false photo-intent fallbacks
This commit is contained in:
@@ -138,17 +138,6 @@ def _looks_like_photo_followup(text: str) -> bool:
|
|||||||
if any(m in t for m in direct_markers):
|
if any(m in t for m in direct_markers):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# If user is correcting previous visual interpretation, route to vision again.
|
|
||||||
correction_markers = [
|
|
||||||
"неправильна відповідь", "не правильна відповідь", "не видумуй", "це не так",
|
|
||||||
"ти помилився", "ти помилилась", "неправильно визначив",
|
|
||||||
"wrong answer", "you are wrong", "that is incorrect",
|
|
||||||
"неправильный ответ", "это не так", "ты ошибся",
|
|
||||||
]
|
|
||||||
photo_topic_markers = ["фото", "зображ", "рослин", "image", "photo", "plant", "растен"]
|
|
||||||
if any(c in t for c in correction_markers) and any(p in t for p in photo_topic_markers):
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Flexible forms: "що на ... фото/зображенні/світлині"
|
# Flexible forms: "що на ... фото/зображенні/світлині"
|
||||||
if re.search(r"(що|what|что)\s+на\s+.*(фото|зображ|світлин|image|photo)", t):
|
if re.search(r"(що|what|что)\s+на\s+.*(фото|зображ|світлин|image|photo)", t):
|
||||||
# Exclude common meta-questions
|
# Exclude common meta-questions
|
||||||
@@ -158,6 +147,37 @@ def _looks_like_photo_followup(text: str) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _needs_photo_only_response(text: str) -> bool:
|
||||||
|
"""
|
||||||
|
Return True only for explicit requests to analyze/describe image content.
|
||||||
|
Do not trigger on meta-dialogue about previous mistakes.
|
||||||
|
"""
|
||||||
|
t = (text or "").strip().lower()
|
||||||
|
if not t:
|
||||||
|
return False
|
||||||
|
explicit_patterns = [
|
||||||
|
r"(що|what|что).{0,24}(на|in).{0,24}(фото|зображ|світлин|image|photo)",
|
||||||
|
r"(опиши|describe|проаналізуй|analyz|анализируй).{0,32}(фото|зображ|image|photo)",
|
||||||
|
r"(яка|какая|what).{0,28}(рослин|plant|культура).{0,28}(на|in).{0,28}(фото|image|photo)",
|
||||||
|
]
|
||||||
|
return any(re.search(p, t) for p in explicit_patterns)
|
||||||
|
|
||||||
|
|
||||||
|
def _is_simple_greeting(text: str) -> bool:
|
||||||
|
t = (text or "").strip().lower()
|
||||||
|
if not t:
|
||||||
|
return False
|
||||||
|
compact = re.sub(r"[^a-zа-яіїєґ0-9 ]+", "", t).strip()
|
||||||
|
greetings = {
|
||||||
|
"привіт", "вітаю", "добрий день", "доброго дня", "доброго вечора",
|
||||||
|
"hello", "hi", "hey", "good morning", "good evening",
|
||||||
|
}
|
||||||
|
if compact in greetings:
|
||||||
|
return True
|
||||||
|
# Short greeting variants like "привіт!" / "hi!"
|
||||||
|
return len(compact.split()) <= 3 and any(g in compact for g in greetings)
|
||||||
|
|
||||||
|
|
||||||
def _extract_unanswered_user_messages(
|
def _extract_unanswered_user_messages(
|
||||||
memory_context: Dict[str, Any],
|
memory_context: Dict[str, Any],
|
||||||
current_user_id: str,
|
current_user_id: str,
|
||||||
@@ -2536,14 +2556,33 @@ async def handle_telegram_webhook(
|
|||||||
text = update.message.get("text", "")
|
text = update.message.get("text", "")
|
||||||
caption = update.message.get("caption", "")
|
caption = update.message.get("caption", "")
|
||||||
|
|
||||||
|
# Friendly greeting fast-path for better UX and less mechanical replies.
|
||||||
|
if _is_simple_greeting(text):
|
||||||
|
greeting_reply = (
|
||||||
|
f"Привіт, {username or 'друже'}! Я {agent_config.name}. "
|
||||||
|
"Можу допомогти з фото рослин, Excel-звітами та короткими практичними порадами."
|
||||||
|
)
|
||||||
|
await send_telegram_message(chat_id, greeting_reply, telegram_token)
|
||||||
|
await memory_client.save_chat_turn(
|
||||||
|
agent_id=agent_config.agent_id,
|
||||||
|
team_id=dao_id,
|
||||||
|
user_id=f"tg:{user_id}",
|
||||||
|
message=text,
|
||||||
|
response=greeting_reply,
|
||||||
|
channel_id=chat_id,
|
||||||
|
scope="short_term",
|
||||||
|
save_agent_response=True,
|
||||||
|
agent_metadata={"greeting_fast_path": True},
|
||||||
|
username=username,
|
||||||
|
)
|
||||||
|
return {"ok": True, "agent": agent_config.agent_id, "mode": "greeting_fast_path"}
|
||||||
|
|
||||||
# Photo/image intent guard:
|
# Photo/image intent guard:
|
||||||
# if text references a photo/image, try to resolve latest file_id and route to vision.
|
# if text references a photo/image, try to resolve latest file_id and route to vision.
|
||||||
photo_intent = False
|
photo_intent = False
|
||||||
if text:
|
if text:
|
||||||
tl = text.lower()
|
tl = text.lower()
|
||||||
photo_intent = _looks_like_photo_followup(text) or any(
|
photo_intent = _looks_like_photo_followup(text)
|
||||||
k in tl for k in ("фото", "зображ", "світлин", "image", "photo")
|
|
||||||
)
|
|
||||||
if not photo_intent:
|
if not photo_intent:
|
||||||
# Robust fallback for common formulations like "що на цьому фото?"
|
# Robust fallback for common formulations like "що на цьому фото?"
|
||||||
photo_intent = bool(
|
photo_intent = bool(
|
||||||
@@ -2590,8 +2629,7 @@ async def handle_telegram_webhook(
|
|||||||
return followup_result
|
return followup_result
|
||||||
|
|
||||||
# Hard guard: don't send photo-related requests to text LLM path when image context is missing.
|
# Hard guard: don't send photo-related requests to text LLM path when image context is missing.
|
||||||
is_question_like = ("?" in text) or any(k in tl for k in ("що", "опиши", "проанал", "what", "describe", "analy", "что"))
|
if _needs_photo_only_response(text):
|
||||||
if is_question_like:
|
|
||||||
await send_telegram_message(
|
await send_telegram_message(
|
||||||
chat_id,
|
chat_id,
|
||||||
"Бачу питання про фото, але не знайшов зображення в історії сесії. Надішли фото ще раз з коротким питанням, і я одразу проаналізую.",
|
"Бачу питання про фото, але не знайшов зображення в історії сесії. Надішли фото ще раз з коротким питанням, і я одразу проаналізую.",
|
||||||
|
|||||||
Reference in New Issue
Block a user