昨天和 Claude 来了一场高强度的 pair programming,目标很明确:把 jianfei-hyper 这个视频预览生成系统从“能用”推到“好用”。
说白了,就是让它更稳、更快、更好维护。
08:00 - 10:00:先加载,再诊断
8 点钟第一件事是让 Claude 加载这个 skill。
它干的事挺有意思——输入 MP4 + SRT 字幕,输出一个可交互的 HTML 预览页,支持四种视觉风格,还能给 HyperFrames 做后续渲染。
我丢了一句:“检查和优化这份代码,以及更新 skill 的描述。”
Claude 花了十几分钟扫了一遍,列了 7 个问题:
SKILL.md版本号还是 2.1.0,但代码早就跑到了 2.3.1asr.py里三个 LLM 调用函数几乎一模一样,重复得有点离谱pipeline.py用了inspect.currentframe()这种黑科技去拿配置,太脆弱- 模板注册是硬编码的,加新模板容易漏
- 缓存模块有竞态条件,可能出错
- 错误处理装饰器已经废弃还在占地方
- 版本日志里有重复条目
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 风格的模板之前修过一个函数签名,但 jianfei 和 slide 风格的同名函数没同步,导致调用时报错:name 'output_dir' is not defined。
这种分布式代码的问题,只能靠完整测试覆盖,或者至少每个风格都跑一遍才能发现。
17:00 - 19:00:Renderer 重写
这是今天最大的技术决策。
原本用 Playwright 的 page.video 做录制,结果发现 headless Chrome 不渲染 <video> 元素。
就是说,HTML 里明明有视频,录出来的 MP4 是黑屏。
查了一圈,这是 Chromium headless 的已知限制。
解决方案有两个:
- 用 headed 模式(有图形界面,CI 环境跑不了)
- 用
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-radius和inset,看起来更精致 - 底部安全区域加大,避免手机导航栏遮挡
- 金句区域宽度调整,文字换行更自然
然后修复了一个很诡异的字幕问题:渲染出来的视频里,字幕之间出现了全角 G 字符。
排查链:渲染代码没问题 → HTML 里的字幕正常 → config-split.json 里的字幕数据异常 → 原始 SRT 是干净的。
根因定位到了:之前的某个步骤把多句字幕合并成长句时,用了全角 G 作为分隔符。
这是一个数据管道里的历史遗留问题,清除后重新生成配置就解决了。
今日收获
- inspect 元编程是技术债,能显式传参就显式传参
- 真实数据是最好测试,mock 数据跑一百遍不如真实视频跑一遍
- 截图替代录屏 在某些场景下更可靠,尤其是涉及视频元素时
- 数据管道的每个环节都要可追踪,
G字符问题花了半小时排查,就是因为中间产物没做版本标记
今天输出的最终文件:rendered_split_v4.mp4,7.0 MB,1080×1920 竖屏,字幕干净,视频画面正常。