@@ -20,16 +20,6 @@ class RobotMenuPlugin(MessagePluginInterface):
|
|||||||
# 功能权限常量
|
# 功能权限常量
|
||||||
FEATURE_KEY = "ROBOT_MENU"
|
FEATURE_KEY = "ROBOT_MENU"
|
||||||
FEATURE_DESCRIPTION = "📋 功能菜单 [菜单 - 显示功能菜单 | 菜单 状态 - 显示功能状态]"
|
FEATURE_DESCRIPTION = "📋 功能菜单 [菜单 - 显示功能菜单 | 菜单 状态 - 显示功能状态]"
|
||||||
AT_QUERY_KEYWORDS = (
|
|
||||||
"功能清单",
|
|
||||||
"功能菜单",
|
|
||||||
"功能列表",
|
|
||||||
"菜单",
|
|
||||||
"怎么用",
|
|
||||||
"如何用",
|
|
||||||
"帮助",
|
|
||||||
"help",
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
@@ -102,56 +92,9 @@ class RobotMenuPlugin(MessagePluginInterface):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
content = str(message.get("content", "")).strip()
|
content = str(message.get("content", "")).strip()
|
||||||
command = content.split(" ")[0] if content else ""
|
command = content.split(" ")[0]
|
||||||
roomid = str(message.get("roomid", "") or "")
|
|
||||||
is_at = bool(message.get("is_at", False))
|
|
||||||
|
|
||||||
# 指令入口
|
return command in self._commands
|
||||||
if command in self._commands:
|
|
||||||
return True
|
|
||||||
|
|
||||||
# @语义入口:只在群聊 + @机器人 + 明确菜单意图时触发
|
|
||||||
if roomid and is_at and self._is_at_menu_query(content):
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _normalize_text(content: str) -> str:
|
|
||||||
text = str(content or "").lower().strip()
|
|
||||||
text = re.sub(r"\s+", "", text)
|
|
||||||
return text
|
|
||||||
|
|
||||||
def _is_at_menu_query(self, content: str) -> bool:
|
|
||||||
text = self._normalize_text(content)
|
|
||||||
if not text:
|
|
||||||
return False
|
|
||||||
return any(self._normalize_text(keyword) in text for keyword in self.AT_QUERY_KEYWORDS)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _extract_usage_from_description(description: str) -> str:
|
|
||||||
"""
|
|
||||||
从 Feature.description 中提取 [ ... ] 内的触发方式
|
|
||||||
例如: '📋 功能菜单 [菜单 - 显示功能菜单]' -> '菜单'
|
|
||||||
"""
|
|
||||||
desc = str(description or "")
|
|
||||||
match = re.search(r"\[(.*?)\]", desc)
|
|
||||||
if not match:
|
|
||||||
return "请发送“菜单”查看"
|
|
||||||
inner = match.group(1).strip()
|
|
||||||
# 取第一段触发方式,避免太长
|
|
||||||
first = inner.split("|")[0].strip()
|
|
||||||
if "-" in first:
|
|
||||||
first = first.split("-", 1)[0].strip()
|
|
||||||
return first or "请发送“菜单”查看"
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _extract_brief_from_description(description: str) -> str:
|
|
||||||
desc = str(description or "")
|
|
||||||
# 去掉开头 emoji 和 [..] 指令块,只保留一句用途
|
|
||||||
desc = re.sub(r"^[^\u4e00-\u9fa5A-Za-z0-9]+", "", desc)
|
|
||||||
desc = re.sub(r"\[.*?\]", "", desc).strip()
|
|
||||||
return desc or "暂无说明"
|
|
||||||
|
|
||||||
def display_menu_status(self, group_id: str) -> str:
|
def display_menu_status(self, group_id: str) -> str:
|
||||||
"""显示所有功能列表及其在指定群组中的当前状态,带emoji"""
|
"""显示所有功能列表及其在指定群组中的当前状态,带emoji"""
|
||||||
@@ -163,64 +106,43 @@ class RobotMenuPlugin(MessagePluginInterface):
|
|||||||
menu.append(f"{status_emoji} {status_str}-{feature.value}-{feature.description}")
|
menu.append(f"{status_emoji} {status_str}-{feature.value}-{feature.description}")
|
||||||
return "\n".join(menu)
|
return "\n".join(menu)
|
||||||
|
|
||||||
def _get_enabled_feature_items(self, group_id: str) -> List[Dict[str, str]]:
|
def get_enabled_features(self, group_id: str) -> str:
|
||||||
"""获取本群已启用且可对用户展示的功能条目"""
|
"""获取某个群已启用的功能列表及其描述,并返回格式化的字符串
|
||||||
items: List[Dict[str, str]] = []
|
只返回描述中包含指令(方括号[])的功能
|
||||||
|
|
||||||
|
Args:
|
||||||
|
group_id: 群ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 格式化的已启用功能列表字符串
|
||||||
|
"""
|
||||||
|
enabled_features = []
|
||||||
|
|
||||||
# 检查群是否在列表中
|
# 检查群是否在列表中
|
||||||
if group_id not in GroupBotManager.local_cache["group_list"]:
|
if group_id not in GroupBotManager.local_cache["group_list"]:
|
||||||
return items
|
return "该群未启用机器人功能"
|
||||||
|
|
||||||
# 遍历所有功能,检查哪些已启用且包含指令
|
# 遍历所有功能,检查哪些已启用且包含指令
|
||||||
for feature in Feature:
|
for feature in Feature:
|
||||||
status = GroupBotManager.get_group_permission(group_id, feature)
|
status = GroupBotManager.get_group_permission(group_id, feature)
|
||||||
# 只添加已启用且描述中包含方括号的功能
|
# 只添加已启用且描述中包含方括号的功能
|
||||||
if status == PermissionStatus.ENABLED and "[" in feature.description and "]" in feature.description:
|
if status == PermissionStatus.ENABLED and "[" in feature.description and "]" in feature.description:
|
||||||
items.append({
|
enabled_features.append({
|
||||||
"id": feature.value,
|
"id": feature.value,
|
||||||
"name": feature.name,
|
"name": feature.name,
|
||||||
"description": feature.description
|
"description": feature.description
|
||||||
})
|
})
|
||||||
return items
|
|
||||||
|
|
||||||
def get_enabled_features(self, group_id: str) -> str:
|
# 如果没有启用任何带指令的功能
|
||||||
"""兼容旧接口:返回简化文本菜单"""
|
|
||||||
enabled_features = self._get_enabled_feature_items(group_id)
|
|
||||||
if group_id not in GroupBotManager.local_cache["group_list"]:
|
|
||||||
return "该群未启用机器人功能"
|
|
||||||
if not enabled_features:
|
if not enabled_features:
|
||||||
return "该群未启用任何带指令的功能"
|
return "该群未启用任何带指令的功能"
|
||||||
result = "群功能菜单:\n"
|
|
||||||
|
# 构建格式化的字符串
|
||||||
|
result = f"不支持@交互,请通过指令触发\n 群功能菜单:\n"
|
||||||
for feature in enabled_features:
|
for feature in enabled_features:
|
||||||
usage = self._extract_usage_from_description(feature["description"])
|
result += f"{feature['id']}.{feature['description']}\n"
|
||||||
brief = self._extract_brief_from_description(feature["description"])
|
|
||||||
result += f"{feature['id']}. {feature['name']} | 触发:{usage} | {brief}\n"
|
|
||||||
return result.strip()
|
|
||||||
|
|
||||||
def build_user_friendly_menu(self, group_id: str) -> str:
|
return result
|
||||||
"""构建给普通群成员看的直观功能菜单"""
|
|
||||||
if group_id not in GroupBotManager.local_cache["group_list"]:
|
|
||||||
return "当前群未开通机器人功能,请联系管理员开启。"
|
|
||||||
|
|
||||||
enabled_features = self._get_enabled_feature_items(group_id)
|
|
||||||
if not enabled_features:
|
|
||||||
return "当前群暂无可用功能。"
|
|
||||||
|
|
||||||
lines = [
|
|
||||||
"本群已开通功能:",
|
|
||||||
"直接复制“触发”里的命令发送即可。",
|
|
||||||
"",
|
|
||||||
]
|
|
||||||
for idx, feature in enumerate(enabled_features, start=1):
|
|
||||||
usage = self._extract_usage_from_description(feature["description"])
|
|
||||||
brief = self._extract_brief_from_description(feature["description"])
|
|
||||||
lines.append(f"{idx}. {feature['name']}")
|
|
||||||
lines.append(f"触发:{usage}")
|
|
||||||
lines.append(f"说明:{brief}")
|
|
||||||
lines.append("")
|
|
||||||
|
|
||||||
lines.append("快捷入口:")
|
|
||||||
lines.append("发送“菜单”可再次查看;发送“菜单 状态”可看全部开关状态。")
|
|
||||||
return "\n".join(lines).strip()
|
|
||||||
|
|
||||||
def get_group_list(self) -> str:
|
def get_group_list(self) -> str:
|
||||||
"""返回所有启用了群机器人的群组清单"""
|
"""返回所有启用了群机器人的群组清单"""
|
||||||
@@ -249,7 +171,6 @@ class RobotMenuPlugin(MessagePluginInterface):
|
|||||||
self.LOG.debug(f"插件执行: {self.name}:{content}")
|
self.LOG.debug(f"插件执行: {self.name}:{content}")
|
||||||
sender = message.get("sender")
|
sender = message.get("sender")
|
||||||
roomid = message.get("roomid", "")
|
roomid = message.get("roomid", "")
|
||||||
is_at = bool(message.get("is_at", False))
|
|
||||||
command = content.split(" ")[0]
|
command = content.split(" ")[0]
|
||||||
gbm: GroupBotManager = message.get("gbm")
|
gbm: GroupBotManager = message.get("gbm")
|
||||||
bot: WechatAPIClient = message.get("bot")
|
bot: WechatAPIClient = message.get("bot")
|
||||||
@@ -266,24 +187,15 @@ class RobotMenuPlugin(MessagePluginInterface):
|
|||||||
return False, "没有权限"
|
return False, "没有权限"
|
||||||
|
|
||||||
target = roomid if roomid else sender
|
target = roomid if roomid else sender
|
||||||
is_at_menu_query = roomid and is_at and self._is_at_menu_query(content)
|
|
||||||
|
|
||||||
# @语义菜单入口:用户@机器人直接问“功能清单/怎么用”
|
|
||||||
if is_at_menu_query and command not in self._commands:
|
|
||||||
menu_text = self.build_user_friendly_menu(roomid)
|
|
||||||
client_msg_id, create_time, new_msg_id = await bot.send_text_message(target, menu_text, sender)
|
|
||||||
revoke.add_message_to_revoke(target, client_msg_id, create_time, new_msg_id, 120)
|
|
||||||
return True, "at菜单问答"
|
|
||||||
|
|
||||||
# 检查命令格式
|
# 检查命令格式
|
||||||
parts = content.split()
|
parts = content.split()
|
||||||
if len(parts) == 1:
|
if len(parts) == 1:
|
||||||
# 显示功能菜单
|
# 显示功能菜单
|
||||||
group_for_menu = roomid if roomid else sender
|
menu_text = self.get_enabled_features(roomid if roomid else sender)
|
||||||
menu_text = self.build_user_friendly_menu(group_for_menu)
|
|
||||||
|
|
||||||
client_msg_id, create_time, new_msg_id = await bot.send_text_message(target, menu_text, sender)
|
client_msg_id, create_time, new_msg_id = await bot.send_text_message(target, menu_text, sender)
|
||||||
revoke.add_message_to_revoke(target, client_msg_id, create_time, new_msg_id, 120)
|
revoke.add_message_to_revoke(target, client_msg_id, create_time, new_msg_id, 90)
|
||||||
return True, "显示功能菜单"
|
return True, "显示功能菜单"
|
||||||
|
|
||||||
# 提取命令名
|
# 提取命令名
|
||||||
|
|||||||
Reference in New Issue
Block a user