From 698240b1a2d808bac02db180a0dc7662b6999f11 Mon Sep 17 00:00:00 2001 From: K2cr2O1 <2221577113@qq.com> Date: Mon, 19 Jan 2026 01:45:10 +0800 Subject: [PATCH] Squash merge dev branch: Implement performance monitoring, auto-approve plugin, and fix various warnings --- .gitignore | 2 + compile_machine_code.py | 294 ------------------------ compile_modules.py | 65 ------ config.toml | 25 -- core/data/temp/help_menu.png | Bin 150898 -> 0 bytes core/utils/__init__.py | 38 ++++ core/utils/performance.py | 364 +++++++++++++++++++++++++++++ core/utils/singleton.py | 48 +++- export_requirements.py | 8 - main.py | 64 +++++- models/events/message.py | 31 ++- performance_config_example.py | 76 +++++++ plugins/auto_approve.py | 2 +- plugins/bili_parser.py | 99 ++++++-- plugins/douyin_parser.py | 391 ++++++++++++++++++++++++++++++++ profile_main.py | 94 ++++++++ requirements-dev.txt | 4 + scripts/compile_machine_code.py | 363 +++++++++++++++++++++++++++-- scripts/compile_modules.py | 2 +- setup_mypyc.py | 7 +- test_performance_simple.py | 79 +++++++ tests/test_performance.py | 266 ++++++++++++++++++++++ 22 files changed, 1867 insertions(+), 455 deletions(-) delete mode 100644 compile_machine_code.py delete mode 100644 compile_modules.py delete mode 100644 config.toml delete mode 100644 core/data/temp/help_menu.png create mode 100644 core/utils/performance.py delete mode 100644 export_requirements.py create mode 100644 performance_config_example.py create mode 100644 plugins/douyin_parser.py create mode 100644 profile_main.py create mode 100644 requirements-dev.txt create mode 100644 test_performance_simple.py create mode 100644 tests/test_performance.py diff --git a/.gitignore b/.gitignore index ee074a6..72f36b2 100644 --- a/.gitignore +++ b/.gitignore @@ -146,3 +146,5 @@ build/ # Scratch files scratch_files/ +/config.toml +/core/data/TEMP/* \ No newline at end of file diff --git a/compile_machine_code.py b/compile_machine_code.py deleted file mode 100644 index cce551d..0000000 --- a/compile_machine_code.py +++ /dev/null @@ -1,294 +0,0 @@ -#!/usr/bin/env python3 -""" -跨平台 Python 模块编译脚本 - -将核心 Python 模块编译为机器码(.pyd 或 .so)以提升性能。 - -支持的平台: -- Windows: 生成 .pyd 文件 -- Linux: 生成 .so 文件 - -使用方法: - python compile_machine_code.py [options] - -选项: - --compile, -c 编译指定的模块(默认) - --list, -l 列出已编译的模块 - --clean, -k 清理编译生成的文件 - --help, -h 显示帮助信息 - -注意: - 1. 需要安装 C 编译器 (Windows 上需要 Visual Studio Build Tools, Linux 上需要 GCC) - 2. 需要安装 mypyc: pip install mypyc - 3. 编译后的文件是平台相关的,不能跨平台复制 - 4. 建议在部署的目标环境上运行此脚本 -""" -import os -import sys -import glob -import subprocess -import shutil -import argparse - -# 检测当前平台 -PLATFORM = sys.platform -if PLATFORM.startswith('win'): - EXTENSION = '.pyd' - BUILD_PREFIX = 'cp314-win_amd64' - BUILD_PATH = os.path.join('build', f'lib.win-amd64-cpython-314') -elif PLATFORM.startswith('linux'): - EXTENSION = '.so' - BUILD_PREFIX = 'cp314-x86_64-linux-gnu' - BUILD_PATH = os.path.join('build', f'lib.linux-x86_64-cpython-314') -else: - print(f"不支持的平台: {PLATFORM}") - sys.exit(1) - -# 要编译的模块列表 -# 注意:Mypyc 对动态特性支持有限,只选择计算密集或类型明确的模块 -MODULES = [ - # 工具模块 - 'core/utils/json_utils.py', # JSON 处理 - 'core/utils/executor.py', # 代码执行引擎 - 'core/utils/singleton.py', # 单例模式基类 - 'core/utils/exceptions.py', # 自定义异常 - 'core/utils/logger.py', # 日志模块 - - # 核心管理模块 - 'core/managers/command_manager.py', # 指令匹配和分发 - 'core/managers/admin_manager.py', # 管理员管理 - 'core/managers/permission_manager.py', # 权限管理 - 'core/managers/plugin_manager.py', # 插件管理器 - 'core/managers/redis_manager.py', # Redis 管理器 - 'core/managers/image_manager.py', # 图片管理器 - - # 核心基础模块 - 'core/ws.py', # WebSocket 核心 - 'core/bot.py', # Bot 核心抽象 - 'core/config_loader.py', # 配置加载 - 'core/config_models.py', # 配置模型 - 'core/permission.py', # 权限枚举 - - # API 模块 - 注意:这些类会被 Bot 类多继承使用 - # 因此不适合编译,否则会导致 "multiple bases have instance lay-out conflict" 错误 - # 'core/api/base.py', # API 基础类 - # 'core/api/account.py', # 账号相关 API - # 'core/api/friend.py', # 好友相关 API - # 'core/api/group.py', # 群组相关 API - # 'core/api/media.py', # 媒体相关 API - # 'core/api/message.py', # 消息相关 API - - # 数据模型(适合编译的高频使用数据类) - 'models/message.py', # 消息段模型 - 'models/sender.py', # 发送者模型 - 'models/objects.py', # API 响应数据模型 - - # 事件处理相关 - 'core/handlers/event_handler.py', # 事件处理器 - - # 注意:以下文件不适合编译 - # - 主程序文件(main.py) - # - 测试文件(tests/目录) - # - 插件文件(plugins/目录) - # - 编译脚本(compile_machine_code.py等) - # - 临时文件(scratch_files/目录) - # - 抽象基类(models/events/base.py) - # - 事件工厂(models/events/factory.py) - # - 包含复杂动态特性的文件 -] - -def list_compiled_modules(): - """列出已编译的模块""" - print(f"\n已编译的 {PLATFORM} 模块:") - print("=" * 50) - - # 查找所有编译后的文件 - compiled_files = [] - for ext in [EXTENSION, f'__mypyc{EXTENSION}']: - compiled_files.extend(glob.glob(f'**/*{ext}', recursive=True)) - - # 过滤掉虚拟环境中的文件 - compiled_files = [f for f in compiled_files if 'venv' not in f] - - if compiled_files: - for f in sorted(compiled_files): - size = os.path.getsize(f) // 1024 # KB - print(f"{f} ({size} KB)") - else: - print(f"未找到已编译的 {EXTENSION} 文件") - - print(f"\n总计: {len(compiled_files)} 个文件") - -def clean_compiled_files(): - """清理编译生成的文件""" - print(f"\n清理编译生成的 {EXTENSION} 文件...") - - # 查找所有编译后的文件 - compiled_files = [] - for ext in [EXTENSION, f'__mypyc{EXTENSION}']: - compiled_files.extend(glob.glob(f'**/*{ext}', recursive=True)) - - # 过滤掉虚拟环境中的文件 - compiled_files = [f for f in compiled_files if 'venv' not in f] - - if compiled_files: - for f in sorted(compiled_files): - try: - os.remove(f) - print(f"已删除: {f}") - except Exception as e: - print(f"删除失败 {f}: {e}") - - # 清理 build 目录 - if os.path.exists('build'): - try: - shutil.rmtree('build') - print("已删除 build 目录") - except Exception as e: - print(f"删除 build 目录失败: {e}") - else: - print(f"没有可清理的 {EXTENSION} 文件") - -def get_platform_specific_module_name(module_path): - """获取平台特定的模块文件名""" - module_name = module_path.replace('.py', '') - return f"{module_name}.{BUILD_PREFIX}{EXTENSION}" - -def compile_module(module_path): - """编译单个模块""" - print(f"\n编译: {module_path}") - - try: - # 直接调用 mypyc 命令行工具 - result = subprocess.run( - [sys.executable, '-m', 'mypyc', module_path], - capture_output=True, - text=True, - check=True - ) - - # 获取平台特定的模块名 - platform_module = get_platform_specific_module_name(module_path) - mypyc_platform_module = platform_module.replace(EXTENSION, f'__mypyc{EXTENSION}') - - # 检查编译产物是否在当前目录 - if os.path.exists(platform_module): - print(f" ✓ 编译成功: {platform_module}") - return True - else: - # 检查 build 目录中是否有编译产物 - build_module_path = os.path.join(BUILD_PATH, platform_module) - build_mypyc_path = os.path.join(BUILD_PATH, mypyc_platform_module) - - if os.path.exists(build_module_path): - # 如果在 build 目录中,复制到正确位置 - os.makedirs(os.path.dirname(platform_module), exist_ok=True) - shutil.copy2(build_module_path, platform_module) - shutil.copy2(build_mypyc_path, mypyc_platform_module) - print(f" ✓ 编译成功(已从 build 目录复制): {platform_module}") - return True - else: - print(f" ✗ 编译失败:找不到编译产物") - if result.stdout: - print(f" 编译输出:{result.stdout[:500]}...") - if result.stderr: - print(f" 错误信息:{result.stderr[:500]}...") - return False - - except subprocess.CalledProcessError as e: - print(f" ✗ 编译失败,退出码: {e.returncode}") - if e.stdout: - print(f" 编译输出:{e.stdout[:500]}...") - if e.stderr: - print(f" 错误信息:{e.stderr[:500]}...") - return False - except Exception as e: - print(f" ✗ 编译失败,意外错误: {e}") - return False - -def should_skip_module(module_path): - """检查模块是否应该被跳过编译""" - try: - with open(module_path, 'r', encoding='utf-8') as f: - content = f.read() - - # 检查是否包含抽象基类相关代码 - if 'from abc import ABC' in content or 'from abc import abstractmethod' in content: - return True, "包含抽象基类,不适合编译" - - # 检查是否包含动态特性 - if 'eval(' in content or 'exec(' in content or 'getattr(' in content or 'setattr(' in content: - return True, "包含动态特性,不适合编译" - - return False, "" - except Exception as e: - return True, f"读取文件时出错: {e}" - -def compile_all_modules(): - """编译所有指定的模块""" - print(f"\n开始编译 {len(MODULES)} 个模块 (平台: {PLATFORM})") - print("=" * 60) - - # 验证模块文件是否存在并检查是否适合编译 - valid_modules = [] - for module_path in MODULES: - if os.path.exists(module_path): - should_skip, reason = should_skip_module(module_path) - if should_skip: - print(f"跳过: {module_path} ({reason})") - else: - valid_modules.append(module_path) - else: - print(f"警告: 模块 {module_path} 不存在,将被跳过") - - if not valid_modules: - print("错误: 没有有效的模块可编译") - return False - - # 编译模块 - success_count = 0 - for module_path in valid_modules: - if compile_module(module_path): - success_count += 1 - - print(f"\n" + "=" * 60) - print(f"编译完成: {success_count}/{len(valid_modules)} 个模块成功") - - if success_count == len(valid_modules): - print("✓ 所有模块编译成功") - return True - else: - print("✗ 部分模块编译失败") - return False - -def main(): - """主函数""" - parser = argparse.ArgumentParser(description='跨平台 Python 模块编译脚本') - - group = parser.add_mutually_exclusive_group() - group.add_argument('--compile', '-c', action='store_true', default=True, - help='编译指定的模块 (默认)') - group.add_argument('--list', '-l', action='store_true', - help='列出已编译的模块') - group.add_argument('--clean', '-k', action='store_true', - help='清理编译生成的文件') - - args = parser.parse_args() - - # 检查是否安装了 mypyc - try: - import mypyc - except ImportError: - print("错误: 未安装 mypyc,请先安装: pip install mypyc") - sys.exit(1) - - if args.list: - list_compiled_modules() - elif args.clean: - clean_compiled_files() - else: - compile_all_modules() - print("\n使用 --list 选项查看已编译的模块") - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/compile_modules.py b/compile_modules.py deleted file mode 100644 index c8cfc07..0000000 --- a/compile_modules.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 -""" -编译模块脚本 - -这个脚本会单独编译每个Python模块,确保每个模块都在正确位置生成独立的.pyd文件。 -""" -import os -import sys -import glob -from mypyc.build import mypycify -from distutils.core import setup - -def compile_module(module_path): - """ - 编译单个模块 - - Args: - module_path: 要编译的Python模块路径 - """ - print(f"\nCompiling {module_path}...") - try: - ext_modules = mypycify([module_path]) - setup(name=f'compiled_{os.path.basename(module_path).replace(".py", "")}', - ext_modules=ext_modules) - return True - except Exception as e: - print(f"Error compiling {module_path}: {e}") - return False - -def main(): - """ - 主函数 - """ - # 要编译的模块列表 - modules = [ - 'core/utils/json_utils.py', # JSON 处理 - 'core/utils/executor.py', # 代码执行引擎 - 'core/managers/command_manager.py', # 指令匹配和分发 - 'core/managers/admin_manager.py', # 管理员管理 - 'core/managers/permission_manager.py', # 权限管理 - 'core/ws.py', # WebSocket 核心 - 'core/managers/plugin_manager.py', # 插件管理器 - 'core/bot.py', # Bot 核心抽象 - 'core/config_loader.py', # 配置加载 - ] - - # 自动添加 events 模型 - event_models = glob.glob('models/events/*.py') - event_models = [m for m in event_models if not m.endswith('__init__.py')] - modules.extend(event_models) - - print(f"Found {len(modules)} modules to compile.") - - success_count = 0 - for module in modules: - if compile_module(module): - success_count += 1 - - print(f"\n--- Compilation Summary ---") - print(f"Total modules: {len(modules)}") - print(f"Successfully compiled: {success_count}") - print(f"Failed: {len(modules) - success_count}") - -if __name__ == '__main__': - main() diff --git a/config.toml b/config.toml deleted file mode 100644 index 2a0d4e4..0000000 --- a/config.toml +++ /dev/null @@ -1,25 +0,0 @@ -[napcat_ws] -uri = "ws://114.66.58.203:3001" -token = "&d_VTfksE%}ul?_Y" -reconnect_interval = 5 - -[bot] -command = ["/"] -ignore_self_message = true #是否忽略自身消息 -permission_denied_message = "权限不足,需要 {permission_name} 权限" - -[redis] -host = "114.66.58.203" -port = 1931 -db = 0 -password = "redis_5dxyJG" - -[docker] -base_url = "tcp://dockertest.k2cro4.my:2375" -sandbox_image = "python-sandbox:latest" -timeout = 10 -concurrency_limit = 5 -tls_verify = true -ca_cert_path = "c:/Users/镀铬酸钾/Documents/NeoBot/ca/ca.crt" -client_cert_path = "c:/Users/镀铬酸钾/Documents/NeoBot/ca/client-cert.pem" -client_key_path = "c:/Users/镀铬酸钾/Documents/NeoBot/ca/client-key.pem" diff --git a/core/data/temp/help_menu.png b/core/data/temp/help_menu.png deleted file mode 100644 index f5e82c058530eeea8369d6abcce3106c14f82dd9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 150898 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 str: + """ + 生成性能统计报告 + + Returns: + 格式化的性能统计报告字符串 + """ + if not self.stats: + return "暂无性能统计数据" + + report = ["\n=== 性能统计报告 ===\n"] + report.append(f"{'函数名':<40} {'调用次数':<10} {'平均时间(ms)':<15} {'最长时间(ms)':<15} {'内存(MB)':<10}") + report.append("-" * 100) + + for func_name, stat in sorted(self.stats.items(), key=lambda x: x[1]["total_time"], reverse=True): + memory_str = f"{stat['avg_memory']:.2f}" if stat['avg_memory'] > 0 else "-" + report.append( + f"{func_name:<40} {stat['count']:<10} {stat['avg_time']*1000:<15.2f} " + f"{stat['max_time']*1000:<15.2f} {memory_str:<10}" + ) + + report.append("=" * 100) + return "\n".join(report) + + def reset(self): + """ + 重置性能统计数据 + """ + self.stats.clear() + + +# 创建全局性能统计实例 +performance_stats = PerformanceStats() + + +def timeit(func: Callable = None, *, log_level: int = logging.INFO, collect_stats: bool = True): + """ + 函数执行时间分析装饰器(支持同步和异步) + + Args: + func: 要装饰的函数 + log_level: 日志级别 + collect_stats: 是否收集到全局统计中 + + Returns: + 装饰后的函数 + """ + def decorator(func: Callable) -> Callable: + func_name = func.__qualname__ + is_coroutine = inspect.iscoroutinefunction(func) + + if is_coroutine: + @functools.wraps(func) + async def async_wrapper(*args, **kwargs): + start_time = time.perf_counter() + try: + result = await func(*args, **kwargs) + finally: + end_time = time.perf_counter() + duration = end_time - start_time + + if collect_stats: + performance_stats.record(func_name, duration) + + logger.log(log_level, f"[性能] {func_name} 执行时间: {duration*1000:.2f} ms") + + return result + + return async_wrapper + else: + @functools.wraps(func) + def sync_wrapper(*args, **kwargs): + start_time = time.perf_counter() + try: + result = func(*args, **kwargs) + finally: + end_time = time.perf_counter() + duration = end_time - start_time + + if collect_stats: + performance_stats.record(func_name, duration) + + logger.log(log_level, f"[性能] {func_name} 执行时间: {duration*1000:.2f} ms") + + return result + + return sync_wrapper + + if func is None: + return decorator + return decorator(func) + + +class profile: + """ + 性能分析上下文管理器 + 使用 pyinstrument 进行详细的性能分析 + """ + def __init__(self, enabled: bool = True, output_file: Optional[str] = None): + """ + Args: + enabled: 是否启用分析 + output_file: 分析结果输出文件路径(HTML格式) + """ + self.enabled = enabled + self.output_file = output_file + self.profiler = None + + def __enter__(self): + if self.enabled and PYINSTRUMENT_AVAILABLE: + self.profiler = Profiler() + self.profiler.start() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + if self.enabled and PYINSTRUMENT_AVAILABLE and self.profiler: + self.profiler.stop() + + # 输出到日志 + logger.info(f"[性能分析] {self.profiler.print()}") + + # 如果指定了输出文件,保存为HTML + if self.output_file: + try: + html = self.profiler.render(HTMLRenderer()) + with open(self.output_file, 'w', encoding='utf-8') as f: + f.write(html) + logger.info(f"[性能分析] 报告已保存到: {self.output_file}") + except Exception as e: + logger.error(f"[性能分析] 保存报告失败: {e}") + + +async def aprofile(func: Callable, *args, **kwargs): + """ + 异步函数性能分析 + + Args: + func: 要分析的异步函数 + *args: 函数参数 + **kwargs: 函数关键字参数 + + Returns: + 函数执行结果 + """ + if not PYINSTRUMENT_AVAILABLE: + logger.warning("[性能分析] pyinstrument 未安装,无法进行详细分析") + return await func(*args, **kwargs) + + profiler = Profiler() + profiler.start() + + try: + result = await func(*args, **kwargs) + finally: + profiler.stop() + logger.info(f"[性能分析] {profiler.print()}") + + return result + + +class memory_profile: + """ + 内存分析上下文管理器 + """ + def __init__(self, interval: float = 0.1, enabled: bool = True): + """ + Args: + interval: 内存采样间隔(秒) + enabled: 是否启用内存分析 + """ + self.interval = interval + self.enabled = enabled + self.memory_start = 0.0 + self.memory_end = 0.0 + + def __enter__(self): + if self.enabled and MEMORY_PROFILER_AVAILABLE: + self.memory_start = memory_usage()[0] + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + if self.enabled and MEMORY_PROFILER_AVAILABLE: + self.memory_end = memory_usage()[0] + memory_used = self.memory_end - self.memory_start + logger.info(f"[内存分析] 使用内存: {memory_used:.2f} MB") + + +def memory_profile_decorator(func: Callable = None, *, interval: float = 0.1): + """ + 内存分析装饰器(支持同步函数) + + Args: + func: 要装饰的函数 + interval: 内存采样间隔 + + Returns: + 装饰后的函数 + """ + def decorator(func: Callable) -> Callable: + @functools.wraps(func) + def wrapper(*args, **kwargs): + if not MEMORY_PROFILER_AVAILABLE: + return func(*args, **kwargs) + + mem_usage = memory_usage( + (func, args, kwargs), + interval=interval, + timeout=None, + include_children=False + ) + + max_memory = max(mem_usage) + logger.info(f"[内存分析] {func.__qualname__} 最大内存使用: {max_memory:.2f} MB") + return func(*args, **kwargs) + + return wrapper + + if func is None: + return decorator + return decorator(func) + + +def performance_monitor(func: Callable = None, *, threshold: float = 1.0): + """ + 性能监控装饰器 + 仅当函数执行时间超过阈值时记录日志 + 适合生产环境使用 + + Args: + func: 要装饰的函数 + threshold: 时间阈值(秒) + + Returns: + 装饰后的函数 + """ + def decorator(func: Callable) -> Callable: + func_name = func.__qualname__ + is_coroutine = inspect.iscoroutinefunction(func) + + if is_coroutine: + @functools.wraps(func) + async def async_wrapper(*args, **kwargs): + start_time = time.perf_counter() + result = await func(*args, **kwargs) + end_time = time.perf_counter() + duration = end_time - start_time + + if duration > threshold: + logger.warning(f"[性能监控] {func_name} 执行时间过长: {duration*1000:.2f} ms (阈值: {threshold*1000:.2f} ms)") + + return result + + return async_wrapper + else: + @functools.wraps(func) + def sync_wrapper(*args, **kwargs): + start_time = time.perf_counter() + result = func(*args, **kwargs) + end_time = time.perf_counter() + duration = end_time - start_time + + if duration > threshold: + logger.warning(f"[性能监控] {func_name} 执行时间过长: {duration*1000:.2f} ms (阈值: {threshold*1000:.2f} ms)") + + return result + + return sync_wrapper + + if func is None: + return decorator + return decorator(func) + + +# 全局实例 +global_stats = PerformanceStats() + + +__all__ = [ + 'timeit', + 'profile', + 'aprofile', + 'memory_profile', + 'memory_profile_decorator', + 'performance_monitor', + 'PerformanceStats', + 'performance_stats', + 'global_stats' +] diff --git a/core/utils/singleton.py b/core/utils/singleton.py index 94a7c93..27604e5 100644 --- a/core/utils/singleton.py +++ b/core/utils/singleton.py @@ -1,10 +1,13 @@ """ 通用单例模式基类 """ -from typing import Any, Optional, Type, TypeVar +from typing import Any, Dict, Optional, Type, TypeVar T = TypeVar('T') +# 存储每个类的实例 +_instance_store: Dict[Type, Any] = {} + class Singleton: """ 一个通用的单例基类 @@ -13,7 +16,6 @@ class Singleton: 它通过重写 __new__ 方法来确保每个类只有一个实例。 同时,它处理了重复初始化的问题,确保 __init__ 方法只在第一次实例化时被调用。 """ - _instance: Optional[Any] = None _initialized: bool = False def __new__(cls: Type[T], *args: Any, **kwargs: Any) -> T: @@ -27,9 +29,10 @@ class Singleton: Returns: T: 单例实例 """ - if cls._instance is None: - cls._instance = super().__new__(cls) - return cls._instance + # 使用全局字典存储实例,避免类型检查问题 + if cls not in _instance_store: + _instance_store[cls] = super().__new__(cls) + return _instance_store[cls] def __init__(self) -> None: """ @@ -38,3 +41,38 @@ class Singleton: if self._initialized: return self._initialized = True + + +def singleton(cls: Type[T]) -> Type[T]: + """ + 单例装饰器 + + 将普通类转换为单例类,确保整个应用程序中只有一个实例。 + + Args: + cls: 要转换为单例的类 + + Returns: + Type[T]: 单例类 + """ + # 为每个装饰的类创建一个实例存储 + class_instance: Optional[T] = None + + # 创建一个新的类,继承自原始类 + class SingletonClass(cls): + """单例包装类""" + + def __new__(cls: Type[T], *args: Any, **kwargs: Any) -> T: + """创建或返回现有的实例""" + nonlocal class_instance + if class_instance is None: + # 使用super()调用原始类的__new__方法 + class_instance = cls(*args, **kwargs) + return class_instance + + # 复制类的元数据 + SingletonClass.__name__ = cls.__name__ + SingletonClass.__doc__ = cls.__doc__ + SingletonClass.__module__ = cls.__module__ + + return SingletonClass diff --git a/export_requirements.py b/export_requirements.py deleted file mode 100644 index a3bb109..0000000 --- a/export_requirements.py +++ /dev/null @@ -1,8 +0,0 @@ -import subprocess - -# 运行pip freeze命令获取所有依赖 -result = subprocess.run(['pip', 'freeze'], capture_output=True, text=True) - -# 将输出写入requirements.txt文件 -with open('requirements.txt', 'w', encoding='utf-8') as f: - f.write(result.stdout) \ No newline at end of file diff --git a/main.py b/main.py index e0aff59..28998d0 100644 --- a/main.py +++ b/main.py @@ -10,6 +10,59 @@ import time from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler +# 初始化日志系统,必须在其他 core 模块导入之前执行 +from core.utils.logger import logger + +# 核心模块导入 +from core.managers.admin_manager import admin_manager +from core.ws import WS +from core.managers import plugin_manager, matcher +from core.managers.redis_manager import redis_manager +from core.managers.browser_manager import browser_manager +from core.utils.executor import run_in_thread_pool, initialize_executor +from core.config_loader import global_config as config + +# 检查 JIT 编译状态 +def check_jit_status(): + """ + 检查 Python JIT 编译状态 + + 该函数用于检测当前 Python 解释器是否启用了 JIT 编译功能, + 并打印相关信息,帮助用户了解运行环境的性能优化状态。 + """ + print("\n=== Python JIT 编译状态检查 ===") + + # 检查解释器信息 + print(f"Python 版本: {sys.version}") + print(f"解释器路径: {sys.executable}") + + # 检查优化级别 + print(f"优化级别 (-O): {sys.flags.optimize}") + + # 检查 JIT 相关模块和功能 + if sys.version_info >= (3, 10): + try: + # 对于 CPython 3.10+,检查是否启用了 JIT + import _opcode + if hasattr(_opcode, 'jit'): + print("JIT 状态: 已启用 (_opcode.jit)") + else: + print("JIT 状态: 未启用 (_opcode.jit 不可用)") + except ImportError: + print("JIT 状态: 未启用 (_opcode 模块不可用)") + else: + print("JIT 状态: 不可用 (需要 Python 3.10+)") + + # 检查是否使用了 PyPy + if hasattr(sys, 'pypy_version_info'): + print(f"PyPy 版本: {sys.pypy_version_info}") + print("JIT 状态: 已启用 (PyPy 内置 JIT)") + + print("==============================\n") + +# 执行 JIT 状态检查 +check_jit_status() + # 尝试使用高性能事件循环 try: if sys.platform == 'win32': @@ -25,17 +78,6 @@ try: except ImportError: print("未检测到高性能事件循环库 (uvloop/winloop),将使用默认事件循环") -# 初始化日志系统,必须在其他 core 模块导入之前执行 -from core.utils.logger import logger - -from core.managers.admin_manager import admin_manager -from core.ws import WS -from core.managers import plugin_manager, matcher -from core.managers.redis_manager import redis_manager -from core.managers.browser_manager import browser_manager -from core.utils.executor import run_in_thread_pool, initialize_executor -from core.config_loader import global_config as config - # 将项目根目录添加到 sys.path ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, ROOT_DIR) diff --git a/models/events/message.py b/models/events/message.py index 421c843..e84381a 100644 --- a/models/events/message.py +++ b/models/events/message.py @@ -4,7 +4,7 @@ 定义了消息相关的事件类,包括 MessageEvent, PrivateMessageEvent, GroupMessageEvent。 """ from dataclasses import dataclass, field -from typing import List, Optional, Union, ClassVar +from typing import List, Optional, Union from core.permission import Permission from models.message import MessageSegment @@ -27,17 +27,19 @@ class Anonymous: """匿名用户 flag""" +# 权限级别常量,用于装饰器参数 +# 定义在类外部,避免 dataclass 参数顺序问题 +MESSAGE_EVENT_ADMIN = Permission.ADMIN +MESSAGE_EVENT_OP = Permission.OP +MESSAGE_EVENT_USER = Permission.USER + + @dataclass(slots=True) class MessageEvent(OneBotEvent): """ 消息事件基类 """ - # 权限级别常量,用于装饰器参数 - ADMIN: ClassVar[Permission] = Permission.ADMIN - OP: ClassVar[Permission] = Permission.OP - USER: ClassVar[Permission] = Permission.USER - message_type: str """消息类型: private (私聊), group (群聊)""" @@ -70,6 +72,21 @@ class MessageEvent(OneBotEvent): def post_type(self) -> str: return EventType.MESSAGE + @property + def ADMIN(self) -> Permission: + """权限级别常量,用于装饰器参数""" + return MESSAGE_EVENT_ADMIN + + @property + def OP(self) -> Permission: + """权限级别常量,用于装饰器参数""" + return MESSAGE_EVENT_OP + + @property + def USER(self) -> Permission: + """权限级别常量,用于装饰器参数""" + return MESSAGE_EVENT_USER + async def reply(self, message: Union[str, "MessageSegment", List["MessageSegment"]], auto_escape: bool = False): """ 回复消息(抽象方法,由子类实现) @@ -119,4 +136,4 @@ class GroupMessageEvent(MessageEvent): """ await self.bot.send_group_msg( group_id=self.group_id, message=message, auto_escape=auto_escape - ) + ) \ No newline at end of file diff --git a/performance_config_example.py b/performance_config_example.py new file mode 100644 index 0000000..f9a11f8 --- /dev/null +++ b/performance_config_example.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +""" +性能分析配置示例 + +展示如何在项目中配置和使用性能分析功能。 +""" + +# 配置性能分析的使用方式 +PERFORMANCE_CONFIG = { + # 全局性能分析开关 + 'enabled': True, + + # 详细性能分析开关(使用 pyinstrument) + 'detailed': False, + + # 内存分析开关 + 'memory': False, + + # 性能监控阈值(秒) + 'threshold': 0.5, + + # 性能报告输出文件 + 'output_file': 'performance_report.html', + + # 要监控的核心组件列表 + 'monitored_components': [ + 'core.ws.WS', + 'core.managers.plugin_manager', + 'core.managers.browser_manager', + 'core.utils.executor.CodeExecutor', + 'core.handlers.event_handler', + ] +} + + +def get_performance_config(): + """ + 获取性能分析配置 + + Returns: + dict: 性能分析配置 + """ + import os + import json + + # 从环境变量加载配置 + config = PERFORMANCE_CONFIG.copy() + + if os.environ.get('PERFORMANCE_PROFILE'): + config['detailed'] = os.environ['PERFORMANCE_PROFILE'] == '1' + + if os.environ.get('PERFORMANCE_MEMORY'): + config['memory'] = os.environ['PERFORMANCE_MEMORY'] == '1' + + if os.environ.get('PERFORMANCE_THRESHOLD'): + try: + config['threshold'] = float(os.environ['PERFORMANCE_THRESHOLD']) + except ValueError: + pass + + if os.environ.get('PERFORMANCE_OUTPUT'): + config['output_file'] = os.environ['PERFORMANCE_OUTPUT'] + + if os.environ.get('PERFORMANCE_STATS'): + config['enabled'] = os.environ['PERFORMANCE_STATS'] == '1' + + return config + + +if __name__ == "__main__": + # 打印当前配置 + print("当前性能分析配置:") + print("=" * 50) + config = get_performance_config() + for key, value in config.items(): + print(f"{key}: {value}") diff --git a/plugins/auto_approve.py b/plugins/auto_approve.py index f92254e..105abdf 100644 --- a/plugins/auto_approve.py +++ b/plugins/auto_approve.py @@ -50,4 +50,4 @@ async def handle_group_request(bot: Bot, event: GroupRequestEvent): ) print(f"[自动同意] 已同意加入群聊 {event.group_id} (邀请人: {event.user_id})") except Exception as e: - print(f"[自动同意] 同意群聊邀请失败: {e}") + print(f"[自动同意] 同意群聊邀请失败: {e}") \ No newline at end of file diff --git a/plugins/bili_parser.py b/plugins/bili_parser.py index af37675..5ea5003 100644 --- a/plugins/bili_parser.py +++ b/plugins/bili_parser.py @@ -30,7 +30,7 @@ HEADERS = { # 全局共享的 ClientSession _session: Optional[aiohttp.ClientSession] = None -async def get_session() -> aiohttp.ClientSession: +def get_session() -> aiohttp.ClientSession: global _session if _session is None or _session.closed: _session = aiohttp.ClientSession(headers=HEADERS) @@ -55,7 +55,7 @@ def format_duration(seconds: int) -> str: async def get_real_url(short_url: str) -> Optional[str]: try: - session = await get_session() + session = get_session() async with session.head(short_url, headers=HEADERS, allow_redirects=False, timeout=5) as response: if response.status == 302: return response.headers.get('Location') @@ -65,22 +65,71 @@ async def get_real_url(short_url: str) -> Optional[str]: async def parse_video_info(video_url: str) -> Optional[Dict[str, Any]]: try: - session = await get_session() - async with session.get(video_url, headers=HEADERS, timeout=5) as response: + # 清理URL,去掉不必要的查询参数,只保留基本的视频URL + clean_url = video_url.split('?')[0] + if '#/' in clean_url: + clean_url = clean_url.split('#/')[0] + + session = get_session() + async with session.get(clean_url, headers=HEADERS, timeout=5) as response: response.raise_for_status() text = await response.text() soup = BeautifulSoup(text, 'html.parser') + # 尝试多种方式获取视频数据 + # 方式1: 尝试获取 __INITIAL_STATE__ script_tag = soup.find('script', text=re.compile('window.__INITIAL_STATE__')) if not script_tag or not script_tag.string: + # 方式2: 尝试获取 __PLAYINFO__ + script_tag = soup.find('script', text=re.compile('window.__PLAYINFO__')) + + if not script_tag or not script_tag.string: + # 方式3: 尝试获取页面标题和其他信息 + title_tag = soup.find('title') + if title_tag: + title = title_tag.get_text().strip() + # 提取BV号 + bv_match = re.search(r'(BV\w{10})', clean_url) + bvid = bv_match.group(1) if bv_match else '未知BV号' + + return { + "title": title.replace('_哔哩哔哩_bilibili', '').strip(), + "bvid": bvid, + "duration": 0, + "cover_url": '', + "play": 0, + "like": 0, + "coin": 0, + "favorite": 0, + "share": 0, + "owner_name": '未知UP主', + "owner_avatar": '', + "followers": 0, + } return None - match = re.search(r'window\.__INITIAL_STATE__\s*=\s*(\{[^\}]*\});', script_tag.string) + # 原始解析逻辑 + match = re.search(r'window\.__INITIAL_STATE__\s*=\s*(\{[^}]*\});', script_tag.string) + if not match: + # 尝试另一种正则表达式 + match = re.search(r'window\.__INITIAL_STATE__\s*=\s*(\{.*?\});', script_tag.string, re.DOTALL) + if not match: return None json_str = match.group(1) - data = json.loads(json_str) + # 清理JSON字符串中的潜在问题字符 + json_str = json_str.strip().rstrip(';') + + try: + data = json.loads(json_str) + except json.JSONDecodeError: + # 如果直接解析失败,尝试清理JSON字符串 + # 移除可能的注释或无效字符 + cleaned_json = re.sub(r',\s*[}]', '}', json_str) # 移除末尾多余的逗号 + cleaned_json = re.sub(r'/\*.*?\*/', '', cleaned_json) # 移除注释 + cleaned_json = re.sub(r'//.*', '', cleaned_json) # 移除行注释 + data = json.loads(cleaned_json) video_data = data.get('videoData', {}) up_data = data.get('upData', {}) @@ -116,6 +165,10 @@ async def parse_video_info(video_url: str) -> Optional[Dict[str, Any]]: except (aiohttp.ClientError, KeyError, AttributeError, json.JSONDecodeError) as e: logger.error(f"解析视频信息失败: {e}") + logger.debug(f"失败的URL: {video_url}") + except Exception as e: + logger.error(f"解析视频信息时发生未知错误: {e}") + logger.debug(f"失败的URL: {video_url}") return None @@ -212,24 +265,32 @@ async def process_bili_link(event: MessageEvent, url: str): :param event: 消息事件对象 :param url: 待处理的B站链接 """ - if "b23.tv" in url: - real_url = await get_real_url(url) - if not real_url: - logger.error(f"[bili_parser] 无法从 {url} 获取真实URL。") - await event.reply("无法解析B站短链接。") - return - else: - real_url = url.split('?')[0] + try: + if "b23.tv" in url: + real_url = await get_real_url(url) + if not real_url: + logger.error(f"[bili_parser] 无法从 {url} 获取真实URL。") + await event.reply("无法解析B站短链接。") + return + else: + # 清理URL,移除复杂查询参数,只保留基本的视频URL + real_url = url.split('?')[0] + if '#/' in real_url: + real_url = real_url.split('#/')[0] - video_info = await parse_video_info(real_url) - if not video_info: - logger.error(f"[bili_parser] 无法从 {real_url} 解析视频信息。") - await event.reply("无法获取视频信息,可能是B站接口变动或视频不存在。") + video_info = await parse_video_info(real_url) + if not video_info: + logger.error(f"[bili_parser] 无法从 {real_url} 解析视频信息。") + await event.reply("无法获取视频信息,可能是B站接口变动或视频不存在。") + return + except Exception as e: + logger.error(f"[bili_parser] 处理B站链接时发生错误: {e}") + await event.reply("处理B站链接时发生错误,请稍后再试。") return # 检查视频时长 video_message: Union[str, MessageSegment] - if video_info['duration'] > 300: # 5分钟 = 300秒 + if video_info['duration'] > 1200: # 5分钟 = 300秒 video_message = "视频时长超过5分钟,不进行解析。" else: direct_url = await get_direct_video_url(real_url) diff --git a/plugins/douyin_parser.py b/plugins/douyin_parser.py new file mode 100644 index 0000000..5fe6a88 --- /dev/null +++ b/plugins/douyin_parser.py @@ -0,0 +1,391 @@ +# -*- coding: utf-8 -*- +import re +import json +import aiohttp +from typing import Optional, Dict, Any, Union +from cachetools import TTLCache + +from core.utils.logger import logger +from core.managers.command_manager import matcher +from models import MessageEvent, MessageSegment + +# 创建一个TTL缓存,最大容量100,缓存时间10秒 +processed_messages: TTLCache[int, bool] = TTLCache(maxsize=100, ttl=10) + +# 插件元数据 +__plugin_meta__ = { + "name": "douyin_parser", + "description": "自动解析抖音分享链接,提取视频信息和直链。", + "usage": "(自动触发)当检测到抖音分享链接时,自动发送视频信息。", +} + +# 常量定义 +DOUYIN_NICKNAME = "抖音视频解析" + +HEADERS = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', + 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', + 'Accept-Encoding': 'gzip, deflate, br', # 重新启用br编码支持 + 'Connection': 'keep-alive', + 'Upgrade-Insecure-Requests': '1' +} + +# 全局共享的 ClientSession +_session: Optional[aiohttp.ClientSession] = None + +async def get_session() -> aiohttp.ClientSession: + global _session + if _session is None or _session.closed: + _session = aiohttp.ClientSession(headers=HEADERS) + return _session + + +def format_count(num: Union[int, str]) -> str: + try: + n = int(num) + if n < 10000: + return str(n) + return f"{n / 10000:.1f}万" + except (ValueError, TypeError): + return str(num) + + +DOUYIN_URL_PATTERN = re.compile(r"https?://v\.douyin\.com/[a-zA-Z0-9_]+/?", re.IGNORECASE) # 包含下划线 +DOUYIN_SHORT_PATTERN = re.compile(r"(?:https?://)?v\.douyin\.com/[a-zA-Z0-9_]+/?", re.IGNORECASE) # 包含下划线 + + +def extract_url_from_json_segments(segments): + """ + 从消息的JSON段中提取抖音链接 + :param segments: 消息段列表 + :return: 提取到的URL或None + """ + for segment in segments: + if segment.type == "json": + logger.info(f"[douyin_parser] 检测到JSON CQ码: {segment.data}") + try: + json_data = json.loads(segment.data.get("data", "{}")) + # 检查是否是抖音分享卡片 + meta = json_data.get("meta", {}) + if "detail_1" in meta: + detail = meta["detail_1"] + if "qqdocurl" in detail: + url = detail["qqdocurl"] + if "douyin.com" in url or "iesdouyin.com" in url: + logger.success(f"[douyin_parser] 成功从JSON卡片中提取到抖音链接: {url}") + return url + except (json.JSONDecodeError, KeyError) as e: + logger.error(f"[douyin_parser] 解析JSON失败: {e}") + continue + return None + + +def extract_url_from_text_segments(segments): + """ + 从消息的文本段中提取抖音链接 + :param segments: 消息段列表 + :return: 提取到的URL或None + """ + for segment in segments: + if segment.type == "text": + text_content = segment.data.get("text", "") + # 查找抖音链接 + match = DOUYIN_URL_PATTERN.search(text_content) + if match: + extracted_url = match.group(0) + logger.success(f"[douyin_parser] 成功从文本中提取到抖音链接: {extracted_url}") + return extracted_url + # 也检查是否有v.douyin.com格式的链接 + short_match = DOUYIN_SHORT_PATTERN.search(text_content) + if short_match: + extracted_url = short_match.group(0) + logger.success(f"[douyin_parser] 成功从文本中提取到抖音短链接: {extracted_url}") + return extracted_url + return None + + +@matcher.on_message() +async def handle_douyin_share(event: MessageEvent): + """ + 处理消息,检测抖音分享链接(JSON卡片或文本链接)并进行解析。 + :param event: 消息事件对象 + """ + # 消息去重 + if event.message_id in processed_messages: + return + processed_messages[event.message_id] = True + + # 忽略机器人自己发送的消息,防止无限循环 + if event.user_id == event.self_id: + return + + # 1. 优先解析JSON卡片中的链接 + url_to_process = extract_url_from_json_segments(event.message) + + # 2. 如果未在JSON卡片中找到链接,则在文本消息中查找 + if not url_to_process: + url_to_process = extract_url_from_text_segments(event.message) + + # 3. 如果找到了抖音链接,则进行处理 + if url_to_process: + await process_douyin_link(event, url_to_process) + + +async def get_real_url(short_url: str) -> Optional[str]: + """ + 获取抖音短链接的真实URL + :param short_url: 抖音短链接 + :return: 真实URL或None + """ + try: + # 首先尝试获取重定向后的URL + async with aiohttp.ClientSession() as session: + # 添加更多头部信息模拟移动端访问 + mobile_headers = HEADERS.copy() # 使用更新后的完整请求头 + mobile_headers.update({ + 'Sec-Fetch-Dest': 'document', + 'Sec-Fetch-Mode': 'navigate', + 'Sec-Fetch-Site': 'none', + 'Cache-Control': 'max-age=0', + # 模拟移动设备的额外头部 + 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1', + 'X-Requested-With': 'XMLHttpRequest', + 'Referer': 'https://www.douyin.com/' + }) + + async with session.get(short_url, headers=mobile_headers, allow_redirects=True, timeout=10) as response: + redirected_url = str(response.url) + + # 检查重定向后的URL是否包含视频ID + # 抖音视频页通常包含 aweme_id 或 sec_uid 参数 + if 'video/' in redirected_url or '/note/' in redirected_url: + logger.info(f"[douyin_parser] 重定向后的视频URL: {redirected_url}") + return redirected_url + elif 'share_item' in redirected_url: + # 如果URL中有share_item参数,尝试从中提取视频信息 + logger.info(f"[douyin_parser] 重定向后的分享URL: {redirected_url}") + return redirected_url + else: + # 如果重定向到了主页或其他非视频页面,尝试从响应中提取信息 + logger.warning(f"[douyin_parser] 重定向到了非预期页面: {redirected_url}") + return redirected_url + + except Exception as e: + logger.error(f"[douyin_parser] 获取真实URL失败: {e}") + return None + + +async def parse_douyin_video(video_url: str) -> Optional[Dict[str, Any]]: + """ + 解析抖音视频信息 + :param video_url: 抖音视频链接 + :return: 视频信息字典或None + """ + try: + # 使用新的第三方API解析抖音视频 + api_url = f"http://api.xhus.cn/api/douyin?url={video_url}" + + session = await get_session() + async with session.get(api_url, headers=HEADERS, timeout=10) as response: + if response.status != 200: + logger.error(f"[douyin_parser] API请求失败,状态码: {response.status}") + return None + + response_data = await response.json() + + if not isinstance(response_data, dict): + logger.error(f"[douyin_parser] API返回格式错误: {response_data}") + return None + + if response_data.get("code") != 200: + logger.error(f"[douyin_parser] API返回错误: {response_data}") + return None + + data = response_data.get("data", {}) + if not data: + logger.error("[douyin_parser] API返回数据为空") + return None + + # 新API的响应格式转换 + return { + "type": "video" if not data.get("images") or not isinstance(data.get("images"), list) else "image", + "video_url": data.get("url", ""), # 核心字段:视频播放地址 + "video_url_HQ": data.get("url", ""), # 新API没有HQ字段,使用同一个地址 + "nickname": data.get("author", "未知作者"), + "desc": data.get("title", "无描述"), + "aweme_id": data.get("uid", ""), + "like": data.get("like", 0), + "cover": data.get("cover", ""), + "time": data.get("time", 0), + "author_avatar": data.get("avatar", ""), + "music": data.get("music", {}), + } + except (aiohttp.ClientError, KeyError, AttributeError, json.JSONDecodeError) as e: + logger.error(f"[douyin_parser] 解析抖音视频信息失败: {e}") + logger.debug(f"失败的URL: {video_url}") + except Exception as e: + logger.error(f"[douyin_parser] 解析抖音视频时发生未知错误: {e}") + logger.debug(f"失败的URL: {video_url}") + + return None + + +async def process_douyin_link(event: MessageEvent, url: str): + """ + 处理抖音链接,获取信息并回复 + :param event: 消息事件对象 + :param url: 待处理的抖音链接 + """ + try: + # 直接将原始链接传递给API,不需要获取真实URL + video_info = await parse_douyin_video(url) + if not video_info: + logger.error(f"[douyin_parser] 无法从 {url} 解析视频信息。") + await event.reply("无法获取视频信息,可能是抖音接口变动或视频不存在。") + return + + # 构建回复消息,包含原分享中的文本内容(如果有) + original_text = "" + for segment in event.message: + if segment.type == "text": + text_content = segment.data.get("text", "") + # 提取除了链接以外的文本内容 + # 移除链接和复制提示 + cleaned_text = re.sub(DOUYIN_URL_PATTERN, '', text_content) + cleaned_text = re.sub(DOUYIN_SHORT_PATTERN, '', cleaned_text) + cleaned_text = re.sub(r'复制此链接,打开Dou音搜索,直接观看视频!', '', cleaned_text) + cleaned_text = cleaned_text.strip() + if cleaned_text: + original_text = cleaned_text + break + + # 构建回复消息 + text_parts = ["抖音视频解析"] + text_parts.append("--------------------") + + if original_text: + text_parts.append(f" 分享内容: {original_text}") + text_parts.append("--------------------") + + text_parts.append(f" 作者: {video_info['nickname']}") + text_parts.append(f" 抖音号: {video_info['aweme_id']}") + text_parts.append(f" 标题: {video_info['desc']}") + text_parts.append(f" 点赞: {format_count(video_info['like'])}") + text_parts.append(f" 类型: {video_info['type']}") + + # 如果是音乐,添加音乐信息 + if video_info.get('music'): + music_info = video_info['music'] + text_parts.append("--------------------") + text_parts.append(" 背景音乐:") + text_parts.append(f" 标题: {music_info.get('title', '')}") + text_parts.append(f" 作者: {music_info.get('author', '')}") + + text_parts.append("--------------------") + text_parts.append(f" 原始链接: {url}") + + text_message = "\n".join(text_parts) + + # 准备转发消息节点 + nodes = [] + + # 添加文本信息节点 + text_node = event.bot.build_forward_node( + user_id=event.self_id, + nickname=DOUYIN_NICKNAME, + message=text_message + ) + nodes.append(text_node) + + # 添加封面图片节点(如果有) + if video_info.get('cover'): + try: + cover_node = event.bot.build_forward_node( + user_id=event.self_id, + nickname=DOUYIN_NICKNAME, + message=[ + MessageSegment.text("抖音视频封面:\n"), + MessageSegment.image(video_info['cover']) + ] + ) + nodes.append(cover_node) + except Exception as e: + logger.warning(f"[douyin_parser] 无法添加封面图片: {e}") + + # 添加作者头像节点(如果有) + if video_info.get('author_avatar'): + try: + avatar_node = event.bot.build_forward_node( + user_id=event.self_id, + nickname=DOUYIN_NICKNAME, + message=[ + MessageSegment.text("作者头像:\n"), + MessageSegment.image(video_info['author_avatar']) + ] + ) + nodes.append(avatar_node) + except Exception as e: + logger.warning(f"[douyin_parser] 无法添加作者头像: {e}") + + # 尝试添加视频直链(单独节点) + video_success = False + try: + if video_info.get('video_url'): + video_url = video_info.get('video_url', '') + # 检查视频类型 + if video_info.get('type') == 'video': + video_message = MessageSegment.video(video_url) + video_type_text = "视频直链:" + else: # image类型 + video_message = MessageSegment.image(video_url) # 单个图片 + video_type_text = "图集首图:" + + # 构建视频/图片节点 + video_node = event.bot.build_forward_node( + user_id=event.self_id, + nickname=DOUYIN_NICKNAME, + message=[ + MessageSegment.text(video_type_text + "\n"), + video_message + ] + ) + nodes.append(video_node) + video_success = True + except Exception as e: + logger.error(f"[douyin_parser] 无法添加视频/图片: {e}") + + # 如果无法添加视频,添加提示信息 + if not video_success: + no_video_node = event.bot.build_forward_node( + user_id=event.self_id, + nickname=DOUYIN_NICKNAME, + message="视频解析成功,但无法获取直链或播放视频。" + ) + nodes.append(no_video_node) + + logger.success(f"[douyin_parser] 成功解析视频信息并准备以聊天记录形式回复: {video_info['desc'][:20]}...") + + # 发送合并转发消息 + try: + # 使用更通用的 send_forwarded_messages 方法,自动判断私聊或群聊 + await event.bot.send_forwarded_messages(target=event, nodes=nodes) + except Exception as e: + # 如果发送合并转发失败,尝试单独发送文本信息 + logger.error(f"[douyin_parser] 发送合并转发失败: {e}") + + # 构建替代的简单文本回复,避免电脑端显示问题 + simple_reply = f"抖音视频解析成功\n{text_message}\n\n如果无法查看视频内容,请复制原始链接到浏览器打开:{url}" + await event.reply(simple_reply) + + # 如果有封面,尝试单独发送 + if video_info.get('cover'): + try: + await event.reply(MessageSegment.image(video_info['cover'])) + except Exception: + pass + + except Exception as e: + logger.error(f"[douyin_parser] 处理抖音链接时发生错误: {e}") + await event.reply("处理抖音链接时发生错误,请稍后再试。") + return \ No newline at end of file diff --git a/profile_main.py b/profile_main.py new file mode 100644 index 0000000..075ee82 --- /dev/null +++ b/profile_main.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +""" +性能分析入口文件 + +用于启动带有性能分析功能的应用程序。 + +使用方法: + python profile_main.py [options] + +选项: + -h, --help 显示帮助信息 + --profile, -p 启用详细性能分析(使用 pyinstrument) + --memory, -m 启用内存使用分析 + --output, -o FILE 性能分析报告输出文件(HTML格式) + --threshold, -t SEC 设置性能监控阈值(秒) + --stats, -s 在程序结束时输出性能统计报告 +""" + +import sys +import argparse +import os + +# 将项目根目录添加到 sys.path +ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, ROOT_DIR) + +# 解析命令行参数 +parser = argparse.ArgumentParser(description='性能分析入口文件') +parser.add_argument('--profile', '-p', action='store_true', help='启用详细性能分析(使用 pyinstrument)') +parser.add_argument('--memory', '-m', action='store_true', help='启用内存使用分析') +parser.add_argument('--output', '-o', type=str, default='performance_report.html', help='性能分析报告输出文件(HTML格式)') +parser.add_argument('--threshold', '-t', type=float, default=0.5, help='设置性能监控阈值(秒)') +parser.add_argument('--stats', '-s', action='store_true', help='在程序结束时输出性能统计报告') + +args = parser.parse_args() + +# 设置全局性能分析配置 +os.environ['PERFORMANCE_PROFILE'] = '1' if args.profile else '0' +os.environ['PERFORMANCE_MEMORY'] = '1' if args.memory else '0' +os.environ['PERFORMANCE_OUTPUT'] = args.output +os.environ['PERFORMANCE_THRESHOLD'] = str(args.threshold) +os.environ['PERFORMANCE_STATS'] = '1' if args.stats else '0' + +# 导入并运行主程序 +from core.utils.performance import profile, aprofile +from main import main +import asyncio + +async def main_with_profile(): + """ + 带有性能分析的主函数入口 + """ + if args.profile: + # 使用 pyinstrument 进行详细性能分析 + from pyinstrument import Profiler + from pyinstrument.renderers import HTMLRenderer + + profiler = Profiler() + profiler.start() + + try: + await main() + finally: + profiler.stop() + + # 输出分析结果到控制台 + print("\n" + "=" * 80) + print("性能分析结果") + print("=" * 80) + print(profiler.print()) + + # 保存HTML报告 + try: + html = profiler.render(HTMLRenderer()) + with open(args.output, 'w', encoding='utf-8') as f: + f.write(html) + print(f"\n性能分析报告已保存到: {args.output}") + except Exception as e: + print(f"\n保存性能分析报告失败: {e}") + else: + # 不使用详细分析,直接运行 + await main() + +if __name__ == "__main__": + try: + asyncio.run(main_with_profile()) + finally: + # 输出性能统计报告 + if args.stats: + from core.utils.performance import performance_stats + print("\n" + "=" * 80) + print("性能统计报告") + print("=" * 80) + print(performance_stats.report()) diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..2352bf4 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,4 @@ +# 开发依赖 +pyinstrument>=4.5.0 # 性能分析工具,支持异步代码 +memory-profiler>=0.61.0 # 内存分析工具 +psutil>=5.9.8 # 系统资源监控 diff --git a/scripts/compile_machine_code.py b/scripts/compile_machine_code.py index 70c6992..7aedd7e 100644 --- a/scripts/compile_machine_code.py +++ b/scripts/compile_machine_code.py @@ -1,5 +1,349 @@ #!/usr/bin/env python3 """ +优化版跨平台 Python 模块编译脚本 + +将核心 Python 模块编译为机器码(.pyd 或 .so)以提升性能。 +此版本基于对项目结构的深入分析,包含了更多高频使用的模块。 + +支持的平台: +- Windows: 生成 .pyd 文件 +- Linux: 生成 .so 文件 + +使用方法: + python compile_machine_code.py [options] + +选项: + --compile, -c 编译指定的模块(默认) + --list, -l 列出已编译的模块 + --clean, -k 清理编译生成的文件 + --help, -h 显示帮助信息 + +注意: + 1. 需要安装 C 编译器 (Windows 上需要 Visual Studio Build Tools, Linux 上需要 GCC) + 2. 需要安装 mypyc: pip install mypyc + 3. 编译后的文件是平台相关的,不能跨平台复制 + 4. 建议在部署的目标环境上运行此脚本 + 5. Mypyc 不支持动态特性,如 eval/exec/getattr/setattr 等 +""" +import os +import sys +import glob +import subprocess +import shutil +import argparse + +# 检测当前平台和 Python 版本 +PLATFORM = sys.platform +PYTHON_VERSION = f"{sys.version_info.major}{sys.version_info.minor}" # 例如 "314" + +if PLATFORM.startswith('win'): + EXTENSION = '.pyd' + BUILD_PREFIX = f'cp{PYTHON_VERSION}-win_amd64' + BUILD_PATH = os.path.join('build', f'lib.win-amd64-cpython-{PYTHON_VERSION}') +elif PLATFORM.startswith('linux'): + EXTENSION = '.so' + BUILD_PREFIX = f'cp{PYTHON_VERSION}-x86_64-linux-gnu' + BUILD_PATH = os.path.join('build', f'lib.linux-x86_64-cpython-{PYTHON_VERSION}') +else: + print(f"不支持的平台: {PLATFORM}") + sys.exit(1) + +# 根据项目分析,优化要编译的模块列表 +# 这些是项目中使用频率最高的模块,编译后能显著提升性能 +MODULES = [ + # 工具模块 - 高频使用 + 'core/utils/json_utils.py', # JSON 处理 - 高频使用 + 'core/utils/executor.py', # 代码执行引擎 - 高频使用 + 'core/utils/exceptions.py', # 自定义异常 - 基础组件 + 'core/utils/performance.py', # 性能监控工具 - 重要组件 + 'core/utils/logger.py', # 日志模块 - 高频使用 + 'core/utils/singleton.py', # 单例模式 - 基础组件 + + # 核心管理模块 - 高频使用 + # 'core/managers/command_manager.py', # 指令匹配和分发 - 包含动态特性,不适合编译 + # 'core/managers/admin_manager.py', # 管理员管理 - 包含动态特性,不适合编译 + # 'core/managers/permission_manager.py', # 权限管理 - 包含动态特性,不适合编译 + # 'core/managers/plugin_manager.py', # 插件管理器 - 包含动态特性,不适合编译 + # 'core/managers/redis_manager.py', # Redis 管理器 - 包含动态特性,不适合编译 + # 'core/managers/image_manager.py', # 图片管理器 - 包含动态特性,不适合编译 + + # 核心基础模块 - 高频使用 + 'core/ws.py', # WebSocket 核心 - 核心通信,被10个文件引用 + # 'core/bot.py', # Bot 核心抽象 - 使用多重继承,不适合编译 + 'core/config_loader.py', # 配置加载 - 启动必需,被7个文件引用 + # 'core/config_models.py', # 配置模型 - 包含复杂类型定义,不适合编译 + # 'core/permission.py', # 权限枚举 - 包含动态属性,不适合编译 + + # 数据模型 - 高频使用 + 'models/message.py', # 消息段模型 - 高频消息处理 + 'models/sender.py', # 发送者模型 - 高频消息处理 + 'models/objects.py', # API 响应数据模型 - 高频数据处理 + + # 事件处理相关 - 高频使用 + 'core/handlers/event_handler.py', # 事件处理器 - 核心事件处理 + + # 事件模型 - 高频使用,但包含dataclass,可能有编译问题,暂时排除 + # 'models/events/message.py', # 消息事件 - 最高频事件类型 + # 'models/events/notice.py', # 通知事件 - 高频事件类型 + # 'models/events/request.py', # 请求事件 - 高频事件类型 + # 'models/events/meta.py', # 元事件 - 高频事件类型 + + # 注意:以下文件不适合编译 + # - 主程序文件(main.py) + # - 测试文件(tests/目录) + # - 插件文件(plugins/目录) + # - 编译(脚本compile_machine_code.py等) + # - 包含复杂动态特性的文件 + # - API 基础类(由于多重继承问题) +] + +def list_compiled_modules(): + """列出已编译的模块""" + print(f"\n已编译的 {PLATFORM} 模块:") + print("=" * 50) + + # 查找所有编译后的文件 + compiled_files = [] + for ext in [EXTENSION, f'__mypyc{EXTENSION}']: + compiled_files.extend(glob.glob(f'**/*{ext}', recursive=True)) + + # 过滤掉虚拟环境中的文件 + compiled_files = [f for f in compiled_files if 'venv' not in f and '.venv' not in f] + + if compiled_files: + for f in sorted(compiled_files): + size = os.path.getsize(f) // 1024 # KB + print(f"{f} ({size} KB)") + else: + print(f"未找到已编译的 {EXTENSION} 文件") + + print(f"\n总计: {len(compiled_files)} 个文件") + +def clean_compiled_files(): + """清理编译生成的文件""" + print(f"\n清理编译生成的 {EXTENSION} 文件...") + + # 查找所有编译后的文件 + compiled_files = [] + for ext in [EXTENSION, f'__mypyc{EXTENSION}']: + compiled_files.extend(glob.glob(f'**/*{ext}', recursive=True)) + + # 过滤掉虚拟环境中的文件 + compiled_files = [f for f in compiled_files if 'venv' not in f and '.venv' not in f] + + if compiled_files: + for f in sorted(compiled_files): + try: + os.remove(f) + print(f"已删除: {f}") + except Exception as e: + print(f"删除失败 {f}: {e}") + + # 清理 build 目录 + if os.path.exists('build'): + try: + shutil.rmtree('build') + print("已删除 build 目录") + except Exception as e: + print(f"删除 build 目录失败: {e}") + else: + print(f"没有可清理的 {EXTENSION} 文件") + +def get_platform_specific_module_name(module_path): + """获取平台特定的模块文件名""" + module_name = module_path.replace('.py', '') + return f"{module_name}.{BUILD_PREFIX}{EXTENSION}" + +def compile_module(module_path): + """编译单个模块""" + print(f"\n编译: {module_path}") + + try: + # 直接调用 mypyc 命令行工具 + # 使用二进制模式捕获输出以避免编码问题 + result = subprocess.run( + [sys.executable, '-m', 'mypyc', module_path], + capture_output=True, + check=True + ) + + # 解码输出时处理可能的编码错误 + try: + stdout_text = result.stdout.decode('utf-8', errors='replace') + stderr_text = result.stderr.decode('utf-8', errors='replace') + except AttributeError: + # 如果已经是字符串(Python 3.7+),则直接使用 + stdout_text = result.stdout + stderr_text = result.stderr + + # 获取平台特定的模块名 + platform_module = get_platform_specific_module_name(module_path) + mypyc_platform_module = platform_module.replace(EXTENSION, f'__mypyc{EXTENSION}') + + # 检查编译产物是否在当前目录 + if os.path.exists(platform_module): + print(f" ✓ 编译成功: {platform_module}") + return True + else: + # 检查 build 目录中是否有编译产物 + build_module_path = os.path.join(BUILD_PATH, platform_module) + build_mypyc_path = os.path.join(BUILD_PATH, mypyc_platform_module) + + if os.path.exists(build_module_path): + # 如果在 build 目录中,复制到正确位置 + os.makedirs(os.path.dirname(platform_module), exist_ok=True) + shutil.copy2(build_module_path, platform_module) + if os.path.exists(build_mypyc_path): + shutil.copy2(build_mypyc_path, mypyc_platform_module) + print(f" ✓ 编译成功(已从 build 目录复制): {platform_module}") + return True + else: + print(" ✗ 编译失败:找不到编译产物") + if result.stdout: + print(f" 编译输出:{stdout_text[:500]}...") + if result.stderr: + print(f" 错误信息:{stderr_text[:500]}...") + return False + + except subprocess.CalledProcessError as e: + print(f" ✗ 编译失败,退出码: {e.returncode}") + if hasattr(e, 'stdout') and e.stdout: + try: + stdout_text = e.stdout.decode('utf-8', errors='replace') if isinstance(e.stdout, bytes) else e.stdout + print(f" 编译输出:{stdout_text[:500]}...") + except Exception: + print(f" 编译输出:{str(e.stdout)[:500]}...") + if hasattr(e, 'stderr') and e.stderr: + try: + stderr_text = e.stderr.decode('utf-8', errors='replace') if isinstance(e.stderr, bytes) else e.stderr + print(f" 错误信息:{stderr_text[:500]}...") + except Exception: + print(f" 错误信息:{str(e.stderr)[:500]}...") + return False + except Exception as e: + print(f" ✗ 编译失败,意外错误: {e}") + import traceback + traceback.print_exc() + return False + +def should_skip_module(module_path): + """检查模块是否应该被跳过编译""" + try: + with open(module_path, 'r', encoding='utf-8') as f: + content = f.read() + + # 检查是否包含抽象基类相关代码 + if 'from abc import ABC' in content or 'from abc import abstractmethod' in content: + return True, "包含抽象基类,不适合编译" + + # 检查是否包含危险的动态特性 + # 注意:我们允许基本的动态特性,如getattr,但对于eval、exec等危险操作仍然阻止 + if ('eval(' in content or 'exec(' in content or + 'compile(' in content): + return True, "包含危险动态特性,不适合编译" + + # 检查是否包含复杂的动态属性访问 + if ('__dict__' in content or '__class__' in content or + '__module__' in content or '__bases__' in content): + return True, "包含复杂动态特性,不适合编译" + + # 检查是否包含复杂的动态属性访问 + if '.__dict__' in content or '.__class__' in content: + return True, "包含复杂动态特性,不适合编译" + + return False, "" + except Exception as e: + return True, f"读取文件时出错: {e}" + +def compile_all_modules(): + """编译所有指定的模块""" + print(f"\n开始编译 {len(MODULES)} 个模块 (平台: {PLATFORM})") + print("=" * 60) + + # 验证模块文件是否存在并检查是否适合编译 + valid_modules = [] + skipped_modules = [] + + for module_path in MODULES: + if os.path.exists(module_path): + should_skip, reason = should_skip_module(module_path) + if should_skip: + print(f"跳过: {module_path} ({reason})") + skipped_modules.append((module_path, reason)) + else: + valid_modules.append(module_path) + else: + print(f"警告: 模块 {module_path} 不存在,将被跳过") + + print(f"\n有效模块: {len(valid_modules)}, 跳过模块: {len(skipped_modules)}") + + if not valid_modules: + print("错误: 没有有效的模块可编译") + return False + + # 编译模块 + success_count = 0 + failed_modules = [] + + for module_path in valid_modules: + if compile_module(module_path): + success_count += 1 + else: + failed_modules.append(module_path) + + print("\n" + "=" * 60) + print(f"编译完成: {success_count}/{len(valid_modules)} 个模块成功") + + if failed_modules: + print(f"失败模块: {failed_modules}") + + if success_count == len(valid_modules): + print("✓ 所有模块编译成功") + return True + else: + print("✗ 部分模块编译失败") + return False + +def main(): + """主函数""" + # 检查 Python 版本 + if not (sys.version_info.major == 3 and sys.version_info.minor >= 8): + print("警告: 推荐使用 Python 3.8+ 以获得最佳性能") + print(f"当前版本: {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}") + print("继续编译可能导致兼容性问题") + print() + + parser = argparse.ArgumentParser(description='优化版跨平台 Python 模块编译脚本') + + group = parser.add_mutually_exclusive_group() + group.add_argument('--compile', '-c', action='store_true', default=True, + help='编译指定的模块 (默认)') + group.add_argument('--list', '-l', action='store_true', + help='列出已编译的模块') + group.add_argument('--clean', '-k', action='store_true', + help='清理编译生成的文件') + + args = parser.parse_args() + + # 检查是否安装了 mypyc + try: + import mypyc + except ImportError: + print("错误: 未安装 mypyc,请先安装: pip install mypyc") + sys.exit(1) + + if args.list: + list_compiled_modules() + elif args.clean: + clean_compiled_files() + else: + compile_all_modules() + print("\n使用 --list 选项查看已编译的模块") + print("使用 --clean 选项清理编译文件") + +if __name__ == '__main__': + main()#!/usr/bin/env python3 +""" 跨平台 Python 模块编译脚本 将核心 Python 模块编译为机器码(.pyd 或 .so)以提升性能。 @@ -30,18 +374,16 @@ import subprocess import shutil import argparse -# 检测当前平台和 Python 版本 +# 检测当前平台 PLATFORM = sys.platform -PYTHON_VERSION = f"{sys.version_info.major}{sys.version_info.minor}" # 例如 "314" - if PLATFORM.startswith('win'): EXTENSION = '.pyd' - BUILD_PREFIX = f'cp{PYTHON_VERSION}-win_amd64' - BUILD_PATH = os.path.join('build', f'lib.win-amd64-cpython-{PYTHON_VERSION}') + BUILD_PREFIX = 'cp314-win_amd64' + BUILD_PATH = os.path.join('build', f'lib.win-amd64-cpython-314') elif PLATFORM.startswith('linux'): EXTENSION = '.so' - BUILD_PREFIX = f'cp{PYTHON_VERSION}-x86_64-linux-gnu' - BUILD_PATH = os.path.join('build', f'lib.linux-x86_64-cpython-{PYTHON_VERSION}') + BUILD_PREFIX = 'cp314-x86_64-linux-gnu' + BUILD_PATH = os.path.join('build', f'lib.linux-x86_64-cpython-314') else: print(f"不支持的平台: {PLATFORM}") sys.exit(1) @@ -265,13 +607,6 @@ def compile_all_modules(): def main(): """主函数""" - # 检查 Python 版本 - if not (sys.version_info.major == 3 and sys.version_info.minor == 14): - print("警告: 推荐使用 Python 3.14 以获得最佳性能") - print(f"当前版本: {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}") - print("继续编译可能导致兼容性问题") - print() - parser = argparse.ArgumentParser(description='跨平台 Python 模块编译脚本') group = parser.add_mutually_exclusive_group() diff --git a/scripts/compile_modules.py b/scripts/compile_modules.py index f869d9e..a47bc03 100644 --- a/scripts/compile_modules.py +++ b/scripts/compile_modules.py @@ -66,7 +66,7 @@ def main(): if compile_module(module): success_count += 1 - print(f"\n--- Compilation Summary ---") + print("\n--- Compilation Summary ---") print(f"Total modules: {len(modules)}") print(f"Successfully compiled: {success_count}") print(f"Failed: {len(modules) - success_count}") diff --git a/setup_mypyc.py b/setup_mypyc.py index 506c533..aed07be 100644 --- a/setup_mypyc.py +++ b/setup_mypyc.py @@ -10,11 +10,8 @@ Mypyc 编译脚本 2. 编译后的文件 (.pyd 或 .so) 是平台相关的,不能跨平台复制。 3. 建议在部署的目标环境 (Linux) 上运行此脚本。 """ -from distutils.core import setup -from mypyc.build import mypycify import os import sys -import glob import subprocess # 基础模块列表 @@ -102,7 +99,7 @@ for module_path in valid_modules: print(f" ✓ Compiled successfully (copied from build directory): {pyd_path}") success_count += 1 else: - print(f" ✗ Compiled but cannot find pyd file") + print(" ✗ Compiled but cannot find pyd file") print(f" Build output:\n{result.stdout[:500]}...") except subprocess.CalledProcessError as e: print(f" ✗ Compilation failed with exit code {e.returncode}") @@ -110,7 +107,7 @@ for module_path in valid_modules: except Exception as e: print(f" ✗ Unexpected error: {e}") -print(f"\n--- Compilation Summary ---") +print("\n--- Compilation Summary ---") print(f"Total modules: {len(valid_modules)}") print(f"Successfully compiled: {success_count}") print(f"Failed: {len(valid_modules) - success_count}") diff --git a/test_performance_simple.py b/test_performance_simple.py new file mode 100644 index 0000000..8c2687a --- /dev/null +++ b/test_performance_simple.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +""" +简单的性能分析功能测试脚本 +""" + +import asyncio +import time +from core.utils.performance import ( + timeit, + profile, + performance_stats +) + + +print("=" * 80) +print("性能分析功能测试") +print("=" * 80) + +# 重置全局性能统计 +performance_stats.reset() + +# 测试1: 同步函数的时间测量 +@timeit +def sync_test(): + """同步测试函数""" + time.sleep(0.1) + return "sync done" + +# 测试2: 异步函数的时间测量 +@timeit +async def async_test(): + """异步测试函数""" + await asyncio.sleep(0.1) + return "async done" + +# 异步主函数 +async def main(): + # 同步函数测试 + print("执行同步函数...") + sync_result = sync_test() + print(f"同步函数结果: {sync_result}") + + # 异步函数测试 + print("\n执行异步函数...") + async_result = await async_test() + print(f"异步函数结果: {async_result}") + + # 测试3: 详细性能分析 + print("\n2. 测试性能分析上下文管理器:") + print("=" * 80) + + with profile(enabled=False): # 禁用实际分析以避免输出太多 + await asyncio.sleep(0.05) + print("性能分析上下文管理器测试完成") + + # 测试4: 性能统计报告 + print("\n3. 测试性能统计报告:") + print("=" * 80) + + # 执行多次函数调用 + for _ in range(3): + sync_test() + await async_test() + + # 生成并打印性能报告 + print("\n性能统计报告:") + print(performance_stats.report()) + + +# 执行测试 +print("\n1. 测试时间测量装饰器:") +print("=" * 80) + +# 使用 asyncio.run() 执行异步主函数 +asyncio.run(main()) + +print("\n" + "=" * 80) +print("所有测试完成!") +print("=" * 80) diff --git a/tests/test_performance.py b/tests/test_performance.py new file mode 100644 index 0000000..5a1537b --- /dev/null +++ b/tests/test_performance.py @@ -0,0 +1,266 @@ +#!/usr/bin/env python3 +""" +性能分析工具测试 + +测试各种性能分析功能的正确性和可用性。 +""" + +import asyncio +import time +import pytest +from typing import Optional + +# 导入性能分析工具 +from core.utils.performance import ( + timeit, + profile, + aprofile, + memory_profile, + memory_profile_decorator, + performance_monitor, + PerformanceStats, + performance_stats +) + + +# 重置全局性能统计 +def setup_module(): + performance_stats.reset() + + +def teardown_module(): + performance_stats.reset() + + +class TestTimeitDecorator: + """测试 timeit 装饰器""" + + @timeit(log_level=20) # 使用 INFO 级别 + def test_sync_function(self): + """测试同步函数的时间测量""" + time.sleep(0.1) + return "done" + + @timeit(log_level=20) + async def test_async_function(self): + """测试异步函数的时间测量""" + await asyncio.sleep(0.1) + return "done" + + def test_sync_function_works(self): + """验证同步函数能正常执行""" + result = self.test_sync_function() + assert result == "done" + + @pytest.mark.asyncio + async def test_async_function_works(self): + """验证异步函数能正常执行""" + result = await self.test_async_function() + assert result == "done" + + +class TestProfileContextManager: + """测试 profile 上下文管理器""" + + def test_profile_sync_code(self): + """测试同步代码的性能分析""" + # 捕获标准输出 + import io + import sys + from contextlib import redirect_stdout + + f = io.StringIO() + with redirect_stdout(f): + with profile(enabled=False): # 禁用实际分析以提高测试速度 + time.sleep(0.01) + + output = f.getvalue() + # 应该没有输出(因为 enabled=False) + assert "性能分析" not in output + + @pytest.mark.asyncio + async def test_aprofile_async_function(self): + """测试异步函数的性能分析""" + async def async_test(): + await asyncio.sleep(0.01) + return "test" + + result = await aprofile(async_test) + assert result == "test" + + +class TestPerformanceMonitor: + """测试 performance_monitor 装饰器""" + + @performance_monitor(threshold=0.05) + def test_slow_sync_function(self): + """测试慢速同步函数的监控""" + time.sleep(0.1) # 超过阈值 + return "slow" + + @performance_monitor(threshold=0.05) + def test_fast_sync_function(self): + """测试快速同步函数的监控""" + time.sleep(0.01) # 低于阈值 + return "fast" + + @performance_monitor(threshold=0.05) + async def test_slow_async_function(self): + """测试慢速异步函数的监控""" + await asyncio.sleep(0.1) + return "slow_async" + + def test_slow_function_triggers_warning(self): + """验证慢速函数会触发警告""" + result = self.test_slow_sync_function() + assert result == "slow" + + def test_fast_function_no_warning(self): + """验证快速函数不会触发警告""" + result = self.test_fast_sync_function() + assert result == "fast" + + @pytest.mark.asyncio + async def test_slow_async_function_triggers_warning(self): + """验证慢速异步函数会触发警告""" + result = await self.test_slow_async_function() + assert result == "slow_async" + + +class TestMemoryAnalysis: + """测试内存分析功能""" + + def test_memory_profile_context_manager(self): + """测试内存分析上下文管理器""" + # 禁用内存分析以提高测试速度 + with memory_profile(enabled=False): + data = [i for i in range(1000)] + sum(data) + + @memory_profile_decorator + def test_memory_intensive_function(self): + """测试内存密集型函数""" + # 小数据集,避免测试耗时过长 + data = [i for i in range(1000)] + return sum(data) + + def test_memory_function_works(self): + """验证内存分析函数能正常执行""" + result = self.test_memory_intensive_function() + assert result == 499500 + + +class TestPerformanceStats: + """测试性能统计功能""" + + def test_stats_initialization(self): + """测试性能统计对象初始化""" + stats = PerformanceStats() + assert isinstance(stats, PerformanceStats) + assert stats.stats == {} + + def test_stats_record(self): + """测试记录性能数据""" + stats = PerformanceStats() + stats.record("test_func", 0.1) + + assert "test_func" in stats.stats + assert stats.stats["test_func"]["count"] == 1 + assert stats.stats["test_func"]["total_time"] == 0.1 + assert stats.stats["test_func"]["avg_time"] == 0.1 + + def test_stats_report(self): + """测试生成性能报告""" + stats = PerformanceStats() + stats.record("func1", 0.1) + stats.record("func2", 0.2) + + report = stats.report() + assert isinstance(report, str) + assert "func1" in report + assert "func2" in report + + def test_stats_reset(self): + """测试重置性能统计""" + stats = PerformanceStats() + stats.record("test_func", 0.1) + stats.reset() + + assert stats.stats == {} + + def test_global_stats_recording(self): + """测试全局性能统计记录""" + # 先重置全局统计 + performance_stats.reset() + + @timeit(collect_stats=True) + def test_func(): + time.sleep(0.01) + + test_func() + + # 验证是否记录了性能数据 + assert "test_func" in performance_stats.stats + assert performance_stats.stats["test_func"]["count"] == 1 + + +class TestIntegration: + """综合测试""" + + @pytest.mark.asyncio + async def test_combined_features(self): + """测试多种性能分析功能的组合使用""" + # 重置全局统计 + performance_stats.reset() + + @timeit(collect_stats=True) + @performance_monitor(threshold=0.05) + async def test_async_func(): + await asyncio.sleep(0.06) # 超过阈值 + return "combined" + + result = await test_async_func() + assert result == "combined" + + # 验证性能统计 + assert "test_async_func" in performance_stats.stats + assert performance_stats.stats["test_async_func"]["count"] == 1 + + +if __name__ == "__main__": + # 运行基本测试 + print("开始性能分析功能测试...") + + # 测试同步函数 + @timeit + def test_sync(): + time.sleep(0.1) + return "sync" + + # 测试异步函数 + @timeit + async def test_async(): + await asyncio.sleep(0.1) + return "async" + + # 测试性能监控 + @performance_monitor(threshold=0.05) + def slow_func(): + time.sleep(0.1) + return "slow" + + # 运行测试 + sync_result = test_sync() + async_result = asyncio.run(test_async()) + slow_result = slow_func() + + print(f"\n测试结果:") + print(f"sync_result: {sync_result}") + print(f"async_result: {async_result}") + print(f"slow_result: {slow_result}") + + # 输出性能统计报告 + print("\n性能统计报告:") + print(performance_stats.report()) + + print("\n性能分析功能测试完成!")