import random from typing import Tuple # 导入新插件系统 from src.plugin_system import BaseAction, ActionActivationType # 导入依赖的系统组件 from src.common.logger import get_logger # 导入API模块 - 标准Python包方式 from src.plugin_system.apis import emoji_api, llm_api, message_api # NoReplyAction已集成到heartFC_chat.py中,不再需要导入 from src.config.config import global_config logger = get_logger("emoji") class EmojiAction(BaseAction): """表情动作 - 发送表情包""" activation_type = ActionActivationType.RANDOM random_activation_probability = global_config.emoji.emoji_chance parallel_action = True # 动作基本信息 action_name = "emoji" action_description = "发送表情包辅助表达情绪" # 动作参数定义 action_parameters = {} # 动作使用场景 action_require = [ "发送表情包辅助表达情绪", "表达情绪时可以选择使用", "不要连续发送,如果你已经发过[表情包],就不要选择此动作", ] # 关联类型 associated_types = ["emoji"] async def execute(self) -> Tuple[bool, str]: # sourcery skip: assign-if-exp, introduce-default-else, swap-if-else-branches, use-named-expression """执行表情动作""" try: # 1. 获取发送表情的原因 # reason = self.action_data.get("reason", "表达当前情绪") reason = self.action_reasoning # 2. 随机获取20个表情包 sampled_emojis = await emoji_api.get_random(30) if not sampled_emojis: logger.warning(f"{self.log_prefix} 无法获取随机表情包") return False, "无法获取随机表情包" # 3. 准备情感数据 emotion_map = {} for b64, desc, emo in sampled_emojis: if emo not in emotion_map: emotion_map[emo] = [] 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} 获取到的表情包均无情感标签, 将随机发送") emoji_base64, emoji_description, _ = random.choice(sampled_emojis) else: # 获取最近的5条消息内容用于判断 recent_messages = message_api.get_recent_messages(chat_id=self.chat_id, limit=5) messages_text = "" if recent_messages: # 使用message_api构建可读的消息字符串 messages_text = message_api.build_readable_messages( messages=recent_messages, timestamp_mode="normal_no_YMD", truncate=False, show_actions=False, ) # 4. 构建prompt让LLM选择情感 prompt = f"""你正在进行QQ聊天,你需要根据聊天记录,选出一个合适的情感标签。 请你根据以下原因和聊天记录进行选择 原因:{reason} 聊天记录: {messages_text} 这里是可用的情感标签: {available_emotions_str} 请直接返回最匹配的那个情感标签,不要进行任何解释或添加其他多余的文字。 """ if global_config.debug.show_prompt: logger.info(f"{self.log_prefix} 生成的LLM Prompt: {prompt}") else: logger.debug(f"{self.log_prefix} 生成的LLM Prompt: {prompt}") # 5. 调用LLM models = llm_api.get_available_models() chat_model_config = models.get("utils") # 使用字典访问方式 if not chat_model_config: logger.error(f"{self.log_prefix} 未找到'utils'模型配置,无法调用LLM") return False, "未找到'utils'模型配置" success, chosen_emotion, _, _ = await llm_api.generate_with_model( prompt, model_config=chat_model_config, request_type="emoji.select" ) if not success: logger.error(f"{self.log_prefix} LLM调用失败: {chosen_emotion}") return False, f"LLM调用失败: {chosen_emotion}" chosen_emotion = chosen_emotion.strip().replace('"', "").replace("'", "") logger.info(f"{self.log_prefix} LLM选择的情感: {chosen_emotion}") # 6. 根据选择的情感匹配表情包 if chosen_emotion in emotion_map: emoji_base64, emoji_description = random.choice(emotion_map[chosen_emotion]) logger.info(f"{self.log_prefix} 发送表情包[{chosen_emotion}],原因: {reason}") else: logger.warning( f"{self.log_prefix} LLM选择的情感 '{chosen_emotion}' 不在可用列表中, 将随机选择一个表情包" ) emoji_base64, emoji_description, _ = random.choice(sampled_emojis) # 7. 发送表情包 success = await self.send_emoji(emoji_base64) if success: # 存储动作信息 await self.store_action_info( action_build_into_prompt=True, action_prompt_display=f"你发送了表情包,原因:{reason}", action_done=True, ) return True, f"成功发送表情包:[表情包:{chosen_emotion}]" else: error_msg = "发送表情包失败" logger.error(f"{self.log_prefix} {error_msg}") await self.send_text("执行表情包动作失败") return False, error_msg except Exception as e: logger.error(f"{self.log_prefix} 表情动作执行失败: {e}", exc_info=True) return False, f"表情发送失败: {str(e)}"