From 40a99c73f7746aa36d75eaa2c08b343c8d7c389d Mon Sep 17 00:00:00 2001 From: Christian Gick Date: Sat, 28 Feb 2026 08:47:33 +0200 Subject: [PATCH] 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 --- bot.py | 124 +-------------------------------------------------------- 1 file changed, 1 insertion(+), 123 deletions(-) diff --git a/bot.py b/bot.py index 55f4d3a..7c64a65 100644 --- a/bot.py +++ b/bot.py @@ -80,7 +80,7 @@ MAX_TOOL_ITERATIONS = 5 SYSTEM_PROMPT = """You are a helpful AI assistant in a Matrix chat room. 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: - 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._verifications: dict[str, dict] = {} # txn_id -> verification state 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}, ...] @staticmethod @@ -1201,62 +1199,6 @@ class Bot: except Exception: 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): """Handle text messages: commands and AI responses.""" if event.sender == BOT_USER: @@ -1298,43 +1240,6 @@ class Bot: 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) image_data = None cached = self._recent_images.get(room.room_id) @@ -1344,31 +1249,6 @@ class Bot: image_data = (b64, mime) 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 confluence_page_id = None 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 if 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).") else: await self._send_text(room.room_id, "Could not identify user.")