diff --git a/.gitignore b/.gitignore index ab81d587b..eb8391a92 100644 --- a/.gitignore +++ b/.gitignore @@ -312,3 +312,5 @@ run_pet.bat /plugins/* !/plugins !/plugins/example_plugin + +config.toml \ No newline at end of file diff --git a/docs/plugins/quick-start.md b/docs/plugins/quick-start.md index a0bb5f530..2b5f38779 100644 --- a/docs/plugins/quick-start.md +++ b/docs/plugins/quick-start.md @@ -122,7 +122,7 @@ class HelloWorldPlugin(BasePlugin): plugin_description = "Hello World演示插件,展示基本的Action和Command用法" plugin_version = "1.0.0" plugin_author = "你的名字" - enable_plugin = True + enable_plugin = True # 默认启用插件 config_file_name = "config.toml" # Python依赖声明(可选) @@ -329,6 +329,53 @@ A: 检查: 2. 命令格式是否精确匹配 3. 是否有其他插件拦截了消息 +## 🔧 插件启用状态管理 + +### 启用状态控制方式 + +插件可以通过以下两种方式控制启用状态: + +1. **类属性控制** +```python +class MyPlugin(BasePlugin): + enable_plugin = True # 在类中设置启用状态 +``` + +2. **配置文件控制** +```toml +[plugin] +enabled = true # 在配置文件中设置启用状态 +``` + +### 启用状态优先级 + +1. 配置文件中的设置优先级高于类属性 +2. 如果配置文件中没有 `[plugin] enabled` 设置,则使用类属性中的值 +3. 如果类属性也没有设置,则使用 `BasePlugin` 的默认值 `False` + +### 最佳实践 + +1. 在开发插件时,建议在类中设置 `enable_plugin = True` +2. 在部署插件时,通过配置文件控制启用状态 +3. 在文档中明确说明插件的默认启用状态 +4. 提供配置示例,说明如何启用/禁用插件 + +### 常见问题 + +1. **插件未加载** + - 检查类属性 `enable_plugin` 是否设置为 `True` + - 检查配置文件中的 `[plugin] enabled` 设置 + - 查看日志中是否有插件加载相关的错误信息 + +2. **配置文件不生效** + - 确保配置文件名称正确(默认为 `config.toml`) + - 确保配置文件格式正确(TOML格式) + - 确保配置文件中的 `[plugin]` 部分存在 + +3. **动态启用/禁用** + - 修改配置文件后需要重启MaiBot才能生效 + - 目前不支持运行时动态启用/禁用插件 + --- 🎉 **成功!你已经掌握了MaiBot插件开发的基础!** \ No newline at end of file diff --git a/plugins/example_plugin/config.toml b/plugins/example_plugin/config.toml deleted file mode 100644 index 30ed2368e..000000000 --- a/plugins/example_plugin/config.toml +++ /dev/null @@ -1,63 +0,0 @@ -# 综合示例插件配置文件 - -[plugin] -name = "example_plugin" -version = "2.0.0" -enabled = true -description = "展示新插件系统完整功能的示例插件" - -# 组件启用控制 -[components] -enable_greeting = false -enable_helpful = false -enable_help = false -enable_send = false -enable_echo = false -enable_info = false -enable_dice = false - -# 智能问候配置 -[greeting] -template = "你好,{username}!欢迎使用MaiBot综合插件系统!" -enable_emoji = true -enable_llm = false # 是否使用LLM生成个性化问候 - -# 消息发送配置 -[send] -max_message_length = 500 -enable_length_check = true -default_platform = "qq" - -# 回声命令配置 -[echo] -max_length = 200 -enable_formatting = true - -# 消息信息配置 -[info] -show_detailed_info = true -include_stream_info = true -max_content_preview = 100 - -# 智能帮助配置 -[helpful] -enable_llm = false -enable_emoji = true -random_activation_probability = 0.15 - -# 帮助系统配置 -[help] -show_extended_help = true -include_action_info = true -include_config_info = true -enable_llm = false -enable_emoji = true - -# 骰子命令配置 -[dice] -enable_dice = true - -# 日志配置 -[logging] -level = "INFO" -prefix = "[ExampleComprehensive]" \ No newline at end of file diff --git a/src/plugin_system/base/base_plugin.py b/src/plugin_system/base/base_plugin.py index 0636ebeb6..21d1658fe 100644 --- a/src/plugin_system/base/base_plugin.py +++ b/src/plugin_system/base/base_plugin.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import Dict, List, Type, Optional, Any +from typing import Dict, List, Type, Optional, Any, Union import os import inspect import toml @@ -9,6 +9,7 @@ from src.plugin_system.base.component_types import ( ComponentInfo, PythonDependency, ) +from src.plugin_system.base.config_types import ConfigField from src.plugin_system.core.component_registry import component_registry logger = get_logger("base_plugin") @@ -31,11 +32,15 @@ class BasePlugin(ABC): plugin_description: str = "" # 插件描述 plugin_version: str = "1.0.0" # 插件版本 plugin_author: str = "" # 插件作者 - enable_plugin: bool = True # 是否启用插件 + enable_plugin: bool = False # 是否启用插件 dependencies: List[str] = [] # 依赖的其他插件 python_dependencies: List[PythonDependency] = [] # Python包依赖 config_file_name: Optional[str] = None # 配置文件名 + # 新增:配置定义 + config_schema: Dict[str, Union[Dict[str, ConfigField], str]] = {} + config_section_descriptions: Dict[str, str] = {} + def __init__(self, plugin_dir: str = None): """初始化插件 @@ -74,6 +79,61 @@ class BasePlugin(ABC): if not self.plugin_description: raise ValueError(f"插件 {self.plugin_name} 必须定义 plugin_description") + def _generate_and_save_default_config(self, config_file_path: str): + """根据插件的Schema生成并保存默认配置文件""" + if not self.config_schema: + logger.debug(f"{self.log_prefix} 插件未定义config_schema,不生成配置文件") + return + + toml_str = f"# {self.plugin_name} - 自动生成的配置文件\n" + toml_str += f"# {self.plugin_description}\n\n" + + # 遍历每个配置节 + for section, fields in self.config_schema.items(): + # 添加节描述 + if section in self.config_section_descriptions: + toml_str += f"# {self.config_section_descriptions[section]}\n" + + toml_str += f"[{section}]\n\n" + + # 遍历节内的字段 + if isinstance(fields, dict): + for field_name, field in fields.items(): + if isinstance(field, ConfigField): + # 添加字段描述 + toml_str += f"# {field.description}" + if field.required: + toml_str += " (必需)" + toml_str += "\n" + + # 如果有示例值,添加示例 + if field.example: + toml_str += f"# 示例: {field.example}\n" + + # 如果有可选值,添加说明 + if field.choices: + choices_str = ", ".join(map(str, field.choices)) + toml_str += f"# 可选值: {choices_str}\n" + + # 添加字段值 + value = field.default + if isinstance(value, str): + toml_str += f'{field_name} = "{value}"\n' + elif isinstance(value, bool): + toml_str += f'{field_name} = {str(value).lower()}\n' + else: + toml_str += f"{field_name} = {value}\n" + + toml_str += "\n" + toml_str += "\n" + + try: + with open(config_file_path, "w", encoding="utf-8") as f: + f.write(toml_str) + logger.info(f"{self.log_prefix} 已生成默认配置文件: {config_file_path}") + except IOError as e: + logger.error(f"{self.log_prefix} 保存默认配置文件失败: {e}", exc_info=True) + def _load_plugin_config(self): """加载插件配置文件""" if not self.config_file_name: @@ -100,7 +160,11 @@ class BasePlugin(ABC): config_file_path = os.path.join(plugin_dir, self.config_file_name) if not os.path.exists(config_file_path): - logger.warning(f"{self.log_prefix} 配置文件 {config_file_path} 不存在") + logger.info(f"{self.log_prefix} 配置文件 {config_file_path} 不存在,将生成默认配置。") + self._generate_and_save_default_config(config_file_path) + + if not os.path.exists(config_file_path): + logger.warning(f"{self.log_prefix} 配置文件 {config_file_path} 不存在且无法生成。") return file_ext = os.path.splitext(self.config_file_name)[1].lower() diff --git a/src/plugin_system/base/config_types.py b/src/plugin_system/base/config_types.py new file mode 100644 index 000000000..c3f997282 --- /dev/null +++ b/src/plugin_system/base/config_types.py @@ -0,0 +1,18 @@ +""" +插件系统配置类型定义 +""" + +from typing import Any, Optional, List +from dataclasses import dataclass, field + + +@dataclass +class ConfigField: + """配置字段定义""" + + type: type # 字段类型 + default: Any # 默认值 + description: str # 字段描述 + example: Optional[str] = None # 示例值 + required: bool = False # 是否必需 + choices: Optional[List[Any]] = field(default_factory=list) # 可选值列表 \ No newline at end of file diff --git a/src/plugins/built_in/core_actions/config.toml b/src/plugins/built_in/core_actions/1config.toml similarity index 100% rename from src/plugins/built_in/core_actions/config.toml rename to src/plugins/built_in/core_actions/1config.toml diff --git a/src/plugins/built_in/core_actions/plugin.py b/src/plugins/built_in/core_actions/plugin.py index 70a3b4f76..67ea65fd6 100644 --- a/src/plugins/built_in/core_actions/plugin.py +++ b/src/plugins/built_in/core_actions/plugin.py @@ -11,6 +11,7 @@ from typing import List, Tuple, Type, Optional # 导入新插件系统 from src.plugin_system import BasePlugin, register_plugin, BaseAction, ComponentInfo, ActionActivationType, ChatMode from src.plugin_system.base.base_command import BaseCommand +from src.plugin_system.base.config_types import ConfigField # 导入依赖的系统组件 from src.common.logger import get_logger @@ -412,37 +413,80 @@ class CoreActionsPlugin(BasePlugin): enable_plugin = True config_file_name = "config.toml" + # 配置节描述 + config_section_descriptions = { + "plugin": "插件基本信息配置", + "components": "核心组件启用配置", + "no_reply": "不回复动作配置", + "emoji": "表情动作配置", + } + + # 配置Schema定义 + config_schema = { + "plugin": { + "name": ConfigField(type=str, default="core_actions", description="插件名称", required=True), + "version": ConfigField(type=str, default="1.0.0", description="插件版本号"), + "enabled": ConfigField(type=bool, default=True, description="是否启用插件"), + "description": ConfigField(type=str, default="系统核心动作插件,提供基础聊天交互功能", description="插件描述", required=True) + }, + "components": { + "enable_reply": ConfigField(type=bool, default=True, description="是否启用'回复'动作"), + "enable_no_reply": ConfigField(type=bool, default=True, description="是否启用'不回复'动作"), + "enable_emoji": ConfigField(type=bool, default=True, description="是否启用'表情'动作"), + "enable_change_to_focus": ConfigField(type=bool, default=True, description="是否启用'切换到专注模式'动作"), + "enable_exit_focus": ConfigField(type=bool, default=True, description="是否启用'退出专注模式'动作"), + "enable_ping_command": ConfigField(type=bool, default=True, description="是否启用'/ping'测试命令"), + "enable_log_command": ConfigField(type=bool, default=True, description="是否启用'/log'日志命令") + }, + "no_reply": { + "waiting_timeout": ConfigField(type=int, default=1200, description="连续不回复时,最长的等待超时时间(秒)"), + "stage_1_wait": ConfigField(type=int, default=10, description="第1次连续不回复的等待时间(秒)"), + "stage_2_wait": ConfigField(type=int, default=60, description="第2次连续不回复的等待时间(秒)"), + "stage_3_wait": ConfigField(type=int, default=600, description="第3次连续不回复的等待时间(秒)"), + }, + "emoji": { + "random_probability": ConfigField( + type=float, + default=0.1, + description="Normal模式下,随机发送表情的概率(0.0到1.0)", + example=0.15 + ) + } + } + def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]: """返回插件包含的组件列表""" - # 从配置获取表情动作的随机概率 + # --- 从配置动态设置Action/Command --- emoji_chance = self.get_config("emoji.random_probability", 0.1) - - # 动态设置EmojiAction的随机概率 EmojiAction.random_activation_probability = emoji_chance - # 从配置获取不回复动作的超时时间 no_reply_timeout = self.get_config("no_reply.waiting_timeout", 1200) - - # 动态设置NoReplyAction的超时时间 NoReplyAction.waiting_timeout = no_reply_timeout - return [ - # 回复动作 - 使用类中定义的所有属性 - (ReplyAction.get_action_info(), ReplyAction), - # 不回复动作 - 使用类中定义的所有属性 - (NoReplyAction.get_action_info(), NoReplyAction), - # 表情动作 - 使用类中定义的所有属性 - (EmojiAction.get_action_info(), EmojiAction), - # 退出专注聊天动作 - 使用类中定义的所有属性 - (ExitFocusChatAction.get_action_info(), ExitFocusChatAction), - # 切换到专注聊天动作 - 使用类中定义的所有属性 - (ChangeToFocusChatAction.get_action_info(), ChangeToFocusChatAction), - # 示例Command - Ping命令 - (PingCommand.get_command_info(name="ping", description="测试机器人响应,拦截后续处理"), PingCommand), - # 示例Command - Log命令 - (LogCommand.get_command_info(name="log", description="记录消息到日志,不拦截后续处理"), LogCommand), - ] + stage1 = self.get_config("no_reply.stage_1_wait", 10) + stage2 = self.get_config("no_reply.stage_2_wait", 60) + stage3 = self.get_config("no_reply.stage_3_wait", 600) + NoReplyAction._waiting_stages = [stage1, stage2, stage3] + + # --- 根据配置注册组件 --- + components = [] + if self.get_config("components.enable_reply", True): + components.append((ReplyAction.get_action_info(), ReplyAction)) + if self.get_config("components.enable_no_reply", True): + components.append((NoReplyAction.get_action_info(), NoReplyAction)) + if self.get_config("components.enable_emoji", True): + components.append((EmojiAction.get_action_info(), EmojiAction)) + if self.get_config("components.enable_exit_focus", True): + components.append((ExitFocusChatAction.get_action_info(), ExitFocusChatAction)) + if self.get_config("components.enable_change_to_focus", True): + components.append((ChangeToFocusChatAction.get_action_info(), ChangeToFocusChatAction)) + if self.get_config("components.enable_ping_command", True): + components.append((PingCommand.get_command_info(name="ping", description="测试机器人响应,拦截后续处理"), PingCommand)) + if self.get_config("components.enable_log_command", True): + components.append((LogCommand.get_command_info(name="log", description="记录消息到日志,不拦截后续处理"), LogCommand)) + + return components # ===== 示例Command组件 ===== diff --git a/src/plugins/built_in/doubao_pic_plugin/config.toml b/src/plugins/built_in/doubao_pic_plugin/config.toml deleted file mode 100644 index f5f8a7e3d..000000000 --- a/src/plugins/built_in/doubao_pic_plugin/config.toml +++ /dev/null @@ -1,20 +0,0 @@ -# 豆包图片生成插件配置文件 - -# API配置 -base_url = "https://ark.cn-beijing.volces.com/api/v3" -volcano_generate_api_key = "9481fe36-8db7-4353-b53d-eae8c74b6b96" - -# 生成参数配置 -default_model = "doubao-seedream-3-0-t2i-250415" -default_size = "1024x1024" -default_watermark = true -default_guidance_scale = 2.5 -default_seed = 42 - -# 缓存配置 -cache_enabled = true -cache_max_size = 10 - -# 组件启用配置 -[components] -enable_image_generation = true \ No newline at end of file diff --git a/src/plugins/built_in/doubao_pic_plugin/plugin.py b/src/plugins/built_in/doubao_pic_plugin/plugin.py index afc0211a2..9f7ae8aa4 100644 --- a/src/plugins/built_in/doubao_pic_plugin/plugin.py +++ b/src/plugins/built_in/doubao_pic_plugin/plugin.py @@ -28,6 +28,7 @@ from src.plugin_system.base.base_plugin import BasePlugin from src.plugin_system.base.base_plugin import register_plugin from src.plugin_system.base.base_action import BaseAction from src.plugin_system.base.component_types import ComponentInfo, ActionActivationType, ChatMode +from src.plugin_system.base.config_types import ConfigField from src.common.logger import get_logger logger = get_logger("doubao_pic_plugin") @@ -102,8 +103,8 @@ class DoubaoImageGenerationAction(BaseAction): logger.info(f"{self.log_prefix} 执行豆包图片生成动作") # 配置验证 - http_base_url = self.api.get_config("base_url") - http_api_key = self.api.get_config("volcano_generate_api_key") + http_base_url = self.api.get_config("api.base_url") + http_api_key = self.api.get_config("api.volcano_generate_api_key") if not (http_base_url and http_api_key): error_msg = "抱歉,图片生成功能所需的HTTP配置(如API地址或密钥)不完整,无法提供服务。" @@ -132,8 +133,8 @@ class DoubaoImageGenerationAction(BaseAction): logger.info(f"{self.log_prefix} 图片描述过长,已截断") # 获取配置 - default_model = self.api.get_config("default_model", "doubao-seedream-3-0-t2i-250415") - image_size = self.action_data.get("size", self.api.get_config("default_size", "1024x1024")) + default_model = self.api.get_config("generation.default_model", "doubao-seedream-3-0-t2i-250415") + image_size = self.action_data.get("size", self.api.get_config("generation.default_size", "1024x1024")) # 验证图片尺寸格式 if not self._validate_image_size(image_size): @@ -183,6 +184,8 @@ class DoubaoImageGenerationAction(BaseAction): if success: image_url = result + # print(f"image_url: {image_url}") + # print(f"result: {result}") logger.info(f"{self.log_prefix} 图片URL获取成功: {image_url[:70]}... 下载并编码.") try: @@ -202,8 +205,9 @@ class DoubaoImageGenerationAction(BaseAction): self._cleanup_cache() await self.send_message_by_expressor("图片已发送!") - return True, "图片已发送" + return True, "图片已成功生成并发送" else: + print(f"send_success: {send_success}") await self.send_message_by_expressor("图片已处理为Base64,但发送失败了。") return False, "图片发送失败 (Base64)" else: @@ -216,7 +220,7 @@ class DoubaoImageGenerationAction(BaseAction): def _get_guidance_scale(self) -> float: """获取guidance_scale配置值""" - guidance_scale_input = self.api.get_config("default_guidance_scale", 2.5) + guidance_scale_input = self.api.get_config("generation.default_guidance_scale", 2.5) try: return float(guidance_scale_input) except (ValueError, TypeError): @@ -225,7 +229,7 @@ class DoubaoImageGenerationAction(BaseAction): def _get_seed(self) -> int: """获取seed配置值""" - seed_config_value = self.api.get_config("default_seed") + seed_config_value = self.api.get_config("generation.default_seed") if seed_config_value is not None: try: return int(seed_config_value) @@ -235,7 +239,7 @@ class DoubaoImageGenerationAction(BaseAction): def _get_watermark(self) -> bool: """获取watermark配置值""" - watermark_source = self.api.get_config("default_watermark", True) + watermark_source = self.api.get_config("generation.default_watermark", True) if isinstance(watermark_source, bool): return watermark_source elif isinstance(watermark_source, str): @@ -321,8 +325,8 @@ class DoubaoImageGenerationAction(BaseAction): self, prompt: str, model: str, size: str, seed: int, guidance_scale: float, watermark: bool ) -> Tuple[bool, str]: """发送HTTP请求生成图片""" - base_url = self.api.get_config("base_url") - generate_api_key = self.api.get_config("volcano_generate_api_key") + base_url = self.api.get_config("api.base_url") + generate_api_key = self.api.get_config("api.volcano_generate_api_key") endpoint = f"{base_url.rstrip('/')}/images/generations" @@ -402,6 +406,74 @@ class DoubaoImagePlugin(BasePlugin): enable_plugin = True config_file_name = "config.toml" + # 配置节描述 + config_section_descriptions = { + "plugin": "插件基本信息配置", + "api": "API相关配置,包含火山引擎API的访问信息", + "generation": "图片生成参数配置,控制生成图片的各种参数", + "cache": "结果缓存配置", + "components": "组件启用配置" + } + + # 配置Schema定义 + config_schema = { + "plugin": { + "name": ConfigField(type=str, default="doubao_pic_plugin", description="插件名称", required=True), + "version": ConfigField(type=str, default="2.0.0", description="插件版本号"), + "enabled": ConfigField(type=bool, default=True, description="是否启用插件"), + "description": ConfigField( + type=str, + default="基于火山引擎豆包模型的AI图片生成插件", + description="插件描述", + required=True + ) + }, + "api": { + "base_url": ConfigField( + type=str, + default="https://ark.cn-beijing.volces.com/api/v3", + description="API基础URL", + example="https://api.example.com/v1" + ), + "volcano_generate_api_key": ConfigField( + type=str, + default="YOUR_DOUBAO_API_KEY_HERE", + description="火山引擎豆包API密钥", + required=True + ) + }, + "generation": { + "default_model": ConfigField( + type=str, + default="doubao-seedream-3-0-t2i-250415", + description="默认使用的文生图模型", + choices=["doubao-seedream-3-0-t2i-250415", "doubao-seedream-2-0-t2i"] + ), + "default_size": ConfigField( + type=str, + default="1024x1024", + description="默认图片尺寸", + example="1024x1024", + choices=["1024x1024", "1024x1280", "1280x1024", "1024x1536", "1536x1024"] + ), + "default_watermark": ConfigField(type=bool, default=True, description="是否默认添加水印"), + "default_guidance_scale": ConfigField( + type=float, + default=2.5, + description="模型指导强度,影响图片与提示的关联性", + example="2.0" + ), + "default_seed": ConfigField(type=int, default=42, description="随机种子,用于复现图片") + }, + "cache": { + "enabled": ConfigField(type=bool, default=True, description="是否启用请求缓存"), + "max_size": ConfigField(type=int, default=10, description="最大缓存数量") + }, + "components": { + "enable_image_generation": ConfigField(type=bool, default=True, description="是否启用图片生成Action") + } + } + def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]: """返回插件包含的组件列表""" diff --git a/src/plugins/built_in/mute_plugin/config.toml b/src/plugins/built_in/mute_plugin/config.toml deleted file mode 100644 index 32d32817f..000000000 --- a/src/plugins/built_in/mute_plugin/config.toml +++ /dev/null @@ -1,71 +0,0 @@ -# 禁言插件配置文件 - -[plugin] -name = "mute_plugin" -version = "2.0.0" -enabled = false -description = "群聊禁言管理插件,提供智能禁言功能" - -# 组件启用控制 -[components] -enable_smart_mute = true # 启用智能禁言Action -enable_mute_command = true # 启用禁言命令Command - -# 禁言配置 -[mute] -# 时长限制(秒) -min_duration = 60 # 最短禁言时长 -max_duration = 2592000 # 最长禁言时长(30天) -default_duration = 300 # 默认禁言时长(5分钟) - -# 是否启用时长美化显示 -enable_duration_formatting = true - -# 是否记录禁言历史 -log_mute_history = true - -# 禁言消息模板 -templates = [ - "好的,禁言 {target} {duration},理由:{reason}", - "收到,对 {target} 执行禁言 {duration},因为{reason}", - "明白了,禁言 {target} {duration},原因是{reason}", - "哇哈哈哈哈哈,已禁言 {target} {duration},理由:{reason}", - "哎呦我去,对 {target} 执行禁言 {duration},因为{reason}", - "{target},你完蛋了,我要禁言你 {duration} 秒,原因:{reason}" -] - -# 错误消息模板 -error_messages = [ - "没有指定禁言对象呢~", - "没有指定禁言时长呢~", - "禁言时长必须是正数哦~", - "禁言时长必须是数字哦~", - "找不到 {target} 这个人呢~", - "查找用户信息时出现问题~" -] - -# 智能禁言Action配置 -[smart_mute] -# LLM判定严格模式 -strict_mode = true - -# 关键词激活设置 -keyword_sensitivity = "normal" # low, normal, high - -# 并行执行设置 -allow_parallel = false - -# 禁言命令配置 -[mute_command] -# 最大批量禁言数量 -max_batch_size = 5 - -# 命令冷却时间(秒) -cooldown_seconds = 3 - -# 日志配置 -[logging] -level = "INFO" -prefix = "[MutePlugin]" -include_user_info = true -include_duration_info = true \ No newline at end of file diff --git a/src/plugins/built_in/mute_plugin/plugin.py b/src/plugins/built_in/mute_plugin/plugin.py index e69bbf1b2..fcdeae071 100644 --- a/src/plugins/built_in/mute_plugin/plugin.py +++ b/src/plugins/built_in/mute_plugin/plugin.py @@ -24,6 +24,7 @@ from src.plugin_system.base.base_plugin import register_plugin from src.plugin_system.base.base_action import BaseAction from src.plugin_system.base.base_command import BaseCommand from src.plugin_system.base.component_types import ComponentInfo, ActionActivationType, ChatMode +from src.plugin_system.base.config_types import ConfigField from src.common.logger import get_logger logger = get_logger("mute_plugin") @@ -381,6 +382,76 @@ class MutePlugin(BasePlugin): enable_plugin = True config_file_name = "config.toml" + # 配置节描述 + config_section_descriptions = { + "plugin": "插件基本信息配置", + "components": "组件启用控制", + "mute": "核心禁言功能配置", + "smart_mute": "智能禁言Action的专属配置", + "mute_command": "禁言命令Command的专属配置", + "logging": "日志记录相关配置" + } + + # 配置Schema定义 + config_schema = { + "plugin": { + "name": ConfigField(type=str, default="mute_plugin", description="插件名称", required=True), + "version": ConfigField(type=str, default="2.0.0", description="插件版本号"), + "enabled": ConfigField(type=bool, default=False, description="是否启用插件"), + "description": ConfigField(type=str, default="群聊禁言管理插件,提供智能禁言功能", description="插件描述", required=True) + }, + "components": { + "enable_smart_mute": ConfigField(type=bool, default=True, description="是否启用智能禁言Action"), + "enable_mute_command": ConfigField(type=bool, default=False, description="是否启用禁言命令Command") + }, + "mute": { + "min_duration": ConfigField(type=int, default=60, description="最短禁言时长(秒)"), + "max_duration": ConfigField(type=int, default=2592000, description="最长禁言时长(秒),默认30天"), + "default_duration": ConfigField(type=int, default=300, description="默认禁言时长(秒),默认5分钟"), + "enable_duration_formatting": ConfigField(type=bool, default=True, description="是否启用人性化的时长显示(如 '5分钟' 而非 '300秒')"), + "log_mute_history": ConfigField(type=bool, default=True, description="是否记录禁言历史(未来功能)"), + "templates": ConfigField( + type=list, + default=[ + "好的,禁言 {target} {duration},理由:{reason}", + "收到,对 {target} 执行禁言 {duration},因为{reason}", + "明白了,禁言 {target} {duration},原因是{reason}", + "哇哈哈哈哈哈,已禁言 {target} {duration},理由:{reason}", + "哎呦我去,对 {target} 执行禁言 {duration},因为{reason}", + "{target},你完蛋了,我要禁言你 {duration} 秒,原因:{reason}" + ], + description="成功禁言后发送的随机消息模板" + ), + "error_messages": ConfigField( + type=list, + default=[ + "没有指定禁言对象呢~", + "没有指定禁言时长呢~", + "禁言时长必须是正数哦~", + "禁言时长必须是数字哦~", + "找不到 {target} 这个人呢~", + "查找用户信息时出现问题~" + ], + description="执行禁言过程中发生错误时发送的随机消息模板" + ) + }, + "smart_mute": { + "strict_mode": ConfigField(type=bool, default=True, description="LLM判定的严格模式"), + "keyword_sensitivity": ConfigField(type=str, default="normal", description="关键词激活的敏感度", choices=["low", "normal", "high"]), + "allow_parallel": ConfigField(type=bool, default=False, description="是否允许并行执行(暂未启用)") + }, + "mute_command": { + "max_batch_size": ConfigField(type=int, default=5, description="最大批量禁言数量(未来功能)"), + "cooldown_seconds": ConfigField(type=int, default=3, description="命令冷却时间(秒)") + }, + "logging": { + "level": ConfigField(type=str, default="INFO", description="日志记录级别", choices=["DEBUG", "INFO", "WARNING", "ERROR"]), + "prefix": ConfigField(type=str, default="[MutePlugin]", description="日志记录前缀"), + "include_user_info": ConfigField(type=bool, default=True, description="日志中是否包含用户信息"), + "include_duration_info": ConfigField(type=bool, default=True, description="日志中是否包含禁言时长信息") + } + } + def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]: """返回插件包含的组件列表""" diff --git a/src/plugins/built_in/tts_plugin/config.toml b/src/plugins/built_in/tts_plugin/config.toml deleted file mode 100644 index 151718e0f..000000000 --- a/src/plugins/built_in/tts_plugin/config.toml +++ /dev/null @@ -1,16 +0,0 @@ -# 文字转语音插件配置文件 - -[plugin] -name = "tts_plugin" -version = "0.1.0" -enabled = true -description = "文字转语音插件" - -# 组件启用控制 -[components] -enable_tts = true - -# 日志配置 -[logging] -level = "INFO" -prefix = "[TTS]" \ No newline at end of file diff --git a/src/plugins/built_in/tts_plugin/plugin.py b/src/plugins/built_in/tts_plugin/plugin.py index 995a97a53..632e25efc 100644 --- a/src/plugins/built_in/tts_plugin/plugin.py +++ b/src/plugins/built_in/tts_plugin/plugin.py @@ -2,6 +2,7 @@ from src.plugin_system.base.base_plugin import BasePlugin, register_plugin from src.plugin_system.base.component_types import ComponentInfo from src.common.logger import get_logger from src.plugin_system.base.base_action import BaseAction, ActionActivationType, ChatMode +from src.plugin_system.base.config_types import ConfigField from typing import Tuple, List, Type logger = get_logger("tts") @@ -107,6 +108,30 @@ class TTSPlugin(BasePlugin): enable_plugin = True config_file_name = "config.toml" + # 配置节描述 + config_section_descriptions = { + "plugin": "插件基本信息配置", + "components": "组件启用控制", + "logging": "日志记录相关配置" + } + + # 配置Schema定义 + config_schema = { + "plugin": { + "name": ConfigField(type=str, default="tts_plugin", description="插件名称", required=True), + "version": ConfigField(type=str, default="0.1.0", description="插件版本号"), + "enabled": ConfigField(type=bool, default=True, description="是否启用插件"), + "description": ConfigField(type=str, default="文字转语音插件", description="插件描述", required=True) + }, + "components": { + "enable_tts": ConfigField(type=bool, default=True, description="是否启用TTS Action") + }, + "logging": { + "level": ConfigField(type=str, default="INFO", description="日志记录级别", choices=["DEBUG", "INFO", "WARNING", "ERROR"]), + "prefix": ConfigField(type=str, default="[TTS]", description="日志记录前缀") + } + } + def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]: """返回插件包含的组件列表""" diff --git a/src/plugins/built_in/vtb_plugin/config.toml b/src/plugins/built_in/vtb_plugin/config.toml deleted file mode 100644 index 0e4d3a482..000000000 --- a/src/plugins/built_in/vtb_plugin/config.toml +++ /dev/null @@ -1,26 +0,0 @@ -# 虚拟主播情感表达插件配置文件 - -[plugin] -name = "vtb_plugin" -version = "0.1.0" -enabled = true -description = "虚拟主播情感表达插件" - -# 组件启用控制 -[components] -enable_vtb = true - -# VTB动作配置 -[vtb_action] -# 情感表达增强选项 -enable_emotion_enhancement = true -max_text_length = 100 -default_emotion = "平静" - -# 激活概率控制(Normal模式) -random_activation_probability = 0.08 - -# 日志配置 -[logging] -level = "INFO" -prefix = "[VTB]"