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:
@@ -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.
|
|
||||||
@@ -1,105 +1,101 @@
|
|||||||
# 🎹 Piano Highlight Generator
|
# Lesson Highlights Generator
|
||||||
|
|
||||||
钢琴课精华视频生成工具。自动从完整课程视频中提取精华片段,转录、纠错、生成字幕,批量烧录到视频中。
|
教学视频精华片段生成工具。输入课程视频 + PPT,自动提取精华片段,转录、纠错、生成字幕,批量烧录到视频中。
|
||||||
|
|
||||||
## ✨ 功能特点
|
## 功能特点
|
||||||
|
|
||||||
- **智能提取**: 自动检测视频中的精彩片段
|
- **PPT 驱动提取**:根据 PPT 知识点定位视频中的讲解片段
|
||||||
- **语音转录**: 支持 Whisper 多模型(tiny/base/small/medium/large)
|
- **语音转录 + 纠错**:Whisper 转录 + LLM 批量校正
|
||||||
- **AI 纠错**: LLM 自动纠正转录错误,优化标题
|
- **双轨字幕**:标题轨 + 内容轨
|
||||||
- **双语字幕**: 支持双轨字幕(标题轨 + 内容轨)
|
- **CLI / GUI 双入口**:共享同一套底层逻辑
|
||||||
- **状态持久化**: 支持暂停/恢复,可中断继续
|
|
||||||
- **手动编辑**: 生成前可人工审核编辑标题和字幕内容
|
|
||||||
|
|
||||||
## 📋 系统要求
|
## 快速开始
|
||||||
|
|
||||||
- Windows 10/11 或 macOS 10.15+
|
### 1. 配置 API
|
||||||
- Python 3.10+
|
|
||||||
- FFmpeg(必须,添加到 PATH)
|
|
||||||
|
|
||||||
## 🚀 快速开始
|
复制配置文件并填入 API Key:
|
||||||
|
|
||||||
### 1. 安装
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 克隆项目
|
cp config.ini.example config.ini
|
||||||
git clone <repo-url>
|
# 编辑 config.ini,填入 api_key
|
||||||
cd piano-highlight-app
|
```
|
||||||
|
|
||||||
# 创建虚拟环境(推荐)
|
### 2. 安装依赖
|
||||||
python -m venv venv
|
|
||||||
.\venv\Scripts\activate # Windows
|
|
||||||
source venv/bin/activate # Linux/macOS
|
|
||||||
|
|
||||||
# 安装依赖
|
```bash
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
# 安装 FFmpeg(Windows - 使用 winget)
|
|
||||||
winget install Gyan.FFmpeg
|
|
||||||
|
|
||||||
# 或 macOS
|
|
||||||
brew install ffmpeg
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 运行
|
### 3. 运行
|
||||||
|
|
||||||
|
**GUI(推荐):**
|
||||||
```bash
|
```bash
|
||||||
python src/main.py
|
.\start.bat
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. 配置
|
**CLI:**
|
||||||
|
```bash
|
||||||
|
.\run_lesson1.bat
|
||||||
|
```
|
||||||
|
|
||||||
首次运行需要配置:
|
或通用方式:
|
||||||
1. **API 设置**: 选择 API 提供商(DeepSeek/硅基流动),输入 API Key
|
```bash
|
||||||
2. **视频设置**: 选择输入视频、输出目录
|
python src/cli.py --video video.mp4 --ppt presentation.pptx --output ./output
|
||||||
3. **转录设置**: 选择 Whisper 模型(推荐 medium)
|
```
|
||||||
|
|
||||||
### 4. 生成
|
## 项目结构
|
||||||
|
|
||||||
1. 点击「开始处理」
|
```
|
||||||
2. 等待各步骤完成
|
lesson-highlights/
|
||||||
3. **标题确认**: LLM 生成标题后,审核并编辑
|
├── src/
|
||||||
4. **字幕确认**: 查看字幕内容,可进一步编辑
|
│ ├── main.py # GUI 入口
|
||||||
5. 等待烧录完成
|
│ ├── 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/
|
output/
|
||||||
├── state.json # 处理状态
|
├── generated_config.yaml # 生成的 clips 配置
|
||||||
├── clips/ # 提取的片段
|
├── clips/ # 提取的片段视频
|
||||||
│ └── clip_001.mp4
|
|
||||||
├── subtitles/ # 字幕文件
|
├── subtitles/ # 字幕文件
|
||||||
│ ├── clip_001_title.srt # 标题轨
|
└── final.mp4 # 最终输出
|
||||||
│ └── clip_001_content.srt # 内容轨
|
|
||||||
└── final/ # 最终输出
|
|
||||||
└── clip_001_final.mp4
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🔧 流水线步骤
|
## 系统要求
|
||||||
|
|
||||||
1. **extract** - 片段提取
|
- Python 3.10+
|
||||||
2. **transcribe** - 语音转录
|
- FFmpeg(已打包在 `ffmpeg/` 目录)
|
||||||
3. **title_correct** - 标题生成与纠错
|
- PySide6(GUI)
|
||||||
4. **generate_subtitles** - 字幕生成
|
- faster-whisper(转录,可选)
|
||||||
5. **merge** - 片段合并
|
|
||||||
6. **burn** - 字幕烧录
|
|
||||||
|
|
||||||
## ⚠️ 常见问题
|
|
||||||
|
|
||||||
### Q: 提示 "FFmpeg not found"
|
|
||||||
A: 确保 FFmpeg 已安装并添加到系统 PATH。重启终端后重试。
|
|
||||||
|
|
||||||
### Q: API 调用失败
|
|
||||||
A: 检查 API Key 是否正确,网络是否正常,或切换 API 提供商。
|
|
||||||
|
|
||||||
### Q: 磁盘空间不足
|
|
||||||
A: 清理输出目录或更换到空间更大的磁盘。
|
|
||||||
|
|
||||||
## 📄 许可证
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
## 🤝 贡献
|
|
||||||
|
|
||||||
欢迎提交 Issue 和 Pull Request!
|
|
||||||
|
|||||||
-148
@@ -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.
|
|
||||||
@@ -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
|
|
||||||
@@ -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 ""
|
|
||||||
@@ -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
|
|
||||||
@@ -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 小时**
|
|
||||||
+66
-64
@@ -1,90 +1,92 @@
|
|||||||
# 架构设计
|
# 架构设计
|
||||||
|
|
||||||
## 1. 技术栈
|
## 1. 核心原则
|
||||||
|
|
||||||
| 层级 | 技术 | 选型理由 |
|
**CLI 和 GUI 共用同一套底层类库**,仅在表示层有差异:
|
||||||
|------|------|----------|
|
- **CLI**:命令行参数输入,日志输出到终端
|
||||||
| GUI 框架 | PySide6 (Qt for Python) | LGPL 许可,功能完备,信号槽机制适合异步更新 |
|
- **GUI**:PySide6 界面,参数输入界面化,日志输出到文本区
|
||||||
| 打包工具 | Nuitka | 编译为 C,性能好,体积小 |
|
|
||||||
| 状态持久化 | JSON 文件 | 简单,无需数据库依赖 |
|
|
||||||
| 核心模块 | 复用现有脚本 | video.py, subtitle.py, llm.py, corrections.py |
|
|
||||||
| 配置格式 | YAML/JSON | 用户友好,可读性好 |
|
|
||||||
|
|
||||||
## 2. 项目结构
|
## 2. 项目结构
|
||||||
|
|
||||||
```
|
```
|
||||||
piano-highlight-app/
|
lesson-highlights/
|
||||||
├── src/
|
├── src/
|
||||||
│ ├── __init__.py
|
│ ├── main.py # GUI 入口
|
||||||
│ ├── main.py # 应用入口
|
│ ├── gui.py # GUI(参数输入 → 调用底层)
|
||||||
│ ├── app.py # QMainWindow 主窗口
|
│ ├── cli.py # CLI 入口
|
||||||
│ ├── gui/ # GUI 组件
|
│ └── core/ # 共享底层
|
||||||
│ │ ├── __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
|
│ ├── __init__.py
|
||||||
│ ├── constants.py # 常量
|
│ ├── ppt_parser.py # PPT 解析 + LLM clips 提取
|
||||||
│ ├── utils.py # 工具函数
|
│ ├── pipeline.py # 视频处理流水线
|
||||||
│ ├── video.py # 视频处理
|
│ ├── subtitle.py # 字幕生成
|
||||||
│ ├── subtitle.py # 字幕处理
|
│ ├── video.py # 视频处理(提取/合并/烧录)
|
||||||
│ ├── llm.py # LLM 调用
|
│ ├── llm.py # LLM 调用
|
||||||
│ └── corrections.py # 纠错规则
|
│ ├── corrections.py # 术语纠正
|
||||||
├── assets/ # 资源文件
|
│ ├── constants.py # 常量配置
|
||||||
│ └── icons/
|
│ └── errors.py # 错误处理
|
||||||
├── requirements.txt # 依赖
|
├── config.ini # API 配置(不提交 git)
|
||||||
├── pyproject.toml # 项目配置
|
├── config.ini.example # 配置模板
|
||||||
├── nuitka_options.py # Nuitka 打包配置
|
├── start.bat # GUI 启动器
|
||||||
└── README.md
|
├── 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 个步骤:
|
### `Pipeline`
|
||||||
1. extract - 片段提取
|
|
||||||
2. transcribe - 语音转录
|
|
||||||
3. title_correct - 标题生成与纠错
|
|
||||||
4. generate_subtitles - 字幕生成
|
|
||||||
5. merge - 片段合并
|
|
||||||
6. burn - 字幕烧录
|
|
||||||
|
|
||||||
### 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. 配置来源
|
||||||
|
|
||||||
| 信号 | 方向 | 说明 |
|
API 配置统一从 `config.ini` 读取,不硬编码在代码中。
|
||||||
|------|------|------|
|
|
||||||
| config_changed | UI → Controller | 配置变更 |
|
|
||||||
| progress_signal | Worker → UI | 进度更新 |
|
|
||||||
| titles_ready_signal | Worker → UI | 标题列表准备好 |
|
|
||||||
| titles_confirmed_signal | UI → Controller | 用户确认的标题 |
|
|
||||||
|
|
||||||
## 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
@@ -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**: 质量交付 - 审查、测试、打包
|
|
||||||
@@ -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
|
|
||||||
@@ -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 ─┘
|
|
||||||
```
|
|
||||||
Reference in New Issue
Block a user