思考啊SIKAOA
10 分钟阅读幻灯片

Claude 会话复盘:一天重构一个视频渲染系统

昨天和 Claude 来了一场高强度的 pair programming,目标很明确:把 jianfei-hyper 这个视频预览生成系统从“能用”推到“好用”。

说白了,就是让它更稳、更快、更好维护。


08:00 - 10:00:先加载,再诊断

8 点钟第一件事是让 Claude 加载这个 skill。
它干的事挺有意思——输入 MP4 + SRT 字幕,输出一个可交互的 HTML 预览页,支持四种视觉风格,还能给 HyperFrames 做后续渲染。

我丢了一句:“检查和优化这份代码,以及更新 skill 的描述。

Claude 花了十几分钟扫了一遍,列了 7 个问题:

  1. SKILL.md 版本号还是 2.1.0,但代码早就跑到了 2.3.1
  2. asr.py 里三个 LLM 调用函数几乎一模一样,重复得有点离谱
  3. pipeline.py 用了 inspect.currentframe() 这种黑科技去拿配置,太脆弱
  4. 模板注册是硬编码的,加新模板容易漏
  5. 缓存模块有竞态条件,可能出错
  6. 错误处理装饰器已经废弃还在占地方
  7. 版本日志里有重复条目

10:00 - 12:00:动手改代码

一个个修,效率还挺高。

提取统一 LLM 客户端

原来 asr.py 里有三个函数都自己拼 prompt、调 API、处理重试,逻辑几乎一样。
Claude 抽了个 _call_llm() 内部函数,三个业务函数直接一行搞定。
代码量少了三分之一,还更容易测试。

干掉 inspect 黑科技

以前为了支持预设配置,写了这么一段:

frame = inspect.currentframe()
args, _, _, values = inspect.getargvalues(frame)

听着牛,其实特别脆——参数名一改就崩。
改成显式传参后,逻辑清晰多了,测试也顺手。

模板自动注册

之前手动 import 每个模板文件,新增模板容易忘。
现在改成基于文件系统自动发现,加个新文件就能自动注册。

其他几项都是顺手修,半小时内全搞定。
37 个现有测试全部通过(有 5 个失败是之前颜色常量改了的遗留问题,跟这次改动无关)。


14:00 - 17:00:实战出真知

代码优化完,我让 Claude 处理一个真实视频:/Users/apple/Documents/Video/051/051_1.mp4

第一个坑:循环符号链接

预设系统生成竖屏版本时,不小心搞出了自己指向自己的符号链接。
ffmpeg 一跑就报错:Invalid data found when processing input
修复方法很简单:生成前判断文件是否存在,存在就删掉再重建。

第二个坑:style 类型不一致

预设里的 style 是字典({accent, theme, locale}),但有些地方期望它是字符串(比如 'film')。
类型对不上,模板渲染直接挂。
加了个类型判断和转换,统一在入口处处理。

第三个坑:参数签名没同步

film 风格的模板之前修过一个函数签名,但 jianfeislide 风格的同名函数没同步,导致调用时报错:name 'output_dir' is not defined
这种分布式代码的问题,只能靠完整测试覆盖,或者至少每个风格都跑一遍才能发现。


17:00 - 19:00:Renderer 重写

这是今天最大的技术决策。

原本用 Playwright 的 page.video 做录制,结果发现 headless Chrome 不渲染 <video> 元素
就是说,HTML 里明明有视频,录出来的 MP4 是黑屏。

查了一圈,这是 Chromium headless 的已知限制。
解决方案有两个:

  1. 用 headed 模式(有图形界面,CI 环境跑不了)
  2. page.screenshot() 逐帧截图,再用 ffmpeg 合成视频

选了方案 2。Claude 重写了 core/renderer.py

  • Playwright 打开页面,设置视口(竖屏 1080×1920)
  • 逐帧截图,每帧存为 PNG
  • ffmpeg 用 h264_videotoolbox(Apple Silicon 硬件加速)合成 MP4
  • 截图速度:20ms/帧,等效 50fps

实测下来,渲染质量比原来更好,因为截图方案没有浏览器的视频编码压缩损失。


19:00 - 21:00:Split 风格调优 + 字幕修复

Split 风格是上下分屏布局:上面 AI 配图,下面左边金句 + 右边原视频。
根据实际效果做了几处微调:

  • 配图区加了 border-radiusinset,看起来更精致
  • 底部安全区域加大,避免手机导航栏遮挡
  • 金句区域宽度调整,文字换行更自然

然后修复了一个很诡异的字幕问题:渲染出来的视频里,字幕之间出现了全角 字符。

排查链:渲染代码没问题 → HTML 里的字幕正常 → config-split.json 里的字幕数据异常 → 原始 SRT 是干净的。

根因定位到了:之前的某个步骤把多句字幕合并成长句时,用了全角 作为分隔符。
这是一个数据管道里的历史遗留问题,清除后重新生成配置就解决了。


今日收获

  1. inspect 元编程是技术债,能显式传参就显式传参
  2. 真实数据是最好测试,mock 数据跑一百遍不如真实视频跑一遍
  3. 截图替代录屏 在某些场景下更可靠,尤其是涉及视频元素时
  4. 数据管道的每个环节都要可追踪 字符问题花了半小时排查,就是因为中间产物没做版本标记

今天输出的最终文件:rendered_split_v4.mp4,7.0 MB,1080×1920 竖屏,字幕干净,视频画面正常。