feat(poke): 优化戳一戳功能,优先使用 user_id 定位用户

之前的戳一戳功能仅依赖 `user_name` 来查找用户,这在某些情况下可能导致识别不准确或失败。

本次更新对计划执行器 (`PlanExecutor`) 进行了增强,使其在处理 `poke_user` 动作时,能直接从目标消息中提取 `user_id`。`PokeAction` 插件现在会优先使用这个更可靠的 `user_id`。如果 `user_id` 不存在,则回退到使用 `user_name` 作为备用方案。

这显著提高了戳一戳功能的准确性和稳定性。
This commit is contained in:
tt-P607
2025-09-22 22:52:28 +08:00
parent d13b83f10c
commit 56b42defdd
2 changed files with 46 additions and 15 deletions

View File

@@ -4,6 +4,7 @@ PlanExecutor: 接收 Plan 对象并执行其中的所有动作。
""" """
import asyncio import asyncio
import re
import time import time
from typing import Dict, List from typing import Dict, List
@@ -216,12 +217,35 @@ class PlanExecutor:
try: try:
logger.info(f"执行其他动作: {action_info.action_type} (原因: {action_info.reasoning})") logger.info(f"执行其他动作: {action_info.action_type} (原因: {action_info.reasoning})")
action_data = action_info.action_data or {}
# 针对 poke_user 动作,特殊处理
if action_info.action_type == "poke_user":
target_message = action_info.action_message
if target_message:
# 优先直接获取 user_id这才是最可靠的信息
user_id = target_message.get("user_id")
if user_id:
action_data["user_id"] = user_id
logger.info(f"检测到戳一戳动作目标用户ID: {user_id}")
else:
# 如果没有 user_id再尝试用 user_nickname 作为备用方案
user_name = target_message.get("user_nickname")
if user_name:
action_data["user_name"] = user_name
logger.info(f"检测到戳一戳动作,目标用户: {user_name}")
else:
logger.warning("无法从戳一戳消息中获取用户ID或昵称。")
# 传递原始消息ID以支持引用
action_data["target_message_id"] = target_message.get("message_id")
# 构建动作参数 # 构建动作参数
action_params = { action_params = {
"chat_id": plan.chat_id, "chat_id": plan.chat_id,
"target_message": action_info.action_message, "target_message": action_info.action_message,
"reasoning": action_info.reasoning, "reasoning": action_info.reasoning,
"action_data": action_info.action_data or {}, "action_data": action_data,
} }
# 通过动作管理器执行动作 # 通过动作管理器执行动作

View File

@@ -30,7 +30,8 @@ class PokeAction(BaseAction):
# === 功能描述(必须填写)=== # === 功能描述(必须填写)===
action_parameters = { action_parameters = {
"user_name": "需要戳一戳的用户的名字", "user_name": "需要戳一戳的用户的名字 (可选)",
"user_id": "需要戳一戳的用户的ID (可选,优先级更高)",
"times": "需要戳一戳的次数 (默认为 1)", "times": "需要戳一戳的次数 (默认为 1)",
} }
action_require = ["当需要戳某个用户时使用", "当你想提醒特定用户时使用"] action_require = ["当需要戳某个用户时使用", "当你想提醒特定用户时使用"]
@@ -46,32 +47,38 @@ class PokeAction(BaseAction):
async def execute(self) -> Tuple[bool, str]: async def execute(self) -> Tuple[bool, str]:
"""执行戳一戳的动作""" """执行戳一戳的动作"""
user_id = self.action_data.get("user_id")
user_name = self.action_data.get("user_name") user_name = self.action_data.get("user_name")
try: try:
times = int(self.action_data.get("times", 1)) times = int(self.action_data.get("times", 1))
except (ValueError, TypeError): except (ValueError, TypeError):
times = 1 times = 1
if not user_name: # 优先使用 user_id
logger.warning("戳一戳动作缺少 'user_name' 参数。") if not user_id:
return False, "缺少 'user_name' 参数" if not user_name:
logger.warning("戳一戳动作缺少 'user_id''user_name' 参数。")
return False, "缺少用户标识参数"
user_info = await get_person_info_manager().get_person_info_by_name(user_name) # 备用方案:通过 user_name 查找
if not user_info or not user_info.get("user_id"): user_info = await get_person_info_manager().get_person_info_by_name(user_name)
logger.info(f"找不到名为 '{user_name}' 的用户。") if not user_info or not user_info.get("user_id"):
return False, f"找不到名为 '{user_name}' 的用户" logger.info(f"找不到名为 '{user_name}' 的用户")
return False, f"找不到名为 '{user_name}' 的用户"
user_id = user_info.get("user_id")
user_id = user_info.get("user_id") display_name = user_name or user_id
for i in range(times): for i in range(times):
logger.info(f"正在向 {user_name} ({user_id}) 发送第 {i + 1}/{times} 次戳一戳...") logger.info(f"正在向 {display_name} ({user_id}) 发送第 {i + 1}/{times} 次戳一戳...")
await self.send_command( await self.send_command(
"SEND_POKE", args={"qq_id": user_id}, display_message=f"戳了戳 {user_name} ({i + 1}/{times})" "SEND_POKE", args={"qq_id": user_id}, display_message=f"戳了戳 {display_name} ({i + 1}/{times})"
) )
# 添加一个小的延迟,以避免发送过快 # 添加一个小的延迟,以避免发送过快
await asyncio.sleep(0.5) await asyncio.sleep(0.5)
success_message = f"已向 {user_name} 发送 {times} 次戳一戳。" success_message = f"已向 {display_name} 发送 {times} 次戳一戳。"
await self.store_action_info( await self.store_action_info(
action_build_into_prompt=True, action_prompt_display=success_message, action_done=True action_build_into_prompt=True, action_prompt_display=success_message, action_done=True
) )