diff --git a/plugins/hello_world_plugin/plugin.py b/plugins/hello_world_plugin/plugin.py index ad5f0f748..60723e227 100644 --- a/plugins/hello_world_plugin/plugin.py +++ b/plugins/hello_world_plugin/plugin.py @@ -1,12 +1,17 @@ from typing import List, Tuple, Type from src.plugin_system import ( - BasePlugin, register_plugin, BaseAction, BaseCommand, - ComponentInfo, ActionActivationType, ChatMode, - ConfigField + BasePlugin, + register_plugin, + BaseAction, + BaseCommand, + ComponentInfo, + ActionActivationType, + ConfigField, ) # ===== Action组件 ===== + class HelloAction(BaseAction): """问候Action - 简单的问候动作""" @@ -15,55 +20,51 @@ class HelloAction(BaseAction): action_description = "向用户发送问候消息" # === 功能描述(必须填写)=== - action_parameters = { - "greeting_message": "要发送的问候消息" - } - action_require = [ - "需要发送友好问候时使用", - "当有人向你问好时使用", - "当你遇见没有见过的人时使用" - ] + action_parameters = {"greeting_message": "要发送的问候消息"} + action_require = ["需要发送友好问候时使用", "当有人向你问好时使用", "当你遇见没有见过的人时使用"] associated_types = ["text"] async def execute(self) -> Tuple[bool, str]: """执行问候动作 - 这是核心功能""" # 发送问候消息 - greeting_message = self.action_data.get("greeting_message","") + greeting_message = self.action_data.get("greeting_message", "") base_message = self.get_config("greeting.message", "嗨!很开心见到你!😊") message = base_message + greeting_message await self.send_text(message) return True, "发送了问候消息" + class ByeAction(BaseAction): """告别Action - 只在用户说再见时激活""" - + action_name = "bye_greeting" action_description = "向用户发送告别消息" - + # 使用关键词激活 focus_activation_type = ActionActivationType.KEYWORD normal_activation_type = ActionActivationType.KEYWORD - + # 关键词设置 activation_keywords = ["再见", "bye", "88", "拜拜"] keyword_case_sensitive = False - + action_parameters = {"bye_message": "要发送的告别消息"} action_require = [ "用户要告别时使用", "当有人要离开时使用", "当有人和你说再见时使用", - ] + ] associated_types = ["text"] - + async def execute(self) -> Tuple[bool, str]: - bye_message = self.action_data.get("bye_message","") - + bye_message = self.action_data.get("bye_message", "") + message = "再见!期待下次聊天!👋" + bye_message await self.send_text(message) return True, "发送了告别消息" + class TimeCommand(BaseCommand): """时间查询Command - 响应/time命令""" @@ -79,21 +80,22 @@ class TimeCommand(BaseCommand): async def execute(self) -> Tuple[bool, str]: """执行时间查询""" import datetime - + # 获取当前时间 time_format = self.get_config("time.format", "%Y-%m-%d %H:%M:%S") now = datetime.datetime.now() time_str = now.strftime(time_format) - + # 发送时间信息 message = f"⏰ 当前时间:{time_str}" await self.send_text(message) - + return True, f"显示了当前时间: {time_str}" # ===== 插件注册 ===== + @register_plugin class HelloWorldPlugin(BasePlugin): """Hello World插件 - 你的第一个MaiCore插件""" @@ -107,34 +109,20 @@ class HelloWorldPlugin(BasePlugin): config_file_name = "config.toml" # 配置文件名 # 配置节描述 - config_section_descriptions = { - "plugin": "插件基本信息", - "greeting": "问候功能配置", - "time": "时间查询配置" - } + config_section_descriptions = {"plugin": "插件基本信息", "greeting": "问候功能配置", "time": "时间查询配置"} # 配置Schema定义 config_schema = { "plugin": { "name": ConfigField(type=str, default="hello_world_plugin", description="插件名称"), "version": ConfigField(type=str, default="1.0.0", description="插件版本"), - "enabled": ConfigField(type=bool, default=False, description="是否启用插件") + "enabled": ConfigField(type=bool, default=False, description="是否启用插件"), }, "greeting": { - "message": ConfigField( - type=str, - default="嗨!很开心见到你!😊", - description="默认问候消息" - ), - "enable_emoji": ConfigField(type=bool, default=True, description="是否启用表情符号") + "message": ConfigField(type=str, default="嗨!很开心见到你!😊", description="默认问候消息"), + "enable_emoji": ConfigField(type=bool, default=True, description="是否启用表情符号"), }, - "time": { - "format": ConfigField( - type=str, - default="%Y-%m-%d %H:%M:%S", - description="时间显示格式" - ) - } + "time": {"format": ConfigField(type=str, default="%Y-%m-%d %H:%M:%S", description="时间显示格式")}, } def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]: @@ -142,4 +130,4 @@ class HelloWorldPlugin(BasePlugin): (HelloAction.get_action_info(), HelloAction), (ByeAction.get_action_info(), ByeAction), # 添加告别Action (TimeCommand.get_command_info(), TimeCommand), - ] \ No newline at end of file + ] diff --git a/plugins/take_picture_plugin/plugin.py b/plugins/take_picture_plugin/plugin.py index de600a1be..ef28140a9 100644 --- a/plugins/take_picture_plugin/plugin.py +++ b/plugins/take_picture_plugin/plugin.py @@ -24,6 +24,7 @@ - 拍照Action - 生成自拍照 - 展示照片Command - 展示最近生成的照片 """ + from typing import List, Tuple, Type, Optional import random import datetime @@ -67,13 +68,9 @@ class TakePictureAction(BaseAction): action_parameters = {} - action_require = [ - "当用户想看你的照片时使用", - "当用户让你发自拍时使用" - "当想随手拍眼前的场景时使用" - ] + action_require = ["当用户想看你的照片时使用", "当用户让你发自拍时使用当想随手拍眼前的场景时使用"] - associated_types = ["text","image"] + associated_types = ["text", "image"] # 内置的Prompt模板,如果配置文件中没有定义,将使用这些模板 DEFAULT_PROMPT_TEMPLATES = [ @@ -107,18 +104,14 @@ class TakePictureAction(BaseAction): # 获取全局配置信息 bot_nickname = self.api.get_global_config("bot.nickname", "麦麦") bot_personality = self.api.get_global_config("personality.personality_core", "") - personality_sides = self.api.get_global_config("personality.personality_sides", []) if personality_sides: bot_personality += random.choice(personality_sides) - + # 准备模板变量 - template_vars = { - "name": bot_nickname, - "personality": bot_personality - } - + template_vars = {"name": bot_nickname, "personality": bot_personality} + logger.info(f"{self.log_prefix} 使用的全局配置: name={bot_nickname}, personality={bot_personality}") # 尝试从配置文件获取模板,如果没有则使用默认模板 @@ -225,11 +218,11 @@ class TakePictureAction(BaseAction): log_file = self.api.get_config("storage.log_file", "picture_log.json") log_path = os.path.join(DATA_DIR, log_file) max_photos = self.api.get_config("storage.max_photos", 50) - + async with file_lock: try: if os.path.exists(log_path): - with open(log_path, 'r', encoding='utf-8') as f: + with open(log_path, "r", encoding="utf-8") as f: log_data = json.load(f) else: log_data = [] @@ -237,18 +230,16 @@ class TakePictureAction(BaseAction): log_data = [] # 添加新照片 - log_data.append({ - "prompt": prompt, - "image_url": image_url, - "timestamp": datetime.datetime.now().isoformat() - }) + log_data.append( + {"prompt": prompt, "image_url": image_url, "timestamp": datetime.datetime.now().isoformat()} + ) # 如果超过最大数量,删除最旧的 if len(log_data) > max_photos: - log_data = sorted(log_data, key=lambda x: x.get('timestamp', ''), reverse=True)[:max_photos] + log_data = sorted(log_data, key=lambda x: x.get("timestamp", ""), reverse=True)[:max_photos] try: - with open(log_path, 'w', encoding='utf-8') as f: + with open(log_path, "w", encoding="utf-8") as f: json.dump(log_data, f, ensure_ascii=False, indent=4) except Exception as e: logger.error(f"{self.log_prefix} 写入照片日志文件失败: {e}", exc_info=True) @@ -323,8 +314,8 @@ class TakePictureAction(BaseAction): try: with urllib.request.urlopen(image_url) as response: image_data = response.read() - - base64_encoded = base64.b64encode(image_data).decode('utf-8') + + base64_encoded = base64.b64encode(image_data).decode("utf-8") return True, base64_encoded except Exception as e: logger.error(f"图片下载编码失败: {e}", exc_info=True) @@ -372,10 +363,10 @@ class TakePictureAction(BaseAction): """更新缓存""" max_cache_size = self.api.get_config("storage.max_cache_size", 10) cache_key = self._get_cache_key(description, model, size) - + # 添加到缓存 self._request_cache[cache_key] = base64_image - + # 如果缓存超过最大大小,删除最旧的项 if len(self._request_cache) > max_cache_size: oldest_key = next(iter(self._request_cache)) @@ -396,14 +387,14 @@ class ShowRecentPicturesCommand(BaseCommand): logger.info(f"{self.log_prefix} 执行展示最近照片命令") log_file = self.api.get_config("storage.log_file", "picture_log.json") log_path = os.path.join(DATA_DIR, log_file) - + async with file_lock: try: if not os.path.exists(log_path): await self.send_text("最近还没有拍过照片哦,快让我自拍一张吧!") return True, "没有照片日志文件" - with open(log_path, 'r', encoding='utf-8') as f: + with open(log_path, "r", encoding="utf-8") as f: log_data = json.load(f) if not log_data: @@ -411,31 +402,29 @@ class ShowRecentPicturesCommand(BaseCommand): return True, "没有照片" # 获取最新的5张照片 - recent_pics = sorted(log_data, key=lambda x: x['timestamp'], reverse=True)[:5] - + recent_pics = sorted(log_data, key=lambda x: x["timestamp"], reverse=True)[:5] + # 先发送文本消息 await self.send_text("这是我最近拍的几张照片~") - + # 逐个发送图片 for pic in recent_pics: # 尝试获取图片URL - image_url = pic.get('image_url') + image_url = pic.get("image_url") if image_url: try: # 下载图片并转换为Base64 with urllib.request.urlopen(image_url) as response: image_data = response.read() - base64_encoded = base64.b64encode(image_data).decode('utf-8') - + base64_encoded = base64.b64encode(image_data).decode("utf-8") + # 发送图片 await self.send_type( - message_type="image", - content=base64_encoded, - display_message="发送最近的照片" + message_type="image", content=base64_encoded, display_message="发送最近的照片" ) except Exception as e: logger.error(f"{self.log_prefix} 下载或发送照片失败: {e}", exc_info=True) - + return True, "成功展示最近的照片" except json.JSONDecodeError: @@ -450,6 +439,7 @@ class ShowRecentPicturesCommand(BaseCommand): @register_plugin class TakePicturePlugin(BasePlugin): """拍照插件""" + plugin_name = "take_picture_plugin" plugin_description = "提供生成自拍照和展示最近照片的功能" plugin_version = "1.0.0" @@ -472,7 +462,9 @@ class TakePicturePlugin(BasePlugin): "name": ConfigField(type=str, default="take_picture_plugin", description="插件名称", required=True), "version": ConfigField(type=str, default="1.3.0", description="插件版本号"), "enabled": ConfigField(type=bool, default=False, description="是否启用插件"), - "description": ConfigField(type=str, default="提供生成自拍照和展示最近照片的功能", description="插件描述", required=True), + "description": ConfigField( + type=str, default="提供生成自拍照和展示最近照片的功能", description="插件描述", required=True + ), }, "api": { "base_url": ConfigField( @@ -509,9 +501,7 @@ class TakePicturePlugin(BasePlugin): ), "default_seed": ConfigField(type=int, default=42, description="随机种子,用于复现图片"), "prompt_templates": ConfigField( - type=list, - default=TakePictureAction.DEFAULT_PROMPT_TEMPLATES, - description="用于生成自拍照的prompt模板" + type=list, default=TakePictureAction.DEFAULT_PROMPT_TEMPLATES, description="用于生成自拍照的prompt模板" ), }, "storage": { @@ -519,7 +509,7 @@ class TakePicturePlugin(BasePlugin): "log_file": ConfigField(type=str, default="picture_log.json", description="照片日志文件名"), "enable_cache": ConfigField(type=bool, default=True, description="是否启用请求缓存"), "max_cache_size": ConfigField(type=int, default=10, description="最大缓存数量"), - } + }, } def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]: @@ -529,4 +519,4 @@ class TakePicturePlugin(BasePlugin): components.append((TakePictureAction.get_action_info(), TakePictureAction)) if self.get_config("components.enable_show_pics_command", True): components.append((ShowRecentPicturesCommand.get_command_info(), ShowRecentPicturesCommand)) - return components \ No newline at end of file + return components