From ed21af9dba4321bac0e489309e3d9ed7dfb76a6b Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Sun, 20 Apr 2025 17:24:51 +0800 Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9A=E9=BA=A6=E9=BA=A6=E4=BC=9A?= =?UTF-8?q?=E5=9C=A8no-reply=E5=90=8E=E7=AD=89=E5=BE=85=E6=96=B0=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/heart_flow/observation.py | 16 +++++++ src/heart_flow/sub_heartflow.py | 12 ++--- src/plugins/chat/message.py | 8 +--- .../chat_module/heartFC_chat/pf_chatting.py | 48 +++++++++++++++++-- 4 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/heart_flow/observation.py b/src/heart_flow/observation.py index 200494e55..28f52a570 100644 --- a/src/heart_flow/observation.py +++ b/src/heart_flow/observation.py @@ -6,6 +6,7 @@ from src.config.config import global_config from src.common.database import db from src.common.logger import get_module_logger import traceback +import asyncio logger = get_module_logger("observation") @@ -178,6 +179,21 @@ class ChattingObservation(Observation): f"Chat {self.chat_id} - 压缩早期记忆:{self.mid_memory_info}\n现在聊天内容:{self.now_message_info}" ) + async def has_new_messages_since(self, timestamp: float) -> bool: + """检查指定时间戳之后是否有新消息""" + try: + # 只需检查是否存在,不需要获取内容,使用 {"_id": 1} 提高效率 + new_message = await asyncio.to_thread( + db.messages.find_one, + {"chat_id": self.chat_id, "time": {"$gt": timestamp}}, + {"_id": 1} + ) + # new_message = db.messages.find_one({"chat_id": self.chat_id, "time": {"$gt": timestamp}}, {"_id": 1}) # find_one 不是异步的 + return new_message is not None + except Exception as e: + logger.error(f"检查新消息时出错 for chat {self.chat_id} since {timestamp}: {e}") + return False + @staticmethod def translate_message_list_to_str(talking_message): talking_message_str = "" diff --git a/src/heart_flow/sub_heartflow.py b/src/heart_flow/sub_heartflow.py index c6afeff06..8ede59398 100644 --- a/src/heart_flow/sub_heartflow.py +++ b/src/heart_flow/sub_heartflow.py @@ -37,18 +37,18 @@ def init_prompt(): # prompt += "{prompt_schedule}\n" # prompt += "{relation_prompt_all}\n" prompt += "{prompt_personality}\n" - prompt += "刚刚你的想法是:\n{current_thinking_info}\n" + prompt += "刚刚你的想法是:\n我是{bot_name},我想,{current_thinking_info}\n" prompt += "-----------------------------------\n" prompt += "现在是{time_now},你正在上网,和qq群里的网友们聊天,群里正在聊的话题是:\n{chat_observe_info}\n" prompt += "你现在{mood_info}\n" # prompt += "你注意到{sender_name}刚刚说:{message_txt}\n" - prompt += "现在请你根据刚刚的想法继续思考,思考时可以想想如何对群聊内容进行回复,关注新话题,可以适当转换话题,大家正在说的话才是聊天的主题。\n" + prompt += "现在请你根据刚刚的想法继续思考,思考时可以想想如何对群聊内容进行回复,要不要对群里的话题进行回复,关注新话题,可以适当转换话题,大家正在说的话才是聊天的主题。\n" prompt += ( - "回复的要求是:平淡一些,简短一些,说中文,尽量不要说你说过的话。如果你要回复,最好只回复一个人的一个话题\n" + "回复的要求是:平淡一些,简短一些,说中文,如果你要回复,最好只回复一个人的一个话题\n" ) - prompt += "请注意不要输出多余内容(包括前后缀,冒号和引号,括号, 表情,等),不要带有括号和动作描写" + prompt += "请注意不要输出多余内容(包括前后缀,冒号和引号,括号, 表情,等),不要带有括号和动作描写。不要回复自己的发言,尽量不要说你说过的话。" prompt += ( - "现在请你继续生成你在这个聊天中的想法,不要分点输出,生成内心想法,文字不要浮夸,注意{bot_name}指的就是你。" + "现在请你继续生成你在这个聊天中的想法,不要分点输出,生成内心想法,文字不要浮夸" ) Prompt(prompt, "sub_heartflow_prompt_before") @@ -230,13 +230,13 @@ class SubHeartflow: extra_info=extra_info_prompt, # relation_prompt_all=relation_prompt_all, prompt_personality=prompt_personality, + bot_name=self.bot_name, current_thinking_info=current_thinking_info, time_now=time_now, chat_observe_info=chat_observe_info, mood_info=mood_info, # sender_name=sender_name_sign, # message_txt=message_txt, - bot_name=self.bot_name, ) prompt = await relationship_manager.convert_all_person_sign_to_person_name(prompt) diff --git a/src/plugins/chat/message.py b/src/plugins/chat/message.py index 9f3db5720..cbea1fd92 100644 --- a/src/plugins/chat/message.py +++ b/src/plugins/chat/message.py @@ -244,13 +244,9 @@ class MessageProcessBase(Message): # time_str = time.strftime("%m-%d %H:%M:%S", time.localtime(self.message_info.time)) timestamp = self.message_info.time user_info = self.message_info.user_info - # name = ( - # f"{user_info.user_nickname}(ta的昵称:{user_info.user_cardname},ta的id:{user_info.user_id})" - # if user_info.user_cardname != None - # else f"{user_info.user_nickname}(ta的id:{user_info.user_id})" - # ) + name = f"<{self.message_info.platform}:{user_info.user_id}:{user_info.user_nickname}:{user_info.user_cardname}>" - return f"[{timestamp}] {name}: {self.processed_plain_text}\n" + return f"[{timestamp}],{name} 说:{self.processed_plain_text}\n" @dataclass diff --git a/src/plugins/chat_module/heartFC_chat/pf_chatting.py b/src/plugins/chat_module/heartFC_chat/pf_chatting.py index bff9608f9..1061e68e0 100644 --- a/src/plugins/chat_module/heartFC_chat/pf_chatting.py +++ b/src/plugins/chat_module/heartFC_chat/pf_chatting.py @@ -14,7 +14,6 @@ from src.common.logger import get_module_logger, LogConfig, DEFAULT_CONFIG # from src.plugins.models.utils_model import LLMRequest from src.plugins.chat.utils import parse_text_timestamps from src.plugins.chat.utils_image import image_path_to_base64 # Local import needed after move -from src.plugins.chat.message import Seg # Local import needed after move # 定义日志配置 (使用 loguru 格式) interest_log_config = LogConfig( @@ -227,21 +226,27 @@ class PFChatting: logger.info(f"{log_prefix} PFChatting: 聊太久了,麦麦打算休息一下 (计时器为 {current_timer:.1f}s)。退出PFChatting。") break + # 记录循环周期开始时间,用于计时和休眠计算 loop_cycle_start_time = time.monotonic() action_taken_this_cycle = False acquired_lock = False + planner_start_db_time = 0.0 # 初始化 + try: # Use try_acquire pattern or timeout? await self._processing_lock.acquire() acquired_lock = True logger.debug(f"{log_prefix} PFChatting: 循环获取到处理锁") + # 在规划前记录数据库时间戳 + planner_start_db_time = time.time() + # --- Planner --- # planner_result = await self._planner() action = planner_result.get("action", "error") reasoning = planner_result.get("reasoning", "Planner did not provide reasoning.") emoji_query = planner_result.get("emoji_query", "") - current_mind = planner_result.get("current_mind", "[Mind unavailable]") + # current_mind = planner_result.get("current_mind", "[Mind unavailable]") # send_emoji_from_tools = planner_result.get("send_emoji_from_tools", "") # Emoji from tools observed_messages = planner_result.get("observed_messages", []) llm_error = planner_result.get("llm_error", False) @@ -304,10 +309,47 @@ class PFChatting: logger.error(f"{log_prefix} 循环: 发送表情失败: {e_emoji}") else: logger.warning(f"{log_prefix} 循环: 无法发送表情, 无法获取锚点.") + action_taken_this_cycle = True # 即使发送失败,Planner 也决策了动作 elif action == "no_reply": logger.info(f"{log_prefix} PFChatting: 麦麦决定不回复. 原因: {reasoning}") - action_taken_this_cycle = False + action_taken_this_cycle = False # 标记为未执行动作 + # --- 新增:等待新消息 --- + logger.debug(f"{log_prefix} PFChatting: 开始等待新消息 (自 {planner_start_db_time})...") + observation = None + if self.sub_hf: + observation = self.sub_hf._get_primary_observation() + + if observation: + wait_start_time = time.monotonic() + while True: + # 检查计时器是否耗尽 + async with self._timer_lock: + if self._loop_timer <= 0: + logger.info(f"{log_prefix} PFChatting: 等待新消息时计时器耗尽。") + break # 计时器耗尽,退出等待 + + # 检查是否有新消息 + has_new = await observation.has_new_messages_since(planner_start_db_time) + if has_new: + logger.info(f"{log_prefix} PFChatting: 检测到新消息,结束等待。") + break # 收到新消息,退出等待 + + # 检查等待是否超时(例如,防止无限等待) + if time.monotonic() - wait_start_time > 60: # 等待60秒示例 + logger.warning(f"{log_prefix} PFChatting: 等待新消息超时(60秒)。") + break # 超时退出 + + # 等待一段时间再检查 + try: + await asyncio.sleep(1.5) # 检查间隔 + except asyncio.CancelledError: + logger.info(f"{log_prefix} 等待新消息的 sleep 被中断。") + raise # 重新抛出取消错误,以便外层循环处理 + + else: + logger.warning(f"{log_prefix} PFChatting: 无法获取 Observation 实例,无法等待新消息。") + # --- 等待结束 --- elif action == "error": # Action specifically set to error by planner logger.error(f"{log_prefix} PFChatting: Planner返回错误状态. 原因: {reasoning}")