import re from typing import List, Tuple, Type from src.plugin_system import ( BasePlugin, register_plugin, BaseAction, ComponentInfo, ActionActivationType, ConfigField, ) from src.common.logger import get_logger from .qq_emoji_list import qq_face from src.plugin_system.base.component_types import ChatType logger = get_logger("set_emoji_like_plugin") def get_emoji_id(emoji_input: str) -> str | None: """根据输入获取表情ID""" # 如果输入本身就是数字ID,直接返回 if emoji_input.isdigit() or (isinstance(emoji_input, str) and emoji_input.startswith("😊")): if emoji_input in qq_face: return emoji_input # 尝试从 "[表情:xxx]" 格式中提取 match = re.search(r"\[表情:(.+?)\]", emoji_input) if match: emoji_name = match.group(1).strip() else: emoji_name = emoji_input.strip() # 遍历查找 for key, value in qq_face.items(): # value 的格式是 "[表情:xxx]" if f"[表情:{emoji_name}]" == value: return key return None # ===== Action组件 ===== class SetEmojiLikeAction(BaseAction): """设置消息表情回应""" # === 基本信息(必须填写)=== action_name = "set_emoji_like" action_description = "为某条已经存在的消息添加‘贴表情’回应(类似点赞),而不是发送新消息。可以在觉得某条消息非常有趣、值得赞同或者需要特殊情感回应时主动使用。" activation_type = ActionActivationType.ALWAYS # 消息接收时激活(?) chat_type_allow = ChatType.GROUP parallel_action = True # === 功能描述(必须填写)=== # 从 qq_face 字典中提取所有表情名称用于提示 emoji_options = [] for name in qq_face.values(): match = re.search(r"\[表情:(.+?)\]", name) if match: emoji_options.append(match.group(1)) action_parameters = { "emoji": f"要回应的表情,必须从以下表情中选择: {', '.join(emoji_options)}", "set": "是否设置回应 (True/False)", } action_require = [ "当需要对一个已存在消息进行‘贴表情’回应时使用", "这是一个对旧消息的操作,而不是发送新消息", "如果你想发送一个新的表情包消息,请使用 'emoji' 动作", ] llm_judge_prompt = """ 判定是否需要使用贴表情动作的条件: 1. 用户明确要求使用贴表情包 2. 这是一个适合表达强烈情绪的场合 3. 不要发送太多表情包,如果你已经发送过多个表情包则回答"否" 请回答"是"或"否"。 """ associated_types = ["text"] async def execute(self) -> Tuple[bool, str]: """执行设置表情回应的动作""" message_id = None if self.has_action_message: logger.debug(str(self.action_message)) if isinstance(self.action_message, dict): message_id = self.action_message.get("message_id") logger.info(f"获取到的消息ID: {message_id}") else: logger.error("未提供消息ID") await self.store_action_info( action_build_into_prompt=True, action_prompt_display=f"执行了set_emoji_like动作:{self.action_name},失败: 未提供消息ID", action_done=False, ) return False, "未提供消息ID" emoji_input = self.action_data.get("emoji") set_like = self.action_data.get("set", True) if not emoji_input: logger.error("未提供表情") return False, "未提供表情" logger.info(f"设置表情回应: {emoji_input}, 是否设置: {set_like}") emoji_id = get_emoji_id(emoji_input) if not emoji_id: logger.error(f"找不到表情: '{emoji_input}'。请从可用列表中选择。") await self.store_action_info( action_build_into_prompt=True, action_prompt_display=f"执行了set_emoji_like动作:{self.action_name},失败: 找不到表情: '{emoji_input}'", action_done=False, ) return False, f"找不到表情: '{emoji_input}'。请从可用列表中选择。" # 4. 使用适配器API发送命令 if not message_id: logger.error("未提供消息ID") await self.store_action_info( action_build_into_prompt=True, action_prompt_display=f"执行了set_emoji_like动作:{self.action_name},失败: 未提供消息ID", action_done=False, ) return False, "未提供消息ID" try: # 使用适配器API发送贴表情命令 success = await self.send_command( command_name="set_emoji_like", args={"message_id": message_id, "emoji_id": emoji_id, "set": set_like}, storage_message=False ) if success: logger.info("设置表情回应成功") await self.store_action_info( action_build_into_prompt=True, action_prompt_display=f"执行了set_emoji_like动作,{emoji_input},设置表情回应: {emoji_id}, 是否设置: {set_like}", action_done=True, ) return True, "成功设置表情回应" else: logger.error("设置表情回应失败") await self.store_action_info( action_build_into_prompt=True, action_prompt_display=f"执行了set_emoji_like动作:{self.action_name},失败", action_done=False, ) return False, "设置表情回应失败" except Exception as e: logger.error(f"设置表情回应失败: {e}") await self.store_action_info( action_build_into_prompt=True, action_prompt_display=f"执行了set_emoji_like动作:{self.action_name},失败: {e}", action_done=False, ) return False, f"设置表情回应失败: {e}" # ===== 插件注册 ===== @register_plugin class SetEmojiLikePlugin(BasePlugin): """设置消息表情回应插件""" # 插件基本信息 plugin_name: str = "set_emoji_like" # 内部标识符 enable_plugin: bool = True dependencies: List[str] = [] # 插件依赖列表 python_dependencies: List[str] = [] # Python包依赖列表,现在使用内置API config_file_name: str = "config.toml" # 配置文件名 # 配置节描述 config_section_descriptions = {"plugin": "插件基本信息", "components": "插件组件"} # 配置Schema定义 config_schema: dict = { "plugin": { "name": ConfigField(type=str, default="set_emoji_like", description="插件名称"), "version": ConfigField(type=str, default="1.0.0", description="插件版本"), "enabled": ConfigField(type=bool, default=True, description="是否启用插件"), "config_version": ConfigField(type=str, default="1.1", description="配置版本"), }, "components": { "action_set_emoji_like": ConfigField(type=bool, default=True, description="是否启用设置表情回应功能"), }, } def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]: if self.get_config("components.action_set_emoji_like"): return [ (SetEmojiLikeAction.get_action_info(), SetEmojiLikeAction), ] return []