""" 企微机器人显示名:出站话术与入站 @ 识别共用。 本文件职责:从后台 reply_code=system.bot_display_name 读显示名; 失败回退默认「智报通AIQ」;过渡期识别仍认旧名「询价小助手」。 禁止:每条群消息同步打主账(走 bot_reply 短缓存);禁止当六态。 """ from __future__ import annotations from typing import Tuple # 后台调用编码:inq_bot_reply.reply_text 只写显示名本身,不要整句。 REPLY_CODE = "system.bot_display_name" # 主账空/失败时的默认显示名(产品已定新名)。 DEFAULT_BOT_DISPLAY_NAME = "智报通AIQ" # 企微改名过渡:旧习惯 @ 仍要听得见(含「价/报」两版现网名)。 LEGACY_BOT_DISPLAY_NAMES: Tuple[str, ...] = ("询价小助手", "智价通AIQ", "智报通AIQ") def bot_display_name() -> str: """ 当前对外显示名(销售话术里的 @ 名)。 读后台短缓存;空串/停用回退默认。只取首行,防止误配整段话术。 """ from agent.policy.bot_reply import lookup_raw raw = (lookup_raw(REPLY_CODE) or "").strip() if not raw: return DEFAULT_BOT_DISPLAY_NAME first = raw.splitlines()[0].strip() return first or DEFAULT_BOT_DISPLAY_NAME def bot_mention_names() -> Tuple[str, ...]: """ 入站识别用的全部名字:当前配置名 + 旧名,去重保序。 销售可见话术只用 bot_display_name();识别必须覆盖过渡期旧 @。 """ names: list[str] = [] for item in (bot_display_name(), *LEGACY_BOT_DISPLAY_NAMES): name = (item or "").strip() if name and name not in names: names.append(name) return tuple(names) def text_mentions_bot(text: str) -> bool: """原文是否带当前或旧显示名(含不带 @ 的粘贴)。""" raw = text or "" return any(name in raw for name in bot_mention_names()) def strip_bot_mention(text: str) -> str: """ 去掉 @显示名 与裸显示名(含旧名),便于抽字段/判「仅工单号」、出站 instructionText。 先剥带 @ 的,再剥裸名,避免残留 @;末尾压空白,避免「@机器人 舱位」留下双空格。 锁舱/释放出站前必须剥干净,禁止把「@智价通AIQ」原样带给 TMS。 """ rest = text or "" # 长名优先,避免短名先剥留下半截。 names = sorted(bot_mention_names(), key=len, reverse=True) for name in names: rest = rest.replace(f"@{name}", "").replace(name, "") return " ".join(rest.split()) def at_bot() -> str: """出站示例用的「@显示名」后缀。""" return f"@{bot_display_name()}"