refactor(at_user): 优化艾特用户插件逻辑并移除模糊匹配
重构了艾特用户插件,主要改动如下: - 移除 `fuzzywuzzy` 依赖和相关的模糊匹配逻辑,改为直接通过 `person_info_manager` 精确查找用户。 - 优化了 `AtAction` 的执行流程,现在通过调用 `DefaultReplyer` 生成更智能、更符合上下文的回复内容,而不是发送固定文本。 - 新增了 `/at` 命令,允许用户通过指令直接艾特指定用户并发送消息。 - 删除了 `proactive_thinker.py` 中不再使用的 `_get_reminder_context` 方法,以清理与旧提醒功能相关的代码。
This commit is contained in:
committed by
Windpicker-owo
parent
5eaa5f74e8
commit
31bdaa3747
@@ -139,20 +139,6 @@ class ProactiveThinker:
|
||||
logger.error(f"{self.context.log_prefix} 主动思考执行异常: {e}")
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
async def _get_reminder_context(self, message_id: str) -> str:
|
||||
"""获取提醒消息的上下文"""
|
||||
try:
|
||||
# 只获取那一条消息
|
||||
message_record = await db_get(Messages, {"message_id": message_id}, single_result=True)
|
||||
if message_record:
|
||||
# 使用 build_readable_messages_with_id 来格式化单条消息
|
||||
chat_context_block, _ = build_readable_messages_with_id(messages=[message_record])
|
||||
return chat_context_block
|
||||
return "无法加载相关的聊天记录。"
|
||||
except Exception as e:
|
||||
logger.error(f"{self.context.log_prefix} 获取提醒上下文失败: {e}")
|
||||
return "无法加载相关的聊天记录。"
|
||||
|
||||
|
||||
async def _generate_proactive_content_and_send(self, action_result: Dict[str, Any], trigger_event: ProactiveTriggerEvent):
|
||||
"""
|
||||
|
||||
@@ -8,6 +8,7 @@ from src.plugin_system import (
|
||||
ActionInfo,
|
||||
ActionActivationType,
|
||||
)
|
||||
from src.person_info.person_info import get_person_info_manager
|
||||
from src.common.logger import get_logger
|
||||
from src.plugin_system.base.component_types import ChatType
|
||||
|
||||
@@ -20,16 +21,16 @@ class AtAction(BaseAction):
|
||||
# === 基本信息(必须填写)===
|
||||
action_name = "at_user"
|
||||
action_description = "发送艾特消息"
|
||||
activation_type = ActionActivationType.LLM_JUDGE
|
||||
activation_type = ActionActivationType.LLM_JUDGE # 消息接收时激活(?)
|
||||
parallel_action = False
|
||||
chat_type_allow = ChatType.GROUP
|
||||
|
||||
# === 功能描述(必须填写)===
|
||||
action_parameters = {"user_name": "需要艾特用户的名字", "at_message": "艾特用户时要发送的消息"}
|
||||
action_parameters = {"user_name": "需要艾特用户的名字", "at_message": "艾特用户时要发送的消,注意消息里不要有@"}
|
||||
action_require = [
|
||||
"当用户明确要求你去'叫'、'喊'、'提醒'或'艾特'某人时使用",
|
||||
"当你判断,为了让特定的人看到消息,需要代表用户去呼叫他/她时使用",
|
||||
"例如:'你去叫一下张三','提醒一下李四开会'",
|
||||
"当需要艾特某个用户时使用",
|
||||
"当你需要提醒特定用户查看消息时使用",
|
||||
"在回复中需要明确指向某个用户时使用",
|
||||
]
|
||||
llm_judge_prompt = """
|
||||
判定是否需要使用艾特用户动作的条件:
|
||||
@@ -47,43 +48,24 @@ class AtAction(BaseAction):
|
||||
|
||||
if not user_name or not at_message:
|
||||
logger.warning("艾特用户的动作缺少必要参数。")
|
||||
await self.store_action_info(
|
||||
action_build_into_prompt=True,
|
||||
action_prompt_display=f"执行了艾特用户动作:艾特用户 {user_name} 并发送消息: {at_message},失败了,因为没有提供必要参数",
|
||||
action_done=False,
|
||||
)
|
||||
return False, "缺少必要参数"
|
||||
|
||||
from src.plugin_system.apis import send_api
|
||||
from fuzzywuzzy import process
|
||||
|
||||
group_id = self.chat_stream.group_info.group_id
|
||||
if not group_id:
|
||||
return False, "无法获取群组ID"
|
||||
|
||||
response = await send_api.adapter_command_to_stream(
|
||||
action="get_group_member_list",
|
||||
params={"group_id": group_id},
|
||||
stream_id=self.chat_id,
|
||||
)
|
||||
|
||||
if response.get("status") != "ok":
|
||||
return False, f"获取群成员列表失败: {response.get('message')}"
|
||||
|
||||
member_list = response.get("data", [])
|
||||
if not member_list:
|
||||
return False, "群成员列表为空"
|
||||
|
||||
# 使用模糊匹配找到最接近的用户名
|
||||
choices = {member["card"] or member["nickname"]: member["user_id"] for member in member_list}
|
||||
best_match, score = process.extractOne(user_name, choices.keys())
|
||||
|
||||
if score < 30: # 设置一个匹配度阈值
|
||||
logger.info(f"找不到与 '{user_name}' 高度匹配的用户 (最佳匹配: {best_match}, 分数: {score})")
|
||||
user_info = await get_person_info_manager().get_person_info_by_name(user_name)
|
||||
if not user_info or not user_info.get("user_id"):
|
||||
logger.info(f"找不到名为 '{user_name}' 的用户。")
|
||||
return False, "用户不存在"
|
||||
|
||||
user_id = choices[best_match]
|
||||
user_info = {"user_id": user_id, "user_nickname": best_match}
|
||||
|
||||
try:
|
||||
# 使用回复器生成艾特回复,而不是直接发送命令
|
||||
from src.chat.replyer.default_generator import DefaultReplyer
|
||||
from src.chat.message_receive.chat_stream import get_chat_manager
|
||||
|
||||
# 获取当前聊天流
|
||||
chat_manager = get_chat_manager()
|
||||
chat_stream = chat_manager.get_stream(self.chat_id)
|
||||
|
||||
@@ -91,56 +73,97 @@ class AtAction(BaseAction):
|
||||
logger.error(f"找不到聊天流: {self.stream_id}")
|
||||
return False, "聊天流不存在"
|
||||
|
||||
# 创建回复器实例
|
||||
replyer = DefaultReplyer(chat_stream)
|
||||
|
||||
# 构建回复对象,将艾特消息作为回复目标
|
||||
reply_to = f"{user_name}:{at_message}"
|
||||
extra_info = f"你需要艾特用户 {user_name} 并回复他们说: {at_message}"
|
||||
|
||||
success, llm_response, _ = await replyer.generate_reply_with_context(
|
||||
reply_to=f"{user_name}:{at_message}",
|
||||
# 使用回复器生成回复
|
||||
success, llm_response, prompt = await replyer.generate_reply_with_context(
|
||||
reply_to=reply_to,
|
||||
extra_info=extra_info,
|
||||
enable_tool=False,
|
||||
enable_tool=False, # 艾特回复通常不需要工具调用
|
||||
from_plugin=False
|
||||
)
|
||||
|
||||
if not success or not llm_response:
|
||||
logger.error("回复器生成回复失败")
|
||||
return False, "回复生成失败"
|
||||
|
||||
final_message_raw = llm_response.get("content", "")
|
||||
if not final_message_raw:
|
||||
logger.warning("回复器生成了空内容")
|
||||
return False, "回复内容为空"
|
||||
|
||||
# 对LLM生成的内容进行后处理,解析[SPLIT]标记并将分段消息合并
|
||||
from src.chat.utils.utils import process_llm_response
|
||||
final_message_segments = process_llm_response(final_message_raw, enable_splitter=True, enable_chinese_typo=False)
|
||||
final_message = " ".join(final_message_segments)
|
||||
if success and llm_response:
|
||||
# 获取生成的回复内容
|
||||
reply_content = llm_response.get("content", "")
|
||||
if reply_content:
|
||||
# 获取用户QQ号,发送真正的艾特消息
|
||||
user_id = user_info.get("user_id")
|
||||
|
||||
# 发送真正的艾特命令,使用回复器生成的智能内容
|
||||
await self.send_command(
|
||||
"SEND_AT_MESSAGE",
|
||||
args={"group_id": self.chat_stream.group_info.group_id, "qq_id": user_id, "text": final_message},
|
||||
display_message=f"艾特用户 {user_name} 并发送消息: {final_message}",
|
||||
args={"qq_id": user_id, "text": reply_content},
|
||||
display_message=f"艾特用户 {user_name} 并发送智能回复: {reply_content}",
|
||||
)
|
||||
|
||||
await self.store_action_info(
|
||||
action_build_into_prompt=True,
|
||||
action_prompt_display=f"执行了艾特用户动作:艾特用户 {user_name} 并发送消息: {final_message}",
|
||||
action_prompt_display=f"执行了艾特用户动作:艾特用户 {user_name} 并发送智能回复: {reply_content}",
|
||||
action_done=True,
|
||||
)
|
||||
|
||||
logger.info(f"成功发送艾特消息给 {user_name}: {final_message}")
|
||||
return True, "艾特消息发送成功"
|
||||
logger.info(f"成功通过回复器生成智能内容并发送真正的艾特消息给 {user_name}: {reply_content}")
|
||||
return True, "智能艾特消息发送成功"
|
||||
else:
|
||||
logger.warning("回复器生成了空内容")
|
||||
return False, "回复内容为空"
|
||||
else:
|
||||
logger.error("回复器生成回复失败")
|
||||
return False, "回复生成失败"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"执行艾特用户动作时发生异常: {e}", exc_info=True)
|
||||
await self.store_action_info(
|
||||
action_build_into_prompt=True,
|
||||
action_prompt_display=f"执行艾特用户动作失败:{str(e)}",
|
||||
action_done=False,
|
||||
)
|
||||
return False, f"执行失败: {str(e)}"
|
||||
|
||||
|
||||
class AtCommand(BaseCommand):
|
||||
command_name: str = "at_user"
|
||||
description: str = "通过名字艾特用户"
|
||||
command_pattern: str = r"/at\s+@?(?P<name>[\S]+)(?:\s+(?P<text>.*))?"
|
||||
|
||||
async def execute(self) -> Tuple[bool, str, bool]:
|
||||
name = self.matched_groups.get("name")
|
||||
text = self.matched_groups.get("text", "")
|
||||
|
||||
if not name:
|
||||
await self.send_text("请指定要艾特的用户名称。")
|
||||
return False, "缺少用户名称", True
|
||||
|
||||
person_info_manager = get_person_info_manager()
|
||||
user_info = await person_info_manager.get_person_info_by_name(name)
|
||||
|
||||
if not user_info or not user_info.get("user_id"):
|
||||
await self.send_text(f"找不到名为 '{name}' 的用户。")
|
||||
return False, "用户不存在", True
|
||||
|
||||
user_id = user_info.get("user_id")
|
||||
|
||||
await self.send_command(
|
||||
"SEND_AT_MESSAGE",
|
||||
args={"qq_id": user_id, "text": text},
|
||||
display_message=f"艾特用户 {name} 并发送消息: {text}",
|
||||
)
|
||||
|
||||
return True, "艾特消息已发送", True
|
||||
|
||||
|
||||
@register_plugin
|
||||
class AtUserPlugin(BasePlugin):
|
||||
plugin_name: str = "at_user_plugin"
|
||||
enable_plugin: bool = True
|
||||
dependencies: list[str] = []
|
||||
python_dependencies: list[str] = ["fuzzywuzzy", "python-Levenshtein"]
|
||||
python_dependencies: list[str] = []
|
||||
config_file_name: str = "config.toml"
|
||||
config_schema: dict = {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user