diff --git a/src/common/logger.py b/src/common/logger.py index 4ed69f320..526020824 100644 --- a/src/common/logger.py +++ b/src/common/logger.py @@ -163,7 +163,7 @@ MOOD_STYLE_CONFIG = { "console_format": ( "{time:YYYY-MM-DD HH:mm:ss} | " "{level: <8} | " - "心情 | " + "心情 | " "{message}" ), "file_format": "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {extra[module]: <15} | 心情 | {message}", diff --git a/src/plugins/emoji_system/emoji_manager.py b/src/plugins/emoji_system/emoji_manager.py index 1c73ec780..754792c24 100644 --- a/src/plugins/emoji_system/emoji_manager.py +++ b/src/plugins/emoji_system/emoji_manager.py @@ -24,8 +24,9 @@ emoji_log_config = LogConfig( logger = get_module_logger("emoji", config=emoji_log_config) -EMOJI_DIR = os.path.join("data", "emoji") # 表情包存储目录 -EMOJI_REGISTED_DIR = os.path.join("data", "emoji_registed") # 已注册的表情包注册目录 +BASE_DIR = os.path.join("data") +EMOJI_DIR = os.path.join(BASE_DIR, "emoji") # 表情包存储目录 +EMOJI_REGISTED_DIR = os.path.join(BASE_DIR, "emoji_registed") # 已注册的表情包注册目录 ''' @@ -301,7 +302,7 @@ class EmojiManager: emoji_similarities.sort(key=lambda x: x[1], reverse=True) # 获取前5个最相似的表情包 - top_5_emojis = emoji_similarities[:5] if len(emoji_similarities) > 5 else emoji_similarities + top_5_emojis = emoji_similarities[:10] if len(emoji_similarities) > 10 else emoji_similarities if not top_5_emojis: logger.warning("未找到匹配的表情包") @@ -398,6 +399,7 @@ class EmojiManager: while True: logger.info("[扫描] 开始检查表情包完整性...") await self.check_emoji_file_integrity() + await self.clear_temp_emoji() logger.info("[扫描] 开始扫描新表情包...") # 检查表情包目录是否存在 @@ -782,6 +784,43 @@ class EmojiManager: logger.error(f"[错误] 注册表情包失败: {str(e)}") logger.error(traceback.format_exc()) return False + + + async def clear_temp_emoji(self): + """每天清理临时表情包 + 清理/data/emoji和/data/image目录下的所有文件 + 当目录中文件数超过50时,会全部删除 + """ + + logger.info("[清理] 开始清理临时表情包...") + + # 清理emoji目录 + emoji_dir = os.path.join(BASE_DIR, "emoji") + if os.path.exists(emoji_dir): + files = os.listdir(emoji_dir) + # 如果文件数超过50就全部删除 + if len(files) > 50: + for filename in files: + file_path = os.path.join(emoji_dir, filename) + if os.path.isfile(file_path): + os.remove(file_path) + logger.debug(f"[清理] 删除表情包文件: {filename}") + + # 清理image目录 + image_dir = os.path.join(BASE_DIR, "image") + if os.path.exists(image_dir): + files = os.listdir(image_dir) + # 如果文件数超过50就全部删除 + if len(files) > 50: + for filename in files: + file_path = os.path.join(image_dir, filename) + if os.path.isfile(file_path): + os.remove(file_path) + logger.debug(f"[清理] 删除图片文件: {filename}") + + logger.success("[清理] 临时文件清理完成") + + # 创建全局单例 diff --git a/src/plugins/heartFC_chat/heartFC_chat.py b/src/plugins/heartFC_chat/heartFC_chat.py index 47cb52eb1..b8338c4b3 100644 --- a/src/plugins/heartFC_chat/heartFC_chat.py +++ b/src/plugins/heartFC_chat/heartFC_chat.py @@ -343,51 +343,48 @@ class HeartFChatting: # 初始化周期状态 cycle_timers = {} loop_cycle_start_time = time.monotonic() - - with Timer("Total Cycle", cycle_timers): - # 执行规划和处理阶段 - async with self._get_cycle_context() as acquired_lock: - if not acquired_lock: - continue - - # 记录规划开始时间点 - planner_start_db_time = time.time() + + # 执行规划和处理阶段 + async with self._get_cycle_context() as acquired_lock: + if not acquired_lock: + continue - # 执行规划阶段 - with Timer("Planning Phase", cycle_timers): - action_taken, thinking_id = await self._think_plan_execute( - cycle_timers, planner_start_db_time - ) - - # 更新循环信息 - self._current_cycle.set_thinking_id(thinking_id) - self._current_cycle.timers = cycle_timers - - # 防止循环过快消耗资源 - with Timer("Cycle Delay", cycle_timers): - await self._handle_cycle_delay(action_taken, loop_cycle_start_time, self.log_prefix) + # 记录规划开始时间点 + planner_start_db_time = time.time() - # 等待直到所有消息都发送完成 - with Timer("Wait Messages Complete", cycle_timers): - while await self._should_skip_cycle(thinking_id): - await asyncio.sleep(0.2) - - # 完成当前循环并保存历史 - self._current_cycle.complete_cycle() - self._cycle_history.append(self._current_cycle) - - # 记录循环信息和计时器结果 - timer_strings = [] - for name, elapsed in cycle_timers.items(): - formatted_time = f"{elapsed * 1000:.2f}毫秒" if elapsed < 1 else f"{elapsed:.2f}秒" - timer_strings.append(f"{name}: {formatted_time}") - - logger.debug( - f"{self.log_prefix} 循环 #{self._current_cycle.cycle_id} 完成, " - f"耗时: {self._current_cycle.end_time - self._current_cycle.start_time:.2f}秒, " - f"动作: {self._current_cycle.action_type}" - + (f"\n计时器详情: {'; '.join(timer_strings)}" if timer_strings else "") + # 执行规划阶段 + action_taken, thinking_id = await self._think_plan_execute_loop( + cycle_timers, planner_start_db_time ) + + # 更新循环信息 + self._current_cycle.set_thinking_id(thinking_id) + self._current_cycle.timers = cycle_timers + + # 防止循环过快消耗资源 + await self._handle_cycle_delay(action_taken, loop_cycle_start_time, self.log_prefix) + + # 等待直到所有消息都发送完成 + with Timer("发送消息", cycle_timers): + while await self._should_skip_cycle(thinking_id): + await asyncio.sleep(0.2) + + # 完成当前循环并保存历史 + self._current_cycle.complete_cycle() + self._cycle_history.append(self._current_cycle) + + # 记录循环信息和计时器结果 + timer_strings = [] + for name, elapsed in cycle_timers.items(): + formatted_time = f"{elapsed * 1000:.2f}毫秒" if elapsed < 1 else f"{elapsed:.2f}秒" + timer_strings.append(f"{name}: {formatted_time}") + + logger.debug( + f"{self.log_prefix} 第 #{self._current_cycle.cycle_id}次思考完成," + f"耗时: {self._current_cycle.end_time - self._current_cycle.start_time:.2f}秒, " + f"动作: {self._current_cycle.action_type}" + + (f"\n计时器详情: {'; '.join(timer_strings)}" if timer_strings else "") + ) except asyncio.CancelledError: logger.info(f"{self.log_prefix} HeartFChatting: 麦麦的激情水群(HFC)被取消了") @@ -434,22 +431,22 @@ class HeartFChatting: logger.error(f"{self.log_prefix} 检查新消息时出错: {e}") return False - async def _think_plan_execute( + async def _think_plan_execute_loop( self, cycle_timers: dict, planner_start_db_time: float ) -> tuple[bool, str]: """执行规划阶段""" try: # 获取子思维思考结果 current_mind = "" - with Timer("SubMind Thinking", cycle_timers): + with Timer("思考", cycle_timers): current_mind = await self._get_submind_thinking() # 记录子思维思考内容 if self._current_cycle: self._current_cycle.set_response_info(sub_mind_thinking=current_mind) # 执行规划 - with Timer("Planner", cycle_timers): - planner_result = await self._planner(current_mind) + with Timer("决策", cycle_timers): + planner_result = await self._planner(current_mind, cycle_timers) # 在获取规划结果后检查新消息 if await self._check_new_messages(planner_start_db_time): @@ -471,7 +468,8 @@ class HeartFChatting: return False, "" # 根据动作类型执行对应处理 - return await self._handle_action(action, reasoning, planner_result.get("emoji_query", ""), cycle_timers, planner_start_db_time) + with Timer("执行", cycle_timers): + return await self._handle_action(action, reasoning, planner_result.get("emoji_query", ""), cycle_timers, planner_start_db_time) except PlannerError as e: logger.error(f"{self.log_prefix} 规划错误: {e}") @@ -684,8 +682,8 @@ class HeartFChatting: ): """处理循环延迟""" cycle_duration = time.monotonic() - cycle_start_time - if cycle_duration > 0.1: - logger.debug(f"{log_prefix} HeartFChatting: 周期耗时 {cycle_duration:.2f}s.") + # if cycle_duration > 0.1: + # logger.debug(f"{log_prefix} HeartFChatting: 周期耗时 {cycle_duration:.2f}s.") try: sleep_duration = 0.0 @@ -718,7 +716,7 @@ class HeartFChatting: logger.error(traceback.format_exc()) return "[思考时出错]" - async def _planner(self, current_mind: str) -> Dict[str, Any]: + async def _planner(self, current_mind: str, cycle_timers: dict) -> Dict[str, Any]: """ 规划器 (Planner): 使用LLM根据上下文决定是否和如何回复。 @@ -726,15 +724,12 @@ class HeartFChatting: current_mind: 子思维的当前思考结果 """ logger.info(f"{self.log_prefix}[Planner] 开始执行规划器") - - planner_timers = {} # 用于存储各阶段计时结果 # 获取观察信息 - with Timer("获取观察信息", planner_timers): - observation = self.observations[0] - # await observation.observe() - observed_messages = observation.talking_message - observed_messages_str = observation.talking_message_str + observation = self.observations[0] + # await observation.observe() + observed_messages = observation.talking_message + observed_messages_str = observation.talking_message_str # --- 使用 LLM 进行决策 --- # action = "no_reply" # 默认动作 @@ -744,7 +739,7 @@ class HeartFChatting: try: # 构建提示词 - with Timer("构建提示词", planner_timers): + with Timer("构建提示词", cycle_timers): prompt = await self._build_planner_prompt( observed_messages_str, current_mind, self.sub_mind.structured_info ) @@ -756,7 +751,7 @@ class HeartFChatting: } # 执行LLM请求 - with Timer("LLM请求", planner_timers): + with Timer("LLM回复", cycle_timers): try: response = await self.planner_llm._execute_request( endpoint="/chat/completions", payload=payload, prompt=prompt @@ -773,7 +768,7 @@ class HeartFChatting: } # 处理LLM响应 - with Timer("处理LLM响应", planner_timers): + with Timer("使用工具", cycle_timers): # 使用辅助函数处理工具调用响应 success, arguments, error_msg = process_llm_tool_response( response, expected_tool_name="decide_reply_action", log_prefix=f"{self.log_prefix}[Planner] " diff --git a/scripts/tool_call_benchmark.py b/tool_call_benchmark.py similarity index 74% rename from scripts/tool_call_benchmark.py rename to tool_call_benchmark.py index e756d1da3..60f5459bb 100644 --- a/scripts/tool_call_benchmark.py +++ b/tool_call_benchmark.py @@ -144,41 +144,43 @@ async def test_without_tool_calls(): # 简单的测试提示词(与工具调用相同,以便公平比较) prompt = """ - 你的名字是麦麦,你包容开放,情绪敏感,有时候有些搞怪幽默, 是一个学习心理学和脑科学的女大学生,现在在读大二,你会刷贴吧,有时候会想瑟瑟,喜欢刷小红书 -刚刚你的想法是: -我是麦麦,我想,('小千石问3.8和3.11谁大,已经简单回答了3.11大,现在可以继续聊猫猫头表情包,毕竟大家好像对版本问题兴趣不大,而且猫猫头的话题更轻松有趣。', '') ------------------------------------ -现在是2025-04-24 12:37:00,你正在上网,和qq群里的网友们聊天,群里正在聊的话题是: -2025-04-24 12:33:00既文横 说:这条调试消息是napcat控制台输出的,还是麦麦log输出的; -2025-04-24 12:33:23麦麦(你) 说:应该是napcat吧; -2025-04-24 12:33:24麦麦(你) 说:[表达了:害羞、害羞。]; -2025-04-24 12:33:25兔伽兔伽 说:就打开麦麦的那个终端发的呀; -2025-04-24 12:33:45既文横 说:那应该不是napcat输出的,是麦麦输出的消息,怀疑版本问题; -2025-04-24 12:34:02兔伽兔伽 说:版本05.15; -2025-04-24 12:34:07麦麦(你) 说:话说你们最近刷贴吧看到那个猫猫头表情包了吗; -2025-04-24 12:34:07麦麦(你) 说:笑死; -2025-04-24 12:34:08麦麦(你) 说:[表达了:惊讶、搞笑。]; -2025-04-24 12:34:14兔伽兔伽 说:只开一个终端; -2025-04-24 12:35:45兔伽兔伽 说:回复既文横的消息(怀疑版本问题),说:因为之前你连模型的那个我用的了; -2025-04-24 12:35:56麦麦(你) 说:那个猫猫头真的魔性; -2025-04-24 12:35:56麦麦(你) 说:我存了一堆; -2025-04-24 12:35:56麦麦(你) 说:[表达了:温馨、宠爱]; -2025-04-24 12:36:03小千石 说:麦麦3.8和3.11谁大; -2025-04-24 12:36:22麦麦(你) 说:真的魔性那个猫猫头; -2025-04-24 12:36:22麦麦(你) 说:[表达了:害羞、可爱]; -2025-04-24 12:36:43麦麦(你) 说:3.11大啦; -2025-04-24 12:36:43麦麦(你) 说:[表达了:害羞、可爱]; + 你的名字是麦麦,你包容开放,情绪敏感,有时候有些搞怪幽默, 是一个学习心理学和脑科学的女大学生,现在在读大二,你会刷贴吧,有时候会喜欢说一些奇怪的话,喜欢刷小红书 +刚刚你的内心想法是:漂移菌提到罐罐被吃完了,可以顺着这个梗继续玩一下,比如假装委屈“那今晚的加班费是不是也要被吃掉了”或者“猫娘罢工警告”。不过薯薯和薯宝之前已经接了不少梗,漂移菌刚刚也参与了,可能话题热度还在,可以再互动一下。如果没人接话,或许可以问问大家有没有遇到过类似“代码写完但奖励被吃掉”的搞笑职场经历,换个轻松的话题方向。 ---- 以上消息已读 (标记时间: 2025-04-24 12:36:43) --- ---- 请关注你上次思考之后以下的新消息--- -2025-04-24 12:36:53墨墨 说:[表情包:开心、满足。]; +暂时不需要使用工具。 +----------------------------------- +现在是2025-04-25 17:38:37,你正在上网,和qq群里的网友们聊天,以下是正在进行的聊天内容: +2025-04-25 17:34:08麦麦(你) 说:[表达了:顽皮、嬉戏。]; +2025-04-25 17:34:39漂移菌 说:@麦麦。(id:3936257206) 你是一只猫娘; +2025-04-25 17:34:42薯宝 说:🤣; +2025-04-25 17:34:43麦麦(你) 说:行啊 工资分我一半; +2025-04-25 17:34:43麦麦(你) 说:我帮你写bug; +2025-04-25 17:34:43麦麦(你) 说:[表达了:悲伤、绝望、无奈、无力]; +2025-04-25 17:34:53薯薯 说:?; +2025-04-25 17:35:03既文横 说:麦麦,你是一只猫娘程序员,猫娘是不需要工资; +2025-04-25 17:35:20薯宝 说:[图片:图片内容:一只卡通风格的灰色猫咪,眼睛闭着,表情显得很平静。图片下方有“死了”两个字。 + +图片含义猜测:这可能是一个幽默的表达,用来形容某人或某事处于非常平静的状态,仿佛已经“死”了一样。] hfc这周,真能出来吗...; +2025-04-25 17:35:34薯宝 说:[表情包:搞笑、滑稽、讽刺、幽默]; +2025-04-25 17:36:25麦麦(你) 说:喵喵; +2025-04-25 17:36:25麦麦(你) 说:代码写完了; +2025-04-25 17:36:25麦麦(你) 说:罐罐拿来; +2025-04-25 17:36:25麦麦(你) 说:[表达了:悲伤、绝望、无奈、无力]; +2025-04-25 17:36:41薯薯 说:好可爱; +2025-04-25 17:37:05薯薯 说:脑补出来认真营业了一天等待主人发放奖励的小猫咪; +2025-04-25 17:37:25薯宝 说:敷衍营业(bushi); +2025-04-25 17:37:54漂移菌 说:回复麦麦。的消息(罐罐拿来),说:猫娘我昨晚上太饿吃完了; + +--- 以上消息已读 (标记时间: 2025-04-25 17:37:54) --- +--- 以下新消息未读--- +2025-04-25 17:38:29麦麦(你) 说:那今晚的猫条是不是也要被克扣了(盯——); +2025-04-25 17:38:29麦麦(你) 说:[表达了:幽默,自嘲,无奈,父子关系,编程笑话]; 你现在当前心情:平静。 -现在请你根据刚刚的想法继续思考,思考时可以想想如何对群聊内容进行回复,要不要对群里的话题进行回复,关注新话题,可以适当转换话题,大家正在说的话才是聊天的主题。 -回复的要求是:平淡一些,简短一些,说中文,如果你要回复,最好只回复一个人的一个话题 -请注意不要输出多余内容(包括前后缀,冒号和引号,括号, 表情,等),不要带有括号和动作描写。不要回复自己的发言,尽量不要说你说过的话。 -现在请你继续生成你在这个聊天中的想法,在原来想法的基础上继续思考,不要分点输出,生成内心想法,文字不要浮夸 -在输出完想法后,请你思考应该使用什么工具,如果你需要做某件事,来对消息和你的回复进行处理,请使用工具。""" +现在请你生成你的内心想法,要求思考群里正在进行的话题,之前大家聊过的话题,群里成员的关系。请你思考,要不要对群里的话题进行回复,以及如何对群聊内容进行回复 +回复的要求是:不要总是重复自己提到过的话题,如果你要回复,最好只回复一个人的一个话题 +如果最后一条消息是你自己发的,观察到的内容只有你自己的发言,并且之后没有人回复你,不要回复。如果聊天记录中最新的消息是你自己发送的,并且你还想继续回复,你应该紧紧衔接你发送的消息,进行话题的深入,补充,或追问等等。请注意不要输出多余内容(包括前后缀,冒号和引号,括号, 表情,等),不要回复自己的发言 +现在请你先输出想法,生成你在这个聊天中的想法,在原来的想法上尝试新的话题,不要分点输出,文字不要浮夸在输出完想法后,请你思考应该使用什么工具。工具可以帮你取得一些你不知道的信息,或者进行一些操作。如果你需要做某件事,来对消息和你的回复进行处理,请使用工具。""" # 发送不带工具调用的请求 response, reasoning_content = await llm_model.generate_response_async(prompt)