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.
|
||||
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.")
|
||||
|
||||
Reference in New Issue
Block a user