Clean up: remove junk files, update docs

- Delete: build scripts, old docs (README_BUILD, design.md, proposal.md, etc.)
- Update README.md and docs/ARCHITECTURE.md to reflect new architecture
- Keep run_lesson1.bat/py, start.bat, config.ini
This commit is contained in:
hmo
2026-05-03 03:30:24 +08:00
parent 9e62247a60
commit cf5004cf6a
12 changed files with 139 additions and 1791 deletions
View File
-10
View File
@@ -1,10 +0,0 @@
# Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Submit a pull request
## Development Setup
See README.md for setup instructions.
+73 -77
View File
@@ -1,105 +1,101 @@
# 🎹 Piano Highlight Generator
# Lesson Highlights Generator
钢琴课精华视频生成工具。自动从完整课程视频中提取精华片段,转录、纠错、生成字幕,批量烧录到视频中。
教学视频精华片段生成工具。输入课程视频 + PPT,自动提取精华片段,转录、纠错、生成字幕,批量烧录到视频中。
## 功能特点
## 功能特点
- **智能提取**: 自动检测视频中的精彩片段
- **语音转录**: 支持 Whisper 多模型(tiny/base/small/medium/large
- **AI 纠错**: LLM 自动纠正转录错误,优化标题
- **双语字幕**: 支持双轨字幕(标题轨 + 内容轨)
- **状态持久化**: 支持暂停/恢复,可中断继续
- **手动编辑**: 生成前可人工审核编辑标题和字幕内容
- **PPT 驱动提取**:根据 PPT 知识点定位视频中的讲解片段
- **语音转录 + 纠错**Whisper 转录 + LLM 批量校正
- **双轨字幕**:标题轨 + 内容轨
- **CLI / GUI 双入口**:共享同一套底层逻辑
## 📋 系统要求
## 快速开始
- Windows 10/11 或 macOS 10.15+
- Python 3.10+
- FFmpeg(必须,添加到 PATH
### 1. 配置 API
## 🚀 快速开始
### 1. 安装
复制配置文件并填入 API Key
```bash
# 克隆项目
git clone <repo-url>
cd piano-highlight-app
cp config.ini.example config.ini
# 编辑 config.ini,填入 api_key
```
# 创建虚拟环境(推荐)
python -m venv venv
.\venv\Scripts\activate # Windows
source venv/bin/activate # Linux/macOS
### 2. 安装依赖
# 安装依赖
```bash
pip install -r requirements.txt
# 安装 FFmpegWindows - 使用 winget
winget install Gyan.FFmpeg
# 或 macOS
brew install ffmpeg
```
### 2. 运行
### 3. 运行
**GUI(推荐):**
```bash
python src/main.py
.\start.bat
```
### 3. 配置
**CLI**
```bash
.\run_lesson1.bat
```
首次运行需要配置
1. **API 设置**: 选择 API 提供商(DeepSeek/硅基流动),输入 API Key
2. **视频设置**: 选择输入视频、输出目录
3. **转录设置**: 选择 Whisper 模型(推荐 medium
或通用方式
```bash
python src/cli.py --video video.mp4 --ppt presentation.pptx --output ./output
```
### 4. 生成
## 项目结构
1. 点击「开始处理」
2. 等待各步骤完成
3. **标题确认**: LLM 生成标题后,审核并编辑
4. **字幕确认**: 查看字幕内容,可进一步编辑
5. 等待烧录完成
```
lesson-highlights/
├── src/
│ ├── main.py # GUI 入口
│ ├── gui.py # GUI(参数输入,调用底层)
│ ├── cli.py # CLI 入口
│ └── core/ # 共享底层
│ ├── ppt_parser.py # PPT 解析 + clips 生成
│ ├── pipeline.py # 视频处理流水线
│ ├── subtitle.py # 字幕生成
│ └── ...
├── config.ini # API 配置(不提交 git
├── config.ini.example # 配置模板
├── start.bat # 启动 GUI
└── run_lesson1.bat # CLI 示例
```
## 📁 输出文件
## 工作流程
1. **PPT 解析**:提取 PPT 文本和知识点
2. **Whisper 转录**:将视频语音转成文本
3. **LLM 校正**:批量校正转录错误
4. **片段提取**:根据 PPT 知识点定位视频片段
5. **字幕烧录**:生成双轨字幕并烧入视频
6. **合并输出**:拼接所有片段为最终视频
## API 配置
编辑 `config.ini`
```ini
[api]
api_host = "https://ark.cn-beijing.volces.com/api/coding/v3"
api_key = your_api_key_here
```
支持火山方舟(doubao-seed-2.0-lite)或兼容 OpenAI API 的后端。
## 输出
```
output/
├── state.json # 处理状态
├── clips/ # 提取的片段
│ └── clip_001.mp4
├── generated_config.yaml # 生成的 clips 配置
├── clips/ # 提取的片段视频
├── subtitles/ # 字幕文件
│ ├── clip_001_title.srt # 标题轨
│ └── clip_001_content.srt # 内容轨
└── final/ # 最终输出
└── clip_001_final.mp4
└── final.mp4 # 最终输出
```
## 🔧 流水线步骤
## 系统要求
1. **extract** - 片段提取
2. **transcribe** - 语音转录
3. **title_correct** - 标题生成与纠错
4. **generate_subtitles** - 字幕生成
5. **merge** - 片段合并
6. **burn** - 字幕烧录
## ⚠️ 常见问题
### Q: 提示 "FFmpeg not found"
A: 确保 FFmpeg 已安装并添加到系统 PATH。重启终端后重试。
### Q: API 调用失败
A: 检查 API Key 是否正确,网络是否正常,或切换 API 提供商。
### Q: 磁盘空间不足
A: 清理输出目录或更换到空间更大的磁盘。
## 📄 许可证
MIT License
## 🤝 贡献
欢迎提交 Issue 和 Pull Request
- Python 3.10+
- FFmpeg(已打包在 `ffmpeg/` 目录)
- PySide6GUI
- faster-whisper(转录,可选)
-148
View File
@@ -1,148 +0,0 @@
# Piano Highlight Generator - Build Instructions
## Prerequisites
### 1. Python
- **Version**: Python 3.10 or higher (3.12 recommended)
- **Download**: https://www.python.org/downloads/
- **Note**: Ensure Python is added to PATH
### 2. FFmpeg (Runtime Requirement)
FFmpeg is required for video processing at runtime, NOT for building.
**Windows:**
- Download from https://ffmpeg.org/download.html
- Or use: `winget install ffmpeg`
- Add FFmpeg binary location to system PATH
**Linux (Ubuntu/Debian):**
```bash
sudo apt update
sudo apt install ffmpeg
```
**macOS:**
```bash
brew install ffmpeg
```
### 3. Additional Build Tools (Windows)
- **Visual Studio Build Tools** or **MinGW** may be required for Nuitka compilation
- Download: https://visualstudio.microsoft.com/visual-cpp-build-tools/
---
## Build Steps
### Windows
1. Open Command Prompt or PowerShell in project directory
2. Run the build script:
```cmd
build.bat
```
Or manually:
```cmd
pip install nuitka pandas
python -m nuitka --standalone --onefile --windows-console-mode=disable --output-dir=dist --output-name=PianoHighlightGenerator --enable-plugin=pyside6 src/main.py
```
### Linux/macOS
1. Make build script executable:
```bash
chmod +x build.sh
```
2. Run the build script:
```bash
./build.sh
```
Or manually:
```bash
pip3 install nuitka pandas
python3 -m nuitka --standalone --onefile --output-dir=dist --output-name=PianoHighlightGenerator --enable-plugin=pyside6 src/main.py
```
---
## Output
| Platform | Output Location | Filename |
|----------|----------------|----------|
| Windows | `dist/` | `PianoHighlightGenerator.exe` |
| Linux | `dist/` | `PianoHighlightGenerator.bin` |
| macOS | `dist/` | `PianoHighlightGenerator.bin` |
---
## Expected Size
- **Standalone executable**: ~150-250 MB
- This includes Python interpreter, PySide6, and all dependencies
---
## Testing the Built Executable
1. Copy FFmpeg to the same directory as the executable OR ensure FFmpeg is in PATH
2. Run the executable:
- **Windows**: Double-click `PianoHighlightGenerator.exe` or run from cmd
- **Linux/macOS**: Run `./PianoHighlightGenerator.bin` in terminal
3. Test basic functionality:
- App should launch with GUI
- Video selection should work
- Processing pipeline should execute
---
## Troubleshooting
### "ffmpeg not found" error
- Ensure FFmpeg is installed and in system PATH
- Test by running `ffmpeg -version` in terminal
### "Missing DLL" errors on Windows
- Install Visual C++ Redistributable: https://aka.ms/vs/17/release/vc_redist.x64.exe
### Build fails with memory error
- Reduce parallelism: Add `--jobs=2` to build command
- Close other applications
### PySide6 plugin issues
- Ensure `--enable-plugin=pyside6` is included
- For special PySide6 handling, add `--pyside6-option=--no-sandbox`
---
## Data Files
If you have a `prompts/` directory with template files, ensure:
- Path: `src/core/prompts/`
- Files are copied with `--include-data-files=src/core/prompts=prompts`
Currently, no prompts directory exists in the project. Create `src/core/prompts/` if needed for custom prompt templates.
---
## Nuitka Configuration (pyproject.toml)
The project includes Nuitka settings in `pyproject.toml`:
```toml
[tool.nuitka]
assume_yes_for_downloads = true
show_progress = true
output_dir = "dist"
output_name = "PianoHighlightGenerator"
python_version = "3.10"
standalone = true
onefile = true
```
You can also use the command line options documented above for more control.
-71
View File
@@ -1,71 +0,0 @@
@echo off
REM Piano Highlight Generator - Build Script for Windows
REM Prerequisites: Python 3.10+, FFmpeg (in PATH)
echo ================================================
echo Piano Highlight Generator - Nuitka Build
echo ================================================
echo.
REM Check Python version
echo Checking Python version...
python --version
if errorlevel 1 (
echo ERROR: Python not found. Please install Python 3.10 or higher.
pause
exit /b 1
)
REM Check FFmpeg
echo.
echo Checking FFmpeg...
where ffmpeg >nul 2>nul
if errorlevel 1 (
echo WARNING: FFmpeg not found in PATH. The built executable will require FFmpeg to be installed.
echo Please install FFmpeg from: https://ffmpeg.org/download.html
echo.
)
REM Create dist directory if not exists
if not exist "dist" mkdir dist
REM Install build dependencies
echo.
echo Installing build dependencies...
pip install nuitka pandas
REM Build command
echo.
echo Starting Nuitka compilation...
echo This may take several minutes on first run...
echo.
python -m nuitka ^
--standalone ^
--onefile ^
--windows-console-mode=disable ^
--output-dir=dist ^
--output-name=PianoHighlightGenerator ^
--enable-plugin=pyside6 ^
--include-data-files=src/core/prompts=prompts ^
--python-version=3.10 ^
src/main.py
if errorlevel 1 (
echo.
echo BUILD FAILED!
pause
exit /b 1
)
echo.
echo ================================================
echo Build complete!
echo ================================================
echo.
echo Output: dist\PianoHighlightGenerator.exe
echo.
echo NOTE: FFmpeg must be in PATH for the executable to work.
echo If FFmpeg is not installed, download from https://ffmpeg.org
echo.
pause
-61
View File
@@ -1,61 +0,0 @@
#!/bin/bash
# Piano Highlight Generator - Build Script for Linux/macOS
# Prerequisites: Python 3.10+, FFmpeg (in PATH)
set -e
echo "================================================"
echo " Piano Highlight Generator - Nuitka Build"
echo "================================================"
echo ""
# Check Python version
echo "Checking Python version..."
python3 --version || { echo "ERROR: Python not found. Please install Python 3.10 or higher."; exit 1; }
# Check FFmpeg
echo ""
echo "Checking FFmpeg..."
if ! command -v ffmpeg &> /dev/null; then
echo "WARNING: FFmpeg not found in PATH. The built executable will require FFmpeg."
echo "Please install FFmpeg: sudo apt install ffmpeg (Ubuntu/Debian) or brew install ffmpeg (macOS)"
echo ""
fi
# Create dist directory if not exists
mkdir -p dist
# Install build dependencies
echo ""
echo "Installing build dependencies..."
pip3 install nuitka pandas
# Build
echo ""
echo "Starting Nuitka compilation..."
echo "This may take several minutes on first run..."
echo ""
python3 -m nuitka \
--standalone \
--onefile \
--output-dir=dist \
--output-name=PianoHighlightGenerator \
--enable-plugin=pyside6 \
--include-data-files=src/core/prompts=prompts \
--python-version=3.10 \
src/main.py
echo ""
echo "================================================"
echo " Build complete!"
echo "================================================"
echo ""
echo "Output: dist/PianoHighlightGenerator.bin"
echo ""
echo "NOTE: FFmpeg must be in PATH for the executable to work."
echo ""
echo "To run FFmpeg from a specific location, either:"
echo " 1. Add FFmpeg to your PATH"
echo " 2. Place FFmpeg binary in the same directory as the executable"
echo ""
-69
View File
@@ -1,69 +0,0 @@
@echo off
REM Piano Highlight Generator - CLI Build Script for Windows
REM Builds a standalone CLI executable from cli.py
set "PYTHON=D:\ProgramData\anaconda3\envs\py312_cuda\python.exe"
set "PYINSTALLER=D:\ProgramData\anaconda3\envs\py312_cuda\Scripts\pyinstaller.exe"
echo ================================================
echo Piano Highlight Generator - CLI Build
echo ================================================
echo.
REM Check Python
"%PYTHON%" --version
if errorlevel 1 (
echo ERROR: Python not found
pause
exit /b 1
)
REM Install pyinstaller if needed
"%PYTHON%" -c "import PyInstaller" 2>nul
if errorlevel 1 (
echo Installing PyInstaller...
"%PYTHON%" -m pip install pyinstaller -q
)
REM Build
echo.
echo Starting PyInstaller compilation...
echo This may take several minutes...
echo.
cd /d "D:\F\NewI\opencode\daily-workspace\projects\piano-highlight-app"
"%PYTHON%" -m PyInstaller ^
--name=PianoHighlightCLI ^
--console ^
--onefile ^
--clean ^
--distpath=dist_cli ^
--workpath=build_cli ^
--specpath=build_cli ^
--additional-hooks-dir= ^
--hidden-import=pkg_resources ^
--hidden-import=faster_whisper ^
--hidden-import=cv2 ^
--hidden-import= yaml ^
--hidden-import=requests ^
--hidden-import=PIL ^
--collect-all=faster_whisper ^
--collect-all=transformers ^
src/cli.py
if errorlevel 1 (
echo.
echo BUILD FAILED!
pause
exit /b 1
)
echo.
echo ================================================
echo Build complete!
echo ================================================
echo.
echo Output: dist_cli\PianoHighlightCLI.exe
echo.
pause
-521
View File
@@ -1,521 +0,0 @@
# Piano Highlight Generator App - 技术设计
> 设计日期:2026-05-02
> 版本:1.0
> 状态:Draft
---
## 1. 技术栈
| 层级 | 技术 | 选型理由 |
|------|------|----------|
| GUI 框架 | PySide6 (Qt for Python) | LGPL 许可,功能完备,信号槽机制适合异步更新 |
| 打包工具 | Nuitka | 编译为 C,性能好,体积小 |
| 状态持久化 | JSON 文件 | 简单,无需数据库依赖 |
| 核心模块 | 复用现有脚本 | video.py, subtitle.py, llm.py, corrections.py |
| 配置格式 | YAML/JSON | 用户友好,可读性好 |
---
## 2. 项目结构
```
piano-highlight-app/
├── src/
│ ├── __init__.py
│ ├── main.py # 应用入口
│ ├── app.py # QMainWindow 主窗口
│ ├── gui/ # GUI 组件
│ │ ├── __init__.py
│ │ ├── config_panel.py # 配置面板
│ │ ├── progress_view.py # 进度监控
│ │ ├── title_editor.py # 标题编辑器
│ │ └── log_view.py # 日志窗口
│ ├── logic/ # 业务逻辑
│ │ ├── __init__.py
│ │ ├── config_manager.py # 配置管理
│ │ ├── pipeline_controller.py # 流水线控制
│ │ ├── state_manager.py # 状态管理
│ │ └── worker.py # 后台工作线程
│ └── core/ # 核心模块(复用)
│ ├── __init__.py
│ ├── constants.py # 常量
│ ├── utils.py # 工具函数
│ ├── video.py # 视频处理
│ ├── subtitle.py # 字幕处理
│ ├── llm.py # LLM 调用
│ └── corrections.py # 纠错规则
├── assets/ # 资源文件
│ └── icons/
├── requirements.txt # 依赖
├── pyproject.toml # 项目配置
├── nuitka_options.py # Nuitka 打包配置
└── README.md
```
---
## 3. 核心类设计
### 3.1 StateManager(状态管理)
```python
class StateManager:
"""状态管理器 - 负责状态持久化"""
def __init__(self, state_file: str):
self.state_file = state_file
self.state = self._load()
def _load(self) -> dict:
"""从文件加载状态"""
def save(self):
"""保存状态到文件"""
def get_current_step(self) -> int:
"""获取当前步骤"""
def set_step_status(self, step: str, status: str):
"""设置步骤状态 (pending/in_progress/completed/failed)"""
def update_clip_status(self, clip_index: int, **kwargs):
"""更新 clip 状态"""
def get_clip_titles(self) -> list:
"""获取所有 clip 的标题(含用户修改)"""
```
### 3.2 PipelineController(流水线控制)
```python
class PipelineController:
"""流水线控制器 - 管理处理流程"""
# 步骤定义
STEPS = [
'ready',
'extracting',
'transcribing',
'title_correcting',
'generating_subtitles',
'merging',
'burning',
'completed'
]
def __init__(self, config: dict, state_manager: StateManager):
self.config = config
self.state = state_manager
self.is_paused = False
self.is_stopped = False
def run(self, worker: Worker):
"""运行流水线"""
def pause(self):
"""暂停流水线"""
def resume(self):
"""恢复流水线"""
def stop(self):
"""停止流水线"""
def step_extracting(self):
"""Step 1: 提取片段"""
def step_transcribing(self):
"""Step 2: 转录"""
def step_title_correcting(self) -> list:
"""Step 3: 标题纠正 - 返回需要用户确认的标题"""
# 返回标题列表,用户可以在此介入修改
def step_generating_subtitles(self):
"""Step 4: 生成字幕"""
def step_merging(self):
"""Step 5: 合并视频"""
def step_burning(self):
"""Step 6: 烧录字幕"""
```
### 3.3 Worker(后台工作线程)
```python
class Worker(QThread):
"""后台工作线程 - 在独立线程中执行流水线"""
progress_signal = pyqtSignal(str, int, str) # step, percent, message
clip_completed_signal = pyqtSignal(int) # clip_index
step_completed_signal = pyqtSignal(str) # step_name
titles_ready_signal = pyqtSignal(list) # 标题列表,等待用户确认
finished_signal = pyqtSignal(bool, str) # success, message
log_signal = pyqtSignal(str) # 日志消息
def __init__(self, controller: PipelineController):
super().__init__()
self.controller = controller
def run(self):
"""执行流水线(可暂停)"""
def request_pause(self):
"""请求暂停(由 UI 调用)"""
```
### 3.4 ConfigPanel(配置面板)
```python
class ConfigPanel(QWidget):
"""配置面板"""
config_changed_signal = pyqtSignal(dict)
def __init__(self):
super().__init__()
self._init_ui()
def _init_ui(self):
"""初始化 UI"""
# API 配置组
# - API Host (QLineEdit)
# - API Key (QLineEdit, 密码模式)
# - 模型选择 (QComboBox)
# 视频配置组
# - 视频文件选择 (QLineEdit + QPushButton)
# - 输出目录选择 (QLineEdit + QPushButton)
# Whisper 配置组
# - 模型选择 (QComboBox: base/small/medium/large)
# - 模型路径 (QLineEdit)
def load_config(self, config: dict):
"""加载配置到 UI"""
def get_config(self) -> dict:
"""从 UI 获取配置"""
def validate(self) -> tuple:
"""验证配置有效性"""
# 返回 (is_valid, error_message)
```
### 3.5 ProgressView(进度视图)
```python
class ProgressView(QWidget):
"""进度监控视图"""
def __init__(self):
super().__init__()
self._init_ui()
def _init_ui(self):
"""初始化 UI"""
# 当前步骤标签 (QLabel)
# 整体进度条 (QProgressBar)
# Clip 进度 (QLabel: "Clip 3/14")
# 日志文本框 (QTextEdit, 只读)
# 控制按钮 (开始/暂停/停止/继续)
def update_progress(self, step: str, percent: int, message: str):
"""更新进度显示"""
def append_log(self, message: str):
"""追加日志"""
def set_clip_progress(self, current: int, total: int):
"""设置 Clip 进度"""
def enable_controls(self, can_start: bool, can_pause: bool, can_stop: bool, can_resume: bool):
"""设置控制按钮状态"""
```
### 3.6 ContentEditor(内容编辑器 - 人工介入点)
```python
class ContentEditor(QWidget):
"""内容编辑器 - 用于人工介入修改标题和字幕内容"""
content_confirmed_signal = pyqtSignal(dict) # 用户确认的内容 {clip_index: {title, subtitles}}
def __init__(self):
super().__init__()
self._init_ui()
def _init_ui(self):
"""初始化 UI"""
# 标签页:标题编辑 / 字幕编辑
# 标题编辑:
# - Clip # | 原始标题 | LLM建议 | 用户修改 | 操作
# - 编辑按钮 (QPushButton)
# 字幕编辑:
# - 按Clip分页,每个Clip显示其字幕内容
# - 每个字幕段可编辑(原始文本 → 纠正后文本 → 用户修改)
# 确认按钮 (QPushButton)
def set_content(self, clips_data: dict):
"""设置内容供用户编辑
clips_data: {
clip_index: {
'title': {...},
'subtitles': [...]
}
}
"""
def get_user_content(self) -> dict:
"""获取用户修改后的内容"""
def edit_clip_title(self, clip_index: int):
"""编辑单个Clip的标题 - 弹出对话框"""
def edit_clip_subtitle(self, clip_index: int, subtitle_index: int):
"""编辑单个字幕段 - 弹出对话框"""
```
### 3.7 SubtitleSegmentEditor(字幕段编辑器)
```python
class SubtitleSegmentEditor(QWidget):
"""单个字幕片段的编辑器"""
def __init__(self, segment_data: dict, parent=None):
super().__init__(parent)
# 显示:时间范围、原始文本、规则纠正后、LLM纠正后、用户可编辑
def get_corrected_text(self) -> str:
"""获取用户修改后的文本"""
```
---
## 4. 流水线状态机
```
┌─────────┐
┌─────────►│ Ready │◄────────┐
│ └────┬────┘ │
│ │ start() │ reset()
│ ▼ │
│ ┌─────────┐ │
│ ┌─────│Extracting│─────┐ │
│ │ └────┬────┘ │ │
│ │ pause │ completed │ │
│ │ ▼ │ │
│ │ ┌───────────┐ │ │
│ └──►│Transcribing│◄────┘ │
│ └─────┬─────┘ │
│ pause │ │ completed │
│ ▼ │
│ ┌─────────────────┐ │
│ │Title Correcting │◄──┐ │ 人工介入点
│ └────────┬────────┘ │ │ 用户可暂停
│ │ completed │ │ 修改标题
│ ▼ │ │
│ ┌──────────────────┐ │ │
│ │Generating Subtitles│───┘ │
│ └─────────┬────────┘ │
│ pause │ │ completed │
│ ▼ │
│ ┌──────────────┐ │
│ │ Merging │◄──┘ │
│ └──────┬───────┘ │
│ pause│ │ completed │
│ ▼ │
│ ┌───────────┐ │
│ │ Burning │◄─────────────┘
│ └─────┬─────┘
│ pause│ │ completed
│ ▼
│ ┌───────────┐
└────│ Completed │
└───────────┘
```
---
## 5. 信号流设计
```
┌─────────────────────────────────────────────────────────────────┐
│ UI Layer │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ ConfigPanel │ │ ProgressView │ │ TitleEditor │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ │ config_changed │ titles_ready │ titles_confirmed │
└─────────┼──────────────────┼──────────────────┼──────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ Controller Layer │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ PipelineController │ │
│ │ - manage_workflow() │ │
│ │ - handle_pause() / handle_resume() │ │
│ │ - collect_user_titles() │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Worker Thread │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Worker (QThread) │ │
│ │ - runs pipeline steps │ │
│ │ - emits progress/titles signals │ │
│ │ - respects pause/stop flags │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
### 信号定义
| 信号 | 方向 | 参数 | 说明 |
|------|------|------|------|
| `config_changed` | UI → Controller | dict | 配置变更 |
| `start_pipeline` | Controller → Worker | dict, StateManager | 启动流水线 |
| `progress_signal` | Worker → UI | step, percent, message | 进度更新 |
| `titles_ready_signal` | Worker → UI | list | 标题列表准备好,等待确认 |
| `titles_confirmed_signal` | UI → Controller | list | 用户确认的标题 |
| `pause_pipeline` | UI → Worker | - | 请求暂停 |
| `resume_pipeline` | UI → Worker | - | 请求恢复 |
| `stop_pipeline` | UI → Worker | - | 请求停止 |
---
## 6. 状态文件格式
```json
{
"version": 1,
"app_version": "1.0.0",
"project_name": "福田夜校-03月18日",
"created_at": "2026-05-02T10:00:00",
"updated_at": "2026-05-02T10:30:00",
"config": {
"video_src": "D:/path/to/video.mp4",
"output_dir": "D:/path/to/output",
"api_key": "xxx",
"api_host": "https://ark.cn-beijing.volces.com/api/coding/v3",
"whisper_model": "large",
"whisper_model_path": "D:/AI/LM-Models/faster-whisper/large-v3",
"video_params": {
"fade_duration": 1,
"title_fontsize": 90,
"title_color": "FFFF00",
"subtitle_fontsize": 24,
"subtitle_color": "FFFFFF"
}
},
"pipeline": {
"current_step": 3,
"steps": {
"extracting": {"status": "completed", "started_at": "...", "completed_at": "..."},
"transcribing": {"status": "completed", "started_at": "...", "completed_at": "..."},
"title_correcting": {"status": "in_progress", "started_at": "...", "completed_at": null},
"generating_subtitles": {"status": "pending", "started_at": null, "completed_at": null},
"merging": {"status": "pending", "started_at": null, "completed_at": null},
"burning": {"status": "pending", "started_at": null, "completed_at": null}
}
},
"clips": [
{
"index": 1,
"title_original": "弹奏",
"title_llm": "弹奏",
"title_user": null,
"title_final": "弹奏",
"start": 412,
"end": 442,
"status": "completed",
"clip_path": "intermediates/clip1_fade.mp4",
"json_path": "intermediates/clip1.json",
"transcription_completed_at": "..."
}
],
"outputs": {
"subtitle_title_path": "subs/v1_title.srt",
"subtitle_content_path": "subs/v1_content.srt",
"merged_video_path": "concat_merged.mp4",
"final_video_path": "v1_final.mp4"
}
}
```
---
## 7. 错误处理策略
| 错误类型 | 处理方式 |
|----------|----------|
| 配置无效 | 阻止开始,提示用户修正 |
| API 调用失败 | 重试 3 次,仍失败则暂停流水线,等待用户处理 |
| 视频文件不存在 | 暂停,提示用户选择其他文件 |
| 磁盘空间不足 | 暂停,提示用户清理空间 |
| 处理异常崩溃 | 状态已持久化,重启后可恢复 |
| 用户取消 | 保存当前进度,清理临时文件(可选) |
---
## 8. 打包配置 (Nuitka)
```python
# nuitka_options.py
import nuitka
nuitka.compile(
script="src/main.py",
mode="standalone",
output_dir="dist",
windows_icon="assets/icon.ico",
include_qt_plugins=["qt_plugins/styles", "qt_plugins/imageformats"],
data_files=[
("assets/icons", "assets/icons"),
],
remove_output_dir=True,
onefile=True, # 打包成单个 exe
company_name="Piano Tools",
product_name="Piano Highlight Generator",
product_version="1.0.0",
)
```
---
## 9. 依赖清单
```
PySide6>=6.6.0
pyyaml>=6.0
requests>=2.31.0
pypinyin>=0.50.0
faster-whisper>=1.0.0 # 可选,如需本地转录
```
---
## 10. 开发优先级
| 优先级 | 模块 | 工期估计 |
|--------|------|----------|
| P0 | 项目骨架 + ConfigPanel + StateManager | 2h |
| P0 | ProgressView + Worker 集成 | 2h |
| P0 | PipelineController 核心逻辑 | 2h |
| P1 | TitleEditor 标题编辑器 | 1.5h |
| P2 | 完善错误处理和边界情况 | 1h |
| P2 | 打包配置 + 测试 | 1.5h |
| P3 | README 和用户文档 | 0.5h |
**总工期估计:约 10 小时**
+65 -63
View File
@@ -1,90 +1,92 @@
# 架构设计
## 1. 技术栈
## 1. 核心原则
| 层级 | 技术 | 选型理由 |
|------|------|----------|
| GUI 框架 | PySide6 (Qt for Python) | LGPL 许可,功能完备,信号槽机制适合异步更新 |
| 打包工具 | Nuitka | 编译为 C,性能好,体积小 |
| 状态持久化 | JSON 文件 | 简单,无需数据库依赖 |
| 核心模块 | 复用现有脚本 | video.py, subtitle.py, llm.py, corrections.py |
| 配置格式 | YAML/JSON | 用户友好,可读性好 |
**CLI 和 GUI 共用同一套底层类库**,仅在表示层有差异:
- **CLI**:命令行参数输入,日志输出到终端
- **GUI**PySide6 界面,参数输入界面化,日志输出到文本区
## 2. 项目结构
```
piano-highlight-app/
lesson-highlights/
├── src/
│ ├── main.py # GUI 入口
│ ├── gui.py # GUI(参数输入 → 调用底层)
│ ├── cli.py # CLI 入口
│ └── core/ # 共享底层
│ ├── __init__.py
├── main.py # 应用入口
├── app.py # QMainWindow 主窗口
├── gui/ # GUI 组件
├── __init__.py
│ │ ├── config_panel.py # 配置面板
│ │ ├── progress_view.py # 进度监控
│ │ ├── title_editor.py # 标题编辑器
│ │ └── log_view.py # 日志窗口
│ ├── logic/ # 业务逻辑
│ │ ├── __init__.py
│ │ ├── config_manager.py # 配置管理
│ │ ├── pipeline_controller.py # 流水线控制
│ │ ├── state_manager.py # 状态管理
│ │ └── worker.py # 后台工作线程
│ └── core/ # 核心模块(复用)
│ ├── __init__.py
│ ├── constants.py # 常量
│ ├── utils.py # 工具函数
│ ├── video.py # 视频处理
│ ├── subtitle.py # 字幕处理
├── ppt_parser.py # PPT 解析 + LLM clips 提取
├── pipeline.py # 视频处理流水线
├── subtitle.py # 字幕生成
├── video.py # 视频处理(提取/合并/烧录)
│ ├── llm.py # LLM 调用
── corrections.py # 纠错规则
├── assets/ # 资源文件
└── icons/
├── requirements.txt # 依赖
├── pyproject.toml # 项目配置
├── nuitka_options.py # Nuitka 打包配置
── README.md
── corrections.py # 术语纠正
│ ├── constants.py # 常量配置
└── errors.py # 错误处理
├── config.ini # API 配置(不提交 git)
├── config.ini.example # 配置模板
├── start.bat # GUI 启动器
── run.bat # 通用 CLI 启动器
└── run_lesson1.bat # 预设课程示例
```
## 3. 核心类设计
## 3. 核心模块
### StateManager(状态管理)
### `parse_ppt_to_config()`
负责状态持久化,支持暂停/恢复。
一键完成 PPT → clips 配置的完整流程:
### PipelineController(流水线控制)
1. **PPT 解析**:提取文本和知识点
2. **Whisper 转录**:视频 → `full_transcript.json`
3. **LLM 校正**:批量校正 → `corrected_transcript.json`
4. **LLM 提取片段**:根据知识点定位视频片段 → clips
5. **重叠合并**:合并重叠片段
管理处理流程的 6 个步骤:
1. extract - 片段提取
2. transcribe - 语音转录
3. title_correct - 标题生成与纠错
4. generate_subtitles - 字幕生成
5. merge - 片段合并
6. burn - 字幕烧录
### `Pipeline`
### Worker(后台工作线程)
视频处理流水线:
在独立线程中执行流水线,通过信号与 UI 通信。
1. **extract**:按时间戳提取片段
2. **transcribe**:逐片段 Whisper 转录
3. **correct_titles**LLM 标题纠正
4. **generate_subtitles**:生成双轨字幕
5. **merge**:合并片段
6. **burn**:烧录字幕
## 4. 流水线状态机
## 4. 数据
```
Ready → Extracting → Transcribing → Title Correcting → Generating Subtitles → Merging → Burning → Completed
└───────────── 用户可暂停并编辑标题 ─────────────┘
视频 + PPT
parse_ppt_to_config()
config = {
"video_src": ...,
"clips": [{"title": ..., "start": ..., "end": ...}, ...],
"output_dir": ...,
"term_corrections": {...}
}
Pipeline(config).run()
final.mp4
```
## 5. 信号流
## 5. 配置来源
| 信号 | 方向 | 说明 |
|------|------|------|
| config_changed | UI → Controller | 配置变更 |
| progress_signal | Worker → UI | 进度更新 |
| titles_ready_signal | Worker → UI | 标题列表准备好 |
| titles_confirmed_signal | UI → Controller | 用户确认的标题 |
API 配置统一从 `config.ini` 读取,不硬编码在代码中。
## 6. 状态文件格式
CLI 支持参数覆盖:
- `--api-key`
- `--api-host`
- `--verbose`
JSON 格式,包含配置、流水线状态、clips 列表等。
## 6. 状态持久化
详见 design.md。
中间结果保存在 `output/intermediates/`
- `full_transcript.json` - 原始转录
- `corrected_transcript.json` - LLM 校正后
- `ppt_knowledge_and_cleaned.json` - PPT 知识点和清理后文本
复用时检测 checkpoint,避免重复 LLM 调用。
-288
View File
@@ -1,288 +0,0 @@
# Piano Highlight Generator App - 需求提案
> 提案日期:2026-05-02
> 提案人:AI Dev Team
> 状态:Draft
---
## 1. 问题描述
### 1.1 现状
当前钢琴课精华视频生成器是 Python CLI 脚本集合:
- `generate_highlights.py` - 命令行程序,一次性执行完整流程
- 无图形界面,需要手动编辑 YAML 配置文件
- 无状态保持,程序中断只能从头开始
- 无人工介入点,无法在处理过程中修改标题
### 1.2 用户需求
用户希望将其重构为**可分发的桌面应用**,具备:
| 需求 | 说明 |
|------|------|
| **配置界面** | 图形化配置 API 大模型参数,无需编辑 YAML |
| **全过程监控** | 实时显示每个处理步骤的状态 |
| **状态保持** | 可在任意步骤暂停,然后继续往下进行 |
| **人工介入** | 暂停时可手动修改标题,然后再最后烧制 |
---
## 2. 用户故事
### 2.1 作为用户,我想要...
**Story 1: 配置管理**
- 打开应用后,能看到清晰的配置界面
- 可以选择/切换不同的 LLM API(当前是火山方舟,可扩展)
- 可以选择 Whisper 模型(用于音频转录)
- 配置可以保存和加载
**Story 2: 全过程监控**
- 启动处理后,能看到每个步骤的实时状态
- 看到当前正在处理哪个片段(Clip 3/14)
- 看到预估剩余时间
- 能看到每个步骤的日志输出
**Story 3: 暂停与恢复**
- 点击"暂停"按钮,处理立即停止
- 关闭应用后,下次打开能从暂停点继续
- 恢复后从最近的检查点继续,不丢失进度
**Story 4: 人工介入**
- 在标题纠正步骤,可以预览每个片段的标题
- 可以手动修改标题
- 可以跳过某些片段
- 所有修改会被保存
**Story 5: 打包分发**
- 生成一个 .exe 文件,双击即可运行
- 无需安装 Python 环境
- 可以在其他电脑上使用
---
## 3. 验收标准
### 3.1 配置界面
- [ ] 应用启动后显示配置面板
- [ ] 可以输入/编辑 API Key 和 API Host
- [ ] 可以选择 Whisper 模型(base/small/medium/large
- [ ] 可以选择输入视频文件(文件选择对话框)
- [ ] 可以选择输出目录
- [ ] 配置可以保存到文件(JSON/YAML)
- [ ] 配置可以从文件加载
### 3.2 全过程监控
- [ ] 显示当前步骤:准备 → 提取片段 → 转录 → 标题纠正 → 合并 → 烧录
- [ ] 每一步显示进度条(百分比)
- [ ] 显示当前片段序号(如 "Clip 3/14"
- [ ] 实时显示处理日志
- [ ] 处理完成后显示最终视频路径
### 3.3 暂停与恢复
- [ ] 有"暂停"按钮,点击后处理停止
- [ ] 暂停时状态持久化到文件
- [ ] 重新打开应用后,自动检测到未完成的任务
- [ ] 可以选择"继续"从暂停点恢复
- [ ] 也可以选择"重新开始"
### 3.4 人工介入
- [ ] 在标题纠正步骤,显示所有片段的标题列表
- [ ] 每个标题可以点击编辑
- [ ] 编辑后自动保存
- [ ] 可以预览修改后的字幕效果
- [ ] 确认后继续后续步骤
### 3.5 打包分发
- [ ] 生成 Windows 可执行文件(.exe
- [ ] 双击运行,无须安装 Python
- [ ] 界面美观,与现代桌面应用一致
---
## 4. 技术选型
### 4.1 GUI 框架
**选择:PySide6 (Qt for Python)**
| 因素 | 结论 |
|------|------|
| 许可证 | LGPL - 可闭源商用,无需购买 |
| 功能 | 成熟完备,适合复杂桌面应用 |
| 状态管理 | 传统保留模式,天然支持暂停/恢复 |
| 多线程 | 信号槽机制完善,支持多线程安全更新 UI |
| 社区 | 文档丰富,社区活跃 |
| 打包 | Nuitka 打包体积小(~10MB),启动快 |
### 4.2 打包方案
**开发阶段**PyInstaller(调试方便)
**正式发布**Nuitka(体积小,性能好)
### 4.3 状态持久化
- 使用 JSON 文件存储处理进度
- 每个项目独立的状态文件
- 包含:当前步骤、已完成片段、用户修改的标题等
---
## 5. 架构设计(预览)
```
┌─────────────────────────────────────────────────────────────┐
│ GUI Layer (PySide6) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ ConfigPanel │ │ ProgressView│ │ TitleEditor │ │
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Business Logic Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ ConfigManager│ │PipelineCtrl │ │ StateManager │ │
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Core Modules (Legacy) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ video.py│ │subtitle │ │ llm.py │ │correction│ │
│ │ │ │ .py │ │ │ │s.py │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### 模块职责
| 模块 | 职责 |
|------|------|
| ConfigPanel | 配置界面(API、视频路径、模型选择) |
| ProgressView | 进度监控(步骤、百分比、日志) |
| TitleEditor | 标题编辑器(预览、编辑用户修改) |
| ConfigManager | 配置加载/保存 |
| PipelineController | 流水线控制(启动/暂停/恢复/停止) |
| StateManager | 状态持久化(保存/恢复进度) |
---
## 6. 流水线步骤
与应用UI对应的处理步骤:
```
Step 0: 准备 (Ready)
└─ 检查配置、初始化环境
Step 1: 提取片段 (Extracting)
└─ 从视频提取 clips -> intermediates/clip{N}_fade.mp4
Step 2: 转录 (Transcribing)
└─ Whisper 转录 -> intermediates/clip{N}.json
Step 3: 标题纠正 (Title Correcting)
└─ LLM 分析 + 用户修改 -> intermediates/corrected_titles.json
[人工介入点] 用户可在此步骤暂停并修改标题
Step 4: 生成字幕 (Generating Subtitles)
└─ 生成双轨字幕 -> subs/v{N}_title.srt, v{N}_content.srt
Step 5: 合并视频 (Merging)
└─ FFmpeg concat -> concat_merged.mp4
Step 6: 烧录字幕 (Burning)
└─ FFmpeg burn -> v{N}_final.mp4
Step 7: 完成 (Completed)
└─ 显示结果,清理临时文件(可选)
```
### 暂停点
用户可以在以下步骤暂停:
- Step 1 完成后(片段已提取)
- Step 2 完成后(转录已完成)
- Step 3 完成后(标题已确认)- **推荐暂停点**
- Step 4 完成后(字幕已生成)
- Step 5 完成后(视频已合并)
---
## 7. 状态数据结构
```json
{
"version": 1,
"project_name": "福田夜校-03月18日",
"config": {
"video_src": "D:/path/to/video.mp4",
"output_dir": "D:/path/to/output",
"api_key": "xxx",
"api_host": "https://...",
"whisper_model": "large"
},
"current_step": 3,
"clips": [
{
"index": 1,
"title_original": "弹奏",
"title_corrected": "弹奏",
"title_user_modified": null,
"start": 412,
"end": 442,
"status": "completed",
"clip_path": "intermediates/clip1_fade.mp4",
"json_path": "intermediates/clip1.json"
}
],
"step_status": {
"extracting": "completed",
"transcribing": "completed",
"title_correcting": "in_progress",
"generating_subtitles": "pending",
"merging": "pending",
"burning": "pending"
},
"created_at": "2026-05-02T10:00:00",
"updated_at": "2026-05-02T10:30:00"
}
```
---
## 8. 边界情况
| 情况 | 处理方式 |
|------|----------|
| API Key 无效 | 显示错误提示,不开始处理 |
| 视频文件不存在 | 配置检查时发现,提示用户 |
| 处理到一半崩溃 | 状态已持久化,重启后可恢复 |
| 用户取消处理 | 保存当前进度,可选择重新开始或继续 |
| Whisper 模型未下载 | 显示下载链接,或使用默认模型 |
| 输出目录磁盘空间不足 | 处理前检查,提示用户 |
---
## 9. 非功能性需求
| 需求 | 标准 |
|------|------|
| 启动时间 | < 3 秒(使用 Nuitka 打包后) |
| UI 响应性 | 所有操作在 100ms 内响应 |
| 内存占用 | < 500MB(不含视频处理) |
| 打包后体积 | < 50MB |
| 兼容性 | Windows 10/11 64-bit |
---
## 10. 后续步骤
1. **Phase 2**: 技术设计 - 详细架构设计、数据库选型、接口定义
2. **Phase 3**: 任务编排 - 拆分并行任务、创建 git worktree
3. **Phase 4**: 并行开发 - 各模块实现
4. **Phase 5**: 质量交付 - 审查、测试、打包
-5
View File
@@ -1,5 +0,0 @@
# Build dependencies for Nuitka compilation
# Install with: pip install -r requirements-build.txt
nuitka>=1.7.0
pandas>=1.5.0
-477
View File
@@ -1,477 +0,0 @@
# Piano Highlight Generator App - 任务拆解
> 创建日期:2026-05-02
> 基于:design.md
---
## 任务总览
| # | 任务 | 依赖 | 优先级 | 工期 |
|---|------|------|--------|------|
| 1 | 项目骨架搭建 | - | P0 | 1h |
| 2 | ConfigPanel 配置面板 | 1 | P0 | 1h |
| 3 | StateManager 状态管理 | 1 | P0 | 0.5h |
| 4 | ProgressView 进度视图 | 1 | P0 | 1h |
| 5 | Worker 后台线程 | 1 | P0 | 1h |
| 6 | PipelineController 流水线控制 | 3, 5 | P0 | 1.5h |
| 7 | TitleEditor 标题编辑器 | 6 | P1 | 1.5h |
| 8 | 主窗口集成 | 2, 4, 7 | P0 | 1h |
| 9 | 核心模块适配 | 1 | P0 | 0.5h |
| 10 | 错误处理完善 | 8 | P2 | 1h |
| 11 | 打包配置 + 测试 | 10 | P2 | 1.5h |
| 12 | 文档和 README | 11 | P3 | 0.5h |
---
## 任务 1: 项目骨架搭建
**文件**
- `src/__init__.py`
- `src/main.py` - 应用入口
- `src/app.py` - QMainWindow 主窗口
- `src/gui/__init__.py`
- `src/logic/__init__.py`
- `src/core/__init__.py`
- `requirements.txt`
- `pyproject.toml`
**内容**
- 创建目录结构
- 创建空的 `__init__.py`
- `main.py` 使用 QApplication 启动
- `app.py` 创建空的主窗口框架
- `requirements.txt` 包含所有依赖
- 配置 pyproject.toml
**验收标准**
- 运行 `python src/main.py` 能启动空窗口
- 窗口标题为 "Piano Highlight Generator"
---
## 任务 2: ConfigPanel 配置面板
**文件**`src/gui/config_panel.py`
**UI 组件**
```
┌─────────────────────────────────────────────┐
│ API 配置 │
│ API Host: [________________________] │
│ API Key: [________________________] │
│ 模型: [火山方舟 Ark v] │
├─────────────────────────────────────────────┤
│ 视频配置 │
│ 视频文件: [________________] [浏览...] │
│ 输出目录: [________________] [浏览...] │
├─────────────────────────────────────────────┤
│ Whisper 配置 │
│ 模型: [large v] │
│ 模型路径: [________________] [浏览...] │
├─────────────────────────────────────────────┤
│ [开始处理] [保存配置] │
└─────────────────────────────────────────────┘
```
**信号**
- `config_changed_signal(dict)` - 配置变更时发出
**方法**
- `load_config(config: dict)` - 加载配置到 UI
- `get_config() -> dict` - 从 UI 获取配置
- `validate() -> (bool, str)` - 验证配置有效性
**验收标准**
- 所有输入框能正常输入
- 文件选择对话框能选择文件和目录
- 配置变更时发出信号
---
## 任务 3: StateManager 状态管理
**文件**`src/logic/state_manager.py`
**类**`StateManager`
**方法**
```python
def __init__(self, state_file: str):
"""初始化,加载或创建状态文件"""
def save(self):
"""保存状态到 JSON 文件"""
def get_current_step(self) -> int:
"""获取当前步骤索引 (0-6)"""
def get_step_name(self) -> str:
"""获取当前步骤名称"""
def set_step_status(self, step_name: str, status: str):
"""设置步骤状态 (pending/in_progress/completed/failed)"""
def update_clip(self, clip_index: int, **kwargs):
"""更新 clip 信息"""
def get_clips(self) -> list:
"""获取所有 clips"""
def get_user_modified_titles(self) -> dict:
"""获取用户修改过的标题 {clip_index: title}"""
def reset(self):
"""重置状态,开始新项目"""
```
**状态文件**`{output_dir}/state.json`
**验收标准**
- 创建新状态时生成默认结构
- 加载已有状态时恢复完整信息
- 保存后 JSON 文件格式正确
---
## 任务 4: ProgressView 进度视图
**文件**`src/gui/progress_view.py`
**UI 组件**
```
┌─────────────────────────────────────────────┐
│ 当前步骤: 提取视频片段 [Clip 3/14] │
│ ████████████░░░░░░░░░░░░ 50% │
├─────────────────────────────────────────────┤
│ [准备] → [提取] → [转录] → [纠正] → [字幕] │
│ → [合并] → [烧录] │
├─────────────────────────────────────────────┤
│ 日志: │
│ ┌───────────────────────────────────────┐ │
│ │ 10:30:01 开始提取片段 3/14 │ │
│ │ 10:30:02 片段 3 提取完成 │ │
│ │ 10:30:03 开始提取片段 4/14 │ │
│ └───────────────────────────────────────┘ │
├─────────────────────────────────────────────┤
│ [暂停] [停止] [继续] │
└─────────────────────────────────────────────┘
```
**信号**
- `start_signal` - 开始处理
- `pause_signal` - 暂停
- `resume_signal` - 继续
- `stop_signal` - 停止
**方法**
- `update_step(step_name: str, percent: int)` - 更新步骤进度
- `update_clip_progress(current: int, total: int)` - 更新 Clip 进度
- `append_log(message: str)` - 追加日志
- `show_titles_for_review(titles: list)` - 显示标题待审核(触发 TitleEditor
**验收标准**
- 进度条能实时更新
- 日志能自动滚动到最新
- 按钮状态能根据流水线状态变化
---
## 任务 5: Worker 后台线程
**文件**`src/logic/worker.py`
**类**`Worker(QThread)`
**信号**
```python
progress_signal = pyqtSignal(str, int, str) # step_name, percent, message
clip_completed_signal = pyqtSignal(int) # clip_index
step_started_signal = pyqtSignal(str) # step_name
step_completed_signal = pyqtSignal(str) # step_name
titles_ready_signal = pyqtSignal(list) # [{clip_index, original, llm_suggested}]
error_signal = pyqtSignal(str) # error_message
finished_signal = pyqtSignal(bool, str) # success, message
log_signal = pyqtSignal(str) # log message
```
**方法**
- `__init__(config, state_manager, controller)`
- `run()` - 执行流水线
- `request_pause()` - 请求暂停
- `request_stop()` - 请求停止
**暂停实现**
```python
def run(self):
for step in self.steps:
if self.is_stopped:
break
if self.is_paused:
self.wait_for_resume() # 等待用户resume信号
# 执行步骤...
```
**验收标准**
- UI 在处理过程中不卡顿
- 暂停信号能在 1 秒内响应
- 所有信号能正确传递到 UI
---
## 任务 6: PipelineController 流水线控制
**文件**`src/logic/pipeline_controller.py`
**类**`PipelineController`
**步骤定义**
```python
STEPS = [
'ready',
'extracting', # 提取片段
'transcribing', # 转录
'title_correcting', # 标题纠正(人工介入点)
'generating_subtitles', # 生成字幕
'merging', # 合并
'burning', # 烧录
'completed'
]
```
**方法**
```python
def __init__(self, config: dict, state: StateManager):
self.config = config
self.state = state
self.is_paused = False
self.is_stopped = False
def run(self, worker: Worker):
"""运行流水线"""
def pause(self):
"""暂停"""
def resume(self):
"""恢复"""
def stop(self):
"""停止"""
def step_extracting(self, worker: Worker):
"""提取片段"""
def step_transcribing(self, worker: Worker):
"""转录(调用 Whisper"""
def step_title_correcting(self, worker: Worker) -> list:
"""标题纠正 - 调用 LLM,返回需要用户确认的标题"""
def step_generating_subtitles(self, worker: Worker):
"""生成字幕"""
def step_merging(self, worker: Worker):
"""合并视频"""
def step_burning(self, worker: Worker):
"""烧录字幕"""
```
**验收标准**
- 每个步骤能正确执行
- 暂停/恢复能正确工作
- 状态能正确保存
---
## 任务 7: TitleEditor 标题编辑器
**文件**`src/gui/title_editor.py`
**UI 组件**
```
┌─────────────────────────────────────────────────────────────┐
│ 标题审核 - 请确认以下标题是否正确 │
├─────────────────────────────────────────────────────────────┤
│ # │ 原始标题 │ LLM建议 │ 修改后 │ 操作 │
├───┼──────────────┼─────────────┼───────────────┼──────────┤
│ 1 │ 弹奏 │ 弹奏 │ [弹奏 ] │ [编辑] │
│ 2 │ 非连奏弹奏法 │ 非连奏弹奏法 │ [非连奏弹奏法] │ [编辑] │
│ 3 │ 时值 │ 休止符 ✗ │ [休止符 ] │ [编辑] │
│ 4 │ 休止符 │ 休止符 │ [休止符 ] │ [编辑] │
│ 5 │ 节奏 │ 节奏 │ [节奏 ] │ [编辑] │
├─────────────────────────────────────────────────────────────┤
│ [全部确认] [取消] │
└─────────────────────────────────────────────────────────────┘
```
**编辑弹窗**
```
┌─────────────────────────────────┐
│ 编辑标题 - Clip #3 │
│ │
│ 原始标题: 时值 │
│ LLM建议: 休止符 │
│ │
│ 修改后: [_______________] │
│ │
│ [确定] [取消] │
└─────────────────────────────────┘
```
**信号**
- `titles_confirmed_signal(list)` - 用户确认的标题
**验收标准**
- 能显示所有标题
- 能编辑单个标题
- 能批量确认
- 确认后返回列表
---
## 任务 8: 主窗口集成
**文件**`src/app.py`
**布局**
```
┌─────────────────────────────────────────────────────────────┐
│ Piano Highlight Generator [_][□][X] │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────┐ ┌─────────────────────────────────┐ │
│ │ │ │ │ │
│ │ 配置面板 │ │ 进度视图 │ │
│ │ ConfigPanel │ │ ProgressView │ │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ │ ├─────────────────────────────────┤ │
│ │ │ │ 标题编辑器 (折叠) │ │
│ │ │ │ TitleEditor │ │
│ └─────────────────┘ └─────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 状态: 就绪 v1.0 │
└─────────────────────────────────────────────────────────────┘
```
**集成逻辑**
1. ConfigPanel 发出 `config_changed_signal` → Controller 接收
2. 用户点击"开始" → Controller 启动 Worker
3. Worker 发出 `titles_ready_signal` → TitleEditor 显示
4. 用户确认标题 → TitleEditor 发出 `titles_confirmed_signal` → Worker 继续
5. Worker 发出 `progress_signal` → ProgressView 更新
**验收标准**
- 能启动处理
- 各组件能正确通信
- 标题编辑器在正确时机显示
---
## 任务 9: 核心模块适配
**文件**`src/core/` (复用现有模块)
**适配工作**
1. 复制 `scripts/` 下的核心模块到 `src/core/`
2. 修改 import 路径
3. 确保 `constants.py` 中的路径配置可从外部传入
4. 适配视频处理函数返回成功/失败状态
**验收标准**
- 核心模块能在 GUI 中正常调用
- 错误能被捕获并传递到 UI
---
## 任务 10: 错误处理完善
**处理场景**
| 场景 | 处理方式 |
|------|----------|
| API Key 无效 | 401 错误,提示用户检查配置 |
| 视频文件不存在 | 暂停,弹窗提示 |
| 磁盘空间不足 | 暂停,弹窗提示 |
| Whisper 模型未找到 | 提示下载或选择其他模型 |
| 处理异常 | 保存状态,显示错误日志 |
**验收标准**
- 错误不导致程序崩溃
- 错误信息清晰用户友好
- 状态正确保存
---
## 任务 11: 打包配置 + 测试
**文件**
- `nuitka_options.py`
- `build.bat` (Windows 打包脚本)
- `build.sh` (Linux/Mac 打包脚本)
**打包步骤**
1. 安装依赖:`pip install -r requirements.txt`
2. 开发测试:`python src/main.py`
3. 打包:`python -m nuitka nuitka_options.py`
4. 测试 exe`dist/PianoHighlightGenerator.exe`
**验收标准**
- 打包后体积 < 50MB
- 双击能正常运行
- 所有功能在打包后正常工作
---
## 任务 12: 文档和 README
**文件**`README.md`
**内容**
- 应用介绍和截图
- 系统要求
- 安装指南(开发安装、打包安装)
- 使用说明
- 常见问题
- 许可证
**验收标准**
- 用户能根据 README 运行应用
- 常见问题有解决方案
---
## 并行化分析
**可并行任务**
| 任务组 | 可并行任务 | 原因 |
|--------|-----------|------|
| UI 组件组 | 2, 4, 7 | 独立开发,独立 UI 组件 |
| 核心逻辑组 | 3, 5, 6 | 有依赖关系,需顺序开发 |
| 集成测试组 | 8, 10 | 依赖前面所有任务 |
**推荐开发顺序**
1. **第一波(可并行)**1, 2, 4, 7, 9
2. **第二波(依赖第一波)**3, 5, 6
3. **第三波(集成)**8, 10
4. **最后**11, 12
---
## Git 分支规划
**建议分支**
- `main` - 主分支,稳定代码
- `feat/ui` - UI 组件开发 (任务 2, 4, 7)
- `feat/core` - 核心逻辑开发 (任务 3, 5, 6)
- `feat/integration` - 集成和打包 (任务 8, 10, 11, 12)
**合并顺序**
```
feat/ui ─────────┐
feat/core ────────┼──► main
feat/integration ─┘
```