From 535dcc76bf8354b0a836430ab48192b75952ceaf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 16 Jun 2025 16:46:11 +0000 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=A4=96=20=E8=87=AA=E5=8A=A8=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96=E4=BB=A3=E7=A0=81=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugin_system/apis/config_api.py | 2 +- .../built_in/take_picture_plugin/plugin.py | 82 ++++++++----------- 2 files changed, 37 insertions(+), 47 deletions(-) diff --git a/src/plugin_system/apis/config_api.py b/src/plugin_system/apis/config_api.py index fba31c10f..49cd40814 100644 --- a/src/plugin_system/apis/config_api.py +++ b/src/plugin_system/apis/config_api.py @@ -27,7 +27,7 @@ class ConfigAPI: # 支持嵌套键访问 keys = key.split(".") current = global_config - + try: for k in keys: if hasattr(current, k): diff --git a/src/plugins/built_in/take_picture_plugin/plugin.py b/src/plugins/built_in/take_picture_plugin/plugin.py index d5ab16bcc..80c6d1e3d 100644 --- a/src/plugins/built_in/take_picture_plugin/plugin.py +++ b/src/plugins/built_in/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}") # 尝试从配置文件获取模板,如果没有则使用默认模板 @@ -136,7 +129,7 @@ class TakePictureAction(BaseAction): # 从配置获取参数 model = self.api.get_config("picture.default_model", "doubao-seedream-3-0-t2i-250415") - style = self.api.get_config("picture.default_style", "动漫") + self.api.get_config("picture.default_style", "动漫") size = self.api.get_config("picture.default_size", "1024x1024") watermark = self.api.get_config("picture.default_watermark", True) guidance_scale = self.api.get_config("picture.default_guidance_scale", 2.5) @@ -160,7 +153,7 @@ class TakePictureAction(BaseAction): # 缓存失败,清除这个缓存项并继续正常流程 del self._request_cache[cache_key] - await self.send_text(f"正在为你拍照,请稍候...") + await self.send_text("正在为你拍照,请稍候...") try: seed = random.randint(1, 1000000) @@ -226,11 +219,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 = [] @@ -238,18 +231,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) @@ -324,8 +315,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) @@ -373,10 +364,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)) @@ -397,14 +388,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: @@ -412,31 +403,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: @@ -451,6 +440,7 @@ class ShowRecentPicturesCommand(BaseCommand): @register_plugin class TakePicturePlugin(BasePlugin): """拍照插件""" + plugin_name = "take_picture_plugin" plugin_description = "提供生成自拍照和展示最近照片的功能" plugin_version = "1.0.0" @@ -473,7 +463,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( @@ -511,9 +503,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": { @@ -521,7 +511,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]]: @@ -531,4 +521,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 From 30356f5fdb9c5374ee96a6d585178a60f2c82488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A2=A8=E6=A2=93=E6=9F=92?= <1787882683@qq.com> Date: Thu, 19 Jun 2025 00:20:37 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix=EF=BC=9A=E4=BF=AE=E6=AD=A3=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E8=B7=AF=E5=BE=84=E7=9A=84=E5=AE=9A=E4=B9=89=EF=BC=8C?= =?UTF-8?q?=E7=A1=AE=E4=BF=9D=E4=BD=BF=E7=94=A8os.path.join=E4=BB=A5?= =?UTF-8?q?=E6=8F=90=E9=AB=98=E8=B7=A8=E5=B9=B3=E5=8F=B0=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/config.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/config/config.py b/src/config/config.py index 67a8b6a25..3dab769d1 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -43,8 +43,10 @@ install(extra_lines=3) # 配置主程序日志格式 logger = get_logger("config") -CONFIG_DIR = "config" -TEMPLATE_DIR = "template" +# 获取当前文件所在目录的父目录的父目录(即MaiBot项目根目录) +PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) +CONFIG_DIR = os.path.join(PROJECT_ROOT, "config") +TEMPLATE_DIR = os.path.join(PROJECT_ROOT, "template") # 考虑到,实际上配置文件中的mai_version是不会自动更新的,所以采用硬编码 # 对该字段的更新,请严格参照语义化版本规范:https://semver.org/lang/zh-CN/ @@ -53,12 +55,12 @@ MMC_VERSION = "0.8.0-snapshot.1" def update_config(): # 获取根目录路径 - old_config_dir = f"{CONFIG_DIR}/old" + old_config_dir = os.path.join(CONFIG_DIR, "old") # 定义文件路径 - template_path = f"{TEMPLATE_DIR}/bot_config_template.toml" - old_config_path = f"{CONFIG_DIR}/bot_config.toml" - new_config_path = f"{CONFIG_DIR}/bot_config.toml" + template_path = os.path.join(TEMPLATE_DIR, "bot_config_template.toml") + old_config_path = os.path.join(CONFIG_DIR, "bot_config.toml") + new_config_path = os.path.join(CONFIG_DIR, "bot_config.toml") # 检查配置文件是否存在 if not os.path.exists(old_config_path): @@ -88,11 +90,9 @@ def update_config(): logger.info("已有配置文件未检测到版本号,可能是旧版本。将进行更新") # 创建old目录(如果不存在) - os.makedirs(old_config_dir, exist_ok=True) - - # 生成带时间戳的新文件名 + os.makedirs(old_config_dir, exist_ok=True) # 生成带时间戳的新文件名 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - old_backup_path = f"{old_config_dir}/bot_config_{timestamp}.toml" + old_backup_path = os.path.join(old_config_dir, f"bot_config_{timestamp}.toml") # 移动旧配置文件到old目录 shutil.move(old_config_path, old_backup_path) @@ -198,5 +198,5 @@ logger.info(f"MaiCore当前版本: {MMC_VERSION}") update_config() logger.info("正在品鉴配置文件...") -global_config = load_config(config_path=f"{CONFIG_DIR}/bot_config.toml") +global_config = load_config(config_path=os.path.join(CONFIG_DIR, "bot_config.toml")) logger.info("非常的新鲜,非常的美味!") From 7916a6b4eaf5ec21a6c57281b347641454fbf0ba Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 18 Jun 2025 16:21:13 +0000 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=A4=96=20=E8=87=AA=E5=8A=A8=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96=E4=BB=A3=E7=A0=81=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/config.py b/src/config/config.py index 3dab769d1..bf4dc33e7 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -90,7 +90,7 @@ def update_config(): logger.info("已有配置文件未检测到版本号,可能是旧版本。将进行更新") # 创建old目录(如果不存在) - os.makedirs(old_config_dir, exist_ok=True) # 生成带时间戳的新文件名 + os.makedirs(old_config_dir, exist_ok=True) # 生成带时间戳的新文件名 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") old_backup_path = os.path.join(old_config_dir, f"bot_config_{timestamp}.toml")