fix: Remove translation detection workflow from DM handler
The auto-detect language + translation menu was misidentifying regular German messages and blocking normal responses. Bot now simply responds in whatever language the user writes in, per updated system prompt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
124
bot.py
124
bot.py
@@ -80,7 +80,7 @@ MAX_TOOL_ITERATIONS = 5
|
|||||||
|
|
||||||
SYSTEM_PROMPT = """You are a helpful AI assistant in a Matrix chat room.
|
SYSTEM_PROMPT = """You are a helpful AI assistant in a Matrix chat room.
|
||||||
Keep answers concise but thorough. Use markdown formatting when helpful.
|
Keep answers concise but thorough. Use markdown formatting when helpful.
|
||||||
Always respond in the same language the user writes in. If you have memories about the user's preferred language, use that language consistently.
|
Always respond in the same language the user writes in. Never switch languages unless the user explicitly asks you to. If a user writes in German, reply in German. If they write in English, reply in English. Do not offer to translate or change language on your own.
|
||||||
|
|
||||||
IMPORTANT RULES — FOLLOW THESE STRICTLY:
|
IMPORTANT RULES — FOLLOW THESE STRICTLY:
|
||||||
- When document context is provided below, use it to answer. Always include any links.
|
- When document context is provided below, use it to answer. Always include any links.
|
||||||
@@ -834,8 +834,6 @@ class Bot:
|
|||||||
self._sync_token_received = False
|
self._sync_token_received = False
|
||||||
self._verifications: dict[str, dict] = {} # txn_id -> verification state
|
self._verifications: dict[str, dict] = {} # txn_id -> verification state
|
||||||
self._pending_connects: dict[str, str] = {} # matrix_user_id -> device_code
|
self._pending_connects: dict[str, str] = {} # matrix_user_id -> device_code
|
||||||
self._pending_translate: dict[str, dict] = {} # sender -> {text, detected_lang, room_id}
|
|
||||||
self._pending_reply: dict[str, dict] = {} # sender -> {target_lang}
|
|
||||||
self._room_document_context: dict[str, list[dict]] = {} # room_id -> [{type, filename, text, timestamp}, ...]
|
self._room_document_context: dict[str, list[dict]] = {} # room_id -> [{type, filename, text, timestamp}, ...]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -1201,62 +1199,6 @@ class Bot:
|
|||||||
except Exception:
|
except Exception:
|
||||||
logger.warning("Memory extraction failed", exc_info=True)
|
logger.warning("Memory extraction failed", exc_info=True)
|
||||||
|
|
||||||
async def _detect_language(self, text: str) -> str:
|
|
||||||
"""Detect the language of a text using a fast LLM call."""
|
|
||||||
if not self.llm:
|
|
||||||
return "Unknown"
|
|
||||||
try:
|
|
||||||
resp = await self.llm.chat.completions.create(
|
|
||||||
model=DEFAULT_MODEL,
|
|
||||||
messages=[
|
|
||||||
{"role": "system", "content": "What language is this text? Reply with ONLY the language name in English."},
|
|
||||||
{"role": "user", "content": text[:500]},
|
|
||||||
],
|
|
||||||
max_tokens=10,
|
|
||||||
)
|
|
||||||
return resp.choices[0].message.content.strip()
|
|
||||||
except Exception:
|
|
||||||
logger.debug("Language detection failed", exc_info=True)
|
|
||||||
return "Unknown"
|
|
||||||
|
|
||||||
async def _translate_text(self, text: str, target_language: str, model: str | None = None) -> str:
|
|
||||||
"""Translate text to the target language using LLM."""
|
|
||||||
if not self.llm:
|
|
||||||
return text
|
|
||||||
try:
|
|
||||||
resp = await self.llm.chat.completions.create(
|
|
||||||
model=model or DEFAULT_MODEL,
|
|
||||||
messages=[
|
|
||||||
{"role": "system", "content": f"Translate the following text to {target_language}. Return ONLY the translation."},
|
|
||||||
{"role": "user", "content": text},
|
|
||||||
],
|
|
||||||
max_tokens=1000,
|
|
||||||
)
|
|
||||||
return resp.choices[0].message.content.strip()
|
|
||||||
except Exception:
|
|
||||||
logger.debug("Translation failed", exc_info=True)
|
|
||||||
return f"[Translation failed] {text}"
|
|
||||||
|
|
||||||
async def _get_preferred_language(self, user_id: str) -> str:
|
|
||||||
"""Get user's preferred language from memories (last match = most recent)."""
|
|
||||||
memories = await self.memory.query(user_id, "preferred language", top_k=5)
|
|
||||||
known_langs = [
|
|
||||||
"English", "German", "French", "Spanish", "Italian", "Portuguese",
|
|
||||||
"Dutch", "Russian", "Chinese", "Japanese", "Korean", "Arabic",
|
|
||||||
"Turkish", "Polish", "Swedish", "Norwegian", "Danish", "Finnish",
|
|
||||||
"Greek", "Hebrew", "Hindi", "Thai", "Vietnamese", "Indonesian",
|
|
||||||
"Czech", "Romanian", "Hungarian", "Ukrainian", "Croatian", "Serbian",
|
|
||||||
]
|
|
||||||
result = "English"
|
|
||||||
for m in memories:
|
|
||||||
fact = m["fact"].lower()
|
|
||||||
if "language" in fact or "speaks" in fact or "prefers" in fact:
|
|
||||||
for lang in known_langs:
|
|
||||||
if lang.lower() in fact:
|
|
||||||
result = lang
|
|
||||||
break
|
|
||||||
return result
|
|
||||||
|
|
||||||
async def on_text_message(self, room, event: RoomMessageText):
|
async def on_text_message(self, room, event: RoomMessageText):
|
||||||
"""Handle text messages: commands and AI responses."""
|
"""Handle text messages: commands and AI responses."""
|
||||||
if event.sender == BOT_USER:
|
if event.sender == BOT_USER:
|
||||||
@@ -1298,43 +1240,6 @@ class Bot:
|
|||||||
|
|
||||||
sender = event.sender
|
sender = event.sender
|
||||||
|
|
||||||
# --- DM translation workflow: handle pending reply composition ---
|
|
||||||
if is_dm and sender in self._pending_reply:
|
|
||||||
pending = self._pending_reply.pop(sender)
|
|
||||||
await self.client.room_typing(room.room_id, typing_state=True)
|
|
||||||
try:
|
|
||||||
translated = await self._translate_text(body, pending["target_lang"])
|
|
||||||
await self._send_text(room.room_id, translated)
|
|
||||||
finally:
|
|
||||||
await self.client.room_typing(room.room_id, typing_state=False)
|
|
||||||
return
|
|
||||||
|
|
||||||
# --- DM translation workflow: handle menu response ---
|
|
||||||
if is_dm and sender in self._pending_translate:
|
|
||||||
pending = self._pending_translate.pop(sender)
|
|
||||||
choice = body.strip().lower()
|
|
||||||
preferred_lang = await self._get_preferred_language(sender)
|
|
||||||
|
|
||||||
if choice in ("1", "1️⃣") or choice.startswith("translate"):
|
|
||||||
await self.client.room_typing(room.room_id, typing_state=True)
|
|
||||||
try:
|
|
||||||
translated = await self._translate_text(pending["text"], preferred_lang)
|
|
||||||
await self._send_text(room.room_id, translated)
|
|
||||||
finally:
|
|
||||||
await self.client.room_typing(room.room_id, typing_state=False)
|
|
||||||
return
|
|
||||||
|
|
||||||
elif choice in ("2", "2️⃣") or choice.startswith("reply"):
|
|
||||||
self._pending_reply[sender] = {"target_lang": pending["detected_lang"]}
|
|
||||||
await self._send_text(
|
|
||||||
room.room_id,
|
|
||||||
f"Type your message — I'll translate it to **{pending['detected_lang']}**.",
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
# choice "3" or anything else → proceed with normal AI response
|
|
||||||
# (fall through to normal flow below with original pending text context)
|
|
||||||
|
|
||||||
# Check if a recent image was sent in this room (within 60s)
|
# Check if a recent image was sent in this room (within 60s)
|
||||||
image_data = None
|
image_data = None
|
||||||
cached = self._recent_images.get(room.room_id)
|
cached = self._recent_images.get(room.room_id)
|
||||||
@@ -1344,31 +1249,6 @@ class Bot:
|
|||||||
image_data = (b64, mime)
|
image_data = (b64, mime)
|
||||||
del self._recent_images[room.room_id]
|
del self._recent_images[room.room_id]
|
||||||
|
|
||||||
# --- DM translation workflow: detect foreign language ---
|
|
||||||
if is_dm and not body.startswith("!ai") and not image_data:
|
|
||||||
preferred_lang = await self._get_preferred_language(sender)
|
|
||||||
detected_lang = await self._detect_language(body)
|
|
||||||
logger.info("Translation check: detected=%s, preferred=%s, len=%d", detected_lang, preferred_lang, len(body))
|
|
||||||
if (
|
|
||||||
detected_lang != "Unknown"
|
|
||||||
and len(detected_lang) < 30 # sanity check: language name, not a sentence
|
|
||||||
and detected_lang.lower() != preferred_lang.lower()
|
|
||||||
and len(body) > 10 # skip very short messages
|
|
||||||
):
|
|
||||||
self._pending_translate[sender] = {
|
|
||||||
"text": body,
|
|
||||||
"detected_lang": detected_lang,
|
|
||||||
"room_id": room.room_id,
|
|
||||||
}
|
|
||||||
menu = (
|
|
||||||
f"This looks like **{detected_lang}**. What would you like?\n"
|
|
||||||
f"1️⃣ **Translate to {preferred_lang}**\n"
|
|
||||||
f"2️⃣ **Help me reply in {detected_lang}** (type your response, I'll translate)\n"
|
|
||||||
f"3️⃣ **Just respond normally**"
|
|
||||||
)
|
|
||||||
await self._send_text(room.room_id, menu)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Detect Confluence page links → store page ID for voice session context
|
# Detect Confluence page links → store page ID for voice session context
|
||||||
confluence_page_id = None
|
confluence_page_id = None
|
||||||
conf_long = re.search(r'agiliton\.atlassian\.net/wiki/.*?pages/(\d+)', body)
|
conf_long = re.search(r'agiliton\.atlassian\.net/wiki/.*?pages/(\d+)', body)
|
||||||
@@ -1885,8 +1765,6 @@ class Bot:
|
|||||||
sender = event.sender if event else None
|
sender = event.sender if event else None
|
||||||
if sender:
|
if sender:
|
||||||
deleted = await self.memory.delete_user(sender)
|
deleted = await self.memory.delete_user(sender)
|
||||||
self._pending_translate.pop(sender, None)
|
|
||||||
self._pending_reply.pop(sender, None)
|
|
||||||
await self._send_text(room.room_id, f"All my memories about you have been deleted ({deleted} facts removed).")
|
await self._send_text(room.room_id, f"All my memories about you have been deleted ({deleted} facts removed).")
|
||||||
else:
|
else:
|
||||||
await self._send_text(room.room_id, "Could not identify user.")
|
await self._send_text(room.room_id, "Could not identify user.")
|
||||||
|
|||||||
Reference in New Issue
Block a user