├── app ├── ui │ ├── services │ │ └── __init__.py │ ├── main │ │ ├── components │ │ │ ├── __init__.py │ │ │ ├── timeline.py │ │ │ ├── video_preview.py │ │ │ ├── properties_panel.py │ │ │ ├── effects_panel.py │ │ │ ├── media_library.py │ │ │ └── navigation_bar.py │ │ ├── layouts │ │ │ ├── __init__.py │ │ │ └── main_layout.py │ │ └── pages │ │ │ └── __init__.py │ └── common │ │ └── widgets │ │ ├── __init__.py │ │ ├── separator.py │ │ ├── ai_suggestion.py │ │ ├── loading_indicator.py │ │ ├── chat_message.py │ │ └── welcome_panel.py ├── __init__.py ├── core │ ├── templates │ │ ├── ai_enhancement │ │ │ ├── template_metadata.json │ │ │ ├── template_info.json │ │ │ └── project_template.json │ │ └── video_tutorial │ │ │ ├── template_metadata.json │ │ │ ├── template_info.json │ │ │ └── project_template.json │ ├── service_container.py │ ├── event_bus.py │ ├── logger.py │ ├── config_manager.py │ ├── icon_manager.py │ ├── macOS_theme_manager.py │ └── service_config.py ├── plugins │ ├── __init__.py │ └── README.md ├── security │ └── __init__.py ├── monitoring │ └── __init__.py ├── services │ ├── video_service │ │ └── __init__.py │ └── ai_service │ │ └── base_ai_service.py └── utils │ └── error_handler.py ├── resources ├── icons │ ├── new.png │ ├── open.png │ ├── save.png │ ├── .DS_Store │ ├── export.png │ ├── handle.png │ ├── settings.png │ ├── app_icon_128.png │ ├── app_icon_256.png │ ├── app_icon_32.png │ ├── app_icon_512.png │ ├── app_icon_64.png │ └── svg │ │ ├── handle.svg │ │ ├── new.svg │ │ ├── open.svg │ │ ├── save.svg │ │ ├── settings.svg │ │ ├── export.svg │ │ └── app_icon.svg ├── resources.qrc └── styles │ └── light_theme.qss ├── .mypy.ini ├── requirements-test.txt ├── tests ├── __init__.py ├── conftest.py ├── test_core │ └── test_application.py └── test_ui │ └── test_components.py ├── .pylintrc ├── .env.example ├── LICENSE ├── .flake8 ├── setup.cfg ├── pyproject.toml ├── requirements.txt ├── SECURITY.md ├── .claude └── index.json ├── CONTRIBUTING.md ├── .gitignore ├── Makefile ├── main.py ├── CHANGELOG.md └── README.md /app/ui/services/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Agions/VideoEpicCreator/HEAD/resources/icons/new.png -------------------------------------------------------------------------------- /resources/icons/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Agions/VideoEpicCreator/HEAD/resources/icons/open.png -------------------------------------------------------------------------------- /resources/icons/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Agions/VideoEpicCreator/HEAD/resources/icons/save.png -------------------------------------------------------------------------------- /resources/icons/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Agions/VideoEpicCreator/HEAD/resources/icons/.DS_Store -------------------------------------------------------------------------------- /resources/icons/export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Agions/VideoEpicCreator/HEAD/resources/icons/export.png -------------------------------------------------------------------------------- /resources/icons/handle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Agions/VideoEpicCreator/HEAD/resources/icons/handle.png -------------------------------------------------------------------------------- /resources/icons/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Agions/VideoEpicCreator/HEAD/resources/icons/settings.png -------------------------------------------------------------------------------- /resources/icons/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Agions/VideoEpicCreator/HEAD/resources/icons/app_icon_128.png -------------------------------------------------------------------------------- /resources/icons/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Agions/VideoEpicCreator/HEAD/resources/icons/app_icon_256.png -------------------------------------------------------------------------------- /resources/icons/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Agions/VideoEpicCreator/HEAD/resources/icons/app_icon_32.png -------------------------------------------------------------------------------- /resources/icons/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Agions/VideoEpicCreator/HEAD/resources/icons/app_icon_512.png -------------------------------------------------------------------------------- /resources/icons/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Agions/VideoEpicCreator/HEAD/resources/icons/app_icon_64.png -------------------------------------------------------------------------------- /app/ui/main/components/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | AI-EditX UI组件库 6 | 提供统一的UI组件接口 7 | """ -------------------------------------------------------------------------------- /app/ui/main/layouts/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 主窗口布局模块 3 | """ 4 | 5 | from .main_layout import MainLayout 6 | 7 | __all__ = [ 8 | 'MainLayout' 9 | ] -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | AI-EditX - 专业AI视频编辑器 3 | 主应用程序模块 4 | """ 5 | 6 | __version__ = "2.0.0" 7 | __author__ = "Agions" 8 | __email__ = "agions@qq.com.com" -------------------------------------------------------------------------------- /app/ui/main/pages/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 页面模块 3 | """ 4 | 5 | from .base_page import BasePage 6 | from .video_editor_page import VideoEditorPage 7 | from .home_page import HomePage 8 | from .settings_page import SettingsPage 9 | 10 | __all__ = [ 11 | 'BasePage', 12 | 'VideoEditorPage', 13 | 'HomePage', 14 | 'SettingsPage' 15 | ] -------------------------------------------------------------------------------- /resources/icons/svg/handle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/core/templates/ai_enhancement/template_metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AI视频增强", 3 | "description": "使用AI技术增强视频质量的模板", 4 | "author": "AI-EditX", 5 | "version": "1.0.0", 6 | "category": "ai_enhancement", 7 | "tags": ["AI", "增强", "智能"], 8 | "requirements": {}, 9 | "dependencies": [], 10 | "variables": { 11 | "project_name": "AI增强项目", 12 | "enhancement_type": "超分辨率", 13 | "target_quality": "高质量" 14 | } 15 | } -------------------------------------------------------------------------------- /app/ui/common/widgets/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 公共UI组件模块 3 | 提供各种可复用的UI组件 4 | """ 5 | 6 | from .separator import Separator 7 | from .welcome_panel import WelcomePanel 8 | from .chat_message import ChatMessage 9 | from .ai_suggestion import AISuggestion 10 | from .loading_indicator import LoadingIndicator 11 | 12 | __all__ = [ 13 | 'Separator', 14 | 'WelcomePanel', 15 | 'ChatMessage', 16 | 'AISuggestion', 17 | 'LoadingIndicator' 18 | ] -------------------------------------------------------------------------------- /app/core/templates/video_tutorial/template_metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "视频教程", 3 | "description": "专业的视频教程模板", 4 | "author": "AI-EditX", 5 | "version": "1.0.0", 6 | "category": "video_editing", 7 | "tags": ["教程", "教育", "培训"], 8 | "requirements": {}, 9 | "dependencies": [], 10 | "variables": { 11 | "project_name": "我的教程", 12 | "instructor_name": "讲师姓名", 13 | "course_title": "课程标题", 14 | "chapter_count": 5 15 | } 16 | } -------------------------------------------------------------------------------- /.mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | python_version = 3.9 3 | warn_return_any = True 4 | warn_unused_configs = True 5 | disallow_untyped_defs = True 6 | disallow_incomplete_defs = True 7 | warn_unused_ignores = True 8 | 9 | files = **/*.py 10 | exclude = 11 | build, 12 | dist, 13 | venv, 14 | .venv, 15 | .pytest_cache, 16 | tests/ 17 | 18 | [mypy-PyQt6.*] 19 | ignore_missing_imports = True 20 | 21 | [mypy-psutil.*] 22 | ignore_missing_imports = True -------------------------------------------------------------------------------- /app/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | AI-EditX 插件系统 6 | 提供插件管理、加载和扩展功能 7 | """ 8 | 9 | from .plugin_manager import PluginManager 10 | from .plugin_interface import PluginInterface, PluginType, PluginStatus 11 | from .plugin_loader import PluginLoader 12 | from .plugin_registry import PluginRegistry 13 | 14 | __all__ = [ 15 | 'PluginManager', 16 | 'PluginInterface', 17 | 'PluginType', 18 | 'PluginStatus', 19 | 'PluginLoader', 20 | 'PluginRegistry' 21 | ] -------------------------------------------------------------------------------- /app/security/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | AI-EditX 安全系统 6 | 提供全面的安全保护和输入验证功能 7 | """ 8 | 9 | from .security_manager import SecurityManager 10 | from .input_validator import InputValidator 11 | from .access_control import AccessControl 12 | from .encryption_manager import EncryptionManager 13 | from .audit_logger import AuditLogger 14 | 15 | __all__ = [ 16 | 'SecurityManager', 17 | 'InputValidator', 18 | 'AccessControl', 19 | 'EncryptionManager', 20 | 'AuditLogger' 21 | ] -------------------------------------------------------------------------------- /requirements-test.txt: -------------------------------------------------------------------------------- 1 | # 测试依赖 2 | pytest>=7.0.0 3 | pytest-qt>=4.0.0 4 | pytest-cov>=4.0.0 5 | pytest-mock>=3.10.0 6 | pytest-xvfb>=3.0.0 7 | pytest-asyncio>=0.21.0 8 | pytest-timeout>=2.1.0 9 | 10 | # 测试工具 11 | coverage>=7.2.0 12 | pytest-html>=3.1.1 13 | pytest-benchmark>=4.0.0 14 | pytest-profiling>=1.7.0 15 | 16 | # 模拟和桩 17 | responses>=0.23.0 18 | faker>=18.0.0 19 | factory-boy>=3.2.0 20 | 21 | # 性能测试 22 | memory-profiler>=0.60.0 23 | line-profiler>=4.0.0 24 | py-spy>=0.3.14 25 | 26 | # 质量检查 27 | flake8>=6.0.0 28 | black>=23.0.0 29 | isort>=5.12.0 30 | mypy>=1.2.0 31 | 32 | # UI 测试 33 | PyQt6-stubs>=6.5.0.3.2 34 | qtawesome>=1.2.3 -------------------------------------------------------------------------------- /app/monitoring/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | AI-EditX 性能监控系统 6 | 提供全面的性能监控、分析和优化建议 7 | """ 8 | 9 | from .performance_monitor import PerformanceMonitor 10 | from .metrics_collector import MetricsCollector 11 | from .performance_analyzer import PerformanceAnalyzer 12 | from .alert_system import AlertSystem 13 | from .resource_monitor import ResourceMonitor 14 | from .operation_profiler import OperationProfiler 15 | 16 | __all__ = [ 17 | 'PerformanceMonitor', 18 | 'MetricsCollector', 19 | 'PerformanceAnalyzer', 20 | 'AlertSystem', 21 | 'ResourceMonitor', 22 | 'OperationProfiler' 23 | ] -------------------------------------------------------------------------------- /resources/resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | resources/styles/macOS/macOS_desktop_stylesheet.qss 5 | resources/styles/macOS/_reset.css 6 | resources/styles/macOS/_typography.css 7 | resources/styles/macOS/_layout.css 8 | resources/styles/macOS/_components.css 9 | resources/styles/macOS/_utils.css 10 | 11 | -------------------------------------------------------------------------------- /app/core/templates/ai_enhancement/template_info.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "ai_enhancement", 3 | "name": "AI视频增强", 4 | "description": "使用AI技术增强视频质量的模板", 5 | "category": "ai_enhancement", 6 | "author": "AI-EditX", 7 | "version": "1.0.0", 8 | "created_at": "2024-01-01T00:00:00", 9 | "updated_at": "2024-01-01T00:00:00", 10 | "file_size": 8192, 11 | "preview_image": null, 12 | "tags": ["AI", "增强", "智能"], 13 | "rating": 4.8, 14 | "download_count": 0, 15 | "is_builtin": true, 16 | "project_type": "ai_enhancement", 17 | "requirements": { 18 | "requires_ai_features": true, 19 | "min_gpu_memory": 2048, 20 | "recommended_resolution": "1920x1080" 21 | } 22 | } -------------------------------------------------------------------------------- /app/core/templates/video_tutorial/template_info.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "video_tutorial", 3 | "name": "视频教程", 4 | "description": "专业的视频教程模板,包含标题、章节和说明文字", 5 | "category": "video_editing", 6 | "author": "AI-EditX", 7 | "version": "1.0.0", 8 | "created_at": "2024-01-01T00:00:00", 9 | "updated_at": "2024-01-01T00:00:00", 10 | "file_size": 10240, 11 | "preview_image": null, 12 | "tags": ["教程", "教育", "培训"], 13 | "rating": 4.5, 14 | "download_count": 0, 15 | "is_builtin": true, 16 | "project_type": "video_editing", 17 | "requirements": { 18 | "min_duration": 60, 19 | "recommended_resolution": "1920x1080", 20 | "requires_ai_features": false 21 | } 22 | } -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | AI-EditX 测试框架 6 | 提供统一的测试基础设施和工具函数 7 | """ 8 | 9 | import sys 10 | import os 11 | from pathlib import Path 12 | 13 | # 添加项目根目录到 Python 路径 14 | project_root = Path(__file__).parent.parent 15 | sys.path.insert(0, str(project_root)) 16 | 17 | # 测试配置 18 | TEST_CONFIG = { 19 | "TEMP_DIR": project_root / "tests" / "temp", 20 | "TEST_DATA": project_root / "tests" / "data", 21 | "MOCK_DATA": project_root / "tests" / "mock_data", 22 | "COVERAGE_THRESHOLD": 80.0, 23 | } 24 | 25 | # 确保测试目录存在 26 | for path in [TEST_CONFIG["TEMP_DIR"], TEST_CONFIG["TEST_DATA"], TEST_CONFIG["MOCK_DATA"]]: 27 | path.mkdir(parents=True, exist_ok=True) -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | init-hook='import sys; sys.path.append(".")' 3 | 4 | [MESSAGES CONTROL] 5 | disable= 6 | C0103, # 无效常量名 7 | C0111, # 缺少文档字符串 8 | C0114, # 缺少模块文档字符串 9 | C0115, # 缺少类文档字符串 10 | C0116, # 缺少函数文档字符串 11 | C0301, # 行太长 12 | C0411, # 导入不在文件顶部 13 | C0414, # 导入的模块未使用 14 | R0903, # 类的方法太少 15 | R0913, # 参数太多 16 | W0212, # 访问受保护成员 17 | W0613, # 未使用的参数 18 | W1113, # 关键字参数重复 19 | 20 | [FORMAT] 21 | max-line-length=88 22 | 23 | [BASIC] 24 | good-names=_,i,j,k,x,y,z,e,f,ex,Run,_ 25 | 26 | [TYPECHECK] 27 | ignored-modules=PyQt6 28 | 29 | [VARIABLES] 30 | dummy-variables-rgx=^_ 31 | 32 | [DESIGN] 33 | max-attributes=15 34 | max-public-methods=30 35 | max-args=10 -------------------------------------------------------------------------------- /resources/icons/svg/new.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /resources/icons/svg/open.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/services/video_service/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | 视频服务模块 6 | 提供视频编辑、分析和导出功能 7 | """ 8 | 9 | from .video_editor import ( 10 | MediaItem, 11 | VideoClip, 12 | AudioClip, 13 | Project, 14 | VideoEditorService 15 | ) 16 | 17 | from .video_analyzer import ( 18 | Scene, 19 | HighlightSegment, 20 | VideoAnalysisResult, 21 | VideoAnalyzerService 22 | ) 23 | 24 | 25 | __all__ = [ 26 | # video_editor.py 27 | "MediaItem", 28 | "VideoClip", 29 | "AudioClip", 30 | "Project", 31 | "VideoEditorService", 32 | # video_analyzer.py 33 | "Scene", 34 | "HighlightSegment", 35 | "VideoAnalysisResult", 36 | "VideoAnalyzerService" 37 | ] 38 | -------------------------------------------------------------------------------- /resources/icons/svg/save.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # AI服务API密钥配置 2 | OPENAI_API_KEY=your_openai_api_key_here 3 | QIANWEN_API_KEY=your_qianwen_api_key_here 4 | 5 | # 应用基本设置 6 | APP_NAME=VideoEpicCreator 7 | APP_VERSION=1.0.0 8 | DEBUG=false 9 | LOG_LEVEL=INFO 10 | 11 | # 性能设置 12 | MAX_MEMORY_USAGE=2048 # MB 13 | CACHE_SIZE=100 # 预览帧数 14 | MAX_CONCURRENT_TASKS=5 15 | 16 | # 视频处理设置 17 | FFMPEG_PATH=ffmpeg 18 | DEFAULT_VIDEO_QUALITY=high 19 | DEFAULT_RESOLUTION=1920x1080 20 | DEFAULT_FPS=30 21 | 22 | # AI模型设置 23 | DEFAULT_AI_MODEL=openai 24 | AI_MAX_TOKENS=2000 25 | AI_TEMPERATURE=0.7 26 | AI_TIMEOUT=60 27 | 28 | # 语音合成设置 29 | TTS_ENGINE=edge-tts 30 | DEFAULT_VOICE=zh-CN-XiaoxiaoNeural 31 | TTS_SPEED=1.0 32 | TTS_PITCH=1.0 33 | 34 | # 文件路径设置 35 | DATA_DIR=./data 36 | CACHE_DIR=./cache 37 | LOG_DIR=./logs 38 | EXPORT_DIR=./exports 39 | 40 | # 网络设置 41 | REQUEST_TIMEOUT=30 42 | MAX_RETRIES=3 43 | RETRY_DELAY=1 44 | 45 | # 开发设置 46 | DEV_MODE=false 47 | TEST_MODE=false 48 | PROFILE_PERFORMANCE=false -------------------------------------------------------------------------------- /resources/icons/svg/settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /resources/icons/svg/export.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Agions 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 88 3 | max-complexity = 10 4 | exclude = 5 | .git, 6 | __pycache__, 7 | build, 8 | dist, 9 | venv, 10 | .venv, 11 | .tox, 12 | .eggs, 13 | *.egg-info, 14 | .pytest_cache, 15 | .coverage, 16 | htmlcov, 17 | .mypy_cache, 18 | .DS_Store, 19 | *.pyc, 20 | *.pyo, 21 | *.pyd, 22 | .Python, 23 | env, 24 | pip-log.txt, 25 | pip-delete-this-directory.txt, 26 | .vscode, 27 | .idea, 28 | *.swp, 29 | *.swo, 30 | *~ 31 | 32 | # 忽略的错误类型 33 | ignore = 34 | # whitespace before ':' 35 | E203, 36 | # line too long (handled by black) 37 | E501, 38 | # line break before binary operator 39 | W503, 40 | # line break after binary operator 41 | W504, 42 | # imported but unused 43 | F401, 44 | # local variable is assigned to but never used 45 | F841 46 | 47 | # 按文件忽略的规则 48 | per-file-ignores = 49 | __init__.py:F401 50 | tests/*:F401,F841 51 | */migrations/*:F401 52 | 53 | # 文档字符串要求 54 | docstring-convention = google 55 | 56 | # 导入顺序检查 57 | import-order-style = google 58 | 59 | # 避免使用特定函数 60 | builtins = _ 61 | additional-builtins = _ -------------------------------------------------------------------------------- /app/ui/main/components/timeline.py: -------------------------------------------------------------------------------- 1 | """ 2 | 时间线组件(占位符) 3 | """ 4 | 5 | from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel 6 | from PyQt6.QtCore import Qt 7 | 8 | 9 | class Timeline(QWidget): 10 | """时间线组件""" 11 | 12 | def __init__(self, application): 13 | super().__init__() 14 | self.application = application 15 | 16 | self._setup_ui() 17 | 18 | def _setup_ui(self): 19 | """设置UI""" 20 | layout = QVBoxLayout(self) 21 | layout.setContentsMargins(0, 0, 0, 0) 22 | 23 | label = QLabel("⏱️ 时间线编辑区域") 24 | label.setStyleSheet(""" 25 | QLabel { 26 | color: #FFFFFF; 27 | font-size: 16px; 28 | background-color: #2D2D2D; 29 | border: 1px solid #555555; 30 | border-radius: 4px; 31 | padding: 20px; 32 | } 33 | """) 34 | label.setAlignment(Qt.AlignmentFlag.AlignCenter) 35 | layout.addWidget(label) 36 | 37 | def set_playback_position(self, position_ms: int): 38 | """设置播放位置""" 39 | pass 40 | 41 | def cleanup(self): 42 | """清理资源""" 43 | pass 44 | 45 | def update_theme(self, is_dark: bool = True): 46 | """更新主题""" 47 | pass -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = ai-editx 3 | version = 2.0.0 4 | description = AI-EditX - Professional Video Editing with AI Integration 5 | author = Agions 6 | author_email = agions@qq.com 7 | url = https://github.com/agions/ai-editx 8 | 9 | classifiers = 10 | Development Status :: 4 - Beta 11 | Environment :: X11 Applications :: Qt 12 | Environment :: MacOS X 13 | Environment :: Win32 (MS Windows) 14 | Intended Audience :: End Users/Desktop 15 | License :: OSI Approved :: MIT License 16 | Operating System :: Microsoft :: Windows 17 | Operating System :: POSIX :: Linux 18 | Operating System :: MacOS 19 | Programming Language :: Python :: 3 20 | Programming Language :: Python :: 3.12 21 | Topic :: Multimedia :: Video 22 | Topic :: Multimedia :: Video :: Non-Linear Editor 23 | 24 | [options] 25 | python_requires = >=3.12 26 | packages = find: 27 | install_requires = 28 | PyQt6>=6.6.0 29 | PyQt6-Qt6>=6.6.0 30 | PyQt6-sip>=13.6.0 31 | opencv-python>=4.8.1 32 | numpy>=1.26.0 33 | pillow>=10.1.0 34 | requests>=2.31.0 35 | ffmpeg-python==0.2.0 36 | python-dotenv>=1.0.0 37 | psutil>=5.9.6 38 | 39 | [options.packages.find] 40 | where = . 41 | include = app* 42 | 43 | [options.entry_points] 44 | console_scripts = 45 | cineai-studio = app.main:main 46 | 47 | [bdist_wheel] 48 | universal = 0 -------------------------------------------------------------------------------- /app/ui/main/components/video_preview.py: -------------------------------------------------------------------------------- 1 | """ 2 | 视频预览组件(占位符) 3 | """ 4 | 5 | from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel 6 | from PyQt6.QtCore import pyqtSignal, Qt 7 | 8 | 9 | class VideoPreview(QWidget): 10 | """视频预览组件""" 11 | 12 | # 信号定义 13 | playback_position_changed = pyqtSignal(int) 14 | 15 | def __init__(self, application): 16 | super().__init__() 17 | self.application = application 18 | self.current_video = None 19 | 20 | self._setup_ui() 21 | 22 | def _setup_ui(self): 23 | """设置UI""" 24 | layout = QVBoxLayout(self) 25 | layout.setContentsMargins(0, 0, 0, 0) 26 | 27 | label = QLabel("🎬 视频预览区域") 28 | label.setStyleSheet(""" 29 | QLabel { 30 | color: #FFFFFF; 31 | font-size: 18px; 32 | background-color: #2D2D2D; 33 | border: 2px dashed #555555; 34 | border-radius: 8px; 35 | padding: 40px; 36 | } 37 | """) 38 | label.setAlignment(Qt.AlignmentFlag.AlignCenter) 39 | layout.addWidget(label) 40 | 41 | def load_video(self, video_path: str): 42 | """加载视频""" 43 | self.current_video = video_path 44 | # TODO: 实现视频加载逻辑 45 | 46 | def cleanup(self): 47 | """清理资源""" 48 | pass 49 | 50 | def update_theme(self, is_dark: bool = True): 51 | """更新主题""" 52 | pass -------------------------------------------------------------------------------- /app/ui/main/components/properties_panel.py: -------------------------------------------------------------------------------- 1 | """ 2 | 属性面板组件(占位符) 3 | """ 4 | 5 | from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel 6 | 7 | 8 | class PropertiesPanel(QWidget): 9 | """属性面板组件""" 10 | 11 | def __init__(self, application): 12 | super().__init__() 13 | self.application = application 14 | 15 | self._setup_ui() 16 | 17 | def _setup_ui(self): 18 | """设置UI""" 19 | layout = QVBoxLayout(self) 20 | layout.setContentsMargins(0, 0, 0, 0) 21 | 22 | # 标题 23 | title = QLabel("⚙️ 属性面板") 24 | title.setStyleSheet(""" 25 | QLabel { 26 | color: #FFFFFF; 27 | font-size: 14px; 28 | font-weight: bold; 29 | padding: 8px; 30 | background-color: #2D2D2D; 31 | border-bottom: 1px solid #555555; 32 | } 33 | """) 34 | layout.addWidget(title) 35 | 36 | # 属性内容 37 | content = QLabel(""" 38 |
39 | 选中对象属性

40 | • 位置: X=0, Y=0
41 | • 大小: 1920x1080
42 | • 持续时间: 00:00:00
43 | • 透明度: 100%

44 | 视频属性

45 | • 分辨率: 1920x1080
46 | • 帧率: 30 FPS
47 | • 编码: H.264
48 | • 比特率: 8000 kbps 49 |
50 | """) 51 | content.setStyleSheet(""" 52 | QLabel { 53 | background-color: #1E1E1E; 54 | border: none; 55 | padding: 10px; 56 | } 57 | """) 58 | content.setWordWrap(True) 59 | layout.addWidget(content) 60 | 61 | layout.addStretch() 62 | 63 | def cleanup(self): 64 | """清理资源""" 65 | pass 66 | 67 | def update_theme(self, is_dark: bool = True): 68 | """更新主题""" 69 | pass -------------------------------------------------------------------------------- /app/ui/main/components/effects_panel.py: -------------------------------------------------------------------------------- 1 | """ 2 | 特效面板组件(占位符) 3 | """ 4 | 5 | from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel, QListWidget 6 | 7 | 8 | class EffectsPanel(QWidget): 9 | """特效面板组件""" 10 | 11 | def __init__(self, application): 12 | super().__init__() 13 | self.application = application 14 | 15 | self._setup_ui() 16 | 17 | def _setup_ui(self): 18 | """设置UI""" 19 | layout = QVBoxLayout(self) 20 | layout.setContentsMargins(0, 0, 0, 0) 21 | 22 | # 标题 23 | title = QLabel("✨ 特效库") 24 | title.setStyleSheet(""" 25 | QLabel { 26 | color: #FFFFFF; 27 | font-size: 14px; 28 | font-weight: bold; 29 | padding: 8px; 30 | background-color: #2D2D2D; 31 | border-bottom: 1px solid #555555; 32 | } 33 | """) 34 | layout.addWidget(title) 35 | 36 | # 特效列表 37 | effects_list = QListWidget() 38 | effects_list.setStyleSheet(""" 39 | QListWidget { 40 | background-color: #1E1E1E; 41 | color: #FFFFFF; 42 | border: none; 43 | } 44 | QListWidget::item { 45 | padding: 6px; 46 | border-bottom: 1px solid #333333; 47 | } 48 | QListWidget::item:selected { 49 | background-color: #2196F3; 50 | } 51 | """) 52 | layout.addWidget(effects_list) 53 | 54 | # 添加特效 55 | effects = [ 56 | "🎨 色彩调整", 57 | "🌟 模糊效果", 58 | "⚡ 速度控制", 59 | "🔄 旋转效果", 60 | "💫 粒子效果", 61 | "🎭 滤镜效果" 62 | ] 63 | 64 | for effect in effects: 65 | effects_list.addItem(effect) 66 | 67 | def cleanup(self): 68 | """清理资源""" 69 | pass 70 | 71 | def update_theme(self, is_dark: bool = True): 72 | """更新主题""" 73 | pass -------------------------------------------------------------------------------- /app/core/service_container.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | AI-EditX 服务容器 - 依赖注入容器 6 | 支持按类型和名称注册获取服务 7 | """ 8 | 9 | from typing import Dict, Type, Any, Optional 10 | 11 | 12 | class ServiceContainer: 13 | """服务容器""" 14 | 15 | def __init__(self): 16 | self._services_by_type: Dict[Type, Any] = {} 17 | self._services_by_name: Dict[str, Any] = {} 18 | 19 | def register(self, service_type: Type, instance: Any) -> None: 20 | """按类型注册服务实例""" 21 | self._services_by_type[service_type] = instance 22 | 23 | def register_by_name(self, name: str, instance: Any) -> None: 24 | """按名称注册服务实例""" 25 | self._services_by_name[name] = instance 26 | 27 | def get(self, service_type: Type) -> Any: 28 | """按类型获取服务实例""" 29 | if service_type not in self._services_by_type: 30 | raise ValueError(f"Service {service_type} not registered") 31 | return self._services_by_type[service_type] 32 | 33 | def get_by_name(self, name: str) -> Any: 34 | """按名称获取服务实例""" 35 | if name not in self._services_by_name: 36 | raise ValueError(f"Service '{name}' not registered") 37 | return self._services_by_name[name] 38 | 39 | def has(self, service_type: Type) -> bool: 40 | """检查服务类型是否存在""" 41 | return service_type in self._services_by_type 42 | 43 | def has_by_name(self, name: str) -> bool: 44 | """检查服务名称是否存在""" 45 | return name in self._services_by_name 46 | 47 | def remove(self, service_type: Type) -> None: 48 | """按类型移除服务实例""" 49 | if service_type in self._services_by_type: 50 | del self._services_by_type[service_type] 51 | 52 | def remove_by_name(self, name: str) -> None: 53 | """按名称移除服务实例""" 54 | if name in self._services_by_name: 55 | del self._services_by_name[name] 56 | 57 | def clear(self) -> None: 58 | """清除所有服务""" 59 | self._services_by_type.clear() 60 | self._services_by_name.clear() -------------------------------------------------------------------------------- /app/core/templates/video_tutorial/project_template.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "${project_name}", 4 | "description": "基于视频教程模板创建的项目", 5 | "created_at": "2024-01-01T00:00:00", 6 | "modified_at": "2024-01-01T00:00:00", 7 | "version": "1.0.0", 8 | "author": "${instructor_name}", 9 | "tags": ["教程", "教育"], 10 | "project_type": "video_editing", 11 | "status": "active" 12 | }, 13 | "settings": { 14 | "video_resolution": "1920x1080", 15 | "video_fps": 30, 16 | "video_bitrate": "8000k", 17 | "audio_sample_rate": 44100, 18 | "audio_bitrate": "192k", 19 | "auto_save_interval": 300, 20 | "backup_enabled": true, 21 | "backup_count": 10, 22 | "ai_settings": { 23 | "default_model": "gpt-3.5-turbo", 24 | "max_tokens": 2000, 25 | "temperature": 0.7 26 | }, 27 | "export_settings": { 28 | "default_format": "mp4", 29 | "quality": "high" 30 | }, 31 | "custom_settings": { 32 | "tutorial_specific": { 33 | "intro_duration": 10, 34 | "outro_duration": 5, 35 | "chapter_transition_duration": 2 36 | } 37 | } 38 | }, 39 | "media_files": {}, 40 | "timeline": { 41 | "tracks": [ 42 | { 43 | "id": "video_track_1", 44 | "type": "video", 45 | "clips": [], 46 | "effects": [] 47 | }, 48 | { 49 | "id": "audio_track_1", 50 | "type": "audio", 51 | "clips": [], 52 | "effects": [] 53 | }, 54 | { 55 | "id": "text_track_1", 56 | "type": "text", 57 | "clips": [], 58 | "effects": [] 59 | } 60 | ], 61 | "duration": 0.0, 62 | "markers": [ 63 | { 64 | "id": "marker_intro", 65 | "time": 0.0, 66 | "name": "开始", 67 | "description": "视频开始位置", 68 | "color": "#4CAF50" 69 | }, 70 | { 71 | "id": "marker_outro", 72 | "time": 600.0, 73 | "name": "结束", 74 | "description": "视频结束位置", 75 | "color": "#F44336" 76 | } 77 | ], 78 | "effects": [] 79 | } 80 | } -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=61.0", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "cineai-studio" 7 | version = "2.0.0" 8 | description = "AI-EditX - Professional Video Editing with AI Integration" 9 | license = {text = "MIT"} 10 | authors = [ 11 | {name = "Agions", email = "agions@qq.com.com"} 12 | ] 13 | classifiers = [ 14 | "Development Status :: 4 - Beta", 15 | "Environment :: X11 Applications :: Qt", 16 | "Environment :: MacOS X", 17 | "Environment :: Win32 (MS Windows)", 18 | "Intended Audience :: End Users/Desktop", 19 | "License :: OSI Approved :: MIT License", 20 | "Operating System :: Microsoft :: Windows", 21 | "Operating System :: POSIX :: Linux", 22 | "Operating System :: MacOS", 23 | "Programming Language :: Python :: 3", 24 | "Programming Language :: Python :: 3.12", 25 | "Topic :: Multimedia :: Video", 26 | "Topic :: Multimedia :: Video :: Non-Linear Editor", 27 | ] 28 | keywords = ["video", "editing", "AI", "multimedia", "PyQt6"] 29 | requires-python = ">=3.12" 30 | dependencies = [ 31 | "PyQt6>=6.6.0", 32 | "PyQt6-Qt6>=6.6.0", 33 | "PyQt6-sip>=13.6.0", 34 | "opencv-python>=4.8.1", 35 | "numpy>=1.26.0", 36 | "pillow>=10.1.0", 37 | "requests>=2.31.0", 38 | "ffmpeg-python==0.2.0", 39 | "python-dotenv>=1.0.0", 40 | "psutil>=5.9.6", 41 | ] 42 | 43 | [project.optional-dependencies] 44 | dev = [ 45 | "pytest>=7.4.0", 46 | "pytest-cov>=4.1.0", 47 | "black>=23.11.0", 48 | "flake8>=6.1.0", 49 | "mypy>=1.7.0", 50 | ] 51 | 52 | [project.scripts] 53 | cineai-studio = "app.main:main" 54 | 55 | [tool.setuptools] 56 | packages = ["app"] 57 | 58 | [tool.black] 59 | line-length = 88 60 | target-version = ['py312'] 61 | 62 | [tool.isort] 63 | profile = "black" 64 | line_length = 88 65 | 66 | [tool.pytest.ini_options] 67 | testpaths = ["tests"] 68 | python_files = "test_*.py" 69 | python_classes = "Test*" 70 | python_functions = "test_*" 71 | 72 | [tool.mypy] 73 | python_version = "3.12" 74 | warn_return_any = true 75 | warn_unused_configs = true 76 | disallow_untyped_defs = true 77 | files = "**/*.py" 78 | exclude = [ 79 | "build", 80 | "dist", 81 | "venv", 82 | ".venv", 83 | "tests" 84 | ] 85 | 86 | [[tool.mypy.overrides]] 87 | module = "PyQt6.*" 88 | ignore_missing_imports = true 89 | 90 | [[tool.mypy.overrides]] 91 | module = "psutil.*" 92 | ignore_missing_imports = true -------------------------------------------------------------------------------- /app/ui/common/widgets/separator.py: -------------------------------------------------------------------------------- 1 | """ 2 | 分隔线组件 - macOS 设计系统风格,使用 QSS 类名 3 | """ 4 | 5 | from PyQt6.QtWidgets import QFrame 6 | from PyQt6.QtCore import Qt 7 | 8 | 9 | class Separator(QFrame): 10 | """分隔线组件 - macOS 风格""" 11 | 12 | def __init__(self, orientation=Qt.Orientation.Horizontal, style="default", thickness=1): 13 | super().__init__() 14 | 15 | self.orientation = orientation 16 | self.style = style 17 | self.thickness = thickness 18 | 19 | self._setup_separator() 20 | 21 | def _setup_separator(self) -> None: 22 | """设置分隔线 - 使用 QSS 类名,零内联样式""" 23 | # 设置基本属性 24 | self.setFrameShadow(QFrame.Shadow.Plain) 25 | 26 | # 设置样式类 27 | if self.orientation == Qt.Orientation.Horizontal: 28 | self.setFrameShape(QFrame.Shape.HLine) 29 | self.setFixedHeight(self.thickness) 30 | self.setProperty("class", f"separator-horizontal {self.style}") 31 | else: 32 | self.setFrameShape(QFrame.Shape.VLine) 33 | self.setFixedWidth(self.thickness) 34 | self.setProperty("class", f"separator-vertical {self.style}") 35 | 36 | # 启用样式支持 37 | self.setAttribute(Qt.WA_StyledBackground, True) 38 | 39 | def set_style(self, style: str) -> None: 40 | """设置样式类型""" 41 | if self.style != style: 42 | self.style = style 43 | if self.orientation == Qt.Orientation.Horizontal: 44 | self.setProperty("class", f"separator-horizontal {style}") 45 | else: 46 | self.setProperty("class", f"separator-vertical {style}") 47 | 48 | # 刷新样式 49 | self.style().unpolish(self) 50 | self.style().polish(self) 51 | 52 | def set_thickness(self, thickness: int) -> None: 53 | """设置粗细""" 54 | if self.thickness != thickness: 55 | self.thickness = thickness 56 | if self.orientation == Qt.Orientation.Horizontal: 57 | self.setFixedHeight(thickness) 58 | else: 59 | self.setFixedWidth(thickness) 60 | 61 | 62 | class HSeparator(Separator): 63 | """水平分隔线(Separator的别名,方向固定为水平)""" 64 | 65 | def __init__(self, style="default", thickness=1): 66 | super().__init__(Qt.Orientation.Horizontal, style, thickness) 67 | 68 | 69 | class VSeparator(Separator): 70 | """垂直分隔线(Separator的别名,方向固定为垂直)""" 71 | 72 | def __init__(self, style="default", thickness=1): 73 | super().__init__(Qt.Orientation.Vertical, style, thickness) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # AI-EditX Requirements 2 | # Python 3.12 Compatible Versions 3 | # Python 3.12 兼容性支持 4 | 5 | # Core UI Framework - Python 3.12 compatible versions 6 | PyQt6>=6.6.0 # 6.6.0+ 支持 Python 3.12 7 | PyQt6-Qt6>=6.6.0 8 | PyQt6-sip>=13.6.0 9 | 10 | # Video Processing - Python 3.12 compatible versions 11 | opencv-python>=4.8.1 # 4.8.1+ 支持 Python 3.12 12 | ffmpeg-python==0.2.0 13 | numpy>=1.26.0 # 1.26.0+ 支持 Python 3.12 14 | Pillow>=10.1.0 # 10.1.0+ 支持 Python 3.12 15 | 16 | # HTTP Requests 17 | requests>=2.31.0 18 | 19 | # Chinese AI Models - Latest versions with Python 3.12 support 20 | dashscope>=1.17.7 # 通义千问 21 | qianfan>=0.4.6 # 文心一言 22 | zhipuai>=2.0.6 # 智谱AI 23 | # sparkdesk-python removed - not available in PyPI 24 | tencentcloud-sdk-python>=3.0.970 # 腾讯混元 25 | deepseek-sdk>=0.1.0 # DeepSeek (latest available version) 26 | 27 | # Voice Synthesis 28 | pyttsx3>=2.90 # Local TTS 29 | azure-cognitiveservices-speech>=1.34.0 # Azure Speech Services 30 | 31 | # Security & Encryption 32 | cryptography>=42.0.0 # 42.0.0+ 支持 Python 3.12 33 | 34 | # Utilities - Python 3.12 compatible versions 35 | cairosvg>=2.7.0 # SVG转PNG 36 | python-dotenv>=1.0.0 # Environment variables 37 | psutil>=5.9.6 # System utilities 38 | # pathlib2 removed - Python 3.12 has pathlib built-in 39 | jieba>=0.42.1 # Chinese text processing 40 | 41 | # Audio Processing - Python 3.12 compatible versions 42 | librosa>=0.10.1 # Audio analysis 43 | soundfile>=0.12.1 # Audio file I/O 44 | 45 | # Scene Detection 46 | scenedetect>=0.6.2 # Video scene detection 47 | 48 | # Video Processing Enhancement 49 | imageio>=2.31.6 # Video I/O operations 50 | imageio-ffmpeg>=0.4.8 # FFmpeg wrapper for imageio 51 | moviepy>=1.0.3 # Video editing and processing 52 | av>=11.0.0 # Pythonic bindings for FFmpeg 53 | 54 | # Performance Optimization 55 | py-cpuinfo>=9.0.0 # CPU information 56 | nvidia-ml-py>=12.535.133 # NVIDIA GPU monitoring 57 | 58 | # System Utilities 59 | # wmi removed - Windows only package 60 | pynvml>=11.5.0 # NVIDIA GPU management 61 | GPUtil>=1.4.0 # GPU utilization monitoring 62 | 63 | # Testing and Quality Assurance 64 | pytest>=7.4.0 65 | pytest-cov>=4.1.0 66 | pytest-qt>=4.2.0 67 | black>=23.7.0 68 | flake8>=6.0.0 69 | mypy>=1.5.0 70 | 71 | # Development Tools 72 | setuptools>=68.0.0 # Python 3.12 compatibility 73 | wheel>=0.41.0 74 | 75 | # Documentation 76 | sphinx>=7.0.0 77 | sphinx-rtd-theme>=1.3.0 78 | 79 | # Build and Packaging 80 | build>=0.1.0 81 | twine>=4.0.0 82 | keyring>=21.2.0 -------------------------------------------------------------------------------- /resources/icons/svg/app_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /app/core/templates/ai_enhancement/project_template.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "${project_name}", 4 | "description": "使用${enhancement_type}技术增强视频质量", 5 | "created_at": "2024-01-01T00:00:00", 6 | "modified_at": "2024-01-01T00:00:00", 7 | "version": "1.0.0", 8 | "author": "AI-EditX", 9 | "tags": ["AI", "增强", "智能"], 10 | "project_type": "ai_enhancement", 11 | "status": "active" 12 | }, 13 | "settings": { 14 | "video_resolution": "1920x1080", 15 | "video_fps": 30, 16 | "video_bitrate": "12000k", 17 | "audio_sample_rate": 48000, 18 | "audio_bitrate": "256k", 19 | "auto_save_interval": 180, 20 | "backup_enabled": true, 21 | "backup_count": 5, 22 | "ai_settings": { 23 | "default_model": "gpt-4", 24 | "max_tokens": 4000, 25 | "temperature": 0.3, 26 | "enhancement_models": { 27 | "super_resolution": "ESRGAN", 28 | "denoising": "BM3D", 29 | "color_grading": "AI_ColorNet" 30 | }, 31 | "processing_settings": { 32 | "gpu_acceleration": true, 33 | "batch_processing": true, 34 | "preview_quality": "medium" 35 | } 36 | }, 37 | "export_settings": { 38 | "default_format": "mp4", 39 | "quality": "ultra", 40 | "ai_enhanced": true 41 | }, 42 | "custom_settings": { 43 | "ai_enhancement": { 44 | "target_scale": 2, 45 | "denoise_strength": 0.5, 46 | "sharpness_amount": 0.7, 47 | "color_enhancement": true 48 | } 49 | } 50 | }, 51 | "media_files": {}, 52 | "timeline": { 53 | "tracks": [ 54 | { 55 | "id": "source_video", 56 | "type": "video", 57 | "clips": [], 58 | "effects": [ 59 | { 60 | "id": "ai_enhancement_effect", 61 | "type": "ai_enhancement", 62 | "name": "AI增强效果", 63 | "enabled": true, 64 | "settings": { 65 | "enhancement_type": "${enhancement_type}", 66 | "target_quality": "${target_quality}" 67 | } 68 | } 69 | ] 70 | }, 71 | { 72 | "id": "enhanced_video", 73 | "type": "video", 74 | "clips": [], 75 | "effects": [] 76 | }, 77 | { 78 | "id": "audio_track_1", 79 | "type": "audio", 80 | "clips": [], 81 | "effects": [] 82 | } 83 | ], 84 | "duration": 0.0, 85 | "markers": [ 86 | { 87 | "id": "marker_source", 88 | "time": 0.0, 89 | "name": "源视频", 90 | "description": "原始视频素材", 91 | "color": "#2196F3" 92 | }, 93 | { 94 | "id": "marker_enhanced", 95 | "time": 0.0, 96 | "name": "增强后", 97 | "description": "AI增强后的视频", 98 | "color": "#4CAF50" 99 | } 100 | ], 101 | "effects": [] 102 | } 103 | } -------------------------------------------------------------------------------- /app/ui/common/widgets/ai_suggestion.py: -------------------------------------------------------------------------------- 1 | """ 2 | AI建议组件 3 | """ 4 | 5 | from PyQt6.QtWidgets import QPushButton 6 | from PyQt6.QtCore import pyqtSignal 7 | from PyQt6.QtGui import QFont 8 | 9 | 10 | class AISuggestion(QPushButton): 11 | """AI建议按钮""" 12 | 13 | def __init__(self, text: str, action: str): 14 | super().__init__() 15 | 16 | self.text = text 17 | self.action = action 18 | 19 | self._setup_ui() 20 | 21 | def _setup_ui(self) -> None: 22 | """设置UI""" 23 | self.setText(self.text) 24 | self.setToolTip(f"点击执行: {self.action}") 25 | 26 | # 设置字体 27 | font = QFont("Microsoft YaHei", 11) 28 | font.setWeight(QFont.Weight.Normal) 29 | self.setFont(font) 30 | 31 | # 设置大小策略 32 | self.setFixedSize(120, 35) 33 | 34 | # 设置样式 35 | self.setStyleSheet(""" 36 | QPushButton { 37 | background-color: #3D3D3D; 38 | color: #FFFFFF; 39 | border: 1px solid #555555; 40 | border-radius: 6px; 41 | padding: 6px 12px; 42 | font-size: 11px; 43 | } 44 | QPushButton:hover { 45 | background-color: #4D4D4D; 46 | border-color: #2196F3; 47 | color: #FFFFFF; 48 | } 49 | QPushButton:pressed { 50 | background-color: #2196F3; 51 | border-color: #2196F3; 52 | } 53 | """) 54 | 55 | def get_action(self) -> str: 56 | """获取动作""" 57 | return self.action 58 | 59 | def set_action(self, action: str) -> None: 60 | """设置动作""" 61 | self.action = action 62 | 63 | def update_theme(self, is_dark: bool = True) -> None: 64 | """更新主题""" 65 | if is_dark: 66 | normal_bg = "#3D3D3D" 67 | hover_bg = "#4D4D4D" 68 | pressed_bg = "#2196F3" 69 | border_color = "#555555" 70 | text_color = "#FFFFFF" 71 | else: 72 | normal_bg = "#F5F5F5" 73 | hover_bg = "#E8E8E8" 74 | pressed_bg = "#2196F3" 75 | border_color = "#DDDDDD" 76 | text_color = "#000000" 77 | 78 | self.setStyleSheet(f""" 79 | QPushButton {{ 80 | background-color: {normal_bg}; 81 | color: {text_color}; 82 | border: 1px solid {border_color}; 83 | border-radius: 6px; 84 | padding: 6px 12px; 85 | font-size: 11px; 86 | }} 87 | QPushButton:hover {{ 88 | background-color: {hover_bg}; 89 | border-color: #2196F3; 90 | color: {'#FFFFFF' if is_dark else '#000000'}; 91 | }} 92 | QPushButton:pressed {{ 93 | background-color: {pressed_bg}; 94 | border-color: {pressed_bg}; 95 | color: #FFFFFF; 96 | }} 97 | """) -------------------------------------------------------------------------------- /app/ui/main/layouts/main_layout.py: -------------------------------------------------------------------------------- 1 | """ 2 | 主窗口布局 - 负责管理主窗口的整体布局 3 | """ 4 | 5 | from PyQt6.QtWidgets import ( 6 | QWidget, QVBoxLayout, QHBoxLayout, QSpacerItem, 7 | QSizePolicy, QStackedWidget 8 | ) 9 | from PyQt6.QtCore import Qt 10 | 11 | 12 | class MainLayout(QVBoxLayout): 13 | """主窗口布局""" 14 | 15 | def __init__(self, parent: QWidget): 16 | super().__init__(parent) 17 | 18 | self.navigation_bar = None 19 | self.content_widget = None 20 | 21 | self._setup_layout() 22 | 23 | def _setup_layout(self) -> None: 24 | """设置布局""" 25 | # 设置布局属性 26 | self.setContentsMargins(0, 0, 0, 0) 27 | self.setSpacing(0) 28 | 29 | # 导航栏区域 30 | self.navigation_bar_layout = QHBoxLayout() 31 | self.navigation_bar_layout.setContentsMargins(0, 0, 0, 0) 32 | self.navigation_bar_layout.setSpacing(0) 33 | 34 | # 添加导航栏占位符 35 | self.addLayout(self.navigation_bar_layout) 36 | 37 | # 添加分隔线 38 | self.addLayout(self._create_separator()) 39 | 40 | # 内容区域 41 | self.content_layout = QVBoxLayout() 42 | self.content_layout.setContentsMargins(0, 0, 0, 0) 43 | self.content_layout.setSpacing(0) 44 | self.content_layout.setAlignment(Qt.AlignmentFlag.AlignTop) 45 | 46 | # 添加内容区域 47 | self.addLayout(self.content_layout) 48 | 49 | # 设置内容区域为可伸缩 50 | self.addStretch() 51 | 52 | def _create_separator(self) -> QHBoxLayout: 53 | """创建分隔线""" 54 | separator_layout = QHBoxLayout() 55 | separator_layout.setContentsMargins(0, 0, 0, 0) 56 | separator_layout.setSpacing(0) 57 | 58 | from ...common.widgets.separator import Separator 59 | separator = Separator(orientation=Qt.Orientation.Horizontal) 60 | separator_layout.addWidget(separator) 61 | 62 | return separator_layout 63 | 64 | def set_navigation_bar(self, navigation_bar) -> None: 65 | """设置导航栏""" 66 | # 清除现有的导航栏 67 | while self.navigation_bar_layout.count(): 68 | item = self.navigation_bar_layout.takeAt(0) 69 | if item.widget(): 70 | item.widget().deleteLater() 71 | 72 | # 添加新的导航栏 73 | if navigation_bar: 74 | self.navigation_bar_layout.addWidget(navigation_bar) 75 | self.navigation_bar = navigation_bar 76 | 77 | def set_content_widget(self, widget: QWidget) -> None: 78 | """设置内容窗口部件""" 79 | # 清除现有的内容窗口部件 80 | while self.content_layout.count(): 81 | item = self.content_layout.takeAt(0) 82 | if item.widget(): 83 | item.widget().deleteLater() 84 | 85 | # 添加新的内容窗口部件 86 | if widget: 87 | self.content_layout.addWidget(widget) 88 | self.content_widget = widget 89 | 90 | def get_navigation_bar(self): 91 | """获取导航栏""" 92 | return self.navigation_bar 93 | 94 | def get_content_widget(self) -> QWidget: 95 | """获取内容窗口部件""" 96 | return self.content_widget -------------------------------------------------------------------------------- /app/ui/main/components/media_library.py: -------------------------------------------------------------------------------- 1 | """ 2 | 媒体库组件(占位符) 3 | """ 4 | 5 | from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel, QListWidget, QListWidgetItem 6 | from PyQt6.QtCore import pyqtSignal 7 | 8 | 9 | class MediaLibrary(QWidget): 10 | """媒体库组件""" 11 | 12 | # 信号定义 13 | video_selected = pyqtSignal(str) 14 | project_opened = pyqtSignal(str) 15 | 16 | def __init__(self, application): 17 | super().__init__() 18 | self.application = application 19 | 20 | self._setup_ui() 21 | 22 | def _setup_ui(self): 23 | """设置UI""" 24 | layout = QVBoxLayout(self) 25 | layout.setContentsMargins(0, 0, 0, 0) 26 | 27 | # 标题 28 | title = QLabel("📁 媒体库") 29 | title.setStyleSheet(""" 30 | QLabel { 31 | color: #FFFFFF; 32 | font-size: 14px; 33 | font-weight: bold; 34 | padding: 8px; 35 | background-color: #2D2D2D; 36 | border-bottom: 1px solid #555555; 37 | } 38 | """) 39 | layout.addWidget(title) 40 | 41 | # 媒体列表 42 | self.media_list = QListWidget() 43 | self.media_list.setStyleSheet(""" 44 | QListWidget { 45 | background-color: #1E1E1E; 46 | color: #FFFFFF; 47 | border: none; 48 | outline: none; 49 | } 50 | QListWidget::item { 51 | padding: 8px; 52 | border-bottom: 1px solid #333333; 53 | } 54 | QListWidget::item:selected { 55 | background-color: #2196F3; 56 | color: white; 57 | } 58 | QListWidget::item:hover { 59 | background-color: #2D2D2D; 60 | } 61 | """) 62 | layout.addWidget(self.media_list) 63 | 64 | # 添加一些示例项 65 | items = [ 66 | "🎥 示例视频1.mp4", 67 | "🎵 示例音频1.mp3", 68 | "🖼️ 示例图片1.png", 69 | "🎥 示例视频2.mp4" 70 | ] 71 | 72 | for item_text in items: 73 | item = QListWidgetItem(item_text) 74 | self.media_list.addItem(item) 75 | 76 | # 连接信号 77 | self.media_list.itemDoubleClicked.connect(self._on_item_double_clicked) 78 | 79 | def _on_item_double_clicked(self, item): 80 | """双击项处理""" 81 | text = item.text() 82 | if "视频" in text: 83 | # 模拟视频选择 84 | video_path = f"/path/to/{text.replace('示例', '')}" 85 | self.video_selected.emit(video_path) 86 | 87 | def add_media_files(self, file_paths): 88 | """添加媒体文件""" 89 | for file_path in file_paths: 90 | import os 91 | filename = os.path.basename(file_path) 92 | item = QListWidgetItem(f"📄 {filename}") 93 | self.media_list.addItem(item) 94 | 95 | def cleanup(self): 96 | """清理资源""" 97 | pass 98 | 99 | def update_theme(self, is_dark: bool = True): 100 | """更新主题""" 101 | pass -------------------------------------------------------------------------------- /app/core/event_bus.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | AI-EditX 事件总线模块 6 | 提供事件发布/订阅功能 7 | """ 8 | 9 | from typing import Dict, List, Callable, Any 10 | from .logger import Logger 11 | 12 | 13 | class EventBus: 14 | """事件总线""" 15 | 16 | def __init__(self): 17 | """初始化事件总线""" 18 | self._handlers: Dict[str, List[Callable]] = {} 19 | self.logger = Logger("EventBus") 20 | 21 | def subscribe(self, event_name: str, handler: Callable) -> None: 22 | """订阅事件 23 | 24 | Args: 25 | event_name: 事件名称 26 | handler: 事件处理函数 27 | """ 28 | if event_name not in self._handlers: 29 | self._handlers[event_name] = [] 30 | 31 | # 避免重复订阅 32 | if handler not in self._handlers[event_name]: 33 | self._handlers[event_name].append(handler) 34 | 35 | def unsubscribe(self, event_name: str, handler: Callable) -> None: 36 | """取消订阅事件 37 | 38 | Args: 39 | event_name: 事件名称 40 | handler: 事件处理函数 41 | """ 42 | if event_name in self._handlers: 43 | try: 44 | self._handlers[event_name].remove(handler) 45 | except ValueError: 46 | pass 47 | 48 | def publish(self, event_name: str, data: Any = None) -> None: 49 | """发布事件 50 | 51 | Args: 52 | event_name: 事件名称 53 | data: 事件数据,可选 54 | """ 55 | if event_name in self._handlers: 56 | for handler in self._handlers[event_name]: 57 | try: 58 | handler(data) 59 | except Exception as e: 60 | self.logger.error(f"事件 {event_name} 处理错误: {e}") 61 | 62 | def emit(self, event_name: str, data: Any = None) -> None: 63 | """发布事件(emit是publish的别名,保持API兼容性) 64 | 65 | Args: 66 | event_name: 事件名称 67 | data: 事件数据,可选 68 | """ 69 | self.publish(event_name, data) 70 | 71 | def clear_handlers(self, event_name: str = None) -> None: 72 | """清除事件处理器 73 | 74 | Args: 75 | event_name: 可选,指定事件名称,若为None则清除所有事件处理器 76 | """ 77 | if event_name: 78 | if event_name in self._handlers: 79 | self._handlers[event_name].clear() 80 | else: 81 | self._handlers.clear() 82 | 83 | def get_handler_count(self, event_name: str = None) -> int: 84 | """获取事件处理器数量 85 | 86 | Args: 87 | event_name: 可选,指定事件名称,若为None则返回所有事件处理器总数 88 | 89 | Returns: 90 | int: 事件处理器数量 91 | """ 92 | if event_name: 93 | return len(self._handlers.get(event_name, [])) 94 | else: 95 | return sum(len(handlers) for handlers in self._handlers.values()) 96 | 97 | def has_handlers(self, event_name: str) -> bool: 98 | """检查事件是否有处理器 99 | 100 | Args: 101 | event_name: 事件名称 102 | 103 | Returns: 104 | bool: 若事件有处理器则返回True,否则返回False 105 | """ 106 | return event_name in self._handlers and len(self._handlers[event_name]) > 0 -------------------------------------------------------------------------------- /app/ui/common/widgets/loading_indicator.py: -------------------------------------------------------------------------------- 1 | """ 2 | 加载指示器组件 3 | """ 4 | 5 | from PyQt6.QtWidgets import ( 6 | QWidget, QVBoxLayout, QHBoxLayout, QLabel, QProgressBar 7 | ) 8 | from PyQt6.QtCore import Qt, QTimer, pyqtSignal 9 | from PyQt6.QtGui import QFont 10 | 11 | 12 | class LoadingIndicator(QWidget): 13 | """加载指示器""" 14 | 15 | def __init__(self, message: str = "加载中..."): 16 | super().__init__() 17 | 18 | self.message = message 19 | self.is_animating = False 20 | 21 | self._setup_ui() 22 | self._create_layout() 23 | self._start_animation() 24 | 25 | def _setup_ui(self) -> None: 26 | """设置UI""" 27 | self.setObjectName("loading_indicator") 28 | self.setFixedSize(200, 60) 29 | 30 | # 应用 macOS 样式 31 | self.setProperty("class", "loading-indicator") 32 | 33 | def _create_layout(self) -> None: 34 | """创建布局""" 35 | main_layout = QHBoxLayout(self) 36 | main_layout.setContentsMargins(15, 10, 15, 10) 37 | main_layout.setSpacing(10) 38 | 39 | # 加载动画标签 40 | self.animation_label = QLabel("⏳") 41 | self.animation_label.setProperty("class", "loading-animation") 42 | self.animation_label.setAlignment(Qt.AlignmentFlag.AlignCenter) 43 | main_layout.addWidget(self.animation_label) 44 | 45 | # 消息标签 46 | self.message_label = QLabel(self.message) 47 | self.message_label.setProperty("class", "loading-message") 48 | self.message_label.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter) 49 | main_layout.addWidget(self.message_label) 50 | 51 | main_layout.addStretch() 52 | 53 | def _start_animation(self) -> None: 54 | """开始动画""" 55 | self.is_animating = True 56 | self.animation_timer = QTimer() 57 | self.animation_timer.timeout.connect(self._update_animation) 58 | self.animation_timer.start(500) # 每500ms更新一次 59 | 60 | def _update_animation(self) -> None: 61 | """更新动画""" 62 | if not self.is_animating: 63 | return 64 | 65 | # 简单的旋转动画 66 | frames = ["⏳", "⌛", "⏳", "⌛"] 67 | current_frame = int((QTimer.currentTime().msecsSinceStartOfDay() / 500) % len(frames)) 68 | self.animation_label.setText(frames[current_frame]) 69 | 70 | def set_message(self, message: str) -> None: 71 | """设置消息""" 72 | self.message = message 73 | if self.message_label: 74 | self.message_label.setText(message) 75 | 76 | def stop_animation(self) -> None: 77 | """停止动画""" 78 | self.is_animating = False 79 | if hasattr(self, 'animation_timer'): 80 | self.animation_timer.stop() 81 | 82 | def start_animation(self) -> None: 83 | """开始动画""" 84 | if not self.is_animating: 85 | self.is_animating = True 86 | if hasattr(self, 'animation_timer'): 87 | self.animation_timer.start(500) 88 | 89 | def update_theme(self, theme_name: str = "dark") -> None: 90 | """更新主题 - 使用 QSS 类名系统""" 91 | self.setProperty("theme", theme_name) 92 | self.style().unpolish(self) 93 | self.style().polish(self) 94 | 95 | def closeEvent(self, event) -> None: 96 | """关闭事件""" 97 | self.stop_animation() 98 | super().closeEvent(event) -------------------------------------------------------------------------------- /app/core/logger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | AI-EditX 日志记录器模块 6 | 提供日志记录和管理功能 7 | """ 8 | 9 | import logging 10 | import sys 11 | from typing import Optional 12 | from enum import Enum 13 | 14 | 15 | class LogLevel(Enum): 16 | """日志级别枚举""" 17 | DEBUG = logging.DEBUG 18 | INFO = logging.INFO 19 | WARNING = logging.WARNING 20 | ERROR = logging.ERROR 21 | CRITICAL = logging.CRITICAL 22 | 23 | 24 | class LogFormat(Enum): 25 | """日志格式枚举""" 26 | SIMPLE = "simple" 27 | DETAILED = "detailed" 28 | STRUCTURED = "structured" 29 | 30 | 31 | class Logger: 32 | """简化日志记录器""" 33 | 34 | def __init__(self, name: str, level: int = logging.INFO): 35 | self.logger = logging.getLogger(name) 36 | self.logger.setLevel(level) 37 | 38 | if not self.logger.handlers: 39 | handler = logging.StreamHandler(sys.stdout) 40 | formatter = logging.Formatter( 41 | '%(asctime)s - %(name)s - %(levelname)s - %(message)s' 42 | ) 43 | handler.setFormatter(formatter) 44 | self.logger.addHandler(handler) 45 | 46 | @classmethod 47 | def get_logger(cls, name: str) -> 'Logger': 48 | """获取日志记录器实例""" 49 | return cls(name) 50 | 51 | def debug(self, message: str) -> None: 52 | """调试日志""" 53 | self.logger.debug(message) 54 | 55 | def info(self, message: str) -> None: 56 | """信息日志""" 57 | self.logger.info(message) 58 | 59 | def warning(self, message: str) -> None: 60 | """警告日志""" 61 | self.logger.warning(message) 62 | 63 | def error(self, message: str) -> None: 64 | """错误日志""" 65 | self.logger.error(message) 66 | 67 | def critical(self, message: str) -> None: 68 | """严重错误日志""" 69 | self.logger.critical(message) 70 | 71 | 72 | def setup_logging( 73 | level: LogLevel = LogLevel.INFO, 74 | format_type: LogFormat = LogFormat.DETAILED, 75 | enable_console: bool = True, 76 | enable_file: bool = True 77 | ) -> None: 78 | """设置全局日志配置""" 79 | # 配置根日志记录器 80 | root_logger = logging.getLogger() 81 | root_logger.setLevel(level.value) 82 | 83 | # 清除现有处理器 84 | for handler in root_logger.handlers[:]: 85 | root_logger.removeHandler(handler) 86 | 87 | # 创建格式化器 88 | if format_type == LogFormat.SIMPLE: 89 | formatter = logging.Formatter('%(levelname)s - %(message)s') 90 | elif format_type == LogFormat.DETAILED: 91 | formatter = logging.Formatter( 92 | '%(asctime)s - %(name)s - %(levelname)s - %(message)s' 93 | ) 94 | else: # STRUCTURED 95 | formatter = logging.Formatter( 96 | '%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s' 97 | ) 98 | 99 | # 控制台处理器 100 | if enable_console: 101 | console_handler = logging.StreamHandler(sys.stdout) 102 | console_handler.setFormatter(formatter) 103 | root_logger.addHandler(console_handler) 104 | 105 | # 文件处理器 106 | if enable_file: 107 | try: 108 | from pathlib import Path 109 | log_dir = Path("logs") 110 | log_dir.mkdir(exist_ok=True) 111 | 112 | file_handler = logging.FileHandler( 113 | log_dir / "AI-EditX.log", 114 | encoding='utf-8' 115 | ) 116 | file_handler.setFormatter(formatter) 117 | root_logger.addHandler(file_handler) 118 | except Exception as e: 119 | print(f"无法创建日志文件: {e}") 120 | 121 | 122 | def get_logger(name: str) -> Logger: 123 | """获取日志记录器实例""" 124 | return Logger(name) -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # 安全政策 2 | 3 | 感谢您对 AI-EditX 项目安全的关注!我们致力于维护一个安全的视频编辑平台,保护用户数据和隐私。 4 | 5 | ## 🔒 安全承诺 6 | 7 | - **用户数据优先**: 我们将用户的数据安全和隐私保护放在首位 8 | - **透明公开**: 我们会公开透明地处理安全相关问题 9 | - **及时响应**: 我们承诺及时响应和修复安全漏洞 10 | - **负责任披露**: 我们遵循负责任的漏洞披露原则 11 | 12 | ## 🛡️ 安全特性 13 | 14 | ### 输入验证和清理 15 | - 全面输入验证系统,支持多种验证级别 16 | - XSS、SQL注入、路径遍历等安全防护 17 | - HTML内容安全处理和清理 18 | - CSRF保护和令牌验证 19 | 20 | ### 数据加密 21 | - 密码使用 PBKDF2 进行安全哈希 22 | - 敏感配置信息加密存储 23 | - 支持系统密钥库集成 24 | - API密钥安全验证和管理 25 | 26 | ### 访问控制 27 | - 基于角色的访问控制(RBAC) 28 | - 插件沙箱隔离执行 29 | - 安全的插件加载和验证 30 | - 审计日志和操作追踪 31 | 32 | ### 网络安全 33 | - HTTPS 强制加密传输 34 | - 安全的 API 密钥管理 35 | - 网络请求验证和过滤 36 | - 恶意网站检测和防护 37 | 38 | ## 🐛 漏洞报告 39 | 40 | ### 报告渠道 41 | 我们鼓励安全研究人员和用户通过以下渠道报告安全问题: 42 | 43 | **首选渠道**: 44 | - 📧 邮箱:security@aieditx.com 45 | - 🔒 加密邮件:使用我们的 PGP 公钥加密(如需要) 46 | 47 | **备用渠道**: 48 | - [GitHub Security Advisory](https://github.com/agions/AI-EditX/security/advisories) 49 | - 私信 GitHub Maintainer 50 | 51 | ### 报告内容 52 | 请包含以下信息以帮助我们更好地理解和修复问题: 53 | 54 | 1. **漏洞类型**: 例如 XSS、SQL注入、权限绕过等 55 | 2. **影响范围**: 受影响的组件和版本 56 | 3. **重现步骤**: 详细的重现步骤和条件 57 | 4. **攻击向量**: 攻击者如何利用该漏洞 58 | 5. **影响评估**: 潜在的数据泄露或系统损害 59 | 6. **修复建议**(可选):如果您有修复建议 60 | 61 | ### 负责任披露原则 62 | 我们承诺遵循负责任的漏洞披露原则: 63 | 64 | 1. **及时确认**: 我们会在 48 小时内确认收到您的报告 65 | 2. **及时修复**: 我们会根据漏洞严重程度,在合理时间内修复问题 66 | 3. **公开协调**: 我们会与您协调公开披露的时间 67 | 4. **credit 认可**: 我们会在修复后公开致谢您的贡献(除非您要求匿名) 68 | 69 | ### 漏洞评级标准 70 | 我们使用 CVSS (Common Vulnerability Scoring System) 评估漏洞严重程度: 71 | 72 | - **严重 (9.0-10.0)**: 可直接获取系统控制或大规模数据泄露 73 | - **高危 (7.0-8.9)**: 可获取敏感数据或影响核心功能 74 | - **中危 (4.0-6.9)**: 有限的权限提升或数据泄露 75 | - **低危 (0.1-3.9)**: 轻微的信息泄露或功能影响 76 | 77 | ### 修复时间目标 78 | - **严重**: 7 天内修复 79 | - **高危**: 14 天内修复 80 | - **中危**: 30 天内修复 81 | - **低危**: 90 天内修复或在下个版本中修复 82 | 83 | ## 🏆 安全致谢计划 84 | 85 | ### 奖励范围 86 | 我们为发现并报告安全漏洞的研究人员提供致谢和奖励: 87 | 88 | #### 奖励等级 89 | - **严重漏洞**: $500 - $2000 90 | - **高危漏洞**: $200 - $500 91 | - **中危漏洞**: $50 - $200 92 | - **低危漏洞**: 荣誉致谢 93 | 94 | ### 奖励条件 95 | 1. 首次报告该漏洞 96 | 2. 提供详细的重现步骤 97 | 3. 遵循负责任披露原则 98 | 4. 不违反法律法规和伦理准则 99 | 100 | ### 致谢方式 101 | - 在项目的 SECURITY.md 中公开致谢 102 | - 在 CHANGELOG.md 中记录贡献 103 | - 邀请加入我们的安全研究员名单 104 | - 根据漏洞严重程度提供经济奖励 105 | 106 | ## 📊 安全事件响应 107 | 108 | ### 事件分类 109 | - **1 级(严重)**: 核心服务不可用,大规模数据泄露 110 | - **2 级(高危)**: 重要功能受影响,敏感数据泄露 111 | - **3 级(中危)**: 部分功能受影响,有限数据泄露 112 | - **4 级(低危)**: 轻微功能影响,少量信息泄露 113 | 114 | ### 响应流程 115 | 1. **检测和识别** (0-2小时) 116 | - 监控系统检测异常 117 | - 用户报告安全事件 118 | - 第三方安全机构通知 119 | 120 | 2. **初步评估** (2-6小时) 121 | - 确定事件严重程度 122 | - 评估影响范围 123 | - 启动应急响应团队 124 | 125 | 3. **遏制和控制** (6-24小时) 126 | - 采取紧急措施防止扩散 127 | - 隔离受影响的系统 128 | - 收集和保护证据 129 | 130 | 4. **根除和恢复** (1-7天) 131 | - 彻底修复漏洞 132 | - 恢复正常服务 133 | - 加强安全防护 134 | 135 | 5. **事后分析** (7-14天) 136 | - 分析事件根本原因 137 | - 改进安全流程 138 | - 更新安全策略 139 | 140 | ## 🔐 安全最佳实践 141 | 142 | ### 用户安全建议 143 | 1. **使用强密码**: 建议使用包含大小写字母、数字和特殊字符的复杂密码 144 | 2. **定期更新**: 及时更新到最新版本以获取安全修复 145 | 3. **谨慎插件**: 只从官方渠道或可信来源安装插件 146 | 4. **数据备份**: 定期备份重要的项目文件和配置 147 | 148 | ### 开发者安全建议 149 | 1. **输入验证**: 始终验证和清理用户输入 150 | 2. **最小权限**: 遵循最小权限原则 151 | 3. **安全编码**: 遵循安全编码最佳实践 152 | 4. **定期审计**: 定期进行安全代码审计 153 | 154 | ## 📞 安全联系方式 155 | 156 | ### 安全团队 157 | - **安全负责人**: security@aieditx.com 158 | - **GitHub Security**: https://github.com/agions/AI-EditX/security 159 | - **紧急安全热线**: +86-xxx-xxxx-xxxx 160 | 161 | ### 相关文档 162 | - [安全开发生命周期 (SDLC)](docs/sdlc.md) 163 | - [安全编码规范](docs/security-coding.md) 164 | - [漏洞披露政策](docs/vulnerability-disclosure.md) 165 | 166 | ## 📋 安全检查清单 167 | 168 | ### 开发阶段 169 | - [ ] 输入验证和输出编码 170 | - [ ] 身份验证和授权 171 | - [ ] 数据加密和传输安全 172 | - [ ] 错误处理和日志记录 173 | - [ ] 配置管理和环境分离 174 | 175 | ### 测试阶段 176 | - [ ] 安全测试用例 177 | - [ ] 渗透测试 178 | - [ ] 依赖安全扫描 179 | - [ ] 代码安全审计 180 | - [ ] 性能安全测试 181 | 182 | ### 部署阶段 183 | - [ ] 生产环境安全配置 184 | - [ ] 监控和告警系统 185 | - [ ] 备份和恢复机制 186 | - [ ] 访问控制和权限管理 187 | - [ ] 安全更新和补丁管理 188 | 189 | ## 🔄 持续改进 190 | 191 | 我们承诺持续改进 AI-EditX 的安全性: 192 | 193 | - **定期安全审计**: 每季度进行安全审计 194 | - **漏洞管理**: 建立完整的漏洞管理流程 195 | - **安全培训**: 为开发团队提供安全培训 196 | - **社区参与**: 鼓励社区参与安全改进 197 | - **透明公开**: 公开安全政策和事件报告 198 | 199 | --- 200 | 201 | **保护用户安全是我们共同的责任!** 🛡️ 202 | 203 | 如果您发现任何安全问题,请立即联系我们。感谢您为 AI-EditX 安全做出的贡献! -------------------------------------------------------------------------------- /.claude/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "timestamp": "2025-01-18T00:00:00Z", 3 | "scan_coverage": { 4 | "total_files": 58, 5 | "scanned_files": 21, 6 | "coverage_percentage": 36.2, 7 | "ignored_files": 37 8 | }, 9 | "modules": { 10 | "root": { 11 | "path": ".", 12 | "type": "project_root", 13 | "entry_files": ["main.py"], 14 | "key_files": ["pyproject.toml", "requirements.txt", "README.md"], 15 | "description": "AI-EditX专业AI视频编辑器项目根目录", 16 | "scan_status": "completed" 17 | }, 18 | "app": { 19 | "path": "app", 20 | "type": "package", 21 | "entry_files": ["__init__.py", "application_launcher.py"], 22 | "key_files": ["core/application.py", "config/config.py"], 23 | "description": "应用程序核心包", 24 | "scan_status": "completed" 25 | }, 26 | "app/core": { 27 | "path": "app/core", 28 | "type": "module", 29 | "entry_files": ["application.py", "service_container.py"], 30 | "key_files": ["logger.py", "event_bus.py", "config_manager.py", "project_manager.py"], 31 | "description": "核心服务模块", 32 | "scan_status": "completed", 33 | "coverage": { 34 | "total": 15, 35 | "scanned": 8, 36 | "percentage": 53.3 37 | } 38 | }, 39 | "app/ui": { 40 | "path": "app/ui", 41 | "type": "module", 42 | "entry_files": ["main/main_window.py"], 43 | "key_files": ["common/widgets/", "main/components/", "main/pages/"], 44 | "description": "用户界面模块", 45 | "scan_status": "partial", 46 | "coverage": { 47 | "total": 24, 48 | "scanned": 3, 49 | "percentage": 12.5 50 | } 51 | }, 52 | "app/services": { 53 | "path": "app/services", 54 | "type": "module", 55 | "entry_files": ["ai_service/ai_service_manager.py", "video_service/video_editor.py"], 56 | "key_files": ["export_service/export_service.py", "ai_service/base_ai_service.py"], 57 | "description": "业务服务模块", 58 | "scan_status": "completed", 59 | "coverage": { 60 | "total": 10, 61 | "scanned": 8, 62 | "percentage": 80.0 63 | } 64 | }, 65 | "app/config": { 66 | "path": "app/config", 67 | "type": "module", 68 | "entry_files": ["config.py"], 69 | "key_files": [], 70 | "description": "配置管理模块", 71 | "scan_status": "completed" 72 | }, 73 | "app/utils": { 74 | "path": "app/utils", 75 | "type": "module", 76 | "entry_files": ["error_handler.py"], 77 | "key_files": [], 78 | "description": "工具类模块", 79 | "scan_status": "partial" 80 | }, 81 | "resources": { 82 | "path": "resources", 83 | "type": "resource", 84 | "entry_files": [], 85 | "key_files": ["styles/", "icons/"], 86 | "description": "资源文件目录", 87 | "scan_status": "ignored", 88 | "reason": "Binary and resource files" 89 | } 90 | }, 91 | "gaps": { 92 | "uncovered_modules": [ 93 | { 94 | "path": "app/ui/common", 95 | "reason": "UI组件目录未被完整扫描", 96 | "priority": "medium" 97 | }, 98 | { 99 | "path": "app/ui/main/pages", 100 | "reason": "页面实现细节未知", 101 | "priority": "medium" 102 | }, 103 | { 104 | "path": "app/utils", 105 | "reason": "工具函数实现未知", 106 | "priority": "low" 107 | }, 108 | { 109 | "path": "docs", 110 | "reason": "文档目录未扫描", 111 | "priority": "low" 112 | } 113 | ], 114 | "missing_tests": { 115 | "description": "项目中未发现测试文件", 116 | "count": 0, 117 | "recommendation": "建议添加tests目录并实现单元测试" 118 | }, 119 | "missing_documentation": { 120 | "description": "API文档和架构文档不完善", 121 | "coverage": "estimated < 30%", 122 | "recommendation": "建议使用Sphinx生成API文档" 123 | } 124 | }, 125 | "ignore_patterns": [ 126 | "venv/**", 127 | "__pycache__/**", 128 | "*.pyc", 129 | ".git/**", 130 | "backup_*/**", 131 | "*.log", 132 | "*.tmp", 133 | "*.mp4", 134 | "*.avi", 135 | "*.mov", 136 | "*.jpg", 137 | "*.png", 138 | "*.qss" 139 | ], 140 | "truncated": false, 141 | "scan_duration": { 142 | "start": "2025-01-18T00:00:00Z", 143 | "end": "2025-01-18T00:30:00Z", 144 | "total_minutes": 30 145 | }, 146 | "next_scan_priorities": [ 147 | "app/ui/common/widgets/", 148 | "app/ui/main/pages/", 149 | "app/utils/error_handler.py", 150 | "app/core/event_bus.py", 151 | "docs/" 152 | ], 153 | "technology_stack": { 154 | "language": "Python", 155 | "version": ">=3.12", 156 | "ui_framework": "PyQt6", 157 | "video_processing": "MoviePy, OpenCV", 158 | "ai_integration": "Multiple AI Services", 159 | "packaging": "setuptools", 160 | "testing": "pytest (planned)" 161 | }, 162 | "architecture_quality": { 163 | "score": 7.2, 164 | "max_score": 10, 165 | "criteria": { 166 | "modularity": 8.0, 167 | "maintainability": 7.5, 168 | "extensibility": 7.0, 169 | "testability": 3.0, 170 | "performance": 7.5, 171 | "documentation": 5.0 172 | } 173 | } 174 | } -------------------------------------------------------------------------------- /app/core/config_manager.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | 简单配置管理器 6 | """ 7 | 8 | import json 9 | import os 10 | from typing import Dict, Any, Optional 11 | from pathlib import Path 12 | 13 | 14 | class ConfigManager: 15 | """简化配置管理器""" 16 | 17 | def __init__(self, config_path: Optional[str] = None): 18 | self.config_path = config_path or os.path.join( 19 | os.path.expanduser("~"), ".cineai-studio", "config.json" 20 | ) 21 | self._config: Dict[str, Any] = self._load_default_config() 22 | self._ensure_config_dir() 23 | self.load() 24 | 25 | def _load_default_config(self) -> Dict[str, Any]: 26 | """加载默认配置""" 27 | return { 28 | "window": { 29 | "width": 1200, 30 | "height": 800, 31 | "x": 100, 32 | "y": 100, 33 | "maximized": False, 34 | "fullscreen": False 35 | }, 36 | "theme": { 37 | "name": "dark_modern", 38 | "mode": "dark", 39 | "primary_color": "#2196F3", 40 | "font_size": 12 41 | }, 42 | "editor": { 43 | "auto_save": True, 44 | "auto_save_interval": 300, 45 | "backup_enabled": True, 46 | "recent_files": [] 47 | }, 48 | "ai": { 49 | "default_model": "openai", 50 | "max_tokens": 2000, 51 | "temperature": 0.7 52 | } 53 | } 54 | 55 | def _ensure_config_dir(self) -> None: 56 | """确保配置目录存在""" 57 | config_dir = Path(self.config_path).parent 58 | config_dir.mkdir(parents=True, exist_ok=True) 59 | 60 | def load(self) -> None: 61 | """加载配置""" 62 | if os.path.exists(self.config_path): 63 | try: 64 | with open(self.config_path, 'r', encoding='utf-8') as f: 65 | loaded_config = json.load(f) 66 | self._config.update(loaded_config) 67 | except (json.JSONDecodeError, IOError): 68 | pass 69 | 70 | def save(self) -> None: 71 | """保存配置""" 72 | try: 73 | with open(self.config_path, 'w', encoding='utf-8') as f: 74 | json.dump(self._config, f, indent=2, ensure_ascii=False) 75 | except IOError: 76 | pass 77 | 78 | def get(self, key: str, default: Any = None) -> Any: 79 | """获取配置值""" 80 | keys = key.split('.') 81 | value = self._config 82 | for k in keys: 83 | if isinstance(value, dict) and k in value: 84 | value = value[k] 85 | else: 86 | return default 87 | return value 88 | 89 | def get_value(self, key: str, default: Any = None) -> Any: 90 | """获取配置值(别名)""" 91 | return self.get(key, default) 92 | 93 | def set(self, key: str, value: Any) -> None: 94 | """设置配置值""" 95 | keys = key.split('.') 96 | config = self._config 97 | for k in keys[:-1]: 98 | if k not in config: 99 | config[k] = {} 100 | config = config[k] 101 | config[keys[-1]] = value 102 | 103 | def get_all(self) -> Dict[str, Any]: 104 | """获取所有配置""" 105 | return self._config.copy() 106 | 107 | def reset(self) -> None: 108 | """重置为默认配置""" 109 | self._config = self._load_default_config() 110 | self.save() 111 | 112 | def set_value(self, key: str, value: Any) -> None: 113 | """设置配置值(别名)""" 114 | self.set(key, value) 115 | 116 | def add_watcher(self, callback) -> None: 117 | """添加配置变更监听器(简化版)""" 118 | # 简化实现,不实现真正的监听功能 119 | pass 120 | 121 | def get_settings(self) -> Dict[str, Any]: 122 | """获取所有设置(别名)""" 123 | return self.get_all() 124 | 125 | def update_settings(self, settings: Dict[str, Any]) -> None: 126 | """更新设置(别名)""" 127 | self._config.update(settings) 128 | self.save() 129 | self._notify_watchers() 130 | 131 | def _notify_watchers(self) -> None: 132 | """通知配置变更监听器""" 133 | if hasattr(self, '_watchers'): 134 | for callback in self._watchers: 135 | try: 136 | callback(self._config) 137 | except Exception as e: 138 | # 捕获监听器异常,避免影响主程序 139 | print(f"配置监听器执行失败: {e}") 140 | 141 | def add_watcher(self, callback: callable) -> None: 142 | """添加配置变更监听器 143 | 144 | Args: 145 | callback: 回调函数,当配置变更时调用,接收当前配置作为参数 146 | """ 147 | if not hasattr(self, '_watchers'): 148 | self._watchers = [] 149 | if callback not in self._watchers: 150 | self._watchers.append(callback) 151 | 152 | def remove_watcher(self, callback: callable) -> None: 153 | """移除配置变更监听器 154 | 155 | Args: 156 | callback: 要移除的回调函数 157 | """ 158 | if hasattr(self, '_watchers'): 159 | try: 160 | self._watchers.remove(callback) 161 | except ValueError: 162 | pass -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | pytest 配置文件 6 | 定义测试夹具和全局测试配置 7 | """ 8 | 9 | import pytest 10 | import tempfile 11 | import shutil 12 | from pathlib import Path 13 | from unittest.mock import Mock, MagicMock 14 | from typing import Dict, Any, Generator 15 | 16 | from app.core.application import Application 17 | from app.core.config_manager import ConfigManager 18 | from app.core.logger import Logger 19 | from app.core.service_container import ServiceContainer 20 | from app.core.event_bus import EventBus 21 | 22 | 23 | @pytest.fixture(scope="session") 24 | def temp_dir() -> Generator[Path, None, None]: 25 | """创建临时目录夹具""" 26 | temp_path = Path(tempfile.mkdtemp()) 27 | yield temp_path 28 | shutil.rmtree(temp_path) 29 | 30 | 31 | @pytest.fixture 32 | def mock_config(temp_dir: Path) -> Dict[str, Any]: 33 | """模拟配置数据""" 34 | return { 35 | "app": { 36 | "name": "AI-EditX-Test", 37 | "version": "2.0.0-test", 38 | "debug": True, 39 | }, 40 | "ui": { 41 | "theme": "dark", 42 | "window": { 43 | "width": 800, 44 | "height": 600, 45 | "min_width": 600, 46 | "min_height": 400, 47 | }, 48 | }, 49 | "paths": { 50 | "projects": str(temp_dir / "projects"), 51 | "temp": str(temp_dir / "temp"), 52 | "cache": str(temp_dir / "cache"), 53 | "logs": str(temp_dir / "logs"), 54 | }, 55 | "ai_services": { 56 | "openai": { 57 | "enabled": False, 58 | "api_key": "test-key", 59 | "base_url": "https://api.openai.com/v1", 60 | } 61 | }, 62 | "video": { 63 | "default_fps": 30, 64 | "max_resolution": "1920x1080", 65 | "supported_formats": [".mp4", ".avi", ".mov", ".mkv"], 66 | } 67 | } 68 | 69 | 70 | @pytest.fixture 71 | def mock_logger(): 72 | """模拟日志记录器""" 73 | logger = Mock(spec=Logger) 74 | logger.debug = Mock() 75 | logger.info = Mock() 76 | logger.warning = Mock() 77 | logger.error = Mock() 78 | logger.critical = Mock() 79 | return logger 80 | 81 | 82 | @pytest.fixture 83 | def mock_event_bus(): 84 | """模拟事件总线""" 85 | event_bus = Mock(spec=EventBus) 86 | event_bus.subscribe = Mock() 87 | event_bus.unsubscribe = Mock() 88 | event_bus.publish = Mock() 89 | return event_bus 90 | 91 | 92 | @pytest.fixture 93 | def mock_service_container(mock_logger, mock_event_bus): 94 | """模拟服务容器""" 95 | container = Mock(spec=ServiceContainer) 96 | 97 | # 注册基本服务 98 | def get_service_side_effect(service_name: str): 99 | if service_name == "logger": 100 | return mock_logger 101 | elif service_name == "event_bus": 102 | return mock_event_bus 103 | else: 104 | return None 105 | 106 | container.get_service = Mock(side_effect=get_service_side_effect) 107 | container.register_service = Mock() 108 | container.unregister_service = Mock() 109 | 110 | return container 111 | 112 | 113 | @pytest.fixture 114 | def test_application(mock_config, mock_service_container): 115 | """测试应用实例""" 116 | app = Application() 117 | app._config = mock_config 118 | app._service_container = mock_service_container 119 | app._initialized = True 120 | return app 121 | 122 | 123 | @pytest.fixture 124 | def sample_video_data(): 125 | """示例视频数据""" 126 | return { 127 | "file_path": "/test/sample.mp4", 128 | "duration": 60.0, 129 | "fps": 30, 130 | "resolution": (1920, 1080), 131 | "codec": "h264", 132 | "bitrate": 5000000, 133 | "size": 50000000, 134 | } 135 | 136 | 137 | @pytest.fixture 138 | def sample_project_data(): 139 | """示例项目数据""" 140 | return { 141 | "name": "测试项目", 142 | "description": "这是一个测试项目", 143 | "created_at": "2024-01-01T00:00:00Z", 144 | "updated_at": "2024-01-01T00:00:00Z", 145 | "settings": { 146 | "resolution": "1920x1080", 147 | "fps": 30, 148 | "codec": "h264", 149 | }, 150 | "media_files": [], 151 | "timeline": [], 152 | "effects": [], 153 | } 154 | 155 | 156 | # 测试标记 157 | pytest_plugins = [] 158 | 159 | def pytest_configure(config): 160 | """pytest 配置钩子""" 161 | config.addinivalue_line( 162 | "markers", "unit: 单元测试" 163 | ) 164 | config.addinivalue_line( 165 | "markers", "integration: 集成测试" 166 | ) 167 | config.addinivalue_line( 168 | "markers", "ui: UI测试" 169 | ) 170 | config.addinivalue_line( 171 | "markers", "slow: 慢速测试" 172 | ) 173 | config.addinivalue_line( 174 | "markers", "gpu: 需要GPU的测试" 175 | ) 176 | 177 | 178 | def pytest_collection_modifyitems(config, items): 179 | """修改测试项""" 180 | for item in items: 181 | # 为UI测试添加标记 182 | if "ui" in item.nodeid: 183 | item.add_marker(pytest.mark.ui) 184 | 185 | # 为GPU相关测试添加标记 186 | if "video" in item.nodeid and "render" in item.nodeid: 187 | item.add_marker(pytest.mark.gpu) 188 | item.add_marker(pytest.mark.slow) -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 贡献指南 2 | 3 | 感谢您对 AI-EditX 项目的关注!我们欢迎各种形式的贡献,包括但不限于代码、文档、测试、问题和建议。 4 | 5 | ## 🤝 贡献方式 6 | 7 | ### 报告问题 8 | - 使用 [GitHub Issues](https://github.com/agions/AI-EditX/issues) 报告 bug 9 | - 提供详细的重现步骤和系统信息 10 | - 包含相关的日志文件和截图 11 | 12 | ### 功能建议 13 | - 在 Issues 中使用 "enhancement" 标签 14 | - 详细描述功能需求和使用场景 15 | - 说明预期的工作流程和用户体验 16 | 17 | ### 代码贡献 18 | - Fork 项目到您的 GitHub 账户 19 | - 创建功能分支:`git checkout -b feature/your-feature-name` 20 | - 提交更改:`git commit -m "Add some feature"` 21 | - 推送到分支:`git push origin feature/your-feature-name` 22 | - 创建 Pull Request 23 | 24 | ### 文档改进 25 | - 修正文档中的错误或不准确信息 26 | - 改进现有文档的可读性 27 | - 添加缺失的文档内容 28 | - 翻译文档到其他语言 29 | 30 | ## 🏗️ 开发环境设置 31 | 32 | ### 环境要求 33 | - Python 3.8+ (推荐 3.12+) 34 | - Git 35 | - 推荐使用 PyCharm、VSCode 等 IDE 36 | 37 | ### 克隆项目 38 | ```bash 39 | git clone https://github.com/agions/AI-EditX.git 40 | cd AI-EditX 41 | ``` 42 | 43 | ### 设置开发环境 44 | ```bash 45 | # 创建虚拟环境 46 | python -m venv venv 47 | source venv/bin/activate # Linux/macOS 48 | # 或 venv\Scripts\activate # Windows 49 | 50 | # 安装开发依赖 51 | pip install -r requirements.txt[dev] 52 | 53 | # 安装 pre-commit hooks 54 | pre-commit install 55 | ``` 56 | 57 | ### 运行测试 58 | ```bash 59 | # 运行所有测试 60 | pytest 61 | 62 | # 运行特定测试文件 63 | pytest tests/test_core/ 64 | 65 | # 生成覆盖率报告 66 | pytest --cov=app tests/ 67 | ``` 68 | 69 | ## 📋 代码规范 70 | 71 | ### Python 代码风格 72 | - 遵循 [PEP 8](https://www.python.org/dev/peps/pep-0008/) 73 | - 使用 [Black](https://black.readthedocs.io/) 进行代码格式化 74 | - 使用 [isort](https://isort.readthedocs.io/) 进行导入排序 75 | - 使用 [flake8](https://flake8.pycqa.org/) 进行代码检查 76 | 77 | ### 类型注解 78 | - 为所有公共函数和方法添加类型注解 79 | - 使用 `typing` 模块中的类型 80 | - 复杂类型使用 `typing.TypeAlias` 81 | 82 | ### 文档字符串 83 | - 为所有公共模块、类和方法添加文档字符串 84 | - 使用 Google 风格的文档字符串 85 | - 包含参数说明、返回值说明和异常说明 86 | 87 | ```python 88 | def example_function(param1: str, param2: int) -> bool: 89 | """示例函数的简短描述。 90 | 91 | 详细描述函数的功能和工作原理。 92 | 93 | Args: 94 | param1: 参数1的描述 95 | param2: 参数2的描述 96 | 97 | Returns: 98 | 返回值的描述 99 | 100 | Raises: 101 | ValueError: 当参数无效时抛出 102 | """ 103 | return True 104 | ``` 105 | 106 | ## 🔌 插件开发 107 | 108 | AI-EditX v3.0 支持插件开发。如果您想为项目贡献插件: 109 | 110 | 1. 阅读 [插件开发指南](app/plugins/README.md) 111 | 2. 查看 [示例插件](examples/plugins/) 112 | 3. 遵循插件接口规范 113 | 4. 提供完整的文档和测试 114 | 115 | ## 📝 提交规范 116 | 117 | ### Commit 消息格式 118 | ``` 119 | (): 120 | 121 | 122 | 123 |