├── 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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/resources/icons/svg/open.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/resources/icons/svg/export.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |