feat:不再需要reply_to,action现拥有 user_id和group_id等信息

This commit is contained in:
SengokuCola
2025-07-16 00:06:15 +08:00
parent 9927322bf9
commit 1b866c89b2
10 changed files with 266 additions and 58 deletions

View File

@@ -259,7 +259,7 @@ class HeartFChatting:
gen_task = asyncio.create_task(self._generate_response(message_data, available_actions, reply_to_str)) gen_task = asyncio.create_task(self._generate_response(message_data, available_actions, reply_to_str))
with Timer("规划器", cycle_timers): with Timer("规划器", cycle_timers):
plan_result = await self.action_planner.plan(mode=self.loop_mode) plan_result, target_message = await self.action_planner.plan(mode=self.loop_mode)
action_result: dict = plan_result.get("action_result", {}) # type: ignore action_result: dict = plan_result.get("action_result", {}) # type: ignore
action_type, action_data, reasoning, is_parallel = ( action_type, action_data, reasoning, is_parallel = (
@@ -310,10 +310,17 @@ class HeartFChatting:
return True return True
else: else:
if message_data:
action_message = message_data
else:
action_message = target_message
# 动作执行计时 # 动作执行计时
with Timer("动作执行", cycle_timers): with Timer("动作执行", cycle_timers):
success, reply_text, command = await self._handle_action( success, reply_text, command = await self._handle_action(
action_type, reasoning, action_data, cycle_timers, thinking_id action_type, reasoning, action_data, cycle_timers, thinking_id, action_message
) )
loop_info = { loop_info = {
@@ -367,6 +374,7 @@ class HeartFChatting:
action_data: dict, action_data: dict,
cycle_timers: dict, cycle_timers: dict,
thinking_id: str, thinking_id: str,
action_message: dict,
) -> tuple[bool, str, str]: ) -> tuple[bool, str, str]:
""" """
处理规划动作,使用动作工厂创建相应的动作处理器 处理规划动作,使用动作工厂创建相应的动作处理器
@@ -392,6 +400,7 @@ class HeartFChatting:
thinking_id=thinking_id, thinking_id=thinking_id,
chat_stream=self.chat_stream, chat_stream=self.chat_stream,
log_prefix=self.log_prefix, log_prefix=self.log_prefix,
action_message=action_message,
) )
except Exception as e: except Exception as e:
logger.error(f"{self.log_prefix} 创建动作处理器时出错: {e}") logger.error(f"{self.log_prefix} 创建动作处理器时出错: {e}")

View File

@@ -80,6 +80,7 @@ class ActionManager:
chat_stream: ChatStream, chat_stream: ChatStream,
log_prefix: str, log_prefix: str,
shutting_down: bool = False, shutting_down: bool = False,
action_message: dict = None,
) -> Optional[BaseAction]: ) -> Optional[BaseAction]:
""" """
创建动作处理器实例 创建动作处理器实例
@@ -125,6 +126,7 @@ class ActionManager:
log_prefix=log_prefix, log_prefix=log_prefix,
shutting_down=shutting_down, shutting_down=shutting_down,
plugin_config=plugin_config, plugin_config=plugin_config,
action_message=action_message,
) )
logger.debug(f"创建Action实例成功: {action_name}") logger.debug(f"创建Action实例成功: {action_name}")

View File

@@ -14,6 +14,7 @@ from src.chat.utils.chat_message_builder import (
build_readable_actions, build_readable_actions,
get_actions_by_timestamp_with_chat, get_actions_by_timestamp_with_chat,
build_readable_messages, build_readable_messages,
build_readable_messages_with_id,
get_raw_msg_before_timestamp_with_chat, get_raw_msg_before_timestamp_with_chat,
) )
from src.chat.utils.utils import get_chat_type_and_target_info from src.chat.utils.utils import get_chat_type_and_target_info
@@ -39,14 +40,14 @@ def init_prompt():
{moderation_prompt} {moderation_prompt}
现在请你根据{by_what}选择合适的action: 现在请你根据{by_what}选择合适的action和触发action的消息:
你刚刚选择并执行过的action是 你刚刚选择并执行过的action是
{actions_before_now_block} {actions_before_now_block}
{no_action_block} {no_action_block}
{action_options_text} {action_options_text}
你必须从上面列出的可用action中选择一个并说明原因。 你必须从上面列出的可用action中选择一个并说明触发action的消息id和原因。
请根据动作示例,以严格的 JSON 格式输出,且仅包含 JSON 内容: 请根据动作示例,以严格的 JSON 格式输出,且仅包含 JSON 内容:
""", """,
@@ -59,7 +60,8 @@ def init_prompt():
动作描述:{action_description} 动作描述:{action_description}
{action_require} {action_require}
{{ {{
"action": "{action_name}",{action_parameters} "action": "{action_name}",{action_parameters}{target_prompt}
"reason":"触发action的原因"
}} }}
""", """,
"action_prompt", "action_prompt",
@@ -79,6 +81,22 @@ class ActionPlanner:
self.last_obs_time_mark = 0.0 self.last_obs_time_mark = 0.0
def find_message_by_id(self, message_id: str, message_id_list: list) -> Optional[Dict[str, Any]]:
"""
根据message_id从message_id_list中查找对应的原始消息
Args:
message_id: 要查找的消息ID
message_id_list: 消息ID列表格式为[{'id': str, 'message': dict}, ...]
Returns:
找到的原始消息字典如果未找到则返回None
"""
for item in message_id_list:
if item.get("id") == message_id:
return item.get("message")
return None
async def plan( async def plan(
self, mode: ChatMode = ChatMode.FOCUS self, mode: ChatMode = ChatMode.FOCUS
) -> Dict[str, Dict[str, Any] | str]: # sourcery skip: dict-comprehension ) -> Dict[str, Dict[str, Any] | str]: # sourcery skip: dict-comprehension
@@ -125,7 +143,7 @@ class ActionPlanner:
} }
# --- 构建提示词 (调用修改后的 PromptBuilder 方法) --- # --- 构建提示词 (调用修改后的 PromptBuilder 方法) ---
prompt = await self.build_planner_prompt( prompt, message_id_list = await self.build_planner_prompt(
is_group_chat=is_group_chat, # <-- Pass HFC state is_group_chat=is_group_chat, # <-- Pass HFC state
chat_target_info=chat_target_info, # <-- 传递获取到的聊天目标信息 chat_target_info=chat_target_info, # <-- 传递获取到的聊天目标信息
current_available_actions=current_available_actions, # <-- Pass determined actions current_available_actions=current_available_actions, # <-- Pass determined actions
@@ -176,6 +194,17 @@ class ActionPlanner:
if key not in ["action", "reasoning"]: if key not in ["action", "reasoning"]:
action_data[key] = value action_data[key] = value
# 在FOCUS模式下非no_reply动作需要target_message_id
if mode == ChatMode.FOCUS and action != "no_reply":
target_message_id = parsed_json.get("target_message_id")
if target_message_id:
# 根据target_message_id查找原始消息
target_message = self.find_message_by_id(target_message_id, message_id_list)
else:
logger.warning(f"{self.log_prefix}FOCUS模式下动作'{action}'缺少target_message_id")
else:
target_message = None
if action == "no_action": if action == "no_action":
reasoning = "normal决定不使用额外动作" reasoning = "normal决定不使用额外动作"
elif action != "no_reply" and action != "reply" and action not in current_available_actions: elif action != "no_reply" and action != "reply" and action not in current_available_actions:
@@ -212,7 +241,7 @@ class ActionPlanner:
return { return {
"action_result": action_result, "action_result": action_result,
"action_prompt": prompt, "action_prompt": prompt,
} }, target_message
async def build_planner_prompt( async def build_planner_prompt(
self, self,
@@ -220,7 +249,7 @@ class ActionPlanner:
chat_target_info: Optional[dict], # Now passed as argument chat_target_info: Optional[dict], # Now passed as argument
current_available_actions: Dict[str, ActionInfo], current_available_actions: Dict[str, ActionInfo],
mode: ChatMode = ChatMode.FOCUS, mode: ChatMode = ChatMode.FOCUS,
) -> str: # sourcery skip: use-join ) -> tuple[str, list]: # sourcery skip: use-join
"""构建 Planner LLM 的提示词 (获取模板并填充数据)""" """构建 Planner LLM 的提示词 (获取模板并填充数据)"""
try: try:
message_list_before_now = get_raw_msg_before_timestamp_with_chat( message_list_before_now = get_raw_msg_before_timestamp_with_chat(
@@ -229,7 +258,7 @@ class ActionPlanner:
limit=int(global_config.chat.max_context_size * 0.6), limit=int(global_config.chat.max_context_size * 0.6),
) )
chat_content_block = build_readable_messages( chat_content_block, message_id_list = build_readable_messages_with_id(
messages=message_list_before_now, messages=message_list_before_now,
timestamp_mode="normal_no_YMD", timestamp_mode="normal_no_YMD",
read_mark=self.last_obs_time_mark, read_mark=self.last_obs_time_mark,
@@ -251,6 +280,7 @@ class ActionPlanner:
if mode == ChatMode.FOCUS: if mode == ChatMode.FOCUS:
by_what = "聊天内容" by_what = "聊天内容"
target_prompt = "\n \"target_message_id\":\"触发action的消息id\""
no_action_block = """重要说明1 no_action_block = """重要说明1
- 'no_reply' 表示只进行不进行回复,等待合适的回复时机 - 'no_reply' 表示只进行不进行回复,等待合适的回复时机
- 当你刚刚发送了消息没有人回复时选择no_reply - 当你刚刚发送了消息没有人回复时选择no_reply
@@ -263,13 +293,13 @@ class ActionPlanner:
- 如果你刚刚进行了回复,不要对同一个话题重复回应 - 如果你刚刚进行了回复,不要对同一个话题重复回应
{ {
"action": "reply", "action": "reply",
"reply_to":"你要回复的对方的发言内容,格式:(用户名:发言内容可以为none"
"reason":"回复的原因" "reason":"回复的原因"
} }
""" """
else: else:
by_what = "聊天内容和用户的最新消息" by_what = "聊天内容和用户的最新消息"
target_prompt = ""
no_action_block = """重要说明: no_action_block = """重要说明:
- 'no_action' 表示只进行普通聊天回复,不执行任何额外动作 - 'no_action' 表示只进行普通聊天回复,不执行任何额外动作
- 其他action表示在普通回复的基础上执行相应的额外动作""" - 其他action表示在普通回复的基础上执行相应的额外动作"""
@@ -304,6 +334,7 @@ class ActionPlanner:
action_description=using_actions_info.description, action_description=using_actions_info.description,
action_parameters=param_text, action_parameters=param_text,
action_require=require_text, action_require=require_text,
target_prompt=target_prompt,
) )
action_options_block += using_action_prompt action_options_block += using_action_prompt
@@ -321,7 +352,7 @@ class ActionPlanner:
identity_block = f"你的名字是{bot_name}{bot_nickname},你{bot_core_personality}" identity_block = f"你的名字是{bot_name}{bot_nickname},你{bot_core_personality}"
planner_prompt_template = await global_prompt_manager.get_prompt_async("planner_prompt") planner_prompt_template = await global_prompt_manager.get_prompt_async("planner_prompt")
return planner_prompt_template.format( prompt = planner_prompt_template.format(
time_block=time_block, time_block=time_block,
by_what=by_what, by_what=by_what,
chat_context_description=chat_context_description, chat_context_description=chat_context_description,
@@ -332,10 +363,11 @@ class ActionPlanner:
moderation_prompt=moderation_prompt_block, moderation_prompt=moderation_prompt_block,
identity_block=identity_block, identity_block=identity_block,
) )
return prompt, message_id_list
except Exception as e: except Exception as e:
logger.error(f"构建 Planner 提示词时出错: {e}") logger.error(f"构建 Planner 提示词时出错: {e}")
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
return "构建 Planner Prompt 时出错" return "构建 Planner Prompt 时出错", []
init_prompt() init_prompt()

View File

@@ -957,7 +957,7 @@ async def get_prompt_info(message: str, threshold: float):
logger.debug("LPMM知识库已禁用跳过知识获取") logger.debug("LPMM知识库已禁用跳过知识获取")
return "" return ""
found_knowledge_from_lpmm = qa_manager.get_knowledge(message) found_knowledge_from_lpmm = await qa_manager.get_knowledge(message)
end_time = time.time() end_time = time.time()
if found_knowledge_from_lpmm is not None: if found_knowledge_from_lpmm is not None:

View File

@@ -10,7 +10,7 @@ from src.common.message_repository import find_messages, count_messages
from src.common.database.database_model import ActionRecords from src.common.database.database_model import ActionRecords
from src.common.database.database_model import Images from src.common.database.database_model import Images
from src.person_info.person_info import PersonInfoManager, get_person_info_manager from src.person_info.person_info import PersonInfoManager, get_person_info_manager
from src.chat.utils.utils import translate_timestamp_to_human_readable from src.chat.utils.utils import translate_timestamp_to_human_readable,assign_message_ids
install(extra_lines=3) install(extra_lines=3)
@@ -252,6 +252,7 @@ def _build_readable_messages_internal(
pic_id_mapping: Optional[Dict[str, str]] = None, pic_id_mapping: Optional[Dict[str, str]] = None,
pic_counter: int = 1, pic_counter: int = 1,
show_pic: bool = True, show_pic: bool = True,
message_id_list: List[Dict[str, Any]] = [],
) -> Tuple[str, List[Tuple[float, str, str]], Dict[str, str], int]: ) -> Tuple[str, List[Tuple[float, str, str]], Dict[str, str], int]:
""" """
内部辅助函数,构建可读消息字符串和原始消息详情列表。 内部辅助函数,构建可读消息字符串和原始消息详情列表。
@@ -278,6 +279,15 @@ def _build_readable_messages_internal(
pic_id_mapping = {} pic_id_mapping = {}
current_pic_counter = pic_counter current_pic_counter = pic_counter
# 创建时间戳到消息ID的映射用于在消息前添加[id]标识符
timestamp_to_id = {}
if message_id_list:
for item in message_id_list:
message = item.get("message", {})
timestamp = message.get("time")
if timestamp is not None:
timestamp_to_id[timestamp] = item.get("id", "")
def process_pic_ids(content: str) -> str: def process_pic_ids(content: str) -> str:
"""处理内容中的图片ID将其替换为[图片x]格式""" """处理内容中的图片ID将其替换为[图片x]格式"""
nonlocal current_pic_counter nonlocal current_pic_counter
@@ -510,12 +520,16 @@ def _build_readable_messages_internal(
# 使用指定的 timestamp_mode 格式化时间 # 使用指定的 timestamp_mode 格式化时间
readable_time = translate_timestamp_to_human_readable(merged["start_time"], mode=timestamp_mode) readable_time = translate_timestamp_to_human_readable(merged["start_time"], mode=timestamp_mode)
# 查找对应的消息ID
message_id = timestamp_to_id.get(merged["start_time"], "")
id_prefix = f"[{message_id}] " if message_id else ""
# 检查是否是动作记录 # 检查是否是动作记录
if merged["is_action"]: if merged["is_action"]:
# 对于动作记录,使用特殊格式 # 对于动作记录,使用特殊格式
output_lines.append(f"{readable_time}, {merged['content'][0]}") output_lines.append(f"{id_prefix}{readable_time}, {merged['content'][0]}")
else: else:
header = f"{readable_time}, {merged['name']} :" header = f"{id_prefix}{readable_time}, {merged['name']} :"
output_lines.append(header) output_lines.append(header)
# 将内容合并,并添加缩进 # 将内容合并,并添加缩进
for line in merged["content"]: for line in merged["content"]:
@@ -640,6 +654,39 @@ async def build_readable_messages_with_list(
return formatted_string, details_list return formatted_string, details_list
def build_readable_messages_with_id(
messages: List[Dict[str, Any]],
replace_bot_name: bool = True,
merge_messages: bool = False,
timestamp_mode: str = "relative",
read_mark: float = 0.0,
truncate: bool = False,
show_actions: bool = False,
show_pic: bool = True,
) -> Tuple[str, List[Dict[str, Any]]]:
"""
将消息列表转换为可读的文本格式,并返回原始(时间戳, 昵称, 内容)列表。
允许通过参数控制格式化行为。
"""
message_id_list = assign_message_ids(messages)
formatted_string = build_readable_messages(
messages = messages,
replace_bot_name=replace_bot_name,
merge_messages=merge_messages,
timestamp_mode=timestamp_mode,
truncate=truncate,
show_actions=show_actions,
show_pic=show_pic,
read_mark=read_mark,
message_id_list=message_id_list,
)
return formatted_string , message_id_list
def build_readable_messages( def build_readable_messages(
messages: List[Dict[str, Any]], messages: List[Dict[str, Any]],
@@ -650,6 +697,7 @@ def build_readable_messages(
truncate: bool = False, truncate: bool = False,
show_actions: bool = False, show_actions: bool = False,
show_pic: bool = True, show_pic: bool = True,
message_id_list: List[Dict[str, Any]] = [],
) -> str: # sourcery skip: extract-method ) -> str: # sourcery skip: extract-method
""" """
将消息列表转换为可读的文本格式。 将消息列表转换为可读的文本格式。
@@ -722,7 +770,7 @@ def build_readable_messages(
if read_mark <= 0: if read_mark <= 0:
# 没有有效的 read_mark直接格式化所有消息 # 没有有效的 read_mark直接格式化所有消息
formatted_string, _, pic_id_mapping, _ = _build_readable_messages_internal( formatted_string, _, pic_id_mapping, _ = _build_readable_messages_internal(
copy_messages, replace_bot_name, merge_messages, timestamp_mode, truncate, show_pic=show_pic copy_messages, replace_bot_name, merge_messages, timestamp_mode, truncate, show_pic=show_pic, message_id_list=message_id_list
) )
# 生成图片映射信息并添加到最前面 # 生成图片映射信息并添加到最前面
@@ -750,6 +798,7 @@ def build_readable_messages(
pic_id_mapping, pic_id_mapping,
pic_counter, pic_counter,
show_pic=show_pic, show_pic=show_pic,
message_id_list=message_id_list,
) )
formatted_after, _, pic_id_mapping, _ = _build_readable_messages_internal( formatted_after, _, pic_id_mapping, _ = _build_readable_messages_internal(
messages_after_mark, messages_after_mark,
@@ -760,6 +809,7 @@ def build_readable_messages(
pic_id_mapping, pic_id_mapping,
pic_counter, pic_counter,
show_pic=show_pic, show_pic=show_pic,
message_id_list=message_id_list,
) )
read_mark_line = "\n--- 以上消息是你已经看过,请关注以下未读的新消息---\n" read_mark_line = "\n--- 以上消息是你已经看过,请关注以下未读的新消息---\n"

View File

@@ -1,12 +1,13 @@
import random import random
import re import re
import string
import time import time
import jieba import jieba
import numpy as np import numpy as np
from collections import Counter from collections import Counter
from maim_message import UserInfo from maim_message import UserInfo
from typing import Optional, Tuple, Dict from typing import Optional, Tuple, Dict, List, Any
from src.common.logger import get_logger from src.common.logger import get_logger
from src.common.message_repository import find_messages, count_messages from src.common.message_repository import find_messages, count_messages
@@ -666,3 +667,107 @@ def get_chat_type_and_target_info(chat_id: str) -> Tuple[bool, Optional[Dict]]:
# Keep defaults on error # Keep defaults on error
return is_group_chat, chat_target_info return is_group_chat, chat_target_info
def assign_message_ids(messages: List[Any]) -> List[Dict[str, Any]]:
"""
为消息列表中的每个消息分配唯一的简短随机ID
Args:
messages: 消息列表
Returns:
包含 {'id': str, 'message': any} 格式的字典列表
"""
result = []
used_ids = set()
len_i = len(messages)
if len_i > 100:
a = 10
b = 99
else:
a = 1
b = 9
for i, message in enumerate(messages):
# 生成唯一的简短ID
while True:
# 使用索引+随机数生成简短ID
random_suffix = random.randint(a, b)
message_id = f"m{i+1}{random_suffix}"
if message_id not in used_ids:
used_ids.add(message_id)
break
result.append({
'id': message_id,
'message': message
})
return result
def assign_message_ids_flexible(
messages: list,
prefix: str = "msg",
id_length: int = 6,
use_timestamp: bool = False
) -> list:
"""
为消息列表中的每个消息分配唯一的简短随机ID增强版
Args:
messages: 消息列表
prefix: ID前缀默认为"msg"
id_length: ID的总长度不包括前缀默认为6
use_timestamp: 是否在ID中包含时间戳默认为False
Returns:
包含 {'id': str, 'message': any} 格式的字典列表
"""
result = []
used_ids = set()
for i, message in enumerate(messages):
# 生成唯一的ID
while True:
if use_timestamp:
# 使用时间戳的后几位 + 随机字符
timestamp_suffix = str(int(time.time() * 1000))[-3:]
remaining_length = id_length - 3
random_chars = ''.join(random.choices(string.ascii_lowercase + string.digits, k=remaining_length))
message_id = f"{prefix}{timestamp_suffix}{random_chars}"
else:
# 使用索引 + 随机字符
index_str = str(i + 1)
remaining_length = max(1, id_length - len(index_str))
random_chars = ''.join(random.choices(string.ascii_lowercase + string.digits, k=remaining_length))
message_id = f"{prefix}{index_str}{random_chars}"
if message_id not in used_ids:
used_ids.add(message_id)
break
result.append({
'id': message_id,
'message': message
})
return result
# 使用示例:
# messages = ["Hello", "World", "Test message"]
#
# # 基础版本
# result1 = assign_message_ids(messages)
# # 结果: [{'id': 'm1123', 'message': 'Hello'}, {'id': 'm2456', 'message': 'World'}, {'id': 'm3789', 'message': 'Test message'}]
#
# # 增强版本 - 自定义前缀和长度
# result2 = assign_message_ids_flexible(messages, prefix="chat", id_length=8)
# # 结果: [{'id': 'chat1abc2', 'message': 'Hello'}, {'id': 'chat2def3', 'message': 'World'}, {'id': 'chat3ghi4', 'message': 'Test message'}]
#
# # 增强版本 - 使用时间戳
# result3 = assign_message_ids_flexible(messages, prefix="ts", use_timestamp=True)
# # 结果: [{'id': 'ts123a1b', 'message': 'Hello'}, {'id': 'ts123c2d', 'message': 'World'}, {'id': 'ts123e3f', 'message': 'Test message'}]

View File

@@ -377,7 +377,7 @@ class RelationshipBuilder:
): ):
person_id = PersonInfoManager.get_person_id(platform, user_id) person_id = PersonInfoManager.get_person_id(platform, user_id)
self._update_message_segments(person_id, msg_time) self._update_message_segments(person_id, msg_time)
logger.info( logger.debug(
f"{self.log_prefix} 更新用户 {person_id} 的消息段,消息时间:{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(msg_time))}" f"{self.log_prefix} 更新用户 {person_id} 的消息段,消息时间:{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(msg_time))}"
) )
self.last_processed_message_time = max(self.last_processed_message_time, msg_time) self.last_processed_message_time = max(self.last_processed_message_time, msg_time)
@@ -395,7 +395,7 @@ class RelationshipBuilder:
) )
elif total_message_count > 0: elif total_message_count > 0:
# 记录进度信息 # 记录进度信息
logger.info( logger.debug(
f"{self.log_prefix} 用户 {person_name} 进度:{total_message_count}/60 条消息,{len(segments)} 个消息段" f"{self.log_prefix} 用户 {person_name} 进度:{total_message_count}/60 条消息,{len(segments)} 个消息段"
) )

View File

@@ -38,6 +38,7 @@ class BaseAction(ABC):
chat_stream: ChatStream, chat_stream: ChatStream,
log_prefix: str = "", log_prefix: str = "",
plugin_config: Optional[dict] = None, plugin_config: Optional[dict] = None,
action_message: dict = None,
**kwargs, **kwargs,
): ):
"""初始化Action组件 """初始化Action组件
@@ -89,38 +90,48 @@ class BaseAction(ABC):
# 获取聊天流对象 # 获取聊天流对象
self.chat_stream = chat_stream or kwargs.get("chat_stream") self.chat_stream = chat_stream or kwargs.get("chat_stream")
self.chat_id = self.chat_stream.stream_id self.chat_id = self.chat_stream.stream_id
# 初始化基础信息(带类型注解)
self.is_group: bool = False
self.platform: Optional[str] = None
self.group_id: Optional[str] = None
self.user_id: Optional[str] = None
self.target_id: Optional[str] = None
self.group_name: Optional[str] = None
self.user_nickname: Optional[str] = None
# 如果有聊天流,提取所有信息
if self.chat_stream:
self.platform = getattr(self.chat_stream, "platform", None) self.platform = getattr(self.chat_stream, "platform", None)
# 获取群聊信息 # 初始化基础信息(带类型注解)
# print(self.chat_stream) self.action_message = action_message
# print(self.chat_stream.group_info)
if self.chat_stream.group_info: self.group_id = None
self.group_name = None
self.user_id = None
self.user_nickname = None
self.is_group = False
self.target_id = None
if self.action_name != "no_reply":
self.group_id = str(self.action_message.get("chat_info_group_id", None))
self.group_name = self.action_message.get("chat_info_group_name", None)
self.user_id = str(self.action_message.get("user_id", None))
self.user_nickname = self.action_message.get("user_nickname", None)
if self.group_id:
self.is_group = True self.is_group = True
self.group_id = str(self.chat_stream.group_info.group_id) self.target_id = self.group_id
self.group_name = getattr(self.chat_stream.group_info, "group_name", None)
else: else:
self.is_group = False self.is_group = False
self.user_id = str(self.chat_stream.user_info.user_id) self.target_id = self.user_id
self.user_nickname = getattr(self.chat_stream.user_info, "user_nickname", None) else:
if self.chat_stream.group_info:
self.group_id = self.chat_stream.group_info.group_id
self.group_name = self.chat_stream.group_info.group_name
self.is_group = True
self.target_id = self.group_id
else:
self.user_id = self.chat_stream.user_info.user_id
self.user_nickname = self.chat_stream.user_info.user_nickname
self.is_group = False
self.target_id = self.user_id
# 设置目标ID群聊用群ID私聊用户ID
self.target_id = self.group_id if self.is_group else self.user_id
logger.debug(f"{self.log_prefix} Action组件初始化完成") logger.debug(f"{self.log_prefix} Action组件初始化完成")
logger.debug( logger.info(
f"{self.log_prefix} 聊天信息: 类型={'群聊' if self.is_group else '私聊'}, 平台={self.platform}, 目标={self.target_id}" f"{self.log_prefix} 聊天信息: 类型={'群聊' if self.is_group else '私聊'}, 平台={self.platform}, 目标={self.target_id}"
) )

View File

@@ -40,7 +40,7 @@ class EmojiAction(BaseAction):
""" """
# 动作参数定义 # 动作参数定义
action_parameters = {"reason": "文字描述你想要发送的表情包原因"} action_parameters = {}
# 动作使用场景 # 动作使用场景
action_require = [ action_require = [

View File

@@ -24,6 +24,7 @@ from src.common.logger import get_logger
from src.plugin_system.apis import generator_api, message_api from src.plugin_system.apis import generator_api, message_api
from src.plugins.built_in.core_actions.no_reply import NoReplyAction from src.plugins.built_in.core_actions.no_reply import NoReplyAction
from src.plugins.built_in.core_actions.emoji import EmojiAction from src.plugins.built_in.core_actions.emoji import EmojiAction
from src.person_info.person_info import person_info_manager
logger = get_logger("core_actions") logger = get_logger("core_actions")
@@ -45,10 +46,7 @@ class ReplyAction(BaseAction):
action_description = "参与聊天回复,发送文本进行表达" action_description = "参与聊天回复,发送文本进行表达"
# 动作参数定义 # 动作参数定义
action_parameters = { action_parameters = {}
"reply_to": "你要回复的对方的发言内容,格式:(用户名:发言内容可以为none",
"reason": "回复的原因",
}
# 动作使用场景 # 动作使用场景
action_require = ["你想要闲聊或者随便附和", "有人提到你", "如果你刚刚进行了回复,不要对同一个话题重复回应"] action_require = ["你想要闲聊或者随便附和", "有人提到你", "如果你刚刚进行了回复,不要对同一个话题重复回应"]
@@ -70,11 +68,14 @@ class ReplyAction(BaseAction):
async def execute(self) -> Tuple[bool, str]: async def execute(self) -> Tuple[bool, str]:
"""执行回复动作""" """执行回复动作"""
logger.info(f"{self.log_prefix} 决定进行回复") logger.info(f"{self.log_prefix} 决定进行回复")
start_time = self.action_data.get("loop_start_time", time.time()) start_time = self.action_data.get("loop_start_time", time.time())
reply_to = self.action_data.get("reply_to", "") user_id = self.user_id
sender, target = self._parse_reply_target(reply_to) platform = self.platform
person_id = person_info_manager.get_person_id(user_id, platform)
person_name = person_info_manager.get_value(person_id, "person_name")
reply_to = f"{person_name}:{self.action_message.get('processed_plain_text', '')}"
try: try:
prepared_reply = self.action_data.get("prepared_reply", "") prepared_reply = self.action_data.get("prepared_reply", "")
@@ -83,6 +84,7 @@ class ReplyAction(BaseAction):
success, reply_set, _ = await asyncio.wait_for( success, reply_set, _ = await asyncio.wait_for(
generator_api.generate_reply( generator_api.generate_reply(
action_data=self.action_data, action_data=self.action_data,
reply_to=reply_to,
chat_id=self.chat_id, chat_id=self.chat_id,
request_type="chat.replyer.focus", request_type="chat.replyer.focus",
enable_tool=global_config.tool.enable_in_focus_chat, enable_tool=global_config.tool.enable_in_focus_chat,
@@ -115,7 +117,7 @@ class ReplyAction(BaseAction):
data = reply_seg[1] data = reply_seg[1]
if not first_replied: if not first_replied:
if need_reply: if need_reply:
await self.send_text(content=data, reply_to=self.action_data.get("reply_to", ""), typing=False) await self.send_text(content=data, reply_to=reply_to, typing=False)
first_replied = True first_replied = True
else: else:
await self.send_text(content=data, typing=False) await self.send_text(content=data, typing=False)
@@ -125,10 +127,7 @@ class ReplyAction(BaseAction):
reply_text += data reply_text += data
# 存储动作记录 # 存储动作记录
if sender and target: reply_text = f"你对{person_name}进行了回复:{reply_text}"
reply_text = f"你对{sender}说的{target},进行了回复:{reply_text}"
else:
reply_text = f"你进行发言:{reply_text}"
await self.store_action_info( await self.store_action_info(
action_build_into_prompt=False, action_build_into_prompt=False,