Files
lesson-highlights/docs/IMPLEMENTATION_PLAN.md
T

261 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Piano Highlight Generator - GUI 编辑功能实现计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 实现 GUI 编辑功能,支持增删改知识点和字幕,CLI/GUI 共用项目文件体系,底层原子化复用。
**Architecture:**
- `generated_config.yaml` = 项目文件(元信息 + clips 配置)
- `config.ini` = 全局配置(API 密钥等),不跟项目
- 底层原子操作在 core/CLI 和 GUI 共用
- 按需重生成(只重烧受影响的 clip)
**Tech Stack:** PySide6 GUI, YAML, faster-whisper, FFmpeg
---
## Phase 0: 配置体系重构
### Task 1: 项目文件增加元信息字段
**Files:**
- Modify: `src/core/pipeline.py` — Pipeline.run() 结束时写 `video_src``ppt_path``max_total_duration` 到 generated_config.yaml
- Modify: `src/core/ppt_parser.py``_create_config()` 写入 `video_src``ppt_path`
**Steps:**
- [ ]`Pipeline.run()``step_generate_subtitles` 结束后,读取 config 中的 `video_src`/`ppt_path`,写入 generated_config.yaml
- [ ] 确保 `_create_config()` 包含 `max_total_duration` 字段
- [ ] 验证:跑完 run.bat 后,generated_config.yaml 包含 video_src 和 ppt_path
---
### Task 2: config.py 重构(项目路径 vs 全局配置分离)
**Files:**
- Modify: `config.py` — 移除 VIDEO/PPT/OUTPUTAPI 配置留在 config.ini
- Modify: `run.py` — 从 config.py 只读 API 相关字段,项目路径由 CLI 参数指定
- Modify: `src/cli.py` — 确认 --video/--ppt/--output 参数能正确传入 pipeline
**Steps:**
- [ ] 修改 `config.py`:只保留 API_KEY/API_HOST/PYTHON/CLI_DIR,移除 VIDEO/PPT/OUTPUT/MAX_TOTAL_DURATION
- [ ] 修改 `run.py`:从 config.py 读 API 配置,VIDEO/PPT/OUTPUT 通过 cli.py 参数传入(cli.py 已有 --video/--ppt/--output
- [ ] 验证:`run.bat` 能正常跑完整流程
---
## Phase 1: 底层原子化
### Task 3: 提取标题匹配函数
**Files:**
- Modify: `src/core/ppt_parser.py` — 提取 `_find_title_in_transcript(title, transcript_segments)` 函数
- Create: `src/core/subtitle_matcher.py` (可选,如果逻辑复杂则独立)
**Steps:**
- [ ]`ppt_parser.py` 中提取 `_find_title_in_transcript(title, corrected_segments)`:
- 输入:标题文字 + corrected_transcript.json 的 segments 列表
- 处理:在每个 segment 的 text 中搜索标题关键词(子串匹配)
- 返回:`(start, end)``None`(匹配不到)
- [ ] 写单元测试验证:mock segments 数据,测试匹配返回正确时间戳,匹配不到返回 None
- [ ] 验证:corrected_transcript.json 存在情况下,给定一个已知标题能找到对应时间段
---
### Task 4: reextract_clip — 单标题重新匹配
**Files:**
- Modify: `src/core/pipeline.py` — 增加 `reextract_clip(clip_index, new_title)` 方法
**Steps:**
- [ ] 在 Pipeline 类中增加 `reextract_clip(self, clip_index, new_title)`:
```python
def reextract_clip(self, clip_index, new_title):
clip = self.clips[clip_index]
# 加载 corrected_transcript.json
# 调用 _find_title_in_transcript(new_title, segments)
# 匹配到 → 更新 clip['start']/clip['end']
# 匹配不到 → clip['matched'] = False(或标记)
# 调用 _merge_overlapping_clips 如有必要
# 保存 updated config to generated_config.yaml
# 删除 clip_index 对应的 json(触发重生成)
```
- [ ] 写测试:用 lesson1 的 output,跑完后 reextract 某个 clip 改标题,验证 config 更新
---
### Task 5: delete_clip — 删除 clip
**Files:**
- Modify: `src/core/pipeline.py` — 增加 `delete_clip(clip_index)` 方法
**Steps:**
- [ ] 在 Pipeline 类中增加 `delete_clip(self, clip_index)`:
```python
def delete_clip(self, clip_index):
# 从 self.clips 删除该 clip
# 删除 intermediates/clipN.json 和 clipN.mp4
# 保存 updated config to generated_config.yaml
```
- [ ] 写测试:跑完后删一个 clip,验证 json/mp4 删除、config 更新
---
### Task 6: add_clip_by_title — 新增知识点
**Files:**
- Modify: `src/core/pipeline.py` — 增加 `add_clip_by_title(new_title)` 方法
**Steps:**
- [ ] 在 Pipeline 类中增加 `add_clip_by_title(self, new_title)`:
```python
def add_clip_by_title(self, new_title):
# 调用 _find_title_in_transcript 匹配时间段
# 匹配到 → 判断是否与现有 clip 重叠 → 合并处理
# 匹配不到 → 标记 matched=False,不加入 self.clips(或加到待确认列表)
# 保存 updated config
```
- [ ] 写测试:加一个新标题,验证 config 更新、json 不生成(待确认状态)
---
### Task 7: reburn_titles / reburn_subtitles — 部分重烧
**Files:**
- Modify: `src/core/pipeline.py` — 增加 `reburn_titles()` 和 `reburn_subtitles(user_texts=None)` 方法
- Modify: `src/core/subtitle.py` — 检查 `generate_from_clips` 能否跳过 LLM 校正直接用用户文本
**Steps:**
- [ ] `reburn_titles(self)`:
```python
def reburn_titles(self):
# 用已有的 clip configs(不重生成 json
# 调用 subtitle_pipeline.generate_from_clips
# 烧录标题轨到 subs/v1_title.srt
```
- [ ] `reburn_subtitles(self, user_texts=None)`:
```python
def reburn_subtitles(self, user_texts=None):
# user_texts: 可选,直接用用户文本烧字幕,跳过 LLM 校正
# 读取 v1_content.srt 或直接用传入的文本
# 烧录字幕轨到 subs/v1_content.srt
```
- [ ] 修改 `burn_only.py` 适配新的 Pipeline 方法
---
## Phase 2: GUI 重构
### Task 8: GUI 两种启动模式
**Files:**
- Modify: `src/gui.py` — 重构为分步界面(启动页 → 处理/编辑页)
**Steps:**
- [ ] 重构 GUI 启动页:两个选项按钮
- "新建项目" → 跳转文件选择(视频+PPT+输出目录)
- "打开已有项目" → 打开目录选择框 → 加载 generated_config.yaml
- [ ] 实现"打开已有项目"
```python
def load_project(self, output_dir):
config = load_yaml(os.path.join(output_dir, 'generated_config.yaml'))
# 设置 video_src, ppt_path, output_dir
# 初始化 Pipeline(config)
# 加载 clips 列表显示
# 加载字幕预览
```
- [ ] 验证:打开 lesson1 output 目录,能正确显示 clip 列表
---
### Task 9: GUI 编辑界面
**Files:**
- Modify: `src/gui.py` — 增加编辑界面组件
**Steps:**
- [ ] 左侧 clip 列表:
- QListWidget 显示 clip 标题列表
- 双击编辑标题
- 右键菜单:删除、新增
- 未匹配 clip 显示红色/警告图标
- [ ] 右侧字幕预览:
- QTextEdit 显示 v1_content.srt 内容
- 用户可直接编辑
- [ ] 底部"应用"按钮:
- 收集所有修改
- 调用底层原子操作
- 进度显示
- 重烧后刷新预览
---
### Task 10: 应用按钮 — 原子操作集成
**Files:**
- Modify: `src/gui.py` — 应用按钮连接到 Pipeline 原子方法
**Steps:**
- [ ] 应用按钮逻辑:
```python
def on_apply(self):
# 检测变化:
# - clip 标题改了 → reextract_clip(i, new_title)
# - clip 删了 → delete_clip(i)
# - 新增知识点 → add_clip_by_title(title)
# - 字幕改了 → reburn_subtitles(user_texts)
# - 任一 clip 变了 → reburn_titles()
# 最后调用 Pipeline.step_burn() 或 reburn 最终视频
```
- [ ] 未匹配 clip 不参与重烧,显示提示
- [ ] 验证:改标题 → 点应用 → final.mp4 更新
---
### Task 11: CLI/GUI 互操作测试
**Steps:**
- [ ] CLI run.bat 跑 lesson1 → 生成完整 output
- [ ] GUI 打开同一 output 目录
- [ ] 改 clip3 标题为"新标题" → 点应用 → 验证 config 更新、final.mp4 更新
- [ ] GUI 删 clip5 → 点应用 → 验证 config 更新、final.mp4 更新
- [ ] GUI 改字幕文本 → 点应用 → 验证 final.mp4 更新
---
## Phase 3: 收尾
### Task 12: 删除死代码
**Files:**
- Identify: 检查 gui.py 中被替换掉的旧代码
- Remove: 删除不再使用的 UI 组件和逻辑
---
### Task 13: 更新文档
**Files:**
- Modify: `docs/USAGE.md` — 增加 GUI 编辑说明
---
### Task 14: commit
**Steps:**
- [ ] git add -A
- [ ] commit: "feat: GUI edit mode with clip/subtitle editing, config separation"
- [ ] push
---
## 自检清单
- [ ] 所有修改文件有备份/可回滚
- [ ] 每个 task 后验证功能正常
- [ ] CLI 完整流程测试通过
- [ ] GUI 新建项目测试通过
- [ ] GUI 打开已有项目测试通过
- [ ] 改/删/增 clip 后 final.mp4 正确更新
- [ ] 字幕编辑后 final.mp4 正确更新
- [ ] 无新增警告或 lint 错误