From 5f4b38e4ddb359f2757505926bbfd8bfd3d7dd51 Mon Sep 17 00:00:00 2001 From: Bakadax Date: Sat, 26 Apr 2025 15:31:48 +0800 Subject: [PATCH 01/13] fix --- src/plugins/PFC/conversation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/PFC/conversation.py b/src/plugins/PFC/conversation.py index dc1e6a349..83081e80e 100644 --- a/src/plugins/PFC/conversation.py +++ b/src/plugins/PFC/conversation.py @@ -77,7 +77,7 @@ class Conversation: raise try: logger.info(f"为 {self.stream_id} 加载初始聊天记录...") - initial_messages = await get_raw_msg_before_timestamp_with_chat( # + initial_messages = get_raw_msg_before_timestamp_with_chat( # chat_id=self.stream_id, timestamp=time.time(), limit=30, # 加载最近30条作为初始上下文,可以调整 From 6e4ba27ffb500ffea5478aa1566f3478df7c9927 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 26 Apr 2025 09:35:36 +0000 Subject: [PATCH 02/13] =?UTF-8?q?=F0=9F=A4=96=20=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E4=BB=A3=E7=A0=81=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/heart_flow/sub_heartflow.py | 6 ++--- src/heart_flow/subheartflow_manager.py | 32 ++++++++++++++----------- src/plugins/heartFC_chat/normal_chat.py | 24 ++++++++++--------- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/heart_flow/sub_heartflow.py b/src/heart_flow/sub_heartflow.py index efd0ea1ed..364303ccd 100644 --- a/src/heart_flow/sub_heartflow.py +++ b/src/heart_flow/sub_heartflow.py @@ -87,12 +87,12 @@ class InterestChatting: def add_interest_dict(self, message: MessageRecv, interest_value: float, is_mentioned: bool): """添加消息到兴趣字典 - + 参数: message: 接收到的消息 interest_value: 兴趣值 is_mentioned: 是否被提及 - + 功能: 1. 将消息添加到兴趣字典 2. 更新最后交互时间 @@ -101,7 +101,7 @@ class InterestChatting: # 添加新消息 self.interest_dict[message.message_info.message_id] = (message, interest_value, is_mentioned) self.last_interaction_time = time.time() - + # 如果字典长度超过10,删除最旧的消息 if len(self.interest_dict) > 10: oldest_key = next(iter(self.interest_dict)) diff --git a/src/heart_flow/subheartflow_manager.py b/src/heart_flow/subheartflow_manager.py index 62d9e2f7b..46e34d1d3 100644 --- a/src/heart_flow/subheartflow_manager.py +++ b/src/heart_flow/subheartflow_manager.py @@ -2,7 +2,7 @@ import asyncio import time import random from typing import Dict, Any, Optional, List -import json # 导入 json 模块 +import json # 导入 json 模块 # 导入日志模块 from src.common.logger import get_module_logger, LogConfig, SUBHEARTFLOW_MANAGER_STYLE_CONFIG @@ -407,13 +407,13 @@ class SubHeartflowManager: f"基于以上信息,该子心流是否表现出足够的活跃迹象或重要性," f"值得将其唤醒并进入常规聊天(CHAT)状态?\n" f"请以 JSON 格式回答,包含一个键 'decision',其值为 true 或 false.\n" - f"例如:{{\"decision\": true}}\n" + f'例如:{{"decision": true}}\n' f"请只输出有效的 JSON 对象。" ) # 调用LLM评估 should_activate = await self._llm_evaluate_state_transition(prompt) - if should_activate is None: # 处理解析失败或意外情况 + if should_activate is None: # 处理解析失败或意外情况 logger.warning(f"{log_prefix} [{stream_name}] LLM评估返回无效结果,跳过。") continue @@ -445,13 +445,13 @@ class SubHeartflowManager: f"基于以上信息,该子心流是否表现出不活跃、对话结束或不再需要关注的迹象," f"应该让其进入休眠(ABSENT)状态?\n" f"请以 JSON 格式回答,包含一个键 'decision',其值为 true (表示应休眠) 或 false (表示不应休眠).\n" - f"例如:{{\"decision\": true}}\n" + f'例如:{{"decision": true}}\n' f"请只输出有效的 JSON 对象。" ) # 调用LLM评估 should_deactivate = await self._llm_evaluate_state_transition(prompt) - if should_deactivate is None: # 处理解析失败或意外情况 + if should_deactivate is None: # 处理解析失败或意外情况 logger.warning(f"{log_prefix} [{stream_name}] LLM评估返回无效结果,跳过。") continue @@ -482,24 +482,28 @@ class SubHeartflowManager: try: # --- 真实的 LLM 调用 --- response_text, _ = await self.llm_state_evaluator.generate_response_async(prompt) - logger.debug(f"{log_prefix} 使用模型 {self.llm_state_evaluator.model_name} 评估,原始响应: ```{response_text}```") + logger.debug( + f"{log_prefix} 使用模型 {self.llm_state_evaluator.model_name} 评估,原始响应: ```{response_text}```" + ) # --- 解析 JSON 响应 --- try: # 尝试去除可能的Markdown代码块标记 - cleaned_response = response_text.strip().strip('`').strip() - if cleaned_response.startswith('json'): + cleaned_response = response_text.strip().strip("`").strip() + if cleaned_response.startswith("json"): cleaned_response = cleaned_response[4:].strip() data = json.loads(cleaned_response) - decision = data.get("decision") # 使用 .get() 避免 KeyError + decision = data.get("decision") # 使用 .get() 避免 KeyError if isinstance(decision, bool): logger.debug(f"{log_prefix} LLM评估结果 (来自JSON): {'建议转换' if decision else '建议不转换'}") return decision else: - logger.warning(f"{log_prefix} LLM 返回的 JSON 中 'decision' 键的值不是布尔型: {decision}。响应: {response_text}") - return None # 值类型不正确 + logger.warning( + f"{log_prefix} LLM 返回的 JSON 中 'decision' 键的值不是布尔型: {decision}。响应: {response_text}" + ) + return None # 值类型不正确 except json.JSONDecodeError as json_err: logger.warning(f"{log_prefix} LLM 返回的响应不是有效的 JSON: {json_err}。响应: {response_text}") @@ -510,15 +514,15 @@ class SubHeartflowManager: if "false" in response_text.lower(): logger.debug(f"{log_prefix} 在非JSON响应中找到 'false',解释为建议不转换") return False - return None # JSON 解析失败,也未找到关键词 - except Exception as parse_err: # 捕获其他可能的解析错误 + return None # JSON 解析失败,也未找到关键词 + except Exception as parse_err: # 捕获其他可能的解析错误 logger.warning(f"{log_prefix} 解析 LLM JSON 响应时发生意外错误: {parse_err}。响应: {response_text}") return None except Exception as e: logger.error(f"{log_prefix} 调用 LLM 或处理其响应时出错: {e}", exc_info=True) traceback.print_exc() - return None # LLM 调用或处理失败 + return None # LLM 调用或处理失败 def count_subflows_by_state(self, state: ChatState) -> int: """统计指定状态的子心流数量""" diff --git a/src/plugins/heartFC_chat/normal_chat.py b/src/plugins/heartFC_chat/normal_chat.py index d7be9bef0..912da3520 100644 --- a/src/plugins/heartFC_chat/normal_chat.py +++ b/src/plugins/heartFC_chat/normal_chat.py @@ -48,7 +48,7 @@ class NormalChat: self.mood_manager = MoodManager.get_instance() # MoodManager 保持单例 # 存储此实例的兴趣监控任务 self.start_time = time.time() - + self._chat_task: Optional[asyncio.Task] = None logger.info(f"[{self.stream_name}] NormalChat 实例初始化完成。") @@ -325,12 +325,12 @@ class NormalChat: """处理启动时存在于 interest_dict 中的高兴趣消息。""" items_to_process = list(self.interest_dict.items()) if not items_to_process: - return # 没有初始消息,直接返回 + return # 没有初始消息,直接返回 logger.info(f"[{self.stream_name}] 发现 {len(items_to_process)} 条初始兴趣消息,开始处理高兴趣部分...") - interest_values = [item[1][1] for item in items_to_process] # 提取兴趣值列表 + interest_values = [item[1][1] for item in items_to_process] # 提取兴趣值列表 - messages_to_reply = [] # 需要立即回复的消息 + messages_to_reply = [] # 需要立即回复的消息 if len(interest_values) == 1: # 如果只有一个消息,直接处理 @@ -342,7 +342,9 @@ class NormalChat: mean_interest = statistics.mean(interest_values) stdev_interest = statistics.stdev(interest_values) threshold = mean_interest + stdev_interest - logger.info(f"[{self.stream_name}] 初始兴趣值 均值: {mean_interest:.2f}, 标准差: {stdev_interest:.2f}, 阈值: {threshold:.2f}") + logger.info( + f"[{self.stream_name}] 初始兴趣值 均值: {mean_interest:.2f}, 标准差: {stdev_interest:.2f}, 阈值: {threshold:.2f}" + ) # 找出高于阈值的消息 for item in items_to_process: @@ -351,7 +353,7 @@ class NormalChat: messages_to_reply.append(item) logger.info(f"[{self.stream_name}] 找到 {len(messages_to_reply)} 条高于阈值的初始消息进行处理。") except statistics.StatisticsError as e: - logger.error(f"[{self.stream_name}] 计算初始兴趣统计值时出错: {e},跳过初始处理。") + logger.error(f"[{self.stream_name}] 计算初始兴趣统计值时出错: {e},跳过初始处理。") # 处理需要回复的消息 processed_count = 0 @@ -359,18 +361,18 @@ class NormalChat: msg_id, (message, interest_value, is_mentioned) = item try: logger.info(f"[{self.stream_name}] 处理初始高兴趣消息 {msg_id} (兴趣值: {interest_value:.2f})") - await self.normal_response( - message=message, is_mentioned=is_mentioned, interested_rate=interest_value - ) + await self.normal_response(message=message, is_mentioned=is_mentioned, interested_rate=interest_value) processed_count += 1 except Exception as e: logger.error(f"[{self.stream_name}] 处理初始兴趣消息 {msg_id} 时出错: {e}\n{traceback.format_exc()}") finally: # 无论成功与否都清空兴趣字典 self.interest_dict.clear() - - logger.info(f"[{self.stream_name}] 初始高兴趣消息处理完毕,共处理 {processed_count} 条。剩余 {len(self.interest_dict)} 条待轮询。") + logger.info( + f"[{self.stream_name}] 初始高兴趣消息处理完毕,共处理 {processed_count} 条。剩余 {len(self.interest_dict)} 条待轮询。" + ) + # --- 新增结束 --- # 保持 staticmethod, 因为不依赖实例状态, 但需要 chat 对象来获取日志上下文 From e7f120319cce81c9affe7ea2f8f33a9ca72c18a3 Mon Sep 17 00:00:00 2001 From: Bakadax Date: Sat, 26 Apr 2025 18:13:11 +0800 Subject: [PATCH 03/13] =?UTF-8?q?=E5=B0=86PFC=E7=9A=84=E9=BA=A6=E9=BA=A6?= =?UTF-8?q?=E5=8F=91=E8=A8=80=E5=AD=98=E8=87=B3=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=EF=BC=8C=E5=88=A0=E6=8E=89=E6=89=8B=E5=8A=A8=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/PFC/conversation.py | 30 ------------------------------ src/plugins/PFC/pfc.py | 1 + 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/src/plugins/PFC/conversation.py b/src/plugins/PFC/conversation.py index 83081e80e..37a35b7a9 100644 --- a/src/plugins/PFC/conversation.py +++ b/src/plugins/PFC/conversation.py @@ -443,36 +443,6 @@ class Conversation: await self.direct_sender.send_message(chat_stream=self.chat_stream, content=reply_content) logger.info(f"消息已发送: {reply_content}") # 可以在发送后加个日志确认 - # --- 添加的立即更新状态逻辑开始 --- - try: - # 内层 try: 专门捕获手动更新状态时可能出现的错误 - # 创建一个代表刚刚发送的消息的字典 - bot_message_info = { - "message_id": f"bot_sent_{current_time}", # 创建一个简单的唯一ID - "time": current_time, - "user_info": UserInfo( # 使用 UserInfo 类构建用户信息 - user_id=str(global_config.BOT_QQ), - user_nickname=global_config.BOT_NICKNAME, - platform=self.chat_stream.platform, # 从 chat_stream 获取平台信息 - ).to_dict(), # 转换为字典格式存储 - "processed_plain_text": reply_content, # 使用发送的内容 - "detailed_plain_text": f"{int(current_time)},{global_config.BOT_NICKNAME}:{reply_content}", # 构造一个简单的详细文本, 时间戳取整 - # 可以根据需要添加其他字段,保持与 observation_info.chat_history 中其他消息结构一致 - } - - # 直接更新 ObservationInfo 实例 - if self.observation_info: - self.observation_info.chat_history.append(bot_message_info) # 将消息添加到历史记录末尾 - self.observation_info.last_bot_speak_time = current_time # 更新 Bot 最后发言时间 - self.observation_info.last_message_time = current_time # 更新最后消息时间 - logger.debug("已手动将Bot发送的消息添加到 ObservationInfo") - else: - logger.warning("无法手动更新 ObservationInfo:实例不存在") - - except Exception as update_err: - logger.error(f"手动更新 ObservationInfo 时出错: {update_err}") - # --- 添加的立即更新状态逻辑结束 --- - # 原有的触发更新和等待代码 self.chat_observer.trigger_update() if not await self.chat_observer.wait_for_update(): diff --git a/src/plugins/PFC/pfc.py b/src/plugins/PFC/pfc.py index 033cf8226..ac8338626 100644 --- a/src/plugins/PFC/pfc.py +++ b/src/plugins/PFC/pfc.py @@ -376,6 +376,7 @@ class DirectMessageSender: # 发送消息 try: await self.send_via_ws(message) + await self.storage.store_message(message, chat_stream) logger.success(f"PFC消息已发送: {content}") except Exception as e: logger.error(f"PFC消息发送失败: {str(e)}") From 293a03960a2e024a6579b05be5e87fcbb83645a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A2=A8=E6=A2=93=E6=9F=92?= <1787882683@qq.com> Date: Sat, 26 Apr 2025 18:40:37 +0800 Subject: [PATCH 04/13] fix: Ruff --- src/plugins/PFC/conversation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/PFC/conversation.py b/src/plugins/PFC/conversation.py index 37a35b7a9..9e675ac3b 100644 --- a/src/plugins/PFC/conversation.py +++ b/src/plugins/PFC/conversation.py @@ -4,7 +4,7 @@ import datetime # from .message_storage import MongoDBMessageStorage from src.plugins.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat -from ...config.config import global_config +# from ...config.config import global_config from typing import Dict, Any from ..chat.message import Message from .pfc_types import ConversationState @@ -436,7 +436,7 @@ class Conversation: try: # 外层 try: 捕获发送消息和后续处理中的主要错误 - current_time = time.time() # 获取当前时间戳 + _current_time = time.time() # 获取当前时间戳 reply_content = self.generated_reply # 获取要发送的内容 # 发送消息 From 10282f3d0c217d5be06d45e0b66c00f0383e5bd1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 26 Apr 2025 10:40:50 +0000 Subject: [PATCH 05/13] =?UTF-8?q?=F0=9F=A4=96=20=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E4=BB=A3=E7=A0=81=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/PFC/conversation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/PFC/conversation.py b/src/plugins/PFC/conversation.py index 9e675ac3b..c56cc3e17 100644 --- a/src/plugins/PFC/conversation.py +++ b/src/plugins/PFC/conversation.py @@ -4,6 +4,7 @@ import datetime # from .message_storage import MongoDBMessageStorage from src.plugins.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat + # from ...config.config import global_config from typing import Dict, Any from ..chat.message import Message From d55043a8a59eaedb006b779857c4f8729d1de638 Mon Sep 17 00:00:00 2001 From: Bakadax Date: Sat, 26 Apr 2025 20:25:24 +0800 Subject: [PATCH 06/13] =?UTF-8?q?PFC=E6=B6=88=E6=81=AF=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=B8=8EHFC=E5=AF=B9=E9=BD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/PFC/action_planner.py | 26 ++++++++++++-------------- src/plugins/PFC/conversation.py | 18 ++++++++++++------ src/plugins/PFC/observation_info.py | 13 +++++++++++-- src/plugins/PFC/pfc.py | 22 ++++++++++++---------- src/plugins/PFC/reply_generator.py | 22 ++++++++++++---------- 5 files changed, 59 insertions(+), 42 deletions(-) diff --git a/src/plugins/PFC/action_planner.py b/src/plugins/PFC/action_planner.py index 4e39483bf..2c083ca15 100644 --- a/src/plugins/PFC/action_planner.py +++ b/src/plugins/PFC/action_planner.py @@ -8,6 +8,7 @@ from .pfc_utils import get_items_from_json from src.individuality.individuality import Individuality from .observation_info import ObservationInfo from .conversation_info import ConversationInfo +from src.plugins.utils.chat_message_builder import build_readable_messages pfc_action_log_config = LogConfig( console_format=PFC_ACTION_PLANNER_STYLE_CONFIG["console_format"], @@ -132,12 +133,7 @@ class ActionPlanner: chat_history_text = "" try: if hasattr(observation_info, "chat_history") and observation_info.chat_history: - chat_history_list = observation_info.chat_history[-20:] - for msg in chat_history_list: - if isinstance(msg, dict) and "detailed_plain_text" in msg: - chat_history_text += f"{msg.get('detailed_plain_text', '')}\n" - elif isinstance(msg, str): - chat_history_text += f"{msg}\n" + chat_history_text = observation_info.chat_history_str if not chat_history_text: # 如果历史记录是空列表 chat_history_text = "还没有聊天记录。\n" else: @@ -146,12 +142,14 @@ class ActionPlanner: if hasattr(observation_info, "new_messages_count") and observation_info.new_messages_count > 0: if hasattr(observation_info, "unprocessed_messages") and observation_info.unprocessed_messages: new_messages_list = observation_info.unprocessed_messages - chat_history_text += f"--- 以下是 {observation_info.new_messages_count} 条新消息 ---\n" - for msg in new_messages_list: - if isinstance(msg, dict) and "detailed_plain_text" in msg: - chat_history_text += f"{msg.get('detailed_plain_text', '')}\n" - elif isinstance(msg, str): - chat_history_text += f"{msg}\n" + new_messages_str = await build_readable_messages( + new_messages_list, + replace_bot_name=True, + merge_messages=False, + timestamp_mode="relative", + read_mark=0.0, + ) + chat_history_text += f"\n--- 以下是 {observation_info.new_messages_count} 条新消息 ---\n{new_messages_str}" # 清理消息应该由调用者或 observation_info 内部逻辑处理,这里不再调用 clear # if hasattr(observation_info, 'clear_unprocessed_messages'): # observation_info.clear_unprocessed_messages() @@ -242,7 +240,7 @@ class ActionPlanner: last_action_context += "- 【重要】失败/取消原因未明确记录。\n" else: last_action_context += f"- 该行动当前状态: {status}\n" - + print(f"chat_history_text:\n{chat_history_text}") # --- 构建最终的 Prompt --- prompt = f"""{persona_text}。现在你在参与一场QQ私聊,请根据以下【所有信息】审慎且灵活的决策下一步行动,可以发言,可以等待,可以倾听,可以调取知识: @@ -304,4 +302,4 @@ end_conversation: 结束对话,对方长时间没回复或者当你觉得对 except Exception as e: logger.error(f"规划行动时调用 LLM 或处理结果出错: {str(e)}") - return "wait", f"行动规划处理中发生错误,暂时等待: {str(e)}" + return "wait", f"行动规划处理中发生错误,暂时等待: {str(e)}" \ No newline at end of file diff --git a/src/plugins/PFC/conversation.py b/src/plugins/PFC/conversation.py index c56cc3e17..b389dbcfc 100644 --- a/src/plugins/PFC/conversation.py +++ b/src/plugins/PFC/conversation.py @@ -3,9 +3,8 @@ import asyncio import datetime # from .message_storage import MongoDBMessageStorage -from src.plugins.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat - -# from ...config.config import global_config +from src.plugins.utils.chat_message_builder import build_readable_messages, get_raw_msg_before_timestamp_with_chat +from ...config.config import global_config from typing import Dict, Any from ..chat.message import Message from .pfc_types import ConversationState @@ -83,9 +82,17 @@ class Conversation: timestamp=time.time(), limit=30, # 加载最近30条作为初始上下文,可以调整 ) + chat_talking_prompt = await build_readable_messages( + initial_messages, + replace_bot_name=True, + merge_messages=False, + timestamp_mode="relative", + read_mark=0.0, + ) if initial_messages: # 将加载的消息填充到 ObservationInfo 的 chat_history self.observation_info.chat_history = initial_messages + self.observation_info.chat_history_str = chat_talking_prompt + "\n" self.observation_info.chat_history_count = len(initial_messages) # 更新 ObservationInfo 中的时间戳等信息 @@ -163,7 +170,7 @@ class Conversation: if hasattr(self.observation_info, "clear_unprocessed_messages"): # 确保 clear_unprocessed_messages 方法存在 logger.debug(f"准备执行 direct_reply,清理 {initial_new_message_count} 条规划时已知的新消息。") - self.observation_info.clear_unprocessed_messages() + await self.observation_info.clear_unprocessed_messages() # 手动重置计数器,确保状态一致性(理想情况下 clear 方法会做这个) if hasattr(self.observation_info, "new_messages_count"): self.observation_info.new_messages_count = 0 @@ -442,7 +449,6 @@ class Conversation: # 发送消息 await self.direct_sender.send_message(chat_stream=self.chat_stream, content=reply_content) - logger.info(f"消息已发送: {reply_content}") # 可以在发送后加个日志确认 # 原有的触发更新和等待代码 self.chat_observer.trigger_update() @@ -454,4 +460,4 @@ class Conversation: except Exception as e: # 这是外层 try 对应的 except logger.error(f"发送消息或更新状态时失败: {str(e)}") - self.state = ConversationState.ANALYZING # 出错也要尝试恢复状态 + self.state = ConversationState.ANALYZING # 出错也要尝试恢复状态 \ No newline at end of file diff --git a/src/plugins/PFC/observation_info.py b/src/plugins/PFC/observation_info.py index 4cb6aaaa8..fa24c1219 100644 --- a/src/plugins/PFC/observation_info.py +++ b/src/plugins/PFC/observation_info.py @@ -7,6 +7,7 @@ from dataclasses import dataclass, field from src.common.logger import get_module_logger from .chat_observer import ChatObserver from .chat_states import NotificationHandler, NotificationType +from src.plugins.utils.chat_message_builder import build_readable_messages logger = get_module_logger("observation_info") @@ -97,6 +98,7 @@ class ObservationInfo: # data_list chat_history: List[str] = field(default_factory=list) + chat_history_str: str = "" unprocessed_messages: List[Dict[str, Any]] = field(default_factory=list) active_users: Set[str] = field(default_factory=set) @@ -223,13 +225,20 @@ class ObservationInfo: return None return time.time() - self.last_bot_speak_time - def clear_unprocessed_messages(self): + async def clear_unprocessed_messages(self): """清空未处理消息列表""" # 将未处理消息添加到历史记录中 for message in self.unprocessed_messages: self.chat_history.append(message) + self.chat_history_str = await build_readable_messages( + self.chat_history[-20:] if len(self.chat_history) > 20 else self.chat_history, + replace_bot_name=True, + merge_messages=False, + timestamp_mode="relative", + read_mark=0.0, + ) # 清空未处理消息列表 self.has_unread_messages = False self.unprocessed_messages.clear() self.chat_history_count = len(self.chat_history) - self.new_messages_count = 0 + self.new_messages_count = 0 \ No newline at end of file diff --git a/src/plugins/PFC/pfc.py b/src/plugins/PFC/pfc.py index ac8338626..e792f16a6 100644 --- a/src/plugins/PFC/pfc.py +++ b/src/plugins/PFC/pfc.py @@ -19,6 +19,7 @@ from src.individuality.individuality import Individuality from .conversation_info import ConversationInfo from .observation_info import ObservationInfo import time +from src.plugins.utils.chat_message_builder import build_readable_messages if TYPE_CHECKING: pass @@ -80,19 +81,20 @@ class GoalAnalyzer: goals_str = f"目标:{goal},产生该对话目标的原因:{reasoning}\n" # 获取聊天历史记录 - chat_history_list = observation_info.chat_history - chat_history_text = "" - for msg in chat_history_list: - chat_history_text += f"{msg}\n" + chat_history_text = observation_info.chat_history if observation_info.new_messages_count > 0: new_messages_list = observation_info.unprocessed_messages + new_messages_str = await build_readable_messages( + new_messages_list, + replace_bot_name=True, + merge_messages=False, + timestamp_mode="relative", + read_mark=0.0, + ) + chat_history_text += f"\n--- 以下是 {observation_info.new_messages_count} 条新消息 ---\n{new_messages_str}" - chat_history_text += f"有{observation_info.new_messages_count}条新消息:\n" - for msg in new_messages_list: - chat_history_text += f"{msg}\n" - - observation_info.clear_unprocessed_messages() + # await observation_info.clear_unprocessed_messages() identity_details_only = self.identity_detail_info identity_addon = "" @@ -379,4 +381,4 @@ class DirectMessageSender: await self.storage.store_message(message, chat_stream) logger.success(f"PFC消息已发送: {content}") except Exception as e: - logger.error(f"PFC消息发送失败: {str(e)}") + logger.error(f"PFC消息发送失败: {str(e)}") \ No newline at end of file diff --git a/src/plugins/PFC/reply_generator.py b/src/plugins/PFC/reply_generator.py index fe9dab6f5..04a1e8cb9 100644 --- a/src/plugins/PFC/reply_generator.py +++ b/src/plugins/PFC/reply_generator.py @@ -7,6 +7,7 @@ from .reply_checker import ReplyChecker from src.individuality.individuality import Individuality from .observation_info import ObservationInfo from .conversation_info import ConversationInfo +from src.plugins.utils.chat_message_builder import build_readable_messages logger = get_module_logger("reply_generator") @@ -73,18 +74,19 @@ class ReplyGenerator: if len(observation_info.chat_history) >= 20 else observation_info.chat_history ) - chat_history_text = "" - for msg in chat_history_list: - chat_history_text += f"{msg.get('detailed_plain_text', '')}\n" + chat_history_text = observation_info.chat_history_str if observation_info.new_messages_count > 0: new_messages_list = observation_info.unprocessed_messages - - chat_history_text += f"有{observation_info.new_messages_count}条新消息:\n" - for msg in new_messages_list: - chat_history_text += f"{msg.get('detailed_plain_text', '')}\n" - - observation_info.clear_unprocessed_messages() + new_messages_str = await build_readable_messages( + new_messages_list, + replace_bot_name=True, + merge_messages=False, + timestamp_mode="relative", + read_mark=0.0, + ) + chat_history_text += f"\n--- 以下是 {observation_info.new_messages_count} 条新消息 ---\n{new_messages_str}" + # await observation_info.clear_unprocessed_messages() identity_details_only = self.identity_detail_info identity_addon = "" @@ -185,4 +187,4 @@ class ReplyGenerator: Returns: Tuple[bool, str, bool]: (是否合适, 原因, 是否需要重新规划) """ - return await self.reply_checker.check(reply, goal, chat_history, retry_count) + return await self.reply_checker.check(reply, goal, chat_history, retry_count) \ No newline at end of file From 6f7074fbb8d51237fabe72b35b6e42d437413f76 Mon Sep 17 00:00:00 2001 From: Bakadax Date: Sat, 26 Apr 2025 20:34:31 +0800 Subject: [PATCH 07/13] =?UTF-8?q?checker=E4=B9=9F=E8=A6=81=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/PFC/conversation.py | 1 + src/plugins/PFC/reply_checker.py | 11 +---------- src/plugins/PFC/reply_generator.py | 4 ++-- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/plugins/PFC/conversation.py b/src/plugins/PFC/conversation.py index b389dbcfc..6db3a0f0a 100644 --- a/src/plugins/PFC/conversation.py +++ b/src/plugins/PFC/conversation.py @@ -280,6 +280,7 @@ class Conversation: reply=self.generated_reply, goal=current_goal_str, chat_history=observation_info.chat_history, + chat_history_str=observation_info.chat_history_str, retry_count=reply_attempt_count - 1, # 传递当前尝试次数(从0开始计数) ) logger.info( diff --git a/src/plugins/PFC/reply_checker.py b/src/plugins/PFC/reply_checker.py index 1f6f91ddf..1379a2c6b 100644 --- a/src/plugins/PFC/reply_checker.py +++ b/src/plugins/PFC/reply_checker.py @@ -22,7 +22,7 @@ class ReplyChecker: self.max_retries = 3 # 最大重试次数 async def check( - self, reply: str, goal: str, chat_history: List[Dict[str, Any]], retry_count: int = 0 + self, reply: str, goal: str, chat_history: List[Dict[str, Any]], chat_history_text: str, retry_count: int = 0 ) -> Tuple[bool, str, bool]: """检查生成的回复是否合适 @@ -36,7 +36,6 @@ class ReplyChecker: """ # 不再从 observer 获取,直接使用传入的 chat_history # messages = self.chat_observer.get_cached_messages(limit=20) - chat_history_text = "" try: # 筛选出最近由 Bot 自己发送的消息 bot_messages = [] @@ -82,14 +81,6 @@ class ReplyChecker: logger.error(f"检查回复时出错: 类型={type(e)}, 值={e}") logger.error(traceback.format_exc()) # 打印详细的回溯信息 - for msg in chat_history[-20:]: - time_str = datetime.datetime.fromtimestamp(msg["time"]).strftime("%H:%M:%S") - user_info = UserInfo.from_dict(msg.get("user_info", {})) - sender = user_info.user_nickname or f"用户{user_info.user_id}" - if sender == self.name: - sender = "你说" - chat_history_text += f"{time_str},{sender}:{msg.get('processed_plain_text', '')}\n" - prompt = f"""请检查以下回复或消息是否合适: 当前对话目标:{goal} diff --git a/src/plugins/PFC/reply_generator.py b/src/plugins/PFC/reply_generator.py index 04a1e8cb9..ee1e28e1c 100644 --- a/src/plugins/PFC/reply_generator.py +++ b/src/plugins/PFC/reply_generator.py @@ -175,7 +175,7 @@ class ReplyGenerator: return "抱歉,我现在有点混乱,让我重新思考一下..." async def check_reply( - self, reply: str, goal: str, chat_history: List[Dict[str, Any]], retry_count: int = 0 + self, reply: str, goal: str, chat_history: List[Dict[str, Any]], chat_history_str: str, retry_count: int = 0 ) -> Tuple[bool, str, bool]: """检查回复是否合适 @@ -187,4 +187,4 @@ class ReplyGenerator: Returns: Tuple[bool, str, bool]: (是否合适, 原因, 是否需要重新规划) """ - return await self.reply_checker.check(reply, goal, chat_history, retry_count) \ No newline at end of file + return await self.reply_checker.check(reply, goal, chat_history, chat_history_str, retry_count) \ No newline at end of file From 2de74c246cdb48fb0d3c7b1feae7482fcc7adf19 Mon Sep 17 00:00:00 2001 From: Bakadax Date: Sat, 26 Apr 2025 20:35:19 +0800 Subject: [PATCH 08/13] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/PFC/action_planner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/PFC/action_planner.py b/src/plugins/PFC/action_planner.py index 2c083ca15..5ac6c62d7 100644 --- a/src/plugins/PFC/action_planner.py +++ b/src/plugins/PFC/action_planner.py @@ -240,7 +240,7 @@ class ActionPlanner: last_action_context += "- 【重要】失败/取消原因未明确记录。\n" else: last_action_context += f"- 该行动当前状态: {status}\n" - print(f"chat_history_text:\n{chat_history_text}") + # --- 构建最终的 Prompt --- prompt = f"""{persona_text}。现在你在参与一场QQ私聊,请根据以下【所有信息】审慎且灵活的决策下一步行动,可以发言,可以等待,可以倾听,可以调取知识: From b34a0a683a9c020de59bb0f8f8d371b55bd6ddfd Mon Sep 17 00:00:00 2001 From: Bakadax Date: Sat, 26 Apr 2025 20:45:40 +0800 Subject: [PATCH 09/13] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E5=9B=9E=E5=8E=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/PFC/conversation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/PFC/conversation.py b/src/plugins/PFC/conversation.py index 6db3a0f0a..df33fc11f 100644 --- a/src/plugins/PFC/conversation.py +++ b/src/plugins/PFC/conversation.py @@ -4,7 +4,7 @@ import datetime # from .message_storage import MongoDBMessageStorage from src.plugins.utils.chat_message_builder import build_readable_messages, get_raw_msg_before_timestamp_with_chat -from ...config.config import global_config +# from ...config.config import global_config from typing import Dict, Any from ..chat.message import Message from .pfc_types import ConversationState From c452be11f8384b962bb5bc0782a8477111cb9501 Mon Sep 17 00:00:00 2001 From: Bakadax Date: Sat, 26 Apr 2025 20:48:26 +0800 Subject: [PATCH 10/13] =?UTF-8?q?=E5=88=A0=E6=8E=89=E6=9C=AA=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=9A=84=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/PFC/reply_generator.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/plugins/PFC/reply_generator.py b/src/plugins/PFC/reply_generator.py index ee1e28e1c..663a529c1 100644 --- a/src/plugins/PFC/reply_generator.py +++ b/src/plugins/PFC/reply_generator.py @@ -69,11 +69,6 @@ class ReplyGenerator: goals_str = f"目标:{goal},产生该对话目标的原因:{reasoning}\n" # 获取聊天历史记录 - chat_history_list = ( - observation_info.chat_history[-20:] - if len(observation_info.chat_history) >= 20 - else observation_info.chat_history - ) chat_history_text = observation_info.chat_history_str if observation_info.new_messages_count > 0: From 9469d605e2a8d002f5287025884a0ee3300c10a6 Mon Sep 17 00:00:00 2001 From: Bakadax Date: Sat, 26 Apr 2025 20:49:40 +0800 Subject: [PATCH 11/13] 1 --- src/plugins/PFC/reply_checker.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/PFC/reply_checker.py b/src/plugins/PFC/reply_checker.py index 1379a2c6b..26b20875c 100644 --- a/src/plugins/PFC/reply_checker.py +++ b/src/plugins/PFC/reply_checker.py @@ -1,5 +1,4 @@ import json -import datetime from typing import Tuple, List, Dict, Any from src.common.logger import get_module_logger from ..models.utils_model import LLMRequest From c33dab01190fb12ac5fe431879e15b4b935677fa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 26 Apr 2025 12:49:58 +0000 Subject: [PATCH 12/13] =?UTF-8?q?=F0=9F=A4=96=20=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E4=BB=A3=E7=A0=81=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/PFC/action_planner.py | 6 ++++-- src/plugins/PFC/conversation.py | 3 ++- src/plugins/PFC/observation_info.py | 2 +- src/plugins/PFC/pfc.py | 2 +- src/plugins/PFC/reply_generator.py | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/plugins/PFC/action_planner.py b/src/plugins/PFC/action_planner.py index 5ac6c62d7..e29d8c4fc 100644 --- a/src/plugins/PFC/action_planner.py +++ b/src/plugins/PFC/action_planner.py @@ -149,7 +149,9 @@ class ActionPlanner: timestamp_mode="relative", read_mark=0.0, ) - chat_history_text += f"\n--- 以下是 {observation_info.new_messages_count} 条新消息 ---\n{new_messages_str}" + chat_history_text += ( + f"\n--- 以下是 {observation_info.new_messages_count} 条新消息 ---\n{new_messages_str}" + ) # 清理消息应该由调用者或 observation_info 内部逻辑处理,这里不再调用 clear # if hasattr(observation_info, 'clear_unprocessed_messages'): # observation_info.clear_unprocessed_messages() @@ -302,4 +304,4 @@ end_conversation: 结束对话,对方长时间没回复或者当你觉得对 except Exception as e: logger.error(f"规划行动时调用 LLM 或处理结果出错: {str(e)}") - return "wait", f"行动规划处理中发生错误,暂时等待: {str(e)}" \ No newline at end of file + return "wait", f"行动规划处理中发生错误,暂时等待: {str(e)}" diff --git a/src/plugins/PFC/conversation.py b/src/plugins/PFC/conversation.py index df33fc11f..6bcb53fe2 100644 --- a/src/plugins/PFC/conversation.py +++ b/src/plugins/PFC/conversation.py @@ -4,6 +4,7 @@ import datetime # from .message_storage import MongoDBMessageStorage from src.plugins.utils.chat_message_builder import build_readable_messages, get_raw_msg_before_timestamp_with_chat + # from ...config.config import global_config from typing import Dict, Any from ..chat.message import Message @@ -461,4 +462,4 @@ class Conversation: except Exception as e: # 这是外层 try 对应的 except logger.error(f"发送消息或更新状态时失败: {str(e)}") - self.state = ConversationState.ANALYZING # 出错也要尝试恢复状态 \ No newline at end of file + self.state = ConversationState.ANALYZING # 出错也要尝试恢复状态 diff --git a/src/plugins/PFC/observation_info.py b/src/plugins/PFC/observation_info.py index fa24c1219..072b1fb6f 100644 --- a/src/plugins/PFC/observation_info.py +++ b/src/plugins/PFC/observation_info.py @@ -241,4 +241,4 @@ class ObservationInfo: self.has_unread_messages = False self.unprocessed_messages.clear() self.chat_history_count = len(self.chat_history) - self.new_messages_count = 0 \ No newline at end of file + self.new_messages_count = 0 diff --git a/src/plugins/PFC/pfc.py b/src/plugins/PFC/pfc.py index e792f16a6..5a70d02f3 100644 --- a/src/plugins/PFC/pfc.py +++ b/src/plugins/PFC/pfc.py @@ -381,4 +381,4 @@ class DirectMessageSender: await self.storage.store_message(message, chat_stream) logger.success(f"PFC消息已发送: {content}") except Exception as e: - logger.error(f"PFC消息发送失败: {str(e)}") \ No newline at end of file + logger.error(f"PFC消息发送失败: {str(e)}") diff --git a/src/plugins/PFC/reply_generator.py b/src/plugins/PFC/reply_generator.py index 663a529c1..65afbf64d 100644 --- a/src/plugins/PFC/reply_generator.py +++ b/src/plugins/PFC/reply_generator.py @@ -182,4 +182,4 @@ class ReplyGenerator: Returns: Tuple[bool, str, bool]: (是否合适, 原因, 是否需要重新规划) """ - return await self.reply_checker.check(reply, goal, chat_history, chat_history_str, retry_count) \ No newline at end of file + return await self.reply_checker.check(reply, goal, chat_history, chat_history_str, retry_count) From 4f34487b45d9e64f6d31fab04ef622b1d45aec81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A2=A8=E6=A2=93=E6=9F=92?= <1787882683@qq.com> Date: Sat, 26 Apr 2025 20:50:22 +0800 Subject: [PATCH 13/13] =?UTF-8?q?docs:=20=E5=9C=A8README.md=E4=B8=AD?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=BA=A6=E9=BA=A6=E4=BB=93=E5=BA=93=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E5=BE=BD=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在README.md文件中添加了麦麦仓库状态徽章,用于展示仓库的活跃度和贡献情况,方便用户快速了解项目状态。 --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index df5c1c94e..65e04a233 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,10 @@ MaiCore是一个开源项目,我们非常欢迎你的参与。你的贡献, - [NapCat](https://github.com/NapNeko/NapCatQQ): 现代化的基于 NTQQ 的 Bot 协议端实现 +## 麦麦仓库状态 + +![Alt](https://repobeats.axiom.co/api/embed/9faca9fccfc467931b87dd357b60c6362b5cfae0.svg "Repobeats analytics image") + ### 贡献者 感谢各位大佬!