From 071366f89ce7ed2e9fb16e4c308ea0b2d87c1a63 Mon Sep 17 00:00:00 2001 From: HexatomicRing <54496918+HexatomicRing@users.noreply.github.com> Date: Tue, 15 Apr 2025 16:33:39 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E6=97=B6=E8=80=83=E8=99=91=E4=B8=8A=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/do_tool/tool_use.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/do_tool/tool_use.py b/src/do_tool/tool_use.py index b14927be8..2bb8a2c65 100644 --- a/src/do_tool/tool_use.py +++ b/src/do_tool/tool_use.py @@ -1,3 +1,4 @@ +from src.plugins.chat.utils import get_recent_group_detailed_plain_text from src.plugins.models.utils_model import LLM_request from src.plugins.config.config import global_config from src.plugins.chat.chat_stream import ChatStream @@ -41,6 +42,12 @@ class ToolUser: else: mid_memory_info = "" + stream_id = chat_stream.stream_id + chat_talking_prompt = "" + if stream_id: + chat_talking_prompt = get_recent_group_detailed_plain_text( + stream_id, limit=global_config.MAX_CONTEXT_SIZE, combine=True + ) new_messages = list( db.messages.find({"chat_id": chat_stream.stream_id, "time": {"$gt": time.time()}}).sort("time", 1).limit(15) ) @@ -54,9 +61,10 @@ class ToolUser: prompt = "" prompt += mid_memory_info prompt += "你正在思考如何回复群里的消息。\n" + prompt += f"之前群里进行了如下讨论:\n" + prompt += chat_talking_prompt prompt += f"你注意到{sender_name}刚刚说:{message_txt}\n" - prompt += f"注意你就是{bot_name},{bot_name}指的就是你。" - + prompt += f"注意你就是{bot_name},{bot_name}是你的名字。根据之前的聊天记录补充问题信息,搜索时避开你的名字。\n" prompt += "你现在需要对群里的聊天内容进行回复,现在选择工具来对消息和你的回复进行处理,你是否需要额外的信息,比如回忆或者搜寻已有的知识,改变关系和情感,或者了解你现在正在做什么。" return prompt From 9fc74cb066f935bdaf1e9de9c3a1ef963933909e Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Wed, 16 Apr 2025 01:13:18 +0800 Subject: [PATCH 2/9] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E5=91=BD=E5=90=8D=E5=8A=9F=E8=83=BD=EF=BC=8C=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E6=9B=BF=E6=8D=A2prompt=E5=86=85=E5=94=AF=E4=B8=80?= =?UTF-8?q?=E6=A0=87=E8=AF=86=E7=AC=A6=EF=BC=8C=E4=BC=98=E5=8C=96prompt?= =?UTF-8?q?=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | Bin 584 -> 574 bytes src/heart_flow/observation.py | 3 +- src/heart_flow/sub_heartflow.py | 71 +++------ src/plugins/chat/message.py | 28 ++-- src/plugins/chat/message_buffer.py | 4 +- src/plugins/chat/utils.py | 138 +++++++++++++++++ .../think_flow_chat/think_flow_chat.py | 44 +++++- .../think_flow_chat/think_flow_generator.py | 72 ++------- .../think_flow_prompt_builder.py | 8 +- src/plugins/config/config.py | 6 +- src/plugins/person_info/person_info.py | 140 ++++++++++++++++++ .../person_info/relationship_manager.py | 57 +++++++ src/plugins/remote/remote.py | 1 + 13 files changed, 443 insertions(+), 129 deletions(-) diff --git a/requirements.txt b/requirements.txt index 0fcb31f83c499ae63c79092dcb349ca3f4112a35..45fb7e6e52e77aea95193b9fc7b9d5e9530410e6 100644 GIT binary patch delta 11 ScmX@XvX5nh9MfbCCItW(4+A^^ delta 17 YcmdnTa)M=p9209ULo!3bWJxAf0516icK`qY diff --git a/src/heart_flow/observation.py b/src/heart_flow/observation.py index df78bd2db..cc225be8f 100644 --- a/src/heart_flow/observation.py +++ b/src/heart_flow/observation.py @@ -58,7 +58,8 @@ class ChattingObservation(Observation): for msg in mid_memory_by_id["messages"]: msg_str += f"{msg['detailed_plain_text']}" time_diff = int((datetime.now().timestamp() - mid_memory_by_id["created_at"]) / 60) - mid_memory_str += f"距离现在{time_diff}分钟前:\n{msg_str}\n" + # mid_memory_str += f"距离现在{time_diff}分钟前:\n{msg_str}\n" + mid_memory_str += f"{msg_str}\n" except Exception as e: logger.error(f"获取mid_memory_id失败: {e}") traceback.print_exc() diff --git a/src/heart_flow/sub_heartflow.py b/src/heart_flow/sub_heartflow.py index b9da0f7ee..c7ff4524f 100644 --- a/src/heart_flow/sub_heartflow.py +++ b/src/heart_flow/sub_heartflow.py @@ -3,8 +3,9 @@ import asyncio from src.plugins.moods.moods import MoodManager from src.plugins.models.utils_model import LLM_request from src.plugins.config.config import global_config -import re import time +from src.plugins.chat.message import UserInfo +from src.plugins.chat.utils import parse_text_timestamps # from src.plugins.schedule.schedule_generator import bot_schedule # from src.plugins.memory_system.Hippocampus import HippocampusManager @@ -37,11 +38,11 @@ def init_prompt(): prompt += "{prompt_personality}\n" prompt += "刚刚你的想法是{current_thinking_info}。可以适当转换话题\n" prompt += "-----------------------------------\n" - prompt += "现在你正在上网,和qq群里的网友们聊天,群里正在聊的话题是:{chat_observe_info}\n" + prompt += "现在是{time_now},你正在上网,和qq群里的网友们聊天,群里正在聊的话题是:\n{chat_observe_info}\n" prompt += "你现在{mood_info}\n" prompt += "你注意到{sender_name}刚刚说:{message_txt}\n" prompt += "现在你接下去继续思考,产生新的想法,不要分点输出,输出连贯的内心独白" - prompt += "思考时可以想想如何对群聊内容进行回复。回复的要求是:平淡一些,简短一些,说中文,尽量不要说你说过的话\n" + prompt += "思考时可以想想如何对群聊内容进行回复。回复的要求是:平淡一些,简短一些,说中文,尽量不要说你说过的话。如果你要回复,最好只回复一个人的一个话题\n" prompt += "请注意不要输出多余内容(包括前后缀,冒号和引号,括号, 表情,等),不要带有括号和动作描写" prompt += "记得结合上述的消息,生成内心想法,文字不要浮夸,注意你就是{bot_name},{bot_name}指的就是你。" Prompt(prompt, "sub_heartflow_prompt_before") @@ -49,7 +50,7 @@ def init_prompt(): # prompt += f"你现在正在做的事情是:{schedule_info}\n" prompt += "{extra_info}\n" prompt += "{prompt_personality}\n" - prompt += "现在你正在上网,和qq群里的网友们聊天,群里正在聊的话题是:{chat_observe_info}\n" + prompt += "现在是{time_now},你正在上网,和qq群里的网友们聊天,群里正在聊的话题是:\n{chat_observe_info}\n" prompt += "刚刚你的想法是{current_thinking_info}。" prompt += "你现在看到了网友们发的新消息:{message_new_info}\n" prompt += "你刚刚回复了群友们:{reply_info}" @@ -154,7 +155,7 @@ class SubHeartflow: await observation.observe() async def do_thinking_before_reply( - self, message_txt: str, sender_name: str, chat_stream: ChatStream, extra_info: str, obs_id: int = None + self, message_txt: str, sender_info: UserInfo, chat_stream: ChatStream, extra_info: str, obs_id: int = None ): current_thinking_info = self.current_mind mood_info = self.current_state.mood @@ -207,8 +208,10 @@ class SubHeartflow: # f"根据你和说话者{sender_name}的关系和态度进行回复,明确你的立场和情感。" # ) relation_prompt_all = (await global_prompt_manager.get_prompt_async("relationship_prompt")).format( - relation_prompt, sender_name + relation_prompt, sender_info.user_nickname ) + + sender_name_sign = f"<{chat_stream.platform}:{sender_info.user_id}:{sender_info.user_nickname}:{sender_info.user_cardname}>" # prompt = "" # # prompt += f"麦麦的总体想法是:{self.main_heartflow_info}\n\n" @@ -226,18 +229,24 @@ class SubHeartflow: # prompt += "请注意不要输出多余内容(包括前后缀,冒号和引号,括号, 表情,等),不要带有括号和动作描写" # prompt += f"记得结合上述的消息,生成内心想法,文字不要浮夸,注意你就是{self.bot_name},{self.bot_name}指的就是你。" + time_now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + prompt = (await global_prompt_manager.get_prompt_async("sub_heartflow_prompt_before")).format( extra_info_prompt, # prompt_schedule, relation_prompt_all, prompt_personality, current_thinking_info, + time_now, chat_observe_info, mood_info, - sender_name, + sender_name_sign, message_txt, self.bot_name, ) + + prompt = await relationship_manager.convert_all_person_sign_to_person_name(prompt) + prompt = parse_text_timestamps(prompt, mode="lite") try: response, reasoning_content = await self.llm_model.generate_response_async(prompt) @@ -285,16 +294,22 @@ class SubHeartflow: message_new_info = chat_talking_prompt reply_info = reply_content + + time_now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) prompt = (await global_prompt_manager.get_prompt_async("sub_heartflow_prompt_after")).format( extra_info_prompt, prompt_personality, + time_now, chat_observe_info, current_thinking_info, message_new_info, reply_info, mood_info, ) + + prompt = await relationship_manager.convert_all_person_sign_to_person_name(prompt) + prompt = parse_text_timestamps(prompt, mode="lite") try: response, reasoning_content = await self.llm_model.generate_response_async(prompt) @@ -308,48 +323,6 @@ class SubHeartflow: self.last_reply_time = time.time() - async def judge_willing(self): - # 开始构建prompt - prompt_personality = "你" - # person - individuality = Individuality.get_instance() - - personality_core = individuality.personality.personality_core - prompt_personality += personality_core - - personality_sides = individuality.personality.personality_sides - random.shuffle(personality_sides) - prompt_personality += f",{personality_sides[0]}" - - identity_detail = individuality.identity.identity_detail - random.shuffle(identity_detail) - prompt_personality += f",{identity_detail[0]}" - - # print("麦麦闹情绪了1") - current_thinking_info = self.current_mind - mood_info = self.current_state.mood - # print("麦麦闹情绪了2") - prompt = "" - prompt += f"{prompt_personality}\n" - prompt += "现在你正在上网,和qq群里的网友们聊天" - prompt += f"你现在的想法是{current_thinking_info}。" - prompt += f"你现在{mood_info}。" - prompt += "现在请你思考,你想不想发言或者回复,请你输出一个数字,1-10,1表示非常不想,10表示非常想。" - prompt += "请你用<>包裹你的回复意愿,输出<1>表示不想回复,输出<10>表示非常想回复。请你考虑,你完全可以不回复" - try: - response, reasoning_content = await self.llm_model.generate_response_async(prompt) - # 解析willing值 - willing_match = re.search(r"<(\d+)>", response) - except Exception as e: - logger.error(f"意愿判断获取失败: {e}") - willing_match = None - if willing_match: - self.current_state.willing = int(willing_match.group(1)) - else: - self.current_state.willing = 0 - - return self.current_state.willing - def update_current_mind(self, response): self.past_mind.append(self.current_mind) self.current_mind = response diff --git a/src/plugins/chat/message.py b/src/plugins/chat/message.py index 5dc688c03..9f55b5741 100644 --- a/src/plugins/chat/message.py +++ b/src/plugins/chat/message.py @@ -142,14 +142,18 @@ class MessageRecv(Message): def _generate_detailed_text(self) -> str: """生成详细文本,包含时间和用户信息""" - time_str = time.strftime("%m-%d %H:%M:%S", time.localtime(self.message_info.time)) + # time_str = time.strftime("%m-%d %H:%M:%S", time.localtime(self.message_info.time)) + time = 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"{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})" + f"<{self.message_info.platform}:{user_info.user_id}:{user_info.user_nickname}:{user_info.user_cardname}>" ) - return f"[{time_str}] {name}: {self.processed_plain_text}\n" + return f"[{time}] {name}: {self.processed_plain_text}\n" @dataclass @@ -239,14 +243,18 @@ class MessageProcessBase(Message): def _generate_detailed_text(self) -> str: """生成详细文本,包含时间和用户信息""" - time_str = time.strftime("%m-%d %H:%M:%S", time.localtime(self.message_info.time)) + # time_str = time.strftime("%m-%d %H:%M:%S", time.localtime(self.message_info.time)) + time = 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"{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})" + f"<{self.message_info.platform}:{user_info.user_id}:{user_info.user_nickname}:{user_info.user_cardname}>" ) - return f"[{time_str}] {name}: {self.processed_plain_text}\n" + return f"[{time}] {name}: {self.processed_plain_text}\n" @dataclass diff --git a/src/plugins/chat/message_buffer.py b/src/plugins/chat/message_buffer.py index f62e015b4..21e490433 100644 --- a/src/plugins/chat/message_buffer.py +++ b/src/plugins/chat/message_buffer.py @@ -153,11 +153,11 @@ class MessageBuffer: # 更新当前消息的processed_plain_text if combined_text and combined_text[0] != message.processed_plain_text and is_update: if type == "text": - message.processed_plain_text = "".join(combined_text) + message.processed_plain_text = ",".join(combined_text) logger.debug(f"整合了{len(combined_text) - 1}条F消息的内容到当前消息") elif type == "emoji": combined_text.pop() - message.processed_plain_text = "".join(combined_text) + message.processed_plain_text = ",".join(combined_text) message.is_emoji = False logger.debug(f"整合了{len(combined_text) - 1}条F消息的内容,覆盖当前emoji消息") diff --git a/src/plugins/chat/utils.py b/src/plugins/chat/utils.py index b4e2cb3c2..3b7d2fc3c 100644 --- a/src/plugins/chat/utils.py +++ b/src/plugins/chat/utils.py @@ -629,3 +629,141 @@ def count_messages_between(start_time: float, end_time: float, stream_id: str) - except Exception as e: logger.error(f"计算消息数量时出错: {str(e)}") return 0, 0 + + +def translate_timestamp_to_human_readable(timestamp: float, mode: str = "normal") -> str: + """将时间戳转换为人类可读的时间格式 + + Args: + timestamp: 时间戳 + mode: 转换模式,"normal"为标准格式,"relative"为相对时间格式 + + Returns: + str: 格式化后的时间字符串 + """ + if mode == "normal": + return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp)) + elif mode == "relative": + now = time.time() + diff = now - timestamp + + if diff < 20: + return "刚刚:" + elif diff < 60: + return f"{int(diff)}秒前:" + elif diff < 1800: + return f"{int(diff / 60)}分钟前:" + elif diff < 3600: + return f"{int(diff / 60)}分钟前:\n" + elif diff < 86400: + return f"{int(diff / 3600)}小时前:\n" + elif diff < 604800: + return f"{int(diff / 86400)}天前:\n" + else: + return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp)) + ":" + +def parse_text_timestamps(text: str, mode: str = "normal") -> str: + """解析文本中的时间戳并转换为可读时间格式 + + Args: + text: 包含时间戳的文本,时间戳应以[]包裹 + mode: 转换模式,传递给translate_timestamp_to_human_readable,"normal"或"relative" + + Returns: + str: 替换后的文本 + + 转换规则: + - normal模式: 将文本中所有时间戳转换为可读格式 + - lite模式: + - 第一个和最后一个时间戳必须转换 + - 以5秒为间隔划分时间段,每段最多转换一个时间戳 + - 不转换的时间戳替换为空字符串 + """ + # 匹配[数字]或[数字.数字]格式的时间戳 + pattern = r'\[(\d+(?:\.\d+)?)\]' + + # 找出所有匹配的时间戳 + matches = list(re.finditer(pattern, text)) + + if not matches: + return text + + # normal模式: 直接转换所有时间戳 + if mode == "normal": + result_text = text + for match in matches: + timestamp = float(match.group(1)) + readable_time = translate_timestamp_to_human_readable(timestamp, "normal") + # 由于替换会改变文本长度,需要使用正则替换而非直接替换 + pattern_instance = re.escape(match.group(0)) + result_text = re.sub(pattern_instance, readable_time, result_text, count=1) + return result_text + else: + # lite模式: 按5秒间隔划分并选择性转换 + result_text = text + + # 提取所有时间戳及其位置 + timestamps = [(float(m.group(1)), m) for m in matches] + timestamps.sort(key=lambda x: x[0]) # 按时间戳升序排序 + + if not timestamps: + return text + + # 获取第一个和最后一个时间戳 + first_timestamp, first_match = timestamps[0] + last_timestamp, last_match = timestamps[-1] + + # 将时间范围划分成5秒间隔的时间段 + time_segments = {} + + # 对所有时间戳按15秒间隔分组 + for ts, match in timestamps: + segment_key = int(ts // 15) # 将时间戳除以15取整,作为时间段的键 + if segment_key not in time_segments: + time_segments[segment_key] = [] + time_segments[segment_key].append((ts, match)) + + # 记录需要转换的时间戳 + to_convert = [] + + # 从每个时间段中选择一个时间戳进行转换 + for segment, segment_timestamps in time_segments.items(): + # 选择这个时间段中的第一个时间戳 + to_convert.append(segment_timestamps[0]) + + # 确保第一个和最后一个时间戳在转换列表中 + first_in_list = False + last_in_list = False + + for ts, match in to_convert: + if ts == first_timestamp: + first_in_list = True + if ts == last_timestamp: + last_in_list = True + + if not first_in_list: + to_convert.append((first_timestamp, first_match)) + if not last_in_list: + to_convert.append((last_timestamp, last_match)) + + # 创建需要转换的时间戳集合,用于快速查找 + to_convert_set = {match.group(0) for _, match in to_convert} + + # 首先替换所有不需要转换的时间戳为空字符串 + for ts, match in timestamps: + if match.group(0) not in to_convert_set: + pattern_instance = re.escape(match.group(0)) + result_text = re.sub(pattern_instance, "", result_text, count=1) + + # 按照时间戳原始顺序排序,避免替换时位置错误 + to_convert.sort(key=lambda x: x[1].start()) + + # 执行替换 + # 由于替换会改变文本长度,从后向前替换 + to_convert.reverse() + for ts, match in to_convert: + readable_time = translate_timestamp_to_human_readable(ts, "relative") + pattern_instance = re.escape(match.group(0)) + result_text = re.sub(pattern_instance, readable_time, result_text, count=1) + + return result_text diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py index 2e3a74693..1e8e844eb 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py @@ -235,6 +235,7 @@ class ThinkFlowChat: do_reply = False if random() < reply_probability: try: + do_reply = True # 回复前处理 @@ -258,7 +259,7 @@ class ThinkFlowChat: await heartflow.get_subheartflow(chat.stream_id).do_observe() except Exception as e: logger.error(f"心流观察失败: {e}") - traceback.print_exc() + logger.error(traceback.format_exc()) info_catcher.catch_after_observe(timing_results["观察"]) @@ -329,13 +330,17 @@ class ThinkFlowChat: chat.stream_id ).do_thinking_before_reply( message_txt=message.processed_plain_text, - sender_name=message.message_info.user_info.user_nickname, + sender_info=message.message_info.user_info, chat_stream=chat, obs_id=get_mid_memory_id, extra_info=tool_result_info, ) except Exception as e: logger.error(f"心流思考前脑内状态失败: {e}") + logger.error(traceback.format_exc()) + # 确保变量被定义,即使在错误情况下 + current_mind = "" + past_mind = "" info_catcher.catch_afer_shf_step(timing_results["思考前脑内状态"], past_mind, current_mind) @@ -373,6 +378,7 @@ class ThinkFlowChat: except Exception as e: logger.error(f"心流处理表情包失败: {e}") + # 思考后脑内状态更新 try: with Timer("思考后脑内状态更新", timing_results): stream_id = message.chat_stream.stream_id @@ -387,9 +393,43 @@ class ThinkFlowChat: ) except Exception as e: logger.error(f"心流思考后脑内状态更新失败: {e}") + logger.error(traceback.format_exc()) # 回复后处理 await willing_manager.after_generate_reply_handle(message.message_info.message_id) + + # 处理认识关系 + try: + is_known = await relationship_manager.is_known_some_one( + message.message_info.platform, + message.message_info.user_info.user_id + ) + if not is_known: + logger.info(f"首次认识用户: {message.message_info.user_info.user_nickname}") + await relationship_manager.first_knowing_some_one( + message.message_info.platform, + message.message_info.user_info.user_id, + message.message_info.user_info.user_nickname, + message.message_info.user_info.user_cardname or message.message_info.user_info.user_nickname, + "" + ) + else: + logger.debug(f"已认识用户: {message.message_info.user_info.user_nickname}") + if not await relationship_manager.is_qved_name( + message.message_info.platform, + message.message_info.user_info.user_id + ): + logger.info(f"更新已认识但未取名的用户: {message.message_info.user_info.user_nickname}") + await relationship_manager.first_knowing_some_one( + message.message_info.platform, + message.message_info.user_info.user_id, + message.message_info.user_info.user_nickname, + message.message_info.user_info.user_cardname or message.message_info.user_info.user_nickname, + "" + ) + except Exception as e: + logger.error(f"处理认识关系失败: {e}") + logger.error(traceback.format_exc()) except Exception as e: logger.error(f"心流处理消息失败: {e}") diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_generator.py b/src/plugins/chat_module/think_flow_chat/think_flow_generator.py index 325ecd5c6..6f6c8bf26 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_generator.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_generator.py @@ -100,15 +100,17 @@ class ResponseGenerator: info_catcher = info_catcher_manager.get_info_catcher(thinking_id) - if message.chat_stream.user_info.user_cardname and message.chat_stream.user_info.user_nickname: - sender_name = ( - f"[({message.chat_stream.user_info.user_id}){message.chat_stream.user_info.user_nickname}]" - f"{message.chat_stream.user_info.user_cardname}" - ) - elif message.chat_stream.user_info.user_nickname: - sender_name = f"({message.chat_stream.user_info.user_id}){message.chat_stream.user_info.user_nickname}" - else: - sender_name = f"用户({message.chat_stream.user_info.user_id})" + # if message.chat_stream.user_info.user_cardname and message.chat_stream.user_info.user_nickname: + # sender_name = ( + # f"[({message.chat_stream.user_info.user_id}){message.chat_stream.user_info.user_nickname}]" + # f"{message.chat_stream.user_info.user_cardname}" + # ) + # elif message.chat_stream.user_info.user_nickname: + # sender_name = f"({message.chat_stream.user_info.user_id}){message.chat_stream.user_info.user_nickname}" + # else: + # sender_name = f"用户({message.chat_stream.user_info.user_id})" + + sender_name = f"<{message.chat_stream.user_info.platform}:{message.chat_stream.user_info.user_id}:{message.chat_stream.user_info.user_nickname}:{message.chat_stream.user_info.user_cardname}>" # 构建prompt with Timer() as t_build_prompt: @@ -119,14 +121,7 @@ class ResponseGenerator: sender_name=sender_name, stream_id=message.chat_stream.stream_id, ) - elif mode == "simple": - prompt = await prompt_builder._build_prompt_simple( - message.chat_stream, - message_txt=message.processed_plain_text, - sender_name=sender_name, - stream_id=message.chat_stream.stream_id, - ) - logger.info(f"构建{mode}prompt时间: {t_build_prompt.human_readable}") + logger.info(f"构建prompt时间: {t_build_prompt.human_readable}") try: content, reasoning_content, self.current_model_name = await model.generate_response(prompt) @@ -141,49 +136,6 @@ class ResponseGenerator: return content - async def _check_response_with_model( - self, message: MessageRecv, content: str, model: LLM_request, thinking_id: str - ) -> str: - _info_catcher = info_catcher_manager.get_info_catcher(thinking_id) - - sender_name = "" - if message.chat_stream.user_info.user_cardname and message.chat_stream.user_info.user_nickname: - sender_name = ( - f"[({message.chat_stream.user_info.user_id}){message.chat_stream.user_info.user_nickname}]" - f"{message.chat_stream.user_info.user_cardname}" - ) - elif message.chat_stream.user_info.user_nickname: - sender_name = f"({message.chat_stream.user_info.user_id}){message.chat_stream.user_info.user_nickname}" - else: - sender_name = f"用户({message.chat_stream.user_info.user_id})" - - # 构建prompt - with Timer() as t_build_prompt_check: - prompt = await prompt_builder._build_prompt_check_response( - message.chat_stream, - message_txt=message.processed_plain_text, - sender_name=sender_name, - stream_id=message.chat_stream.stream_id, - content=content, - ) - logger.info(f"构建check_prompt: {prompt}") - logger.info(f"构建check_prompt时间: {t_build_prompt_check.human_readable}") - - try: - checked_content, reasoning_content, self.current_model_name = await model.generate_response(prompt) - - # info_catcher.catch_after_llm_generated( - # prompt=prompt, - # response=content, - # reasoning_content=reasoning_content, - # model_name=self.current_model_name) - - except Exception: - logger.exception("检查回复时出错") - return None - - return checked_content - async def _get_emotion_tags(self, content: str, processed_plain_text: str): """提取情感标签,结合立场和情绪""" try: diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py b/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py index ed7ca72f3..29863ba72 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py @@ -8,7 +8,8 @@ from src.common.logger import get_module_logger from ....individuality.individuality import Individuality from src.heart_flow.heartflow import heartflow from src.plugins.utils.prompt_builder import Prompt, global_prompt_manager - +from src.plugins.person_info.relationship_manager import relationship_manager +from src.plugins.chat.utils import parse_text_timestamps logger = get_module_logger("prompt") @@ -160,7 +161,10 @@ class PromptBuilder: prompt_ger=prompt_ger, moderation_prompt=await global_prompt_manager.get_prompt_async("moderation_prompt"), ) - + + prompt = await relationship_manager.convert_all_person_sign_to_person_name(prompt) + prompt = parse_text_timestamps(prompt, mode="lite") + return prompt async def _build_prompt_simple( diff --git a/src/plugins/config/config.py b/src/plugins/config/config.py index d0a209d35..8238078c2 100644 --- a/src/plugins/config/config.py +++ b/src/plugins/config/config.py @@ -26,9 +26,9 @@ config_config = LogConfig( logger = get_module_logger("config", config=config_config) # 考虑到,实际上配置文件中的mai_version是不会自动更新的,所以采用硬编码 -is_test = False -mai_version_main = "0.6.2" -mai_version_fix = "" +is_test = True +mai_version_main = "0.6.3" +mai_version_fix = "snapshot-1" if mai_version_fix: if is_test: diff --git a/src/plugins/person_info/person_info.py b/src/plugins/person_info/person_info.py index 1eb1d28dd..068c37d07 100644 --- a/src/plugins/person_info/person_info.py +++ b/src/plugins/person_info/person_info.py @@ -6,6 +6,9 @@ from typing import Any, Callable, Dict import datetime import asyncio import numpy as np +from src.plugins.models.utils_model import LLM_request +from src.plugins.config.config import global_config +from src.individuality.individuality import Individuality import matplotlib @@ -13,6 +16,8 @@ matplotlib.use("Agg") import matplotlib.pyplot as plt from pathlib import Path import pandas as pd +import json +import re """ @@ -32,6 +37,8 @@ logger = get_module_logger("person_info") person_info_default = { "person_id": None, + "person_name": None, + "name_reason": None, "platform": None, "user_id": None, "nickname": None, @@ -48,16 +55,46 @@ person_info_default = { class PersonInfoManager: def __init__(self): + self.person_name_list = {} + self.qv_name_llm = LLM_request( + model=global_config.llm_normal, + max_tokens=256, + request_type="qv_name", + ) if "person_info" not in db.list_collection_names(): db.create_collection("person_info") db.person_info.create_index("person_id", unique=True) + + # 初始化时读取所有person_name + cursor = db.person_info.find( + {"person_name": {"$exists": True}}, + {"person_id": 1, "person_name": 1, "_id": 0} + ) + for doc in cursor: + if doc.get("person_name"): + self.person_name_list[doc["person_id"]] = doc["person_name"] + logger.debug(f"已加载 {len(self.person_name_list)} 个用户名称") def get_person_id(self, platform: str, user_id: int): """获取唯一id""" + #如果platform中存在-,就截取-后面的部分 + if "-" in platform: + platform = platform.split("-")[1] + components = [platform, str(user_id)] key = "_".join(components) return hashlib.md5(key.encode()).hexdigest() + def is_person_known(self, platform: str, user_id: int): + """判断是否认识某人""" + person_id = self.get_person_id(platform, user_id) + document = db.person_info.find_one({"person_id": person_id}) + if document: + return True + else: + return False + + async def create_person_info(self, person_id: str, data: dict = None): """创建一个项""" if not person_id: @@ -88,6 +125,109 @@ class PersonInfoManager: Data[field_name] = value logger.debug(f"更新时{person_id}不存在,已新建") await self.create_person_info(person_id, Data) + + async def has_one_field(self, person_id: str, field_name: str): + """判断是否存在某一个字段""" + document = db.person_info.find_one({"person_id": person_id}, {field_name: 1}) + if document: + return True + else: + return False + + def _extract_json_from_text(self, text: str) -> dict: + """从文本中提取JSON数据的高容错方法""" + try: + + # 尝试直接解析 + return json.loads(text) + except json.JSONDecodeError: + try: + # 尝试找到JSON格式的部分 + json_pattern = r'\{[^{}]*\}' + matches = re.findall(json_pattern, text) + if matches: + return json.loads(matches[0]) + + # 如果上面都失败了,尝试提取键值对 + nickname_pattern = r'"nickname"[:\s]+"([^"]+)"' + reason_pattern = r'"reason"[:\s]+"([^"]+)"' + + nickname_match = re.search(nickname_pattern, text) + reason_match = re.search(reason_pattern, text) + + if nickname_match: + return { + "nickname": nickname_match.group(1), + "reason": reason_match.group(1) if reason_match else "未提供理由" + } + except Exception as e: + logger.error(f"JSON提取失败: {str(e)}") + + # 如果所有方法都失败了,返回空结果 + return {"nickname": "", "reason": ""} + + async def qv_person_name(self, person_id: str, user_nickname: str, user_cardname: str, user_avatar: str): + """给某个用户取名""" + if not person_id: + logger.debug("取名失败:person_id不能为空") + return + + old_name = await self.get_value(person_id, "person_name") + old_reason = await self.get_value(person_id, "name_reason") + + max_retries = 5 # 最大重试次数 + current_try = 0 + existing_names = "" + while current_try < max_retries: + individuality = Individuality.get_instance() + prompt_personality = individuality.get_prompt(type="personality", x_person=2, level=1) + bot_name = individuality.personality.bot_nickname + + qv_name_prompt = f"你是{bot_name},你{prompt_personality}" + qv_name_prompt += f"现在你想给一个用户取一个昵称,用户是的qq昵称是{user_nickname}," + qv_name_prompt += f"用户的qq群昵称名是{user_cardname}," + if user_avatar: + qv_name_prompt += f"用户的qq头像是{user_avatar}," + if old_name: + qv_name_prompt += f"你之前叫他{old_name},是因为{old_reason}," + + qv_name_prompt += "\n请根据以上用户信息,想想你叫他什么比较好,请最好使用用户的qq昵称,可以稍作修改" + if existing_names: + qv_name_prompt += f"\n请注意,以下名称已被使用,不要使用以下昵称:{existing_names}。\n" + qv_name_prompt += "请用json给出你的想法,并给出理由,示例如下:" + qv_name_prompt += '''{ + "nickname": "昵称", + "reason": "理由" + }''' + logger.debug(f"取名提示词:{qv_name_prompt}") + response = await self.qv_name_llm.generate_response(qv_name_prompt) + logger.debug(f"取名回复:{response}") + result = self._extract_json_from_text(response[0]) + + if not result["nickname"]: + logger.error("生成的昵称为空,重试中...") + current_try += 1 + continue + + # 检查生成的昵称是否已存在 + if result["nickname"] not in self.person_name_list.values(): + # 更新数据库和内存中的列表 + await self.update_one_field(person_id, "person_name", result["nickname"]) + # await self.update_one_field(person_id, "nickname", user_nickname) + # await self.update_one_field(person_id, "avatar", user_avatar) + await self.update_one_field(person_id, "name_reason", result["reason"]) + + self.person_name_list[person_id] = result["nickname"] + logger.debug(f"用户 {person_id} 的名称已更新为 {result['nickname']},原因:{result['reason']}") + return result + else: + existing_names += f"{result['nickname']}、" + + logger.debug(f"生成的昵称 {result['nickname']} 已存在,重试中...") + current_try += 1 + + logger.error(f"在{max_retries}次尝试后仍未能生成唯一昵称") + return None async def del_one_document(self, person_id: str): """删除指定 person_id 的文档""" diff --git a/src/plugins/person_info/relationship_manager.py b/src/plugins/person_info/relationship_manager.py index 23ae7f6c8..673e0b07f 100644 --- a/src/plugins/person_info/relationship_manager.py +++ b/src/plugins/person_info/relationship_manager.py @@ -4,6 +4,8 @@ import math from bson.decimal128 import Decimal128 from .person_info import person_info_manager import time +import re +import traceback relationship_config = LogConfig( # 使用关系专用样式 @@ -74,6 +76,61 @@ class RelationshipManager: return mood_value * coefficient else: return mood_value / coefficient + + async def is_known_some_one(self, platform , user_id): + """判断是否认识某人""" + is_known = person_info_manager.is_person_known(platform, user_id) + return is_known + + async def is_qved_name(self, platform , user_id): + """判断是否认识某人""" + person_id = person_info_manager.get_person_id(platform, user_id) + is_qved = await person_info_manager.has_one_field(person_id, "person_name") + old_name = await person_info_manager.get_value(person_id, "person_name") + print(f"old_name: {old_name}") + print(f"is_qved: {is_qved}") + if is_qved and old_name != None: + return True + else: + return False + + async def first_knowing_some_one(self, platform , user_id, user_nickname, user_cardname, user_avatar): + """判断是否认识某人""" + person_id = person_info_manager.get_person_id(platform,user_id) + await person_info_manager.update_one_field(person_id, "nickname", user_nickname) + # await person_info_manager.update_one_field(person_id, "user_cardname", user_cardname) + # await person_info_manager.update_one_field(person_id, "user_avatar", user_avatar) + await person_info_manager.qv_person_name(person_id, user_nickname, user_cardname, user_avatar) + + async def convert_all_person_sign_to_person_name(self,input_text:str): + """将所有人的格式转换为person_name""" + try: + # 使用正则表达式匹配格式 + all_person = person_info_manager.person_name_list + + pattern = r'<([^:]+):(\d+):([^:]+):([^>]+)>' + matches = re.findall(pattern, input_text) + + # 遍历匹配结果,将替换为person_name + result_text = input_text + for platform, user_id, nickname, cardname in matches: + person_id = person_info_manager.get_person_id(platform, user_id) + # 默认使用昵称作为人名 + person_name = nickname.strip() if nickname.strip() else cardname.strip() + + if person_id in all_person: + if all_person[person_id] != None: + person_name = all_person[person_id] + + print(f"将<{platform}:{user_id}:{nickname}:{cardname}>替换为{person_name}") + + + result_text = result_text.replace(f"<{platform}:{user_id}:{nickname}:{cardname}>", person_name) + + return result_text + except Exception as e: + logger.error(traceback.format_exc()) + return input_text async def calculate_update_relationship_value(self, chat_stream: ChatStream, label: str, stance: str) -> tuple: """计算并变更关系值 diff --git a/src/plugins/remote/remote.py b/src/plugins/remote/remote.py index a2084435f..bc7437057 100644 --- a/src/plugins/remote/remote.py +++ b/src/plugins/remote/remote.py @@ -126,6 +126,7 @@ def main(): """主函数,启动心跳线程""" # 配置 SERVER_URL = "http://hyybuth.xyz:10058" + # SERVER_URL = "http://localhost:10058" HEARTBEAT_INTERVAL = 300 # 5分钟(秒) # 创建并启动心跳线程 From 1aad7f4f6e141ba001bdaa691ee3f4854dd6affc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=A5=E6=B2=B3=E6=99=B4?= Date: Wed, 16 Apr 2025 15:04:00 +0900 Subject: [PATCH 3/9] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4MongoDBMessag?= =?UTF-8?q?eStorage=E7=B1=BB=E4=B8=AD=E7=9A=84self.db=E5=BC=95=E7=94=A8?= =?UTF-8?q?=EF=BC=8C=E7=9B=B4=E6=8E=A5=E4=BD=BF=E7=94=A8db?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/PFC/message_storage.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/plugins/PFC/message_storage.py b/src/plugins/PFC/message_storage.py index 55bccb14e..b57f5d2b5 100644 --- a/src/plugins/PFC/message_storage.py +++ b/src/plugins/PFC/message_storage.py @@ -50,21 +50,18 @@ class MessageStorage(ABC): class MongoDBMessageStorage(MessageStorage): """MongoDB消息存储实现""" - def __init__(self): - self.db = db - async def get_messages_after(self, chat_id: str, message_time: float) -> List[Dict[str, Any]]: query = {"chat_id": chat_id} # print(f"storage_check_message: {message_time}") query["time"] = {"$gt": message_time} - return list(self.db.messages.find(query).sort("time", 1)) + return list(db.messages.find(query).sort("time", 1)) async def get_messages_before(self, chat_id: str, time_point: float, limit: int = 5) -> List[Dict[str, Any]]: query = {"chat_id": chat_id, "time": {"$lt": time_point}} - messages = list(self.db.messages.find(query).sort("time", -1).limit(limit)) + messages = list(db.messages.find(query).sort("time", -1).limit(limit)) # 将消息按时间正序排列 messages.reverse() @@ -73,7 +70,7 @@ class MongoDBMessageStorage(MessageStorage): async def has_new_messages(self, chat_id: str, after_time: float) -> bool: query = {"chat_id": chat_id, "time": {"$gt": after_time}} - return self.db.messages.find_one(query) is not None + return db.messages.find_one(query) is not None # # 创建一个内存消息存储实现,用于测试 From 5421e625394edb28692d4c317c568d2e4639c2ad Mon Sep 17 00:00:00 2001 From: tcmofashi Date: Wed, 16 Apr 2025 14:12:24 +0800 Subject: [PATCH 4/9] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=AF=B9?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=B7=BB=E5=8A=A0is=5Fmentioned=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/chat/utils.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/plugins/chat/utils.py b/src/plugins/chat/utils.py index b07c33c39..5c0c4df8d 100644 --- a/src/plugins/chat/utils.py +++ b/src/plugins/chat/utils.py @@ -46,6 +46,16 @@ def is_mentioned_bot_in_message(message: MessageRecv) -> bool: is_at = False is_mentioned = False + if "is_mentioned" in message.message_info.additional_config.keys(): + try: + reply_probability = float(message.message_info.additional_config.get("is_mentioned")) + is_mentioned = True + return is_mentioned, reply_probability + except Exception as e: + logger.warning( + f"消息中包含不合理的设置 is_mentioned: {message.message_info.additional_config.get('is_mentioned')}" + ) + # 判断是否被@ if re.search(f"@[\s\S]*?(id:{global_config.BOT_QQ})", message.processed_plain_text): is_at = True From a8d48fc6cfad652daaf82f967b9ee328f0d22c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=A5=E6=B2=B3=E6=99=B4?= Date: Wed, 16 Apr 2025 16:16:37 +0900 Subject: [PATCH 5/9] =?UTF-8?q?style:=20=E6=A0=BC=E5=BC=8F=E5=8C=96?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=EF=BC=8C=E4=BF=AE=E5=A4=8D=E4=B8=8D=E4=B8=80?= =?UTF-8?q?=E8=87=B4=E7=9A=84=E7=A9=BA=E6=A0=BC=E5=92=8C=E6=B3=A8=E9=87=8A?= =?UTF-8?q?=EF=BC=8C=E6=9B=B4=E6=96=B0ruff=20action?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ruff.yml | 5 +- src/heart_flow/observation.py | 2 +- src/heart_flow/sub_heartflow.py | 14 +++-- src/plugins/chat/message.py | 8 +-- src/plugins/chat/utils.py | 61 ++++++++++--------- .../think_flow_chat/think_flow_chat.py | 19 +++--- .../think_flow_chat/think_flow_generator.py | 2 +- .../think_flow_prompt_builder.py | 5 +- src/plugins/person_info/person_info.py | 51 +++++++--------- .../person_info/relationship_manager.py | 33 +++++----- 10 files changed, 98 insertions(+), 102 deletions(-) diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml index 9c8cba5dc..b3056fa6a 100644 --- a/.github/workflows/ruff.yml +++ b/.github/workflows/ruff.yml @@ -12,7 +12,10 @@ jobs: with: fetch-depth: 0 ref: ${{ github.head_ref || github.ref_name }} - - uses: astral-sh/ruff-action@v3 + - name: Install the latest version of ruff + uses: astral-sh/ruff-action@v3 + with: + version: "latest" - run: ruff check --fix - run: ruff format - name: Commit changes diff --git a/src/heart_flow/observation.py b/src/heart_flow/observation.py index cc225be8f..481e4beb7 100644 --- a/src/heart_flow/observation.py +++ b/src/heart_flow/observation.py @@ -57,7 +57,7 @@ class ChattingObservation(Observation): msg_str = "" for msg in mid_memory_by_id["messages"]: msg_str += f"{msg['detailed_plain_text']}" - time_diff = int((datetime.now().timestamp() - mid_memory_by_id["created_at"]) / 60) + # time_diff = int((datetime.now().timestamp() - mid_memory_by_id["created_at"]) / 60) # mid_memory_str += f"距离现在{time_diff}分钟前:\n{msg_str}\n" mid_memory_str += f"{msg_str}\n" except Exception as e: diff --git a/src/heart_flow/sub_heartflow.py b/src/heart_flow/sub_heartflow.py index c7ff4524f..cb53c2240 100644 --- a/src/heart_flow/sub_heartflow.py +++ b/src/heart_flow/sub_heartflow.py @@ -210,8 +210,10 @@ class SubHeartflow: relation_prompt_all = (await global_prompt_manager.get_prompt_async("relationship_prompt")).format( relation_prompt, sender_info.user_nickname ) - - sender_name_sign = f"<{chat_stream.platform}:{sender_info.user_id}:{sender_info.user_nickname}:{sender_info.user_cardname}>" + + sender_name_sign = ( + f"<{chat_stream.platform}:{sender_info.user_id}:{sender_info.user_nickname}:{sender_info.user_cardname}>" + ) # prompt = "" # # prompt += f"麦麦的总体想法是:{self.main_heartflow_info}\n\n" @@ -230,7 +232,7 @@ class SubHeartflow: # prompt += f"记得结合上述的消息,生成内心想法,文字不要浮夸,注意你就是{self.bot_name},{self.bot_name}指的就是你。" time_now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) - + prompt = (await global_prompt_manager.get_prompt_async("sub_heartflow_prompt_before")).format( extra_info_prompt, # prompt_schedule, @@ -244,7 +246,7 @@ class SubHeartflow: message_txt, self.bot_name, ) - + prompt = await relationship_manager.convert_all_person_sign_to_person_name(prompt) prompt = parse_text_timestamps(prompt, mode="lite") @@ -294,7 +296,7 @@ class SubHeartflow: message_new_info = chat_talking_prompt reply_info = reply_content - + time_now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) prompt = (await global_prompt_manager.get_prompt_async("sub_heartflow_prompt_after")).format( @@ -307,7 +309,7 @@ class SubHeartflow: reply_info, mood_info, ) - + prompt = await relationship_manager.convert_all_person_sign_to_person_name(prompt) prompt = parse_text_timestamps(prompt, mode="lite") diff --git a/src/plugins/chat/message.py b/src/plugins/chat/message.py index 9f55b5741..6279e8f25 100644 --- a/src/plugins/chat/message.py +++ b/src/plugins/chat/message.py @@ -150,9 +150,7 @@ class MessageRecv(Message): # 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}>" - ) + name = f"<{self.message_info.platform}:{user_info.user_id}:{user_info.user_nickname}:{user_info.user_cardname}>" return f"[{time}] {name}: {self.processed_plain_text}\n" @@ -251,9 +249,7 @@ class MessageProcessBase(Message): # 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}>" - ) + name = f"<{self.message_info.platform}:{user_info.user_id}:{user_info.user_nickname}:{user_info.user_cardname}>" return f"[{time}] {name}: {self.processed_plain_text}\n" diff --git a/src/plugins/chat/utils.py b/src/plugins/chat/utils.py index 0172289ff..5f2d0105c 100644 --- a/src/plugins/chat/utils.py +++ b/src/plugins/chat/utils.py @@ -643,11 +643,11 @@ def count_messages_between(start_time: float, end_time: float, stream_id: str) - def translate_timestamp_to_human_readable(timestamp: float, mode: str = "normal") -> str: """将时间戳转换为人类可读的时间格式 - + Args: timestamp: 时间戳 mode: 转换模式,"normal"为标准格式,"relative"为相对时间格式 - + Returns: str: 格式化后的时间字符串 """ @@ -656,7 +656,7 @@ def translate_timestamp_to_human_readable(timestamp: float, mode: str = "normal" elif mode == "relative": now = time.time() diff = now - timestamp - + if diff < 20: return "刚刚:" elif diff < 60: @@ -671,33 +671,34 @@ def translate_timestamp_to_human_readable(timestamp: float, mode: str = "normal" return f"{int(diff / 86400)}天前:\n" else: return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp)) + ":" - + + def parse_text_timestamps(text: str, mode: str = "normal") -> str: """解析文本中的时间戳并转换为可读时间格式 - + Args: text: 包含时间戳的文本,时间戳应以[]包裹 mode: 转换模式,传递给translate_timestamp_to_human_readable,"normal"或"relative" - + Returns: str: 替换后的文本 - + 转换规则: - normal模式: 将文本中所有时间戳转换为可读格式 - - lite模式: + - lite模式: - 第一个和最后一个时间戳必须转换 - 以5秒为间隔划分时间段,每段最多转换一个时间戳 - 不转换的时间戳替换为空字符串 """ # 匹配[数字]或[数字.数字]格式的时间戳 - pattern = r'\[(\d+(?:\.\d+)?)\]' - + pattern = r"\[(\d+(?:\.\d+)?)\]" + # 找出所有匹配的时间戳 matches = list(re.finditer(pattern, text)) - + if not matches: return text - + # normal模式: 直接转换所有时间戳 if mode == "normal": result_text = text @@ -711,63 +712,63 @@ def parse_text_timestamps(text: str, mode: str = "normal") -> str: else: # lite模式: 按5秒间隔划分并选择性转换 result_text = text - + # 提取所有时间戳及其位置 timestamps = [(float(m.group(1)), m) for m in matches] timestamps.sort(key=lambda x: x[0]) # 按时间戳升序排序 - + if not timestamps: return text - + # 获取第一个和最后一个时间戳 first_timestamp, first_match = timestamps[0] last_timestamp, last_match = timestamps[-1] - + # 将时间范围划分成5秒间隔的时间段 time_segments = {} - + # 对所有时间戳按15秒间隔分组 for ts, match in timestamps: segment_key = int(ts // 15) # 将时间戳除以15取整,作为时间段的键 if segment_key not in time_segments: time_segments[segment_key] = [] time_segments[segment_key].append((ts, match)) - + # 记录需要转换的时间戳 to_convert = [] - + # 从每个时间段中选择一个时间戳进行转换 - for segment, segment_timestamps in time_segments.items(): + for _, segment_timestamps in time_segments.items(): # 选择这个时间段中的第一个时间戳 to_convert.append(segment_timestamps[0]) - + # 确保第一个和最后一个时间戳在转换列表中 first_in_list = False last_in_list = False - - for ts, match in to_convert: + + for ts, _ in to_convert: if ts == first_timestamp: first_in_list = True if ts == last_timestamp: last_in_list = True - + if not first_in_list: to_convert.append((first_timestamp, first_match)) if not last_in_list: to_convert.append((last_timestamp, last_match)) - + # 创建需要转换的时间戳集合,用于快速查找 to_convert_set = {match.group(0) for _, match in to_convert} - + # 首先替换所有不需要转换的时间戳为空字符串 - for ts, match in timestamps: + for _, match in timestamps: if match.group(0) not in to_convert_set: pattern_instance = re.escape(match.group(0)) result_text = re.sub(pattern_instance, "", result_text, count=1) - + # 按照时间戳原始顺序排序,避免替换时位置错误 to_convert.sort(key=lambda x: x[1].start()) - + # 执行替换 # 由于替换会改变文本长度,从后向前替换 to_convert.reverse() @@ -775,5 +776,5 @@ def parse_text_timestamps(text: str, mode: str = "normal") -> str: readable_time = translate_timestamp_to_human_readable(ts, "relative") pattern_instance = re.escape(match.group(0)) result_text = re.sub(pattern_instance, readable_time, result_text, count=1) - + return result_text diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py index 1e8e844eb..6a896167a 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py @@ -235,7 +235,6 @@ class ThinkFlowChat: do_reply = False if random() < reply_probability: try: - do_reply = True # 回复前处理 @@ -397,12 +396,11 @@ class ThinkFlowChat: # 回复后处理 await willing_manager.after_generate_reply_handle(message.message_info.message_id) - + # 处理认识关系 try: is_known = await relationship_manager.is_known_some_one( - message.message_info.platform, - message.message_info.user_info.user_id + message.message_info.platform, message.message_info.user_info.user_id ) if not is_known: logger.info(f"首次认识用户: {message.message_info.user_info.user_nickname}") @@ -410,22 +408,23 @@ class ThinkFlowChat: message.message_info.platform, message.message_info.user_info.user_id, message.message_info.user_info.user_nickname, - message.message_info.user_info.user_cardname or message.message_info.user_info.user_nickname, - "" + message.message_info.user_info.user_cardname + or message.message_info.user_info.user_nickname, + "", ) else: logger.debug(f"已认识用户: {message.message_info.user_info.user_nickname}") if not await relationship_manager.is_qved_name( - message.message_info.platform, - message.message_info.user_info.user_id + message.message_info.platform, message.message_info.user_info.user_id ): logger.info(f"更新已认识但未取名的用户: {message.message_info.user_info.user_nickname}") await relationship_manager.first_knowing_some_one( message.message_info.platform, message.message_info.user_info.user_id, message.message_info.user_info.user_nickname, - message.message_info.user_info.user_cardname or message.message_info.user_info.user_nickname, - "" + message.message_info.user_info.user_cardname + or message.message_info.user_info.user_nickname, + "", ) except Exception as e: logger.error(f"处理认识关系失败: {e}") diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_generator.py b/src/plugins/chat_module/think_flow_chat/think_flow_generator.py index 6f6c8bf26..029ed160c 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_generator.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_generator.py @@ -109,7 +109,7 @@ class ResponseGenerator: # sender_name = f"({message.chat_stream.user_info.user_id}){message.chat_stream.user_info.user_nickname}" # else: # sender_name = f"用户({message.chat_stream.user_info.user_id})" - + sender_name = f"<{message.chat_stream.user_info.platform}:{message.chat_stream.user_info.user_id}:{message.chat_stream.user_info.user_nickname}:{message.chat_stream.user_info.user_cardname}>" # 构建prompt diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py b/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py index 29863ba72..eeee9ccb5 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_prompt_builder.py @@ -10,6 +10,7 @@ from src.heart_flow.heartflow import heartflow from src.plugins.utils.prompt_builder import Prompt, global_prompt_manager from src.plugins.person_info.relationship_manager import relationship_manager from src.plugins.chat.utils import parse_text_timestamps + logger = get_module_logger("prompt") @@ -161,10 +162,10 @@ class PromptBuilder: prompt_ger=prompt_ger, moderation_prompt=await global_prompt_manager.get_prompt_async("moderation_prompt"), ) - + prompt = await relationship_manager.convert_all_person_sign_to_person_name(prompt) prompt = parse_text_timestamps(prompt, mode="lite") - + return prompt async def _build_prompt_simple( diff --git a/src/plugins/person_info/person_info.py b/src/plugins/person_info/person_info.py index 068c37d07..7a8a0d1d5 100644 --- a/src/plugins/person_info/person_info.py +++ b/src/plugins/person_info/person_info.py @@ -64,12 +64,9 @@ class PersonInfoManager: if "person_info" not in db.list_collection_names(): db.create_collection("person_info") db.person_info.create_index("person_id", unique=True) - + # 初始化时读取所有person_name - cursor = db.person_info.find( - {"person_name": {"$exists": True}}, - {"person_id": 1, "person_name": 1, "_id": 0} - ) + cursor = db.person_info.find({"person_name": {"$exists": True}}, {"person_id": 1, "person_name": 1, "_id": 0}) for doc in cursor: if doc.get("person_name"): self.person_name_list[doc["person_id"]] = doc["person_name"] @@ -77,10 +74,10 @@ class PersonInfoManager: def get_person_id(self, platform: str, user_id: int): """获取唯一id""" - #如果platform中存在-,就截取-后面的部分 + # 如果platform中存在-,就截取-后面的部分 if "-" in platform: platform = platform.split("-")[1] - + components = [platform, str(user_id)] key = "_".join(components) return hashlib.md5(key.encode()).hexdigest() @@ -93,8 +90,7 @@ class PersonInfoManager: return True else: return False - - + async def create_person_info(self, person_id: str, data: dict = None): """创建一个项""" if not person_id: @@ -125,7 +121,7 @@ class PersonInfoManager: Data[field_name] = value logger.debug(f"更新时{person_id}不存在,已新建") await self.create_person_info(person_id, Data) - + async def has_one_field(self, person_id: str, field_name: str): """判断是否存在某一个字段""" document = db.person_info.find_one({"person_id": person_id}, {field_name: 1}) @@ -133,36 +129,35 @@ class PersonInfoManager: return True else: return False - + def _extract_json_from_text(self, text: str) -> dict: """从文本中提取JSON数据的高容错方法""" try: - # 尝试直接解析 return json.loads(text) except json.JSONDecodeError: try: # 尝试找到JSON格式的部分 - json_pattern = r'\{[^{}]*\}' + json_pattern = r"\{[^{}]*\}" matches = re.findall(json_pattern, text) if matches: return json.loads(matches[0]) - + # 如果上面都失败了,尝试提取键值对 nickname_pattern = r'"nickname"[:\s]+"([^"]+)"' reason_pattern = r'"reason"[:\s]+"([^"]+)"' - + nickname_match = re.search(nickname_pattern, text) reason_match = re.search(reason_pattern, text) - + if nickname_match: return { "nickname": nickname_match.group(1), - "reason": reason_match.group(1) if reason_match else "未提供理由" + "reason": reason_match.group(1) if reason_match else "未提供理由", } except Exception as e: logger.error(f"JSON提取失败: {str(e)}") - + # 如果所有方法都失败了,返回空结果 return {"nickname": "", "reason": ""} @@ -171,10 +166,10 @@ class PersonInfoManager: if not person_id: logger.debug("取名失败:person_id不能为空") return - + old_name = await self.get_value(person_id, "person_name") old_reason = await self.get_value(person_id, "name_reason") - + max_retries = 5 # 最大重试次数 current_try = 0 existing_names = "" @@ -182,7 +177,7 @@ class PersonInfoManager: individuality = Individuality.get_instance() prompt_personality = individuality.get_prompt(type="personality", x_person=2, level=1) bot_name = individuality.personality.bot_nickname - + qv_name_prompt = f"你是{bot_name},你{prompt_personality}" qv_name_prompt += f"现在你想给一个用户取一个昵称,用户是的qq昵称是{user_nickname}," qv_name_prompt += f"用户的qq群昵称名是{user_cardname}," @@ -195,20 +190,20 @@ class PersonInfoManager: if existing_names: qv_name_prompt += f"\n请注意,以下名称已被使用,不要使用以下昵称:{existing_names}。\n" qv_name_prompt += "请用json给出你的想法,并给出理由,示例如下:" - qv_name_prompt += '''{ + qv_name_prompt += """{ "nickname": "昵称", "reason": "理由" - }''' + }""" logger.debug(f"取名提示词:{qv_name_prompt}") response = await self.qv_name_llm.generate_response(qv_name_prompt) logger.debug(f"取名回复:{response}") result = self._extract_json_from_text(response[0]) - + if not result["nickname"]: logger.error("生成的昵称为空,重试中...") current_try += 1 continue - + # 检查生成的昵称是否已存在 if result["nickname"] not in self.person_name_list.values(): # 更新数据库和内存中的列表 @@ -216,16 +211,16 @@ class PersonInfoManager: # await self.update_one_field(person_id, "nickname", user_nickname) # await self.update_one_field(person_id, "avatar", user_avatar) await self.update_one_field(person_id, "name_reason", result["reason"]) - + self.person_name_list[person_id] = result["nickname"] logger.debug(f"用户 {person_id} 的名称已更新为 {result['nickname']},原因:{result['reason']}") return result else: existing_names += f"{result['nickname']}、" - + logger.debug(f"生成的昵称 {result['nickname']} 已存在,重试中...") current_try += 1 - + logger.error(f"在{max_retries}次尝试后仍未能生成唯一昵称") return None diff --git a/src/plugins/person_info/relationship_manager.py b/src/plugins/person_info/relationship_manager.py index 673e0b07f..696a6391b 100644 --- a/src/plugins/person_info/relationship_manager.py +++ b/src/plugins/person_info/relationship_manager.py @@ -76,13 +76,13 @@ class RelationshipManager: return mood_value * coefficient else: return mood_value / coefficient - - async def is_known_some_one(self, platform , user_id): + + async def is_known_some_one(self, platform, user_id): """判断是否认识某人""" is_known = person_info_manager.is_person_known(platform, user_id) return is_known - async def is_qved_name(self, platform , user_id): + async def is_qved_name(self, platform, user_id): """判断是否认识某人""" person_id = person_info_manager.get_person_id(platform, user_id) is_qved = await person_info_manager.has_one_field(person_id, "person_name") @@ -93,42 +93,41 @@ class RelationshipManager: return True else: return False - - async def first_knowing_some_one(self, platform , user_id, user_nickname, user_cardname, user_avatar): + + async def first_knowing_some_one(self, platform, user_id, user_nickname, user_cardname, user_avatar): """判断是否认识某人""" - person_id = person_info_manager.get_person_id(platform,user_id) + person_id = person_info_manager.get_person_id(platform, user_id) await person_info_manager.update_one_field(person_id, "nickname", user_nickname) # await person_info_manager.update_one_field(person_id, "user_cardname", user_cardname) # await person_info_manager.update_one_field(person_id, "user_avatar", user_avatar) await person_info_manager.qv_person_name(person_id, user_nickname, user_cardname, user_avatar) - - async def convert_all_person_sign_to_person_name(self,input_text:str): + + async def convert_all_person_sign_to_person_name(self, input_text: str): """将所有人的格式转换为person_name""" try: # 使用正则表达式匹配格式 all_person = person_info_manager.person_name_list - - pattern = r'<([^:]+):(\d+):([^:]+):([^>]+)>' + + pattern = r"<([^:]+):(\d+):([^:]+):([^>]+)>" matches = re.findall(pattern, input_text) - + # 遍历匹配结果,将替换为person_name result_text = input_text for platform, user_id, nickname, cardname in matches: person_id = person_info_manager.get_person_id(platform, user_id) # 默认使用昵称作为人名 person_name = nickname.strip() if nickname.strip() else cardname.strip() - + if person_id in all_person: if all_person[person_id] != None: person_name = all_person[person_id] - + print(f"将<{platform}:{user_id}:{nickname}:{cardname}>替换为{person_name}") - - + result_text = result_text.replace(f"<{platform}:{user_id}:{nickname}:{cardname}>", person_name) - + return result_text - except Exception as e: + except Exception: logger.error(traceback.format_exc()) return input_text From 328d759ace42e31404d1bd83e12bb9d06ed96702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=A5=E6=B2=B3=E6=99=B4?= Date: Wed, 16 Apr 2025 16:26:15 +0900 Subject: [PATCH 6/9] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=AD=A3=E5=88=99?= =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F=E4=B8=AD=E7=9A=84=E6=8B=AC=E5=8F=B7?= =?UTF-8?q?=E5=8C=B9=E9=85=8D=EF=BC=8C=E4=BC=98=E5=8C=96=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - src/plugins/chat/utils.py | 19 ++++++++++--------- src/plugins/utils/prompt_builder.py | 4 ++-- src/plugins/utils/statistic.py | 16 +++------------- 4 files changed, 15 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 3e9b98685..37813f433 100644 --- a/.gitignore +++ b/.gitignore @@ -29,7 +29,6 @@ config/bot_config_dev.toml config/bot_config.toml config/bot_config.toml.bak src/plugins/remote/client_uuid.json -run_none.bat (测试版)麦麦生成人格.bat (临时版)麦麦开始学习.bat src/plugins/utils/statistic.py diff --git a/src/plugins/chat/utils.py b/src/plugins/chat/utils.py index 5f2d0105c..b223e87da 100644 --- a/src/plugins/chat/utils.py +++ b/src/plugins/chat/utils.py @@ -46,12 +46,13 @@ def is_mentioned_bot_in_message(message: MessageRecv) -> bool: is_at = False is_mentioned = False - if "is_mentioned" in message.message_info.additional_config.keys(): + if message.message_info.additional_config.get("is_mentioned") is not None: try: reply_probability = float(message.message_info.additional_config.get("is_mentioned")) is_mentioned = True return is_mentioned, reply_probability except Exception as e: + logger.warning(e) logger.warning( f"消息中包含不合理的设置 is_mentioned: {message.message_info.additional_config.get('is_mentioned')}" ) @@ -71,7 +72,7 @@ def is_mentioned_bot_in_message(message: MessageRecv) -> bool: is_mentioned = True # 判断内容中是否被提及 - message_content = re.sub(r"\@[\s\S]*?((\d+))", "", message.processed_plain_text) + message_content = re.sub(r"@[\s\S]*?((\d+))", "", message.processed_plain_text) message_content = re.sub(r"回复[\s\S]*?\((\d+)\)的消息,说: ", "", message_content) for keyword in keywords: if keyword in message_content: @@ -335,7 +336,7 @@ def random_remove_punctuation(text: str) -> str: def process_llm_response(text: str) -> List[str]: # 提取被 () 或 [] 包裹的内容 - pattern = re.compile(r"[\(\[].*?[\)\]]") + pattern = re.compile(r"[(\[].*?[\)\]") _extracted_contents = pattern.findall(text) # 去除 () 和 [] 及其包裹的内容 cleaned_text = pattern.sub("", text) @@ -496,16 +497,16 @@ def protect_kaomoji(sentence): """ kaomoji_pattern = re.compile( r"(" - r"[\(\[(【]" # 左括号 + r"[(\[(【]" # 左括号 r"[^()\[\]()【】]*?" # 非括号字符(惰性匹配) - r"[^\u4e00-\u9fa5a-zA-Z0-9\s]" # 非中文、非英文、非数字、非空格字符(必须包含至少一个) + r"[^一-龥a-zA-Z0-9\s]" # 非中文、非英文、非数字、非空格字符(必须包含至少一个) r"[^()\[\]()【】]*?" # 非括号字符(惰性匹配) - r"[\)\])】]" # 右括号 + r"[\)\])】" # 右括号 + r"]" r")" r"|" - r"(" - r"[▼▽・ᴥω・﹏^><≧≦ ̄`´∀ヮДд︿﹀へ。゚╥╯╰︶︹•⁄]{2,15}" - r")" + r"([▼▽・ᴥω・﹏^><≧≦ ̄`´∀ヮДд︿﹀へ。゚╥╯╰︶︹•⁄]{2,15" + r"}" ) kaomoji_matches = kaomoji_pattern.findall(sentence) diff --git a/src/plugins/utils/prompt_builder.py b/src/plugins/utils/prompt_builder.py index f3de24e4f..578d9677f 100644 --- a/src/plugins/utils/prompt_builder.py +++ b/src/plugins/utils/prompt_builder.py @@ -119,7 +119,7 @@ class Prompt(str): # 解析模板 template_args = [] - result = re.findall(r"\{(.*?)\}", processed_fstr) + result = re.findall(r"\{(.*?)}", processed_fstr) for expr in result: if expr and expr not in template_args: template_args.append(expr) @@ -164,7 +164,7 @@ class Prompt(str): processed_template = cls._process_escaped_braces(template) template_args = [] - result = re.findall(r"\{(.*?)\}", processed_template) + result = re.findall(r"\{(.*?)}", processed_template) for expr in result: if expr and expr not in template_args: template_args.append(expr) diff --git a/src/plugins/utils/statistic.py b/src/plugins/utils/statistic.py index 10133f2b7..af7138744 100644 --- a/src/plugins/utils/statistic.py +++ b/src/plugins/utils/statistic.py @@ -175,13 +175,8 @@ class LLMStatistics: def _format_stats_section(self, stats: Dict[str, Any], title: str) -> str: """格式化统计部分的输出""" - output = [] + output = ["\n" + "-" * 84, f"{title}", "-" * 84, f"总请求数: {stats['total_requests']}"] - output.append("\n" + "-" * 84) - output.append(f"{title}") - output.append("-" * 84) - - output.append(f"总请求数: {stats['total_requests']}") if stats["total_requests"] > 0: output.append(f"总Token数: {stats['total_tokens']}") output.append(f"总花费: {stats['total_cost']:.4f}¥") @@ -238,11 +233,7 @@ class LLMStatistics: def _format_stats_section_lite(self, stats: Dict[str, Any], title: str) -> str: """格式化统计部分的输出""" - output = [] - - output.append("\n" + "-" * 84) - output.append(f"{title}") - output.append("-" * 84) + output = ["\n" + "-" * 84, f"{title}", "-" * 84] # output.append(f"总请求数: {stats['total_requests']}") if stats["total_requests"] > 0: @@ -303,8 +294,7 @@ class LLMStatistics: """将统计结果保存到文件""" current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - output = [] - output.append(f"LLM请求统计报告 (生成时间: {current_time})") + output = [f"LLM请求统计报告 (生成时间: {current_time})"] # 添加各个时间段的统计 sections = [ From a0b1b1f8d8c2e43f30f59e192a2c43127b837b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=A5=E6=B2=B3=E6=99=B4?= Date: Wed, 16 Apr 2025 16:34:33 +0900 Subject: [PATCH 7/9] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9is=5Fmentioned=5Fb?= =?UTF-8?q?ot=5Fin=5Fmessage=E5=87=BD=E6=95=B0=EF=BC=8C=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E6=94=B9=E4=B8=BA=E5=85=83=E7=BB=84=E5=B9=B6?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=9B=9E=E5=A4=8D=E6=A6=82=E7=8E=87=E4=B8=BA?= =?UTF-8?q?=E6=B5=AE=E7=82=B9=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/chat/utils.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/plugins/chat/utils.py b/src/plugins/chat/utils.py index b223e87da..81c19af80 100644 --- a/src/plugins/chat/utils.py +++ b/src/plugins/chat/utils.py @@ -38,15 +38,18 @@ def db_message_to_str(message_dict: Dict) -> str: return result -def is_mentioned_bot_in_message(message: MessageRecv) -> bool: +def is_mentioned_bot_in_message(message: MessageRecv) -> tuple[bool, float]: """检查消息是否提到了机器人""" keywords = [global_config.BOT_NICKNAME] nicknames = global_config.BOT_ALIAS_NAMES - reply_probability = 0 + reply_probability = 0.0 is_at = False is_mentioned = False - if message.message_info.additional_config.get("is_mentioned") is not None: + if ( + message.message_info.additional_config is not None + and message.message_info.additional_config.get("is_mentioned") is not None + ): try: reply_probability = float(message.message_info.additional_config.get("is_mentioned")) is_mentioned = True @@ -63,7 +66,7 @@ def is_mentioned_bot_in_message(message: MessageRecv) -> bool: is_mentioned = True if is_at and global_config.at_bot_inevitable_reply: - reply_probability = 1 + reply_probability = 1.0 logger.info("被@,回复概率设置为100%") else: if not is_mentioned: @@ -81,7 +84,7 @@ def is_mentioned_bot_in_message(message: MessageRecv) -> bool: if nickname in message_content: is_mentioned = True if is_mentioned and global_config.mentioned_bot_inevitable_reply: - reply_probability = 1 + reply_probability = 1.0 logger.info("被提及,回复概率设置为100%") return is_mentioned, reply_probability From dc2cf843e50cc5c1aba438c8b3fafa6ff8f2b726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=A5=E6=B2=B3=E6=99=B4?= Date: Wed, 16 Apr 2025 17:37:28 +0900 Subject: [PATCH 8/9] =?UTF-8?q?=E6=94=B9=E5=90=84=E7=A7=8D=E5=B0=8F?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/do_tool/tool_use.py | 9 ++++--- src/heart_flow/heartflow.py | 4 +-- src/heart_flow/observation.py | 4 +-- src/heart_flow/sub_heartflow.py | 4 +-- src/individuality/offline_llm.py | 2 +- src/individuality/per_bf_gen.py | 10 +++---- src/main.py | 2 +- src/plugins/PFC/action_planner.py | 4 +-- src/plugins/PFC/message_sender.py | 2 +- src/plugins/PFC/observation_info.py | 11 +++++--- src/plugins/PFC/pfc.py | 6 ++--- src/plugins/PFC/pfc_KnowledgeFetcher.py | 4 +-- src/plugins/PFC/reply_checker.py | 4 +-- src/plugins/PFC/reply_generator.py | 4 +-- src/plugins/chat/__init__.py | 2 +- src/plugins/chat/bot.py | 4 +-- src/plugins/chat/emoji_manager.py | 6 ++--- src/plugins/chat/message_buffer.py | 8 +++--- .../{message_sender.py => messagesender.py} | 6 ++--- src/plugins/chat/utils.py | 6 ++--- src/plugins/chat/utils_image.py | 4 +-- .../reasoning_chat/reasoning_chat.py | 2 +- .../reasoning_chat/reasoning_generator.py | 10 +++---- .../think_flow_chat/think_flow_chat.py | 2 +- .../think_flow_chat/think_flow_generator.py | 8 +++--- src/plugins/config/config.py | 3 +-- src/plugins/memory_system/Hippocampus.py | 26 +++++++++---------- .../memory_system/manually_alter_memory.py | 22 ++++++++-------- src/plugins/memory_system/offline_llm.py | 2 +- src/plugins/message/api.py | 3 ++- src/plugins/models/utils_model.py | 2 +- src/plugins/person_info/person_info.py | 13 +++++----- src/plugins/personality_s/renqingziji.py | 4 +-- src/plugins/remote/remote.py | 8 +++--- src/plugins/schedule/schedule_generator.py | 6 ++--- .../topic_identify/topic_identifier.py | 4 +-- 36 files changed, 114 insertions(+), 107 deletions(-) rename src/plugins/chat/{message_sender.py => messagesender.py} (99%) diff --git a/src/do_tool/tool_use.py b/src/do_tool/tool_use.py index b14927be8..af7c1b314 100644 --- a/src/do_tool/tool_use.py +++ b/src/do_tool/tool_use.py @@ -1,4 +1,4 @@ -from src.plugins.models.utils_model import LLM_request +from src.plugins.models.utils_model import LLMRequest from src.plugins.config.config import global_config from src.plugins.chat.chat_stream import ChatStream from src.common.database import db @@ -18,7 +18,7 @@ logger = get_module_logger("tool_use", config=tool_use_config) class ToolUser: def __init__(self): - self.llm_model_tool = LLM_request( + self.llm_model_tool = LLMRequest( model=global_config.llm_tool_use, temperature=0.2, max_tokens=1000, request_type="tool_use" ) @@ -107,7 +107,7 @@ class ToolUser: return None async def use_tool( - self, message_txt: str, sender_name: str, chat_stream: ChatStream, subheartflow: SubHeartflow = None + self, message_txt: str, sender_name: str, chat_stream: ChatStream, sub_heartflow: SubHeartflow = None ): """使用工具辅助思考,判断是否需要额外信息 @@ -115,13 +115,14 @@ class ToolUser: message_txt: 用户消息文本 sender_name: 发送者名称 chat_stream: 聊天流对象 + sub_heartflow: 子心流对象(可选) Returns: dict: 工具使用结果,包含结构化的信息 """ try: # 构建提示词 - prompt = await self._build_tool_prompt(message_txt, sender_name, chat_stream, subheartflow) + prompt = await self._build_tool_prompt(message_txt, sender_name, chat_stream, sub_heartflow) # 定义可用工具 tools = self._define_tools() diff --git a/src/heart_flow/heartflow.py b/src/heart_flow/heartflow.py index d6116d0d5..9f0d202ea 100644 --- a/src/heart_flow/heartflow.py +++ b/src/heart_flow/heartflow.py @@ -1,7 +1,7 @@ from .sub_heartflow import SubHeartflow from .observation import ChattingObservation from src.plugins.moods.moods import MoodManager -from src.plugins.models.utils_model import LLM_request +from src.plugins.models.utils_model import LLMRequest from src.plugins.config.config import global_config from src.plugins.schedule.schedule_generator import bot_schedule from src.plugins.utils.prompt_builder import Prompt, global_prompt_manager @@ -60,7 +60,7 @@ class Heartflow: self.current_mind = "你什么也没想" self.past_mind = [] self.current_state: CurrentState = CurrentState() - self.llm_model = LLM_request( + self.llm_model = LLMRequest( model=global_config.llm_heartflow, temperature=0.6, max_tokens=1000, request_type="heart_flow" ) diff --git a/src/heart_flow/observation.py b/src/heart_flow/observation.py index 481e4beb7..c1e321c17 100644 --- a/src/heart_flow/observation.py +++ b/src/heart_flow/observation.py @@ -1,7 +1,7 @@ # 定义了来自外部世界的信息 # 外部世界可以是某个聊天 不同平台的聊天 也可以是任意媒体 from datetime import datetime -from src.plugins.models.utils_model import LLM_request +from src.plugins.models.utils_model import LLMRequest from src.plugins.config.config import global_config from src.common.database import db from src.common.logger import get_module_logger @@ -40,7 +40,7 @@ class ChattingObservation(Observation): self.updating_old = False - self.llm_summary = LLM_request( + self.llm_summary = LLMRequest( model=global_config.llm_observation, temperature=0.7, max_tokens=300, request_type="chat_observation" ) diff --git a/src/heart_flow/sub_heartflow.py b/src/heart_flow/sub_heartflow.py index cb53c2240..e1ccb193e 100644 --- a/src/heart_flow/sub_heartflow.py +++ b/src/heart_flow/sub_heartflow.py @@ -1,7 +1,7 @@ from .observation import Observation, ChattingObservation import asyncio from src.plugins.moods.moods import MoodManager -from src.plugins.models.utils_model import LLM_request +from src.plugins.models.utils_model import LLMRequest from src.plugins.config.config import global_config import time from src.plugins.chat.message import UserInfo @@ -79,7 +79,7 @@ class SubHeartflow: self.current_mind = "" self.past_mind = [] self.current_state: CurrentState = CurrentState() - self.llm_model = LLM_request( + self.llm_model = LLMRequest( model=global_config.llm_sub_heartflow, temperature=global_config.llm_sub_heartflow["temp"], max_tokens=600, diff --git a/src/individuality/offline_llm.py b/src/individuality/offline_llm.py index 7a698fc1d..2b5b6dc25 100644 --- a/src/individuality/offline_llm.py +++ b/src/individuality/offline_llm.py @@ -10,7 +10,7 @@ from src.common.logger import get_module_logger logger = get_module_logger("offline_llm") -class LLM_request_off: +class LLMRequestOff: def __init__(self, model_name="Pro/deepseek-ai/DeepSeek-V3", **kwargs): self.model_name = model_name self.params = kwargs diff --git a/src/individuality/per_bf_gen.py b/src/individuality/per_bf_gen.py index d898ea5e3..7e630bdd9 100644 --- a/src/individuality/per_bf_gen.py +++ b/src/individuality/per_bf_gen.py @@ -19,7 +19,7 @@ with open(config_path, "r", encoding="utf-8") as f: # 现在可以导入src模块 from src.individuality.scene import get_scene_by_factor, PERSONALITY_SCENES # noqa E402 from src.individuality.questionnaire import FACTOR_DESCRIPTIONS # noqa E402 -from src.individuality.offline_llm import LLM_request_off # noqa E402 +from src.individuality.offline_llm import LLMRequestOff # noqa E402 # 加载环境变量 env_path = os.path.join(root_path, ".env") @@ -65,7 +65,7 @@ def adapt_scene(scene: str) -> str: 现在,请你给出改编后的场景描述 """ - llm = LLM_request_off(model_name=config["model"]["llm_normal"]["name"]) + llm = LLMRequestOff(model_name=config["model"]["llm_normal"]["name"]) adapted_scene, _ = llm.generate_response(prompt) # 检查返回的场景是否为空或错误信息 @@ -79,7 +79,7 @@ def adapt_scene(scene: str) -> str: return scene -class PersonalityEvaluator_direct: +class PersonalityEvaluatorDirect: def __init__(self): self.personality_traits = {"开放性": 0, "严谨性": 0, "外向性": 0, "宜人性": 0, "神经质": 0} self.scenarios = [] @@ -110,7 +110,7 @@ class PersonalityEvaluator_direct: {"场景": scene["scenario"], "评估维度": [trait, secondary_trait], "场景编号": scene_key} ) - self.llm = LLM_request_off() + self.llm = LLMRequestOff() def evaluate_response(self, scenario: str, response: str, dimensions: List[str]) -> Dict[str, float]: """ @@ -269,7 +269,7 @@ class PersonalityEvaluator_direct: def main(): - evaluator = PersonalityEvaluator_direct() + evaluator = PersonalityEvaluatorDirect() result = evaluator.run_evaluation() # 准备简化的结果数据 diff --git a/src/main.py b/src/main.py index d8f667153..11e01f7b6 100644 --- a/src/main.py +++ b/src/main.py @@ -9,7 +9,7 @@ from .plugins.willing.willing_manager import willing_manager from .plugins.chat.chat_stream import chat_manager from .heart_flow.heartflow import heartflow from .plugins.memory_system.Hippocampus import HippocampusManager -from .plugins.chat.message_sender import message_manager +from .plugins.chat.messagesender import message_manager from .plugins.storage.storage import MessageStorage from .plugins.config.config import global_config from .plugins.chat.bot import chat_bot diff --git a/src/plugins/PFC/action_planner.py b/src/plugins/PFC/action_planner.py index cc904662d..0b1b633ab 100644 --- a/src/plugins/PFC/action_planner.py +++ b/src/plugins/PFC/action_planner.py @@ -1,6 +1,6 @@ from typing import Tuple from src.common.logger import get_module_logger -from ..models.utils_model import LLM_request +from ..models.utils_model import LLMRequest from ..config.config import global_config from .chat_observer import ChatObserver from .pfc_utils import get_items_from_json @@ -23,7 +23,7 @@ class ActionPlanner: """行动规划器""" def __init__(self, stream_id: str): - self.llm = LLM_request( + self.llm = LLMRequest( model=global_config.llm_normal, temperature=global_config.llm_normal["temp"], max_tokens=1000, diff --git a/src/plugins/PFC/message_sender.py b/src/plugins/PFC/message_sender.py index bc4499ed9..6a5eb9709 100644 --- a/src/plugins/PFC/message_sender.py +++ b/src/plugins/PFC/message_sender.py @@ -4,7 +4,7 @@ from ..chat.chat_stream import ChatStream from ..chat.message import Message from ..message.message_base import Seg from src.plugins.chat.message import MessageSending, MessageSet -from src.plugins.chat.message_sender import message_manager +from src.plugins.chat.messagesender import message_manager logger = get_module_logger("message_sender") diff --git a/src/plugins/PFC/observation_info.py b/src/plugins/PFC/observation_info.py index 08ff3c046..97d9a6146 100644 --- a/src/plugins/PFC/observation_info.py +++ b/src/plugins/PFC/observation_info.py @@ -120,6 +120,10 @@ class ObservationInfo: # #spec # meta_plan_trigger: bool = False + def __init__(self): + self.last_message_id = None + self.chat_observer = None + def __post_init__(self): """初始化后创建handler""" self.chat_observer = None @@ -129,7 +133,7 @@ class ObservationInfo: """绑定到指定的chat_observer Args: - stream_id: 聊天流ID + chat_observer: 要绑定的ChatObserver实例 """ self.chat_observer = chat_observer self.chat_observer.notification_manager.register_handler( @@ -171,7 +175,8 @@ class ObservationInfo: self.last_bot_speak_time = message["time"] else: self.last_user_speak_time = message["time"] - self.active_users.add(user_info.user_id) + if user_info.user_id is not None: + self.active_users.add(str(user_info.user_id)) self.new_messages_count += 1 self.unprocessed_messages.append(message) @@ -227,7 +232,7 @@ class ObservationInfo: """清空未处理消息列表""" # 将未处理消息添加到历史记录中 for message in self.unprocessed_messages: - self.chat_history.append(message) + self.chat_history.append(message) # TODO NEED FIX TYPE??? # 清空未处理消息列表 self.has_unread_messages = False self.unprocessed_messages.clear() diff --git a/src/plugins/PFC/pfc.py b/src/plugins/PFC/pfc.py index a53258888..a3b4bb065 100644 --- a/src/plugins/PFC/pfc.py +++ b/src/plugins/PFC/pfc.py @@ -8,7 +8,7 @@ from src.common.logger import get_module_logger from ..chat.chat_stream import ChatStream from ..message.message_base import UserInfo, Seg from ..chat.message import Message -from ..models.utils_model import LLM_request +from ..models.utils_model import LLMRequest from ..config.config import global_config from src.plugins.chat.message import MessageSending from ..message.api import global_api @@ -30,7 +30,7 @@ class GoalAnalyzer: """对话目标分析器""" def __init__(self, stream_id: str): - self.llm = LLM_request( + self.llm = LLMRequest( model=global_config.llm_normal, temperature=0.7, max_tokens=1000, request_type="conversation_goal" ) @@ -350,7 +350,7 @@ class DirectMessageSender: # logger.info(f"发送消息到{end_point}") # logger.info(message_json) try: - await global_api.send_message_REST(end_point, message_json) + await global_api.send_message_rest(end_point, message_json) except Exception as e: logger.error(f"REST方式发送失败,出现错误: {str(e)}") logger.info("尝试使用ws发送") diff --git a/src/plugins/PFC/pfc_KnowledgeFetcher.py b/src/plugins/PFC/pfc_KnowledgeFetcher.py index 9c5c55076..5458f61e3 100644 --- a/src/plugins/PFC/pfc_KnowledgeFetcher.py +++ b/src/plugins/PFC/pfc_KnowledgeFetcher.py @@ -1,7 +1,7 @@ from typing import List, Tuple from src.common.logger import get_module_logger from src.plugins.memory_system.Hippocampus import HippocampusManager -from ..models.utils_model import LLM_request +from ..models.utils_model import LLMRequest from ..config.config import global_config from ..chat.message import Message @@ -12,7 +12,7 @@ class KnowledgeFetcher: """知识调取器""" def __init__(self): - self.llm = LLM_request( + self.llm = LLMRequest( model=global_config.llm_normal, temperature=global_config.llm_normal["temp"], max_tokens=1000, diff --git a/src/plugins/PFC/reply_checker.py b/src/plugins/PFC/reply_checker.py index 6889f7ca8..f9753d44e 100644 --- a/src/plugins/PFC/reply_checker.py +++ b/src/plugins/PFC/reply_checker.py @@ -2,7 +2,7 @@ import json import datetime from typing import Tuple from src.common.logger import get_module_logger -from ..models.utils_model import LLM_request +from ..models.utils_model import LLMRequest from ..config.config import global_config from .chat_observer import ChatObserver from ..message.message_base import UserInfo @@ -14,7 +14,7 @@ class ReplyChecker: """回复检查器""" def __init__(self, stream_id: str): - self.llm = LLM_request( + self.llm = LLMRequest( model=global_config.llm_normal, temperature=0.7, max_tokens=1000, request_type="reply_check" ) self.name = global_config.BOT_NICKNAME diff --git a/src/plugins/PFC/reply_generator.py b/src/plugins/PFC/reply_generator.py index 85a067d23..8a5d77fe2 100644 --- a/src/plugins/PFC/reply_generator.py +++ b/src/plugins/PFC/reply_generator.py @@ -1,6 +1,6 @@ from typing import Tuple from src.common.logger import get_module_logger -from ..models.utils_model import LLM_request +from ..models.utils_model import LLMRequest from ..config.config import global_config from .chat_observer import ChatObserver from .reply_checker import ReplyChecker @@ -15,7 +15,7 @@ class ReplyGenerator: """回复生成器""" def __init__(self, stream_id: str): - self.llm = LLM_request( + self.llm = LLMRequest( model=global_config.llm_normal, temperature=global_config.llm_normal["temp"], max_tokens=300, diff --git a/src/plugins/chat/__init__.py b/src/plugins/chat/__init__.py index 8d9aa1f8e..a68caaf1c 100644 --- a/src/plugins/chat/__init__.py +++ b/src/plugins/chat/__init__.py @@ -1,7 +1,7 @@ from .emoji_manager import emoji_manager from ..person_info.relationship_manager import relationship_manager from .chat_stream import chat_manager -from .message_sender import message_manager +from .messagesender import message_manager from ..storage.storage import MessageStorage diff --git a/src/plugins/chat/bot.py b/src/plugins/chat/bot.py index 3dc732274..bb83ade24 100644 --- a/src/plugins/chat/bot.py +++ b/src/plugins/chat/bot.py @@ -42,7 +42,7 @@ class ChatBot: self._started = True - async def _create_PFC_chat(self, message: MessageRecv): + async def _create_pfc_chat(self, message: MessageRecv): try: chat_id = str(message.chat_stream.stream_id) @@ -112,7 +112,7 @@ class ChatBot: ) message.update_chat_stream(chat) await self.only_process_chat.process_message(message) - await self._create_PFC_chat(message) + await self._create_pfc_chat(message) else: if groupinfo.group_id in global_config.talk_allowed_groups: # logger.debug(f"开始群聊模式{str(message_data)[:50]}...") diff --git a/src/plugins/chat/emoji_manager.py b/src/plugins/chat/emoji_manager.py index de3a5a54d..7a860b855 100644 --- a/src/plugins/chat/emoji_manager.py +++ b/src/plugins/chat/emoji_manager.py @@ -13,7 +13,7 @@ from ...common.database import db from ..config.config import global_config from ..chat.utils import get_embedding from ..chat.utils_image import ImageManager, image_path_to_base64 -from ..models.utils_model import LLM_request +from ..models.utils_model import LLMRequest from src.common.logger import get_module_logger logger = get_module_logger("emoji") @@ -34,8 +34,8 @@ class EmojiManager: def __init__(self): self._scan_task = None - self.vlm = LLM_request(model=global_config.vlm, temperature=0.3, max_tokens=1000, request_type="emoji") - self.llm_emotion_judge = LLM_request( + self.vlm = LLMRequest(model=global_config.vlm, temperature=0.3, max_tokens=1000, request_type="emoji") + self.llm_emotion_judge = LLMRequest( model=global_config.llm_emotion_judge, max_tokens=600, temperature=0.8, request_type="emoji" ) # 更高的温度,更少的token(后续可以根据情绪来调整温度) diff --git a/src/plugins/chat/message_buffer.py b/src/plugins/chat/message_buffer.py index 21e490433..e175b442f 100644 --- a/src/plugins/chat/message_buffer.py +++ b/src/plugins/chat/message_buffer.py @@ -59,20 +59,20 @@ class MessageBuffer: logger.debug(f"被新消息覆盖信息id: {cache_msg.message.message_info.message_id}") # 查找最近的处理成功消息(T) - recent_F_count = 0 + recent_f_count = 0 for msg_id in reversed(self.buffer_pool[person_id_]): msg = self.buffer_pool[person_id_][msg_id] if msg.result == "T": break elif msg.result == "F": - recent_F_count += 1 + recent_f_count += 1 # 判断条件:最近T之后有超过3-5条F - if recent_F_count >= random.randint(3, 5): + if recent_f_count >= random.randint(3, 5): new_msg = CacheMessages(message=message, result="T") new_msg.cache_determination.set() self.buffer_pool[person_id_][message.message_info.message_id] = new_msg - logger.debug(f"快速处理消息(已堆积{recent_F_count}条F): {message.message_info.message_id}") + logger.debug(f"快速处理消息(已堆积{recent_f_count}条F): {message.message_info.message_id}") return # 添加新消息 diff --git a/src/plugins/chat/message_sender.py b/src/plugins/chat/messagesender.py similarity index 99% rename from src/plugins/chat/message_sender.py rename to src/plugins/chat/messagesender.py index c223bbe4d..7dfee271e 100644 --- a/src/plugins/chat/message_sender.py +++ b/src/plugins/chat/messagesender.py @@ -23,7 +23,7 @@ sender_config = LogConfig( logger = get_module_logger("msg_sender", config=sender_config) -class Message_Sender: +class MessageSender: """发送器""" def __init__(self): @@ -83,7 +83,7 @@ class Message_Sender: # logger.info(f"发送消息到{end_point}") # logger.info(message_json) try: - await global_api.send_message_REST(end_point, message_json) + await global_api.send_message_rest(end_point, message_json) except Exception as e: logger.error(f"REST方式发送失败,出现错误: {str(e)}") logger.info("尝试使用ws发送") @@ -286,4 +286,4 @@ class MessageManager: # 创建全局消息管理器实例 message_manager = MessageManager() # 创建全局发送器实例 -message_sender = Message_Sender() +message_sender = MessageSender() diff --git a/src/plugins/chat/utils.py b/src/plugins/chat/utils.py index 81c19af80..492f46f31 100644 --- a/src/plugins/chat/utils.py +++ b/src/plugins/chat/utils.py @@ -8,7 +8,7 @@ import jieba import numpy as np from src.common.logger import get_module_logger -from ..models.utils_model import LLM_request +from ..models.utils_model import LLMRequest from ..utils.typo_generator import ChineseTypoGenerator from ..config.config import global_config from .message import MessageRecv, Message @@ -91,7 +91,7 @@ def is_mentioned_bot_in_message(message: MessageRecv) -> tuple[bool, float]: async def get_embedding(text, request_type="embedding"): """获取文本的embedding向量""" - llm = LLM_request(model=global_config.embedding, request_type=request_type) + llm = LLMRequest(model=global_config.embedding, request_type=request_type) # return llm.get_embedding_sync(text) try: embedding = await llm.get_embedding(text) @@ -105,7 +105,7 @@ async def get_recent_group_messages(chat_id: str, limit: int = 12) -> list: """从数据库获取群组最近的消息记录 Args: - group_id: 群组ID + chat_id: 群组ID limit: 获取消息数量,默认12条 Returns: diff --git a/src/plugins/chat/utils_image.py b/src/plugins/chat/utils_image.py index ed78dc17e..4fe0c5fcc 100644 --- a/src/plugins/chat/utils_image.py +++ b/src/plugins/chat/utils_image.py @@ -9,7 +9,7 @@ import io from ...common.database import db from ..config.config import global_config -from ..models.utils_model import LLM_request +from ..models.utils_model import LLMRequest from src.common.logger import get_module_logger @@ -32,7 +32,7 @@ class ImageManager: self._ensure_description_collection() self._ensure_image_dir() self._initialized = True - self._llm = LLM_request(model=global_config.vlm, temperature=0.4, max_tokens=300, request_type="image") + self._llm = LLMRequest(model=global_config.vlm, temperature=0.4, max_tokens=300, request_type="image") def _ensure_image_dir(self): """确保图像存储目录存在""" diff --git a/src/plugins/chat_module/reasoning_chat/reasoning_chat.py b/src/plugins/chat_module/reasoning_chat/reasoning_chat.py index 2ce218a6f..82e041cb1 100644 --- a/src/plugins/chat_module/reasoning_chat/reasoning_chat.py +++ b/src/plugins/chat_module/reasoning_chat/reasoning_chat.py @@ -8,7 +8,7 @@ from ...config.config import global_config from ...chat.emoji_manager import emoji_manager from .reasoning_generator import ResponseGenerator from ...chat.message import MessageSending, MessageRecv, MessageThinking, MessageSet -from ...chat.message_sender import message_manager +from ...chat.messagesender import message_manager from ...storage.storage import MessageStorage from ...chat.utils import is_mentioned_bot_in_message from ...chat.utils_image import image_path_to_base64 diff --git a/src/plugins/chat_module/reasoning_chat/reasoning_generator.py b/src/plugins/chat_module/reasoning_chat/reasoning_generator.py index 46602b5d7..6c8221d12 100644 --- a/src/plugins/chat_module/reasoning_chat/reasoning_generator.py +++ b/src/plugins/chat_module/reasoning_chat/reasoning_generator.py @@ -1,7 +1,7 @@ from typing import List, Optional, Tuple, Union import random -from ...models.utils_model import LLM_request +from ...models.utils_model import LLMRequest from ...config.config import global_config from ...chat.message import MessageThinking from .reasoning_prompt_builder import prompt_builder @@ -22,20 +22,20 @@ logger = get_module_logger("llm_generator", config=llm_config) class ResponseGenerator: def __init__(self): - self.model_reasoning = LLM_request( + self.model_reasoning = LLMRequest( model=global_config.llm_reasoning, temperature=0.7, max_tokens=3000, request_type="response_reasoning", ) - self.model_normal = LLM_request( + self.model_normal = LLMRequest( model=global_config.llm_normal, temperature=global_config.llm_normal["temp"], max_tokens=256, request_type="response_reasoning", ) - self.model_sum = LLM_request( + self.model_sum = LLMRequest( model=global_config.llm_summary_by_topic, temperature=0.7, max_tokens=3000, request_type="relation" ) self.current_model_type = "r1" # 默认使用 R1 @@ -68,7 +68,7 @@ class ResponseGenerator: logger.info(f"{self.current_model_type}思考,失败") return None - async def _generate_response_with_model(self, message: MessageThinking, model: LLM_request, thinking_id: str): + async def _generate_response_with_model(self, message: MessageThinking, model: LLMRequest, thinking_id: str): sender_name = "" info_catcher = info_catcher_manager.get_info_catcher(thinking_id) diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py index 6a896167a..611eb5966 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py @@ -8,7 +8,7 @@ from ...config.config import global_config from ...chat.emoji_manager import emoji_manager from .think_flow_generator import ResponseGenerator from ...chat.message import MessageSending, MessageRecv, MessageThinking, MessageSet -from ...chat.message_sender import message_manager +from ...chat.messagesender import message_manager from ...storage.storage import MessageStorage from ...chat.utils import is_mentioned_bot_in_message, get_recent_group_detailed_plain_text from ...chat.utils_image import image_path_to_base64 diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_generator.py b/src/plugins/chat_module/think_flow_chat/think_flow_generator.py index 029ed160c..129feaab2 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_generator.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_generator.py @@ -2,7 +2,7 @@ from typing import List, Optional import random -from ...models.utils_model import LLM_request +from ...models.utils_model import LLMRequest from ...config.config import global_config from ...chat.message import MessageRecv from .think_flow_prompt_builder import prompt_builder @@ -25,14 +25,14 @@ logger = get_module_logger("llm_generator", config=llm_config) class ResponseGenerator: def __init__(self): - self.model_normal = LLM_request( + self.model_normal = LLMRequest( model=global_config.llm_normal, temperature=global_config.llm_normal["temp"], max_tokens=256, request_type="response_heartflow", ) - self.model_sum = LLM_request( + self.model_sum = LLMRequest( model=global_config.llm_summary_by_topic, temperature=0.6, max_tokens=2000, request_type="relation" ) self.current_model_type = "r1" # 默认使用 R1 @@ -94,7 +94,7 @@ class ResponseGenerator: return None async def _generate_response_with_model( - self, message: MessageRecv, model: LLM_request, thinking_id: str, mode: str = "normal" + self, message: MessageRecv, model: LLMRequest, thinking_id: str, mode: str = "normal" ) -> str: sender_name = "" diff --git a/src/plugins/config/config.py b/src/plugins/config/config.py index 8238078c2..ebde77734 100644 --- a/src/plugins/config/config.py +++ b/src/plugins/config/config.py @@ -62,8 +62,7 @@ def update_config(): shutil.copy2(template_path, old_config_path) logger.info(f"已创建新配置文件,请填写后重新运行: {old_config_path}") # 如果是新创建的配置文件,直接返回 - quit() - return + return quit() # 读取旧配置文件和模板文件 with open(old_config_path, "r", encoding="utf-8") as f: diff --git a/src/plugins/memory_system/Hippocampus.py b/src/plugins/memory_system/Hippocampus.py index c2c090d58..2378011e2 100644 --- a/src/plugins/memory_system/Hippocampus.py +++ b/src/plugins/memory_system/Hippocampus.py @@ -9,7 +9,7 @@ import networkx as nx import numpy as np from collections import Counter from ...common.database import db -from ...plugins.models.utils_model import LLM_request +from ...plugins.models.utils_model import LLMRequest from src.common.logger import get_module_logger, LogConfig, MEMORY_STYLE_CONFIG from src.plugins.memory_system.sample_distribution import MemoryBuildScheduler # 分布生成器 from .memory_config import MemoryConfig @@ -91,7 +91,7 @@ memory_config = LogConfig( logger = get_module_logger("memory_system", config=memory_config) -class Memory_graph: +class MemoryGraph: def __init__(self): self.G = nx.Graph() # 使用 networkx 的图结构 @@ -229,7 +229,7 @@ class Memory_graph: # 海马体 class Hippocampus: def __init__(self): - self.memory_graph = Memory_graph() + self.memory_graph = MemoryGraph() self.llm_topic_judge = None self.llm_summary_by_topic = None self.entorhinal_cortex = None @@ -243,8 +243,8 @@ class Hippocampus: self.parahippocampal_gyrus = ParahippocampalGyrus(self) # 从数据库加载记忆图 self.entorhinal_cortex.sync_memory_from_db() - self.llm_topic_judge = LLM_request(self.config.llm_topic_judge, request_type="memory") - self.llm_summary_by_topic = LLM_request(self.config.llm_summary_by_topic, request_type="memory") + self.llm_topic_judge = LLMRequest(self.config.llm_topic_judge, request_type="memory") + self.llm_summary_by_topic = LLMRequest(self.config.llm_summary_by_topic, request_type="memory") def get_all_node_names(self) -> list: """获取记忆图中所有节点的名字列表""" @@ -346,7 +346,8 @@ class Hippocampus: Args: text (str): 输入文本 - num (int, optional): 需要返回的记忆数量。默认为5。 + max_memory_num (int, optional): 记忆数量限制。默认为3。 + max_memory_length (int, optional): 记忆长度限制。默认为2。 max_depth (int, optional): 记忆检索深度。默认为2。 fast_retrieval (bool, optional): 是否使用快速检索。默认为False。 如果为True,使用jieba分词和TF-IDF提取关键词,速度更快但可能不够准确。 @@ -540,7 +541,6 @@ class Hippocampus: Args: text (str): 输入文本 - num (int, optional): 需要返回的记忆数量。默认为5。 max_depth (int, optional): 记忆检索深度。默认为2。 fast_retrieval (bool, optional): 是否使用快速检索。默认为False。 如果为True,使用jieba分词和TF-IDF提取关键词,速度更快但可能不够准确。 @@ -937,7 +937,7 @@ class EntorhinalCortex: # 海马体 class Hippocampus: def __init__(self): - self.memory_graph = Memory_graph() + self.memory_graph = MemoryGraph() self.llm_topic_judge = None self.llm_summary_by_topic = None self.entorhinal_cortex = None @@ -951,8 +951,8 @@ class Hippocampus: self.parahippocampal_gyrus = ParahippocampalGyrus(self) # 从数据库加载记忆图 self.entorhinal_cortex.sync_memory_from_db() - self.llm_topic_judge = LLM_request(self.config.llm_topic_judge, request_type="memory") - self.llm_summary_by_topic = LLM_request(self.config.llm_summary_by_topic, request_type="memory") + self.llm_topic_judge = LLMRequest(self.config.llm_topic_judge, request_type="memory") + self.llm_summary_by_topic = LLMRequest(self.config.llm_summary_by_topic, request_type="memory") def get_all_node_names(self) -> list: """获取记忆图中所有节点的名字列表""" @@ -1054,8 +1054,9 @@ class Hippocampus: Args: text (str): 输入文本 - num (int, optional): 需要返回的记忆数量。默认为5。 - max_depth (int, optional): 记忆检索深度。默认为2。 + max_memory_num (int, optional): 返回的记忆条目数量上限。默认为3,表示最多返回3条与输入文本相关度最高的记忆。 + max_memory_length (int, optional): 每个主题最多返回的记忆条目数量。默认为2,表示每个主题最多返回2条相似度最高的记忆。 + max_depth (int, optional): 记忆检索深度。默认为3。值越大,检索范围越广,可以获取更多间接相关的记忆,但速度会变慢。 fast_retrieval (bool, optional): 是否使用快速检索。默认为False。 如果为True,使用jieba分词和TF-IDF提取关键词,速度更快但可能不够准确。 如果为False,使用LLM提取关键词,速度较慢但更准确。 @@ -1248,7 +1249,6 @@ class Hippocampus: Args: text (str): 输入文本 - num (int, optional): 需要返回的记忆数量。默认为5。 max_depth (int, optional): 记忆检索深度。默认为2。 fast_retrieval (bool, optional): 是否使用快速检索。默认为False。 如果为True,使用jieba分词和TF-IDF提取关键词,速度更快但可能不够准确。 diff --git a/src/plugins/memory_system/manually_alter_memory.py b/src/plugins/memory_system/manually_alter_memory.py index ce1883e57..818742113 100644 --- a/src/plugins/memory_system/manually_alter_memory.py +++ b/src/plugins/memory_system/manually_alter_memory.py @@ -177,7 +177,7 @@ def remove_mem_edge(hippocampus: Hippocampus): # 修改节点信息 def alter_mem_node(hippocampus: Hippocampus): - batchEnviroment = dict() + batch_environment = dict() while True: concept = input("请输入节点概念名(输入'终止'以结束):\n") if concept.lower() == "终止": @@ -229,7 +229,7 @@ def alter_mem_node(hippocampus: Hippocampus): break try: - user_exec(command, node_environment, batchEnviroment) + user_exec(command, node_environment, batch_environment) except Exception as e: console.print(e) console.print( @@ -239,7 +239,7 @@ def alter_mem_node(hippocampus: Hippocampus): # 修改边信息 def alter_mem_edge(hippocampus: Hippocampus): - batchEnviroment = dict() + batch_enviroment = dict() while True: source = input("请输入 **第一个节点** 名称(输入'终止'以结束):\n") if source.lower() == "终止": @@ -262,21 +262,21 @@ def alter_mem_edge(hippocampus: Hippocampus): console.print("[yellow]你将获得一个执行任意代码的环境[/yellow]") console.print("[red]你已经被警告过了。[/red]\n") - edgeEnviroment = {"source": "<节点名>", "target": "<节点名>", "strength": "<强度值,装在一个list里>"} + edge_environment = {"source": "<节点名>", "target": "<节点名>", "strength": "<强度值,装在一个list里>"} console.print( "[green]环境变量中会有env与batchEnv两个dict, env在切换节点时会清空, batchEnv在操作终止时才会清空[/green]" ) console.print( - f"[green] env 会被初始化为[/green]\n{edgeEnviroment}\n[green]且会在用户代码执行完毕后被提交 [/green]" + f"[green] env 会被初始化为[/green]\n{edge_environment}\n[green]且会在用户代码执行完毕后被提交 [/green]" ) console.print( "[yellow]为便于书写临时脚本,请手动在输入代码通过Ctrl+C等方式触发KeyboardInterrupt来结束代码执行[/yellow]" ) # 拷贝数据以防操作炸了 - edgeEnviroment["strength"] = [edge["strength"]] - edgeEnviroment["source"] = source - edgeEnviroment["target"] = target + edge_environment["strength"] = [edge["strength"]] + edge_environment["source"] = source + edge_environment["target"] = target while True: @@ -288,8 +288,8 @@ def alter_mem_edge(hippocampus: Hippocampus): except KeyboardInterrupt: # 稍微防一下小天才 try: - if isinstance(edgeEnviroment["strength"][0], int): - edge["strength"] = edgeEnviroment["strength"][0] + if isinstance(edge_environment["strength"][0], int): + edge["strength"] = edge_environment["strength"][0] else: raise Exception @@ -301,7 +301,7 @@ def alter_mem_edge(hippocampus: Hippocampus): break try: - user_exec(command, edgeEnviroment, batchEnviroment) + user_exec(command, edge_environment, batch_enviroment) except Exception as e: console.print(e) console.print( diff --git a/src/plugins/memory_system/offline_llm.py b/src/plugins/memory_system/offline_llm.py index 9c3fa81d9..fc50b17bc 100644 --- a/src/plugins/memory_system/offline_llm.py +++ b/src/plugins/memory_system/offline_llm.py @@ -10,7 +10,7 @@ from src.common.logger import get_module_logger logger = get_module_logger("offline_llm") -class LLM_request_off: +class LLMRequestOff: def __init__(self, model_name="deepseek-ai/DeepSeek-V3", **kwargs): self.model_name = model_name self.params = kwargs diff --git a/src/plugins/message/api.py b/src/plugins/message/api.py index 0c3e3a5a1..e01289e95 100644 --- a/src/plugins/message/api.py +++ b/src/plugins/message/api.py @@ -233,7 +233,8 @@ class MessageServer(BaseMessageHandler): async def send_message(self, message: MessageBase): await self.broadcast_to_platform(message.message_info.platform, message.to_dict()) - async def send_message_REST(self, url: str, data: Dict[str, Any]) -> Dict[str, Any]: + @staticmethod + async def send_message_rest(url: str, data: Dict[str, Any]) -> Dict[str, Any]: """发送消息到指定端点""" async with aiohttp.ClientSession() as session: try: diff --git a/src/plugins/models/utils_model.py b/src/plugins/models/utils_model.py index 604e74155..f9d563e49 100644 --- a/src/plugins/models/utils_model.py +++ b/src/plugins/models/utils_model.py @@ -16,7 +16,7 @@ from ..config.config import global_config logger = get_module_logger("model_utils") -class LLM_request: +class LLMRequest: # 定义需要转换的模型列表,作为类变量避免重复 MODELS_NEEDING_TRANSFORMATION = [ "o3-mini", diff --git a/src/plugins/person_info/person_info.py b/src/plugins/person_info/person_info.py index 7a8a0d1d5..2b15adc62 100644 --- a/src/plugins/person_info/person_info.py +++ b/src/plugins/person_info/person_info.py @@ -6,7 +6,7 @@ from typing import Any, Callable, Dict import datetime import asyncio import numpy as np -from src.plugins.models.utils_model import LLM_request +from src.plugins.models.utils_model import LLMRequest from src.plugins.config.config import global_config from src.individuality.individuality import Individuality @@ -56,7 +56,7 @@ person_info_default = { class PersonInfoManager: def __init__(self): self.person_name_list = {} - self.qv_name_llm = LLM_request( + self.qv_name_llm = LLMRequest( model=global_config.llm_normal, max_tokens=256, request_type="qv_name", @@ -107,7 +107,7 @@ class PersonInfoManager: db.person_info.insert_one(_person_info_default) - async def update_one_field(self, person_id: str, field_name: str, value, Data: dict = None): + async def update_one_field(self, person_id: str, field_name: str, value, data: dict = None): """更新某一个字段,会补全""" if field_name not in person_info_default.keys(): logger.debug(f"更新'{field_name}'失败,未定义的字段") @@ -118,11 +118,12 @@ class PersonInfoManager: if document: db.person_info.update_one({"person_id": person_id}, {"$set": {field_name: value}}) else: - Data[field_name] = value + data[field_name] = value logger.debug(f"更新时{person_id}不存在,已新建") - await self.create_person_info(person_id, Data) + await self.create_person_info(person_id, data) - async def has_one_field(self, person_id: str, field_name: str): + @staticmethod + async def has_one_field(person_id: str, field_name: str): """判断是否存在某一个字段""" document = db.person_info.find_one({"person_id": person_id}, {field_name: 1}) if document: diff --git a/src/plugins/personality_s/renqingziji.py b/src/plugins/personality_s/renqingziji.py index 04cbec099..ce4c268b8 100644 --- a/src/plugins/personality_s/renqingziji.py +++ b/src/plugins/personality_s/renqingziji.py @@ -38,7 +38,7 @@ else: print("将使用默认配置") -class PersonalityEvaluator_direct: +class PersonalityEvaluatorDirect: def __init__(self): self.personality_traits = {"开放性": 0, "严谨性": 0, "外向性": 0, "宜人性": 0, "神经质": 0} self.scenarios = [] @@ -135,7 +135,7 @@ def main(): print("\n准备好了吗?按回车键开始...") input() - evaluator = PersonalityEvaluator_direct() + evaluator = PersonalityEvaluatorDirect() final_scores = {"开放性": 0, "严谨性": 0, "外向性": 0, "宜人性": 0, "神经质": 0} dimension_counts = {trait: 0 for trait in final_scores.keys()} diff --git a/src/plugins/remote/remote.py b/src/plugins/remote/remote.py index bc7437057..58be19dde 100644 --- a/src/plugins/remote/remote.py +++ b/src/plugins/remote/remote.py @@ -125,12 +125,12 @@ def main(): if global_config.remote_enable: """主函数,启动心跳线程""" # 配置 - SERVER_URL = "http://hyybuth.xyz:10058" - # SERVER_URL = "http://localhost:10058" - HEARTBEAT_INTERVAL = 300 # 5分钟(秒) + server_url = "http://hyybuth.xyz:10058" + # server_url = "http://localhost:10058" + heartbeat_interval = 300 # 5分钟(秒) # 创建并启动心跳线程 - heartbeat_thread = HeartbeatThread(SERVER_URL, HEARTBEAT_INTERVAL) + heartbeat_thread = HeartbeatThread(server_url, heartbeat_interval) heartbeat_thread.start() return heartbeat_thread # 返回线程对象,便于外部控制 diff --git a/src/plugins/schedule/schedule_generator.py b/src/plugins/schedule/schedule_generator.py index f75065cf8..a67de28fc 100644 --- a/src/plugins/schedule/schedule_generator.py +++ b/src/plugins/schedule/schedule_generator.py @@ -11,7 +11,7 @@ sys.path.append(root_path) from src.common.database import db # noqa: E402 from src.common.logger import get_module_logger, SCHEDULE_STYLE_CONFIG, LogConfig # noqa: E402 -from src.plugins.models.utils_model import LLM_request # noqa: E402 +from src.plugins.models.utils_model import LLMRequest # noqa: E402 from src.plugins.config.config import global_config # noqa: E402 TIME_ZONE = tz.gettz(global_config.TIME_ZONE) # 设置时区 @@ -30,13 +30,13 @@ class ScheduleGenerator: def __init__(self): # 使用离线LLM模型 - self.llm_scheduler_all = LLM_request( + self.llm_scheduler_all = LLMRequest( model=global_config.llm_reasoning, temperature=global_config.SCHEDULE_TEMPERATURE + 0.3, max_tokens=7000, request_type="schedule", ) - self.llm_scheduler_doing = LLM_request( + self.llm_scheduler_doing = LLMRequest( model=global_config.llm_normal, temperature=global_config.SCHEDULE_TEMPERATURE, max_tokens=2048, diff --git a/src/plugins/topic_identify/topic_identifier.py b/src/plugins/topic_identify/topic_identifier.py index 743e45870..9a1797ecd 100644 --- a/src/plugins/topic_identify/topic_identifier.py +++ b/src/plugins/topic_identify/topic_identifier.py @@ -1,7 +1,7 @@ from typing import List, Optional -from ..models.utils_model import LLM_request +from ..models.utils_model import LLMRequest from ..config.config import global_config from src.common.logger import get_module_logger, LogConfig, TOPIC_STYLE_CONFIG @@ -17,7 +17,7 @@ logger = get_module_logger("topic_identifier", config=topic_config) class TopicIdentifier: def __init__(self): - self.llm_topic_judge = LLM_request(model=global_config.llm_topic_judge, request_type="topic") + self.llm_topic_judge = LLMRequest(model=global_config.llm_topic_judge, request_type="topic") async def identify_topic_llm(self, text: str) -> Optional[List[str]]: """识别消息主题,返回主题列表""" From 1a165c067a717546f01a7616bbdd2e747e6948e1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 16 Apr 2025 08:37:51 +0000 Subject: [PATCH 9/9] =?UTF-8?q?=F0=9F=A4=96=20=E8=87=AA=E5=8A=A8=E6=A0=BC?= =?UTF-8?q?=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/observation_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/PFC/observation_info.py b/src/plugins/PFC/observation_info.py index 97d9a6146..f92f12306 100644 --- a/src/plugins/PFC/observation_info.py +++ b/src/plugins/PFC/observation_info.py @@ -232,7 +232,7 @@ class ObservationInfo: """清空未处理消息列表""" # 将未处理消息添加到历史记录中 for message in self.unprocessed_messages: - self.chat_history.append(message) # TODO NEED FIX TYPE??? + self.chat_history.append(message) # TODO NEED FIX TYPE??? # 清空未处理消息列表 self.has_unread_messages = False self.unprocessed_messages.clear()