8.6 KiB
8.6 KiB
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/OUTPUT,API 配置留在 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):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):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):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):def reburn_titles(self): # 用已有的 clip configs(不重生成 json) # 调用 subtitle_pipeline.generate_from_clips # 烧录标题轨到 subs/v1_title.srtreburn_subtitles(self, user_texts=None):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
- 实现"打开已有项目":
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:
- 应用按钮逻辑:
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 错误