fix(chat): AI 回覆截斷問題 — 強制 persona + Markdown 清理 + 600字上限
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 14m39s
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 14m39s
問題: OpenClaw/NemoClaw 回覆 Markdown 語法 + 超長,Telegram 顯示截斷 修正: 1. chat_manager: _call_openclaw/_call_nemotron 強制前置 persona (含不超過300字規範) 2. telegram_gateway: _clean_ai_reply() 移除 **bold** *italic* # header 語法 移除 deepseek-r1 <think> 標籤,截斷 > 600 字並在段落邊界截 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -85,7 +85,11 @@ class ChatManager:
|
||||
|
||||
2026-04-03 ogt: 老闆指示改用 Gemini,費用控管月上限 $10 USD
|
||||
每次回覆附帶 token 用量與費用統計
|
||||
|
||||
2026-04-10 Claude Code: 強制合併 OPENCLAW_PERSONA,確保字數限制與格式規範
|
||||
"""
|
||||
# 強制在 system_prompt 前置 persona,確保 LLM 遵守字數與格式
|
||||
system_prompt = f"{OPENCLAW_PERSONA}\n{system_prompt}"
|
||||
import httpx
|
||||
from src.core.config import get_settings
|
||||
settings = get_settings()
|
||||
@@ -153,7 +157,12 @@ class ChatManager:
|
||||
|
||||
2026-04-09 ogt: 改接 192.168.0.111 Ollama deepseek-r1:14b,SRE 推理能力最強
|
||||
deepseek-r1 含 <think> 標籤,需過濾後才回傳
|
||||
|
||||
2026-04-10 Claude Code: 強制合併 NEMOCLAW_PERSONA,確保字數限制與格式規範
|
||||
"""
|
||||
# 強制在 system_prompt 前置 persona
|
||||
system_prompt = f"{NEMOCLAW_PERSONA}\n{system_prompt}"
|
||||
|
||||
import httpx
|
||||
import re
|
||||
|
||||
|
||||
@@ -3683,14 +3683,32 @@ class TelegramGateway:
|
||||
|
||||
context = await chat_mgr.get_system_context()
|
||||
|
||||
def _clean_ai_reply(text: str, max_chars: int = 600) -> str:
|
||||
"""清理 AI 回覆:移除 Markdown 語法,截斷超長內容"""
|
||||
import re
|
||||
# 移除 Markdown bold/italic (**text**, *text*, __text__, _text_)
|
||||
text = re.sub(r'\*\*(.+?)\*\*', r'\1', text)
|
||||
text = re.sub(r'\*(.+?)\*', r'\1', text)
|
||||
text = re.sub(r'__(.+?)__', r'\1', text)
|
||||
text = re.sub(r'_(.+?)_', r'\1', text)
|
||||
# 移除 Markdown header (#, ##, ###)
|
||||
text = re.sub(r'^#{1,3}\s+', '', text, flags=re.MULTILINE)
|
||||
# 移除 <think> 標籤(deepseek-r1)
|
||||
text = re.sub(r'<think>.*?</think>', '', text, flags=re.DOTALL).strip()
|
||||
# 截斷
|
||||
if len(text) > max_chars:
|
||||
text = text[:max_chars].rsplit('\n', 1)[0] + '…'
|
||||
return text.strip()
|
||||
|
||||
if mention_openclaw and not mention_nemo:
|
||||
# 只 OpenClaw 回應
|
||||
result = await chat_mgr._call_openclaw(
|
||||
f"{context}\n用戶 {username} 在 SRE 戰情室問你:",
|
||||
clean_text,
|
||||
)
|
||||
body = _clean_ai_reply(result) if result else '🔴 無響應'
|
||||
await self.send_as_openclaw(
|
||||
text=f"🦞 <b>OpenClaw</b>\n\n{result or '🔴 無響應'}",
|
||||
text=f"🦞 <b>OpenClaw</b>\n\n{body}",
|
||||
reply_to_message_id=message_id,
|
||||
)
|
||||
|
||||
@@ -3700,8 +3718,9 @@ class TelegramGateway:
|
||||
f"{context}\n用戶 {username} 在 SRE 戰情室問你:",
|
||||
clean_text,
|
||||
)
|
||||
body = _clean_ai_reply(result) if result else '🔴 無響應 (NIM 超時)'
|
||||
await self.send_as_nemotron(
|
||||
text=f"🤖 <b>NemoClaw</b>\n\n{result or '🔴 無響應 (NIM 超時)'}",
|
||||
text=f"🤖 <b>NemoClaw</b>\n\n{body}",
|
||||
reply_to_message_id=message_id,
|
||||
)
|
||||
|
||||
@@ -3717,13 +3736,13 @@ class TelegramGateway:
|
||||
|
||||
if oc_result and not isinstance(oc_result, Exception):
|
||||
await self.send_as_openclaw(
|
||||
text=f"🦞 <b>OpenClaw</b>\n\n{oc_result}",
|
||||
text=f"🦞 <b>OpenClaw</b>\n\n{_clean_ai_reply(oc_result)}",
|
||||
reply_to_message_id=message_id,
|
||||
)
|
||||
|
||||
if nemo_result and not isinstance(nemo_result, Exception):
|
||||
await self.send_as_nemotron(
|
||||
text=f"🤖 <b>NemoClaw</b>\n\n{nemo_result}",
|
||||
text=f"🤖 <b>NemoClaw</b>\n\n{_clean_ai_reply(nemo_result)}",
|
||||
reply_to_message_id=message_id,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user