From f30d472c0bdc8dffcb8b11a0450277387739ad2a Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Fri, 2 May 2025 00:58:55 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E4=BC=98=E5=8C=96=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E8=B0=83=E7=94=A8=E7=9A=84=E5=BE=97=E5=88=B0=E7=9A=84?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E8=B0=83=E7=94=A8=E5=92=8C=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tool_can_use/compare_numbers_tool.py | 6 +- src/do_tool/tool_can_use/get_knowledge.py | 8 +- src/do_tool/tool_can_use/get_memory.py | 7 +- src/do_tool/tool_can_use/get_time_date.py | 4 +- .../tool_can_use/lpmm_get_knowledge.py | 28 +++++- .../tool_can_use/rename_person_tool.py | 18 ++-- src/heart_flow/observation.py | 5 +- src/heart_flow/sub_mind.py | 98 +++++++++++++++---- src/heart_flow/subheartflow_manager.py | 2 + src/heart_flow/utils_chat.py | 2 +- src/plugins/chat/message.py | 15 ++- src/plugins/chat/utils.py | 47 --------- src/plugins/heartFC_chat/heartFC_chat.py | 7 +- src/plugins/heartFC_chat/normal_chat.py | 20 ++-- 14 files changed, 154 insertions(+), 113 deletions(-) diff --git a/src/do_tool/tool_can_use/compare_numbers_tool.py b/src/do_tool/tool_can_use/compare_numbers_tool.py index ef037de9e..2bb292a1a 100644 --- a/src/do_tool/tool_can_use/compare_numbers_tool.py +++ b/src/do_tool/tool_can_use/compare_numbers_tool.py @@ -9,7 +9,7 @@ class CompareNumbersTool(BaseTool): """比较两个数大小的工具""" name = "compare_numbers" - description = "比较两个数的大小,返回较大的数" + description = "使用工具 比较两个数的大小,返回较大的数" parameters = { "type": "object", "properties": { @@ -39,10 +39,10 @@ class CompareNumbersTool(BaseTool): else: result = f"{num1} 等于 {num2}" - return {"name": self.name, "content": result} + return {"type": "comparison_result", "id": f"{num1}_vs_{num2}", "content": result} except Exception as e: logger.error(f"比较数字失败: {str(e)}") - return {"name": self.name, "content": f"比较数字失败: {str(e)}"} + return {"type": "info", "id": f"{num1}_vs_{num2}", "content": f"比较数字失败,炸了: {str(e)}"} # 注册工具 diff --git a/src/do_tool/tool_can_use/get_knowledge.py b/src/do_tool/tool_can_use/get_knowledge.py index 20a922646..90a446550 100644 --- a/src/do_tool/tool_can_use/get_knowledge.py +++ b/src/do_tool/tool_can_use/get_knowledge.py @@ -11,7 +11,7 @@ class SearchKnowledgeTool(BaseTool): """从知识库中搜索相关信息的工具""" name = "search_knowledge" - description = "从知识库中搜索相关信息" + description = "使用工具从知识库中搜索相关信息" parameters = { "type": "object", "properties": { @@ -42,11 +42,11 @@ class SearchKnowledgeTool(BaseTool): content = f"你知道这些知识: {knowledge_info}" else: content = f"你不太了解有关{query}的知识" - return {"name": "search_knowledge", "content": content} - return {"name": "search_knowledge", "content": f"无法获取关于'{query}'的嵌入向量"} + return {"type": "knowledge", "id": query, "content": content} + return {"type": "info", "id": query, "content": f"无法获取关于'{query}'的嵌入向量,你知识库炸了"} except Exception as e: logger.error(f"知识库搜索工具执行失败: {str(e)}") - return {"name": "search_knowledge", "content": f"知识库搜索失败: {str(e)}"} + return {"type": "info", "id": query, "content": f"知识库搜索失败,炸了: {str(e)}"} @staticmethod def get_info_from_db( diff --git a/src/do_tool/tool_can_use/get_memory.py b/src/do_tool/tool_can_use/get_memory.py index c1bcc9277..481942daf 100644 --- a/src/do_tool/tool_can_use/get_memory.py +++ b/src/do_tool/tool_can_use/get_memory.py @@ -10,7 +10,7 @@ class GetMemoryTool(BaseTool): """从记忆系统中获取相关记忆的工具""" name = "get_memory" - description = "从记忆系统中获取相关记忆" + description = "使用工具从记忆系统中获取相关记忆" parameters = { "type": "object", "properties": { @@ -53,10 +53,11 @@ class GetMemoryTool(BaseTool): else: content = f"{topic}的记忆,你记不太清" - return {"name": "get_memory", "content": content} + return {"type": "memory", "id": topic_list, "content": content} except Exception as e: logger.error(f"记忆获取工具执行失败: {str(e)}") - return {"name": "get_memory", "content": f"记忆获取失败: {str(e)}"} + # 在失败时也保持格式一致,但id可能不适用或设为None/Error + return {"type": "memory_error", "id": topic_list, "content": f"记忆获取失败: {str(e)}"} # 注册工具 diff --git a/src/do_tool/tool_can_use/get_time_date.py b/src/do_tool/tool_can_use/get_time_date.py index bd3b1a9c1..1cb23fdbd 100644 --- a/src/do_tool/tool_can_use/get_time_date.py +++ b/src/do_tool/tool_can_use/get_time_date.py @@ -2,6 +2,7 @@ from src.do_tool.tool_can_use.base_tool import BaseTool from src.common.logger_manager import get_logger from typing import Dict, Any from datetime import datetime +import time logger = get_logger("get_time_date") @@ -32,6 +33,7 @@ class GetCurrentDateTimeTool(BaseTool): current_weekday = datetime.now().strftime("%A") return { - "name": "get_current_date_time", + "type": "time_info", + "id": f"time_info_{time.time()}", "content": f"当前时间: {current_time}, 日期: {current_date}, 年份: {current_year}, 星期: {current_weekday}", } diff --git a/src/do_tool/tool_can_use/lpmm_get_knowledge.py b/src/do_tool/tool_can_use/lpmm_get_knowledge.py index 8754e603b..5eec260d5 100644 --- a/src/do_tool/tool_can_use/lpmm_get_knowledge.py +++ b/src/do_tool/tool_can_use/lpmm_get_knowledge.py @@ -46,11 +46,14 @@ class SearchKnowledgeFromLPMMTool(BaseTool): content = f"你知道这些知识: {knowledge_info}" else: content = f"你不太了解有关{query}的知识" - return {"name": "search_knowledge", "content": content} - return {"name": "search_knowledge", "content": f"无法获取关于'{query}'的嵌入向量"} + return {"type": "lpmm_knowledge", "id": query, "content": content} + # 如果获取嵌入失败 + return {"type": "info", "id": query, "content": f"无法获取关于'{query}'的嵌入向量,你lpmm知识库炸了"} except Exception as e: logger.error(f"知识库搜索工具执行失败: {str(e)}") - return {"name": "search_knowledge", "content": f"知识库搜索失败: {str(e)}"} + # 在其他异常情况下,确保 id 仍然是 query (如果它被定义了) + query_id = query if 'query' in locals() else 'unknown_query' + return {"type": "info", "id": query_id, "content": f"lpmm知识库搜索失败,炸了: {str(e)}"} # def get_info_from_db( # self, query_embedding: list, limit: int = 1, threshold: float = 0.5, return_raw: bool = False @@ -133,6 +136,25 @@ class SearchKnowledgeFromLPMMTool(BaseTool): # # 返回所有找到的内容,用换行分隔 # return "\n".join(str(result["content"]) for result in results) + def _format_results(self, results: list) -> str: + """格式化结果""" + if not results: + return "未找到相关知识。" + + formatted_string = "我找到了一些相关知识:\n" + for i, result in enumerate(results): + chunk_id = result.get("chunk_id") + text = result.get("text", "") + source = result.get("source", "未知来源") + source_type = result.get("source_type", "未知类型") + similarity = result.get("similarity", 0.0) + + formatted_string += f"{i + 1}. (相似度: {similarity:.2f}) 类型: {source_type}, 来源: {source} \n内容片段: {text}\n\n" + # 暂时去掉chunk_id + # formatted_string += f"{i + 1}. (相似度: {similarity:.2f}) 类型: {source_type}, 来源: {source}, Chunk ID: {chunk_id} \n内容片段: {text}\n\n" + + return formatted_string + # 注册工具 # register_tool(SearchKnowledgeTool) diff --git a/src/do_tool/tool_can_use/rename_person_tool.py b/src/do_tool/tool_can_use/rename_person_tool.py index 875e4ddc9..9e796931d 100644 --- a/src/do_tool/tool_can_use/rename_person_tool.py +++ b/src/do_tool/tool_can_use/rename_person_tool.py @@ -1,7 +1,9 @@ from src.do_tool.tool_can_use.base_tool import BaseTool, register_tool from src.plugins.person_info.person_info import person_info_manager from src.common.logger_manager import get_logger +from src.plugins.person_info.relationship_manager import relationship_manager import json +import time logger = get_logger("rename_person_tool") @@ -82,10 +84,10 @@ class RenamePersonTool(BaseTool): new_name = result["nickname"] reason = result.get("reason", "未提供理由") logger.info(f"成功为用户 {person_id} 取了新昵称: {new_name}") - return { - "name": self.name, - "content": f"好的,我已经给 '{person_name_to_find}' 取了新昵称:'{new_name}'。因为:{reason}" - } + + content = f"已成功将用户 {person_name_to_find} 的备注名更新为 {new_name}" + logger.info(content) + return {"type": "info", "id": f"rename_success_{time.time()}", "content": content} else: logger.warning(f"为用户 {person_id} 调用 qv_person_name 后未能成功获取新昵称。") # 尝试从内存中获取可能已经更新的名字 @@ -102,11 +104,9 @@ class RenamePersonTool(BaseTool): } except Exception as e: - logger.error(f"执行 rename_person 工具时出错: {e}", exc_info=True) - return { - "name": self.name, - "content": f"执行重命名操作时遇到内部错误: {e}" - } + error_msg = f"重命名失败: {str(e)}" + logger.error(error_msg, exc_info=True) + return {"type": "info_error", "id": f"rename_error_{time.time()}", "content": error_msg} # 注册工具 register_tool(RenamePersonTool) \ No newline at end of file diff --git a/src/heart_flow/observation.py b/src/heart_flow/observation.py index 0d51c9380..0c63e7519 100644 --- a/src/heart_flow/observation.py +++ b/src/heart_flow/observation.py @@ -79,9 +79,8 @@ class ChattingObservation(Observation): async def initialize(self): # --- Use utility function to determine chat type and fetch info --- self.is_group_chat, self.chat_target_info = await get_chat_type_and_target_info(self.chat_id) - logger.debug( - f"ChattingObservation {self.chat_id} initialized: is_group={self.is_group_chat}, target_info={self.chat_target_info}" - ) + # logger.debug(f"is_group_chat: {self.is_group_chat}") + # logger.debug(f"chat_target_info: {self.chat_target_info}") # --- End using utility function --- # Fetch initial messages (existing logic) diff --git a/src/heart_flow/sub_mind.py b/src/heart_flow/sub_mind.py index 4ce2fe417..0dfc836c2 100644 --- a/src/heart_flow/sub_mind.py +++ b/src/heart_flow/sub_mind.py @@ -1,4 +1,4 @@ -from .observation import Observation +from .observation import Observation, ChattingObservation from src.plugins.models.utils_model import LLMRequest from src.config.config import global_config import time @@ -114,7 +114,7 @@ def calculate_replacement_probability(similarity: float) -> float: class SubMind: - def __init__(self, subheartflow_id: str, chat_state: ChatStateInfo, observations: Observation): + def __init__(self, subheartflow_id: str, chat_state: ChatStateInfo, observations: ChattingObservation): self.last_active_time = None self.subheartflow_id = subheartflow_id @@ -130,10 +130,41 @@ class SubMind: self.current_mind = "" self.past_mind = [] - self.structured_info = {} + self.structured_info = [] + self.structured_info_str = "" name = chat_manager.get_stream_name(self.subheartflow_id) self.log_prefix = f"[{name}] " + self._update_structured_info_str() + + def _update_structured_info_str(self): + """根据 structured_info 更新 structured_info_str""" + if not self.structured_info: + self.structured_info_str = "" + return + + lines = ["【信息】"] + for item in self.structured_info: + # 简化展示,突出内容和类型,包含TTL供调试 + type_str = item.get('type', '未知类型') + content_str = item.get('content', '') + ttl = item.get('ttl', '?') + + if type_str == "info": + lines.append(f"刚刚: {content_str}") + elif type_str == "memory": + lines.append(f"{content_str}") + elif type_str == "comparison_result": + lines.append(f"数字大小比较结果: {content_str}") + elif type_str == "time_info": + lines.append(f"{content_str}") + elif type_str == "lpmm_knowledge": + lines.append(f"你知道:{content_str}") + else: + lines.append(f"{type_str}的信息: {content_str}") + + self.structured_info_str = "\n".join(lines) + logger.debug(f"{self.log_prefix} 更新 structured_info_str: \n{self.structured_info_str}") async def do_thinking_before_reply(self, history_cycle: list[CycleInfo] = None): """ @@ -145,19 +176,36 @@ class SubMind: # 更新活跃时间 self.last_active_time = time.time() + # ---------- 0. 更新和清理 structured_info ---------- + if self.structured_info: + logger.debug(f"{self.log_prefix} 更新前的 structured_info: {safe_json_dumps(self.structured_info, ensure_ascii=False)}") + updated_info = [] + for item in self.structured_info: + item['ttl'] -= 1 + if item['ttl'] > 0: + updated_info.append(item) + else: + logger.debug(f"{self.log_prefix} 移除过期的 structured_info 项: {item['id']}") + self.structured_info = updated_info + logger.debug(f"{self.log_prefix} 更新后的 structured_info: {safe_json_dumps(self.structured_info, ensure_ascii=False)}") + self._update_structured_info_str() + logger.debug(f"{self.log_prefix} 当前完整的 structured_info: {safe_json_dumps(self.structured_info, ensure_ascii=False)}") + # ---------- 1. 准备基础数据 ---------- # 获取现有想法和情绪状态 previous_mind = self.current_mind if self.current_mind else "" mood_info = self.chat_state.mood # 获取观察对象 - observation = self.observations[0] if self.observations else None + observation: ChattingObservation = self.observations[0] if self.observations else None if not observation or not hasattr(observation, "is_group_chat"): # Ensure it's ChattingObservation or similar logger.error(f"{self.log_prefix} 无法获取有效的观察对象或缺少聊天类型信息") self.update_current_mind("(观察出错了...)") return self.current_mind, self.past_mind - + is_group_chat = observation.is_group_chat + # logger.debug(f"is_group_chat: {is_group_chat}") + chat_target_info = observation.chat_target_info chat_target_name = "对方" # Default for private if not is_group_chat and chat_target_info: @@ -277,10 +325,11 @@ class SubMind: # ---------- 4. 构建最终提示词 ---------- # --- Choose template based on chat type --- + logger.debug(f"is_group_chat: {is_group_chat}") if is_group_chat: template_name = "sub_heartflow_prompt_before" prompt = (await global_prompt_manager.get_prompt_async(template_name)).format( - extra_info="", + extra_info=self.structured_info_str, prompt_personality=prompt_personality, relation_prompt=relation_prompt, bot_name=individuality.name, @@ -295,7 +344,7 @@ class SubMind: else: # Private chat template_name = "sub_heartflow_prompt_private_before" prompt = (await global_prompt_manager.get_prompt_async(template_name)).format( - extra_info="", + extra_info=self.structured_info_str, prompt_personality=prompt_personality, relation_prompt=relation_prompt, # Might need adjustment for private context bot_name=individuality.name, @@ -447,7 +496,7 @@ class SubMind: tool_instance: 工具使用器实例 """ tool_results = [] - structured_info = {} # 动态生成键 + new_structured_items = [] # 收集新产生的结构化信息 # 执行所有工具调用 for tool_call in tool_calls: @@ -455,23 +504,34 @@ class SubMind: result = await tool_instance._execute_tool_call(tool_call) if result: tool_results.append(result) + # 创建新的结构化信息项 + new_item = { + "type": result.get("type", "unknown_type"), # 使用 'type' 键 + "id": result.get("id", f"fallback_id_{time.time()}"), # 使用 'id' 键 + "content": result.get("content", ""), # 'content' 键保持不变 + "ttl": 3 + } + new_structured_items.append(new_item) - # 使用工具名称作为键 - tool_name = result["name"] - if tool_name not in structured_info: - structured_info[tool_name] = [] - - structured_info[tool_name].append({"name": result["name"], "content": result["content"]}) except Exception as tool_e: logger.error(f"[{self.subheartflow_id}] 工具执行失败: {tool_e}") + logger.error(traceback.format_exc()) # 添加 traceback 记录 - # 如果有工具结果,记录并更新结构化信息 - if structured_info: - logger.debug(f"工具调用收集到结构化信息: {safe_json_dumps(structured_info, ensure_ascii=False)}") - self.structured_info = structured_info + # 如果有新的工具结果,记录并更新结构化信息 + if new_structured_items: + self.structured_info.extend(new_structured_items) # 添加到现有列表 + logger.debug(f"工具调用收集到新的结构化信息: {safe_json_dumps(new_structured_items, ensure_ascii=False)}") + # logger.debug(f"当前完整的 structured_info: {safe_json_dumps(self.structured_info, ensure_ascii=False)}") # 可以取消注释以查看完整列表 + self._update_structured_info_str() # 添加新信息后,更新字符串表示 def update_current_mind(self, response): - self.past_mind.append(self.current_mind) + if self.current_mind: # 只有当 current_mind 非空时才添加到 past_mind + self.past_mind.append(self.current_mind) + # 可以考虑限制 past_mind 的大小,例如: + # max_past_mind_size = 10 + # if len(self.past_mind) > max_past_mind_size: + # self.past_mind.pop(0) # 移除最旧的 + self.current_mind = response diff --git a/src/heart_flow/subheartflow_manager.py b/src/heart_flow/subheartflow_manager.py index 04153abfa..fa8aaa964 100644 --- a/src/heart_flow/subheartflow_manager.py +++ b/src/heart_flow/subheartflow_manager.py @@ -127,6 +127,8 @@ class SubHeartflowManager: # 添加聊天观察者 observation = ChattingObservation(chat_id=subheartflow_id) + await observation.initialize() + new_subflow.add_observation(observation) # 注册子心流 diff --git a/src/heart_flow/utils_chat.py b/src/heart_flow/utils_chat.py index 3e082b6da..c3f81a14a 100644 --- a/src/heart_flow/utils_chat.py +++ b/src/heart_flow/utils_chat.py @@ -18,7 +18,7 @@ async def get_chat_type_and_target_info(chat_id: str) -> Tuple[bool, Optional[Di Tuple[bool, Optional[Dict]]: - bool: 是否为群聊 (True 是群聊, False 是私聊或未知) - Optional[Dict]: 如果是私聊,包含对方信息的字典;否则为 None。 - 字典包含: platform, user_id, user_nickname, person_id, person_name + 字典包含: platform, user_id, user_nickname, person_id, person_name """ is_group_chat = False # Default to private/unknown chat_target_info = None diff --git a/src/plugins/chat/message.py b/src/plugins/chat/message.py index e753a9994..a29d0ab29 100644 --- a/src/plugins/chat/message.py +++ b/src/plugins/chat/message.py @@ -31,19 +31,21 @@ class Message(MessageBase): def __init__( self, message_id: str, - timestamp: float, chat_stream: ChatStream, user_info: UserInfo, message_segment: Optional[Seg] = None, + timestamp: Optional[float] = None, reply: Optional["MessageRecv"] = None, detailed_plain_text: str = "", processed_plain_text: str = "", ): + # 使用传入的时间戳或当前时间 + current_timestamp = timestamp if timestamp is not None else round(time.time(), 3) # 构造基础消息信息 message_info = BaseMessageInfo( platform=chat_stream.platform, message_id=message_id, - time=timestamp, + time=current_timestamp, group_info=chat_stream.group_info, user_info=user_info, ) @@ -164,11 +166,12 @@ class MessageProcessBase(Message): message_segment: Optional[Seg] = None, reply: Optional["MessageRecv"] = None, thinking_start_time: float = 0, + timestamp: Optional[float] = None, ): - # 调用父类初始化 + # 调用父类初始化,传递时间戳 super().__init__( message_id=message_id, - timestamp=round(time.time(), 3), # 保留3位小数 + timestamp=timestamp, chat_stream=chat_stream, user_info=bot_user_info, message_segment=message_segment, @@ -238,8 +241,9 @@ class MessageThinking(MessageProcessBase): bot_user_info: UserInfo, reply: Optional["MessageRecv"] = None, thinking_start_time: float = 0, + timestamp: Optional[float] = None, ): - # 调用父类初始化 + # 调用父类初始化,传递时间戳 super().__init__( message_id=message_id, chat_stream=chat_stream, @@ -247,6 +251,7 @@ class MessageThinking(MessageProcessBase): message_segment=None, # 思考状态不需要消息段 reply=reply, thinking_start_time=thinking_start_time, + timestamp=timestamp, ) # 思考状态特有属性 diff --git a/src/plugins/chat/utils.py b/src/plugins/chat/utils.py index cdaa21942..9b71ecc5f 100644 --- a/src/plugins/chat/utils.py +++ b/src/plugins/chat/utils.py @@ -107,53 +107,6 @@ async def get_embedding(text, request_type="embedding"): return embedding -async def get_recent_group_messages(chat_id: str, limit: int = 12) -> list: - """从数据库获取群组最近的消息记录 - - Args: - chat_id: 群组ID - limit: 获取消息数量,默认12条 - - Returns: - list: Message对象列表,按时间正序排列 - """ - - # 从数据库获取最近消息 - recent_messages = list( - db.messages.find( - {"chat_id": chat_id}, - ) - .sort("time", -1) - .limit(limit) - ) - - if not recent_messages: - return [] - - # 转换为 Message对象列表 - message_objects = [] - for msg_data in recent_messages: - try: - chat_info = msg_data.get("chat_info", {}) - chat_stream = ChatStream.from_dict(chat_info) - user_info = msg_data.get("user_info", {}) - user_info = UserInfo.from_dict(user_info) - msg = Message( - message_id=msg_data["message_id"], - chat_stream=chat_stream, - timestamp=msg_data["time"], - user_info=user_info, - processed_plain_text=msg_data.get("processed_text", ""), - detailed_plain_text=msg_data.get("detailed_plain_text", ""), - ) - message_objects.append(msg) - except KeyError: - logger.warning("数据库中存在无效的消息") - continue - - # 按时间正序排列 - message_objects.reverse() - return message_objects def get_recent_group_detailed_plain_text(chat_stream_id: str, limit: int = 12, combine=False): diff --git a/src/plugins/heartFC_chat/heartFC_chat.py b/src/plugins/heartFC_chat/heartFC_chat.py index dd078f7ce..f203926f4 100644 --- a/src/plugins/heartFC_chat/heartFC_chat.py +++ b/src/plugins/heartFC_chat/heartFC_chat.py @@ -264,9 +264,6 @@ class HeartFChatting: logger.error(f"[HFC:{self.stream_id}] 获取ChatStream时出错 in _initialize: {e}") return False - logger.debug( - f"{self.log_prefix} HeartFChatting initialized: is_group={self.is_group_chat}, target_info={self.chat_target_info}" - ) # --- End using utility function --- self._initialized = True @@ -861,7 +858,7 @@ class HeartFChatting: cycle_history=self._cycle_history, # <-- Pass HFC state observed_messages_str=observed_messages_str, # <-- Pass local variable current_mind=current_mind, # <-- Pass argument - structured_info=self.sub_mind.structured_info, # <-- Pass SubMind info + structured_info=self.sub_mind.structured_info_str, # <-- Pass SubMind info current_available_actions=current_available_actions, # <-- Pass determined actions ) @@ -1301,7 +1298,7 @@ class HeartFChatting: # Focus specific args: reason=reason, current_mind_info=self.sub_mind.current_mind, - structured_info=self.sub_mind.structured_info, + structured_info=self.sub_mind.structured_info_str, sender_name=sender_name_for_prompt, # Pass determined name # Normal specific args (not used in focus mode): # message_txt="", diff --git a/src/plugins/heartFC_chat/normal_chat.py b/src/plugins/heartFC_chat/normal_chat.py index 6b8fb9ce2..dd89782fd 100644 --- a/src/plugins/heartFC_chat/normal_chat.py +++ b/src/plugins/heartFC_chat/normal_chat.py @@ -63,15 +63,12 @@ class NormalChat: self.is_group_chat, self.chat_target_info = await get_chat_type_and_target_info(self.stream_id) # Update stream_name again after potential async call in util func self.stream_name = chat_manager.get_stream_name(self.stream_id) or self.stream_id - logger.debug( - f"[{self.stream_name}] NormalChat initialized: is_group={self.is_group_chat}, target_info={self.chat_target_info}" - ) # --- End using utility function --- self._initialized = True logger.info(f"[{self.stream_name}] NormalChat 实例 initialize 完成 (异步部分)。") # 改为实例方法 - async def _create_thinking_message(self, message: MessageRecv) -> str: + async def _create_thinking_message(self, message: MessageRecv, timestamp: Optional[float] = None) -> str: """创建思考消息""" messageinfo = message.message_info @@ -85,15 +82,15 @@ class NormalChat: thinking_id = "mt" + str(thinking_time_point) thinking_message = MessageThinking( message_id=thinking_id, - chat_stream=self.chat_stream, # 使用 self.chat_stream + chat_stream=self.chat_stream, bot_user_info=bot_user_info, reply=message, thinking_start_time=thinking_time_point, + timestamp=timestamp if timestamp is not None else None ) await message_manager.add_message(thinking_message) return thinking_id - # 改为实例方法 async def _add_messages_to_manager( self, message: MessageRecv, response_set: List[str], thinking_id @@ -209,7 +206,7 @@ class NormalChat: try: # 处理消息 await self.normal_response( - message=message, is_mentioned=is_mentioned, interested_rate=interest_value + message=message, is_mentioned=is_mentioned, interested_rate=interest_value, rewind_response = False ) except Exception as e: logger.error(f"[{self.stream_name}] 处理兴趣消息{msg_id}时出错: {e}\n{traceback.format_exc()}") @@ -217,7 +214,7 @@ class NormalChat: self.interest_dict.pop(msg_id, None) # 改为实例方法, 移除 chat 参数 - async def normal_response(self, message: MessageRecv, is_mentioned: bool, interested_rate: float) -> None: + async def normal_response(self, message: MessageRecv, is_mentioned: bool, interested_rate: float, rewind_response: bool = False) -> None: # 检查收到的消息是否属于当前实例处理的 chat stream if message.chat_stream.stream_id != self.stream_id: logger.error( @@ -264,7 +261,10 @@ class NormalChat: await willing_manager.before_generate_reply_handle(message.message_info.message_id) with Timer("创建思考消息", timing_results): - thinking_id = await self._create_thinking_message(message) + if rewind_response: + thinking_id = await self._create_thinking_message(message, message.message_info.time) + else: + thinking_id = await self._create_thinking_message(message) logger.debug(f"[{self.stream_name}] 创建捕捉器,thinking_id:{thinking_id}") @@ -393,7 +393,7 @@ class NormalChat: 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, rewind_response = True) processed_count += 1 except Exception as e: logger.error(f"[{self.stream_name}] 处理初始兴趣消息 {msg_id} 时出错: {e}\\n{traceback.format_exc()}")