From 0964676bfb76cc3758d2764aa6e3906c09147a59 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Wed, 24 Sep 2025 17:32:47 +0800 Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9A=E8=A1=A8=E6=83=85=E5=8C=85?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=8F=92=E4=BB=B6=E5=8F=AF=E5=B7=A5=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/emoji_manage_plugin/plugin.py | 166 +++++++++------------ plugins/hello_world_plugin/plugin.py | 3 +- src/chat/express/expression_learner.py | 69 ++------- src/chat/heart_flow/heartFC_chat.py | 4 + src/chat/planner_actions/planner.py | 4 +- src/plugins/built_in/emoji_plugin/emoji.py | 31 ++-- 6 files changed, 112 insertions(+), 165 deletions(-) diff --git a/plugins/emoji_manage_plugin/plugin.py b/plugins/emoji_manage_plugin/plugin.py index 56a9aa71..b042cabb 100644 --- a/plugins/emoji_manage_plugin/plugin.py +++ b/plugins/emoji_manage_plugin/plugin.py @@ -18,18 +18,84 @@ from src.plugin_system import ( ) from maim_message import Seg from src.config.config import global_config +from src.common.logger import get_logger +logger = get_logger("emoji_manage_plugin") class AddEmojiCommand(BaseCommand): command_name = "add_emoji" command_description = "添加表情包" command_pattern = r".*/emoji add.*" - + async def execute(self) -> Tuple[bool, str, bool]: + # 查找消息中的表情包 + logger.info(f"查找消息中的表情包: {self.message.message_segment}") + emoji_base64_list = self.find_and_return_emoji_in_message(self.message.message_segment) - return True, f"找到了{len(emoji_base64_list)}个表情包", True - - def find_and_return_emoji_in_message(self, message_segments: List[Seg]) -> List[str]: + + if not emoji_base64_list: + return False, "未在消息中找到表情包或图片", False + + # 注册找到的表情包 + success_count = 0 + fail_count = 0 + results = [] + + for i, emoji_base64 in enumerate(emoji_base64_list): + try: + # 使用emoji_api注册表情包 + result = await emoji_api.register_emoji(emoji_base64, filename=f"emoji_{i+1}") + + if result["success"]: + success_count += 1 + description = result.get("description", "未知描述") + emotions = result.get("emotions", []) + replaced = result.get("replaced", False) + + result_msg = f"表情包 {i+1} 注册成功{'(替换旧表情包)' if replaced else '(新增表情包)'}" + if description: + result_msg += f"\n描述: {description}" + if emotions: + result_msg += f"\n情感标签: {', '.join(emotions)}" + + results.append(result_msg) + else: + fail_count += 1 + error_msg = result.get("message", "注册失败") + results.append(f"表情包 {i+1} 注册失败: {error_msg}") + + except Exception as e: + fail_count += 1 + results.append(f"表情包 {i+1} 注册时发生错误: {str(e)}") + + # 构建返回消息 + total_count = success_count + fail_count + summary_msg = f"表情包注册完成: 成功 {success_count} 个,失败 {fail_count} 个,共处理 {total_count} 个" + + # 如果有结果详情,添加到返回消息中 + if results: + details_msg = "\n" + "\n".join(results) + final_msg = summary_msg + details_msg + else: + final_msg = summary_msg + + return success_count > 0, final_msg, success_count > 0 + + def find_and_return_emoji_in_message(self, message_segments) -> List[str]: emoji_base64_list = [] + + # 处理单个Seg对象的情况 + if isinstance(message_segments, Seg): + if message_segments.type == "emoji": + emoji_base64_list.append(message_segments.data) + elif message_segments.type == "image": + # 假设图片数据是base64编码的 + emoji_base64_list.append(message_segments.data) + elif message_segments.type == "seglist": + # 递归处理嵌套的Seg列表 + emoji_base64_list.extend(self.find_and_return_emoji_in_message(message_segments.data)) + return emoji_base64_list + + # 处理Seg列表的情况 for seg in message_segments: if seg.type == "emoji": emoji_base64_list.append(seg.data) @@ -66,67 +132,6 @@ class ListEmojiCommand(BaseCommand): return True, f"显示了当前时间: {time_str}", True -class PrintMessage(BaseEventHandler): - """打印消息事件处理器 - 处理打印消息事件""" - - event_type = EventType.ON_MESSAGE - handler_name = "print_message_handler" - handler_description = "打印接收到的消息" - - async def execute(self, message: MaiMessages | None) -> Tuple[bool, bool, str | None, None, None]: - """执行打印消息事件处理""" - # 打印接收到的消息 - if self.get_config("print_message.enabled", False): - print(f"接收到消息: {message.raw_message if message else '无效消息'}") - return True, True, "消息已打印", None, None - - -class ForwardMessages(BaseEventHandler): - """ - 把接收到的消息转发到指定聊天ID - - 此组件是HYBRID消息和FORWARD消息的使用示例。 - 每收到10条消息,就会以1%的概率使用HYBRID消息转发,否则使用FORWARD消息转发。 - """ - - event_type = EventType.ON_MESSAGE - handler_name = "forward_messages_handler" - handler_description = "把接收到的消息转发到指定聊天ID" - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.counter = 0 # 用于计数转发的消息数量 - self.messages: List[str] = [] - - async def execute(self, message: MaiMessages | None) -> Tuple[bool, bool, None, None, None]: - if not message: - return True, True, None, None, None - stream_id = message.stream_id or "" - - if message.plain_text: - self.messages.append(message.plain_text) - self.counter += 1 - if self.counter % 10 == 0: - if random.random() < 0.01: - success = await self.send_hybrid(stream_id, [(ReplyContentType.TEXT, msg) for msg in self.messages]) - else: - success = await self.send_forward( - stream_id, - [ - ( - str(global_config.bot.qq_account), - str(global_config.bot.nickname), - [(ReplyContentType.TEXT, msg)], - ) - for msg in self.messages - ], - ) - if not success: - raise ValueError("转发消息失败") - self.messages = [] - return True, True, None, None, None - - class RandomEmojis(BaseCommand): command_name = "random_emojis" command_description = "发送多张随机表情包" @@ -169,36 +174,13 @@ class EmojiManagePlugin(BasePlugin): # 配置Schema定义 config_schema: dict = { "plugin": { - "version": ConfigField(type=str, default="1.0.0", description="插件版本"), - "enabled": ConfigField(type=bool, default=False, description="是否启用插件"), + "enabled": ConfigField(type=bool, default=True, description="是否启用插件"), + "config_version": ConfigField(type=str, default="1.0.1", description="配置文件版本"), }, } def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]: return [ - (PrintMessage.get_handler_info(), PrintMessage), - (ForwardMessages.get_handler_info(), ForwardMessages), (RandomEmojis.get_command_info(), RandomEmojis), - ] - - -# @register_plugin -# class HelloWorldEventPlugin(BaseEPlugin): -# """Hello World事件插件 - 处理问候和告别事件""" - -# plugin_name = "hello_world_event_plugin" -# enable_plugin = False -# dependencies = [] -# python_dependencies = [] -# config_file_name = "event_config.toml" - -# config_schema = { -# "plugin": { -# "name": ConfigField(type=str, default="hello_world_event_plugin", description="插件名称"), -# "version": ConfigField(type=str, default="1.0.0", description="插件版本"), -# "enabled": ConfigField(type=bool, default=True, description="是否启用插件"), -# }, -# } - -# def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]: -# return [(PrintMessage.get_handler_info(), PrintMessage)] + (AddEmojiCommand.get_command_info(), AddEmojiCommand), + ] \ No newline at end of file diff --git a/plugins/hello_world_plugin/plugin.py b/plugins/hello_world_plugin/plugin.py index 020748a3..3965ca97 100644 --- a/plugins/hello_world_plugin/plugin.py +++ b/plugins/hello_world_plugin/plugin.py @@ -237,8 +237,7 @@ class HelloWorldPlugin(BasePlugin): # 配置Schema定义 config_schema: dict = { "plugin": { - "name": ConfigField(type=str, default="hello_world_plugin", description="插件名称"), - "version": ConfigField(type=str, default="1.0.0", description="插件版本"), + "config_version": ConfigField(type=str, default="1.0.0", description="配置文件版本"), "enabled": ConfigField(type=bool, default=False, description="是否启用插件"), }, "greeting": { diff --git a/src/chat/express/expression_learner.py b/src/chat/express/expression_learner.py index e36d4d57..968586c2 100644 --- a/src/chat/express/expression_learner.py +++ b/src/chat/express/expression_learner.py @@ -62,6 +62,7 @@ class ExpressionLearner: model_set=model_config.model_task_config.replyer, request_type="expression.learner" ) self.chat_id = chat_id + self.chat_stream = get_chat_manager().get_stream(chat_id) self.chat_name = get_chat_manager().get_stream_name(chat_id) or chat_id # 维护每个chat的上次学习时间 @@ -69,24 +70,8 @@ class ExpressionLearner: # 学习参数 self.min_messages_for_learning = 25 # 触发学习所需的最少消息数 - self.min_learning_interval = 300 # 最短学习时间间隔(秒) - - def can_learn_for_chat(self) -> bool: - """ - 检查指定聊天流是否允许学习表达 - - Args: - chat_id: 聊天流ID - - Returns: - bool: 是否允许学习 - """ - try: - use_expression, enable_learning, _ = global_config.expression.get_expression_config_for_chat(self.chat_id) - return enable_learning - except Exception as e: - logger.error(f"检查学习权限失败: {e}") - return False + _, self.enable_learning, self.learning_intensity = global_config.expression.get_expression_config_for_chat(self.chat_id) + self.min_learning_interval = 300 / self.learning_intensity def should_trigger_learning(self) -> bool: """ @@ -98,27 +83,13 @@ class ExpressionLearner: Returns: bool: 是否应该触发学习 """ - current_time = time.time() - - # 获取该聊天流的学习强度 - try: - _, enable_learning, learning_intensity = global_config.expression.get_expression_config_for_chat( - self.chat_id - ) - except Exception as e: - logger.error(f"获取聊天流 {self.chat_id} 的学习配置失败: {e}") - return False - # 检查是否允许学习 - if not enable_learning: + if not self.enable_learning: return False - # 根据学习强度计算最短学习时间间隔 - min_interval = self.min_learning_interval / learning_intensity - # 检查时间间隔 - time_diff = current_time - self.last_learning_time - if time_diff < min_interval: + time_diff = time.time() - self.last_learning_time + if time_diff < self.min_learning_interval: return False # 检查消息数量(只检查指定聊天流的消息) @@ -228,32 +199,17 @@ class ExpressionLearner: """ 学习并存储表达方式 """ - # 检查是否允许在此聊天流中学习(在函数最前面检查) - if not self.can_learn_for_chat(): - logger.debug(f"聊天流 {self.chat_name} 不允许学习表达,跳过学习") - return [] - res = await self.learn_expression(num) if res is None: + logger.info("没有学习到表达风格") return [] learnt_expressions, chat_id = res - - chat_stream = get_chat_manager().get_stream(chat_id) - if chat_stream is None: - group_name = f"聊天流 {chat_id}" - elif chat_stream.group_info: - group_name = chat_stream.group_info.group_name - else: - group_name = f"{chat_stream.user_info.user_nickname}的私聊" learnt_expressions_str = "" for _chat_id, situation, style in learnt_expressions: learnt_expressions_str += f"{situation}->{style}\n" - logger.info(f"在 {group_name} 学习到表达风格:\n{learnt_expressions_str}") - - if not learnt_expressions: - logger.info("没有学习到表达风格") - return [] + + logger.info(f"在 {self.chat_name} 学习到表达风格:\n{learnt_expressions_str}") # 按chat_id分组 chat_dict: Dict[str, List[Dict[str, Any]]] = {} @@ -316,7 +272,7 @@ class ExpressionLearner: current_time = time.time() - # 获取上次学习时间 + # 获取上次学习之后的消息 random_msg = get_raw_msg_by_timestamp_with_chat_inclusive( chat_id=self.chat_id, timestamp_start=self.last_learning_time, @@ -330,14 +286,15 @@ class ExpressionLearner: chat_id: str = random_msg[0].chat_id # random_msg_str: str = build_readable_messages(random_msg, timestamp_mode="normal") random_msg_str: str = await build_anonymous_messages(random_msg) - # print(f"random_msg_str:{random_msg_str}") + prompt: str = await global_prompt_manager.format_prompt( prompt, chat_str=random_msg_str, ) - logger.debug(f"学习{type_str}的prompt: {prompt}") + print(f"random_msg_str:{random_msg_str}") + logger.info(f"学习{type_str}的prompt: {prompt}") try: response, _ = await self.express_learn_model.generate_response_async(prompt, temperature=0.3) diff --git a/src/chat/heart_flow/heartFC_chat.py b/src/chat/heart_flow/heartFC_chat.py index 778e0c3d..56d63fb4 100644 --- a/src/chat/heart_flow/heartFC_chat.py +++ b/src/chat/heart_flow/heartFC_chat.py @@ -344,6 +344,10 @@ class HeartFChatting: available_actions=available_actions, ) ) + + logger.info( + f"{self.log_prefix}决定执行{len(action_to_use_info)}个动作: {' '.join([a.action_type for a in action_to_use_info])}" + ) # 3. 并行执行所有动作 action_tasks = [ diff --git a/src/chat/planner_actions/planner.py b/src/chat/planner_actions/planner.py index ed59207a..46967075 100644 --- a/src/chat/planner_actions/planner.py +++ b/src/chat/planner_actions/planner.py @@ -502,8 +502,8 @@ class ActionPlanner: action.action_data = action.action_data or {} action.action_data["loop_start_time"] = loop_start_time - logger.info( - f"{self.log_prefix}规划器决定执行{len(actions)}个动作: {' '.join([a.action_type for a in actions])}" + logger.debug( + f"{self.log_prefix}规划器选择了{len(actions)}个动作: {' '.join([a.action_type for a in actions])}" ) return actions diff --git a/src/plugins/built_in/emoji_plugin/emoji.py b/src/plugins/built_in/emoji_plugin/emoji.py index da620d22..63a9cc51 100644 --- a/src/plugins/built_in/emoji_plugin/emoji.py +++ b/src/plugins/built_in/emoji_plugin/emoji.py @@ -46,8 +46,9 @@ class EmojiAction(BaseAction): """执行表情动作""" try: # 1. 获取发送表情的原因 - reason = self.action_data.get("reason", "表达当前情绪") - + # reason = self.action_data.get("reason", "表达当前情绪") + reason = self.reasoning + # 2. 随机获取20个表情包 sampled_emojis = await emoji_api.get_random(30) if not sampled_emojis: @@ -62,6 +63,9 @@ class EmojiAction(BaseAction): emotion_map[emo].append((b64, desc)) available_emotions = list(emotion_map.keys()) + available_emotions_str = "" + for emotion in available_emotions: + available_emotions_str += f"{emotion}\n" if not available_emotions: logger.warning(f"{self.log_prefix} 获取到的表情包均无情感标签, 将随机发送") @@ -80,14 +84,15 @@ class EmojiAction(BaseAction): ) # 4. 构建prompt让LLM选择情感 - prompt = f""" - 你是一个正在进行聊天的网友,你需要根据一个理由和最近的聊天记录,从一个情感标签列表中选择最匹配的一个。 - 这是最近的聊天记录: - {messages_text} - - 这是理由:“{reason}” - 这里是可用的情感标签:{available_emotions} - 请直接返回最匹配的那个情感标签,不要进行任何解释或添加其他多余的文字。 + prompt = f"""你正在进行QQ聊天,你需要根据聊天记录,选出一个合适的情感标签。 +请你根据以下原因和聊天记录进行选择 +原因:{reason} +聊天记录: +{messages_text} + +这里是可用的情感标签: +{available_emotions_str} +请直接返回最匹配的那个情感标签,不要进行任何解释或添加其他多余的文字。 """ if global_config.debug.show_prompt: @@ -97,10 +102,10 @@ class EmojiAction(BaseAction): # 5. 调用LLM models = llm_api.get_available_models() - chat_model_config = models.get("utils_small") # 使用字典访问方式 + chat_model_config = models.get("replyer") # 使用字典访问方式 if not chat_model_config: - logger.error(f"{self.log_prefix} 未找到'utils_small'模型配置,无法调用LLM") - return False, "未找到'utils_small'模型配置" + logger.error(f"{self.log_prefix} 未找到'replyer'模型配置,无法调用LLM") + return False, "未找到'replyer'模型配置" success, chosen_emotion, _, _ = await llm_api.generate_with_model( prompt, model_config=chat_model_config, request_type="emoji"