一个文件,为每种屏幕形状裁切字幕。
一个.overtone.json文件,在 16:9 和 9:16 播放器中(social样式包),基于
Blender 开源电影 Tears of Steel。影片:(CC) Blender Foundation |mango.blender.org,CC BY 3.0
。
快速开始
重新裁切你已有的字幕。离线运行,无需 API key,无需 ffmpeg(Node.js 22.12 或更新版本):
curl -O https://download.blender.org/demo/movies/ToS/subtitles/TOS-en.srt npx overtone-captions recut TOS-en.srt
你会得到TOS-en.overtone.json、.horizontal和.vertical .vtt以及.srt文件,还有一份转录文本。词级时间是从字幕提示估算的。
从音频为视频生成字幕。这需要ffmpeg以及服务商的 API key(默认是 OpenAI 和 Azure AI Speech;overtone providers列出了相关环境变量)。--dry-run会显示音频的去向和预估费用,并且不会发送任何内容:
npm install -g overtone-captions overtone transcribe talk.mp4 --language en --context "关于城市骑行的座谈" --dry-run overtone transcribe talk.mp4 --language en --context "关于城市骑行的座谈"
--local改为离线运行,使用 whisper.cpp 和 Ollama。
在 video.js 中显示字幕:
import videojs from 'video.js'; import 'video.js/dist/video-js.css'; import 'videojs-overtone'; import 'videojs-overtone/themes/base.css'; import 'videojs-overtone/themes/clean.css'; videojs('my-video')。overtone({ src: 'talk.overtone.json' });
为什么
大多数字幕只裁切一次,针对一块屏幕,做法是把每行填到长度上限。16:9 的裁切对 9:16 的手机视频来说太宽,行尾会落在 "the" 或 "of" 上,而且两位说话人共用一条字幕。
Overtone 在一个文件里为每种屏幕形状保留一份裁切。这些裁切遵循阅读规则:行尾避免落在虚词上,人名和数字保持在一起,每位说话人都有自己的字幕,停顿会变成换行或字幕断点,这样听不到犹豫的观众也能读出来。
同一段来自 NASA 采访的词句和时间,按 9:16 裁切(22 字符 × 2 行):
| 填到长度上限 | Overtone |
|---|---|
the 2004 class. Jim, thank you for joining | Jim, thank you for joining us. |
through you? Okay. A little about me: I | Okay. A little about me: |
为什么要用新格式而不是 WebVTT 或 TTML:它们存储的是成品字幕提示,所以播放器只能重新折行。.overtone.json将每个词存储一次,外加任意数量的指向这些词的切分点。需要标准文件时,可按切分点导出 WebVTT 或 SRT。
为什么不用 WhisperX、stable-ts 或托管语音 API:它们能给出不错的词和时间,通常还更便宜。Overtone 在其上增加了字幕布局。overtone recut重新切分它们输出的 SRT 或 WebVTT,因此你可以保留自己的引擎。
工作原理
- 听审。多个引擎听取音频。文本听审(
gpt-transcribe)给出词;时间听审(Azure AI Speech)给出词时间和说话人。启用ELEVENLABS_API_KEY后,ElevenLabs Scribe 会增加第二次听审。 - 文本投票。当各听审结果不一致时,文本模型会重新聆听该片段,并由一个 LLM 选择器挑选词。
- 编辑器。LLM 利用你的上下文、你的术语表和自身的世界知识来纠正听错的词、名称和术语(它无需提示就能把 "Telecom Cell" 修正为 "Telkomsel"),标注说话人并标记关键词。它不确定的修改会进入复核列表,供你靠耳朵检查。
- 行切分。一套带版本的规则集为每个配置切分行。相同的词和规则集,得到相同的字幕。
LLM 从不设置时间戳:每个词的时间来自各引擎。代码只检查 LLM 修改的结构。流水线如何工作包含每一步。
包
| 包 | 它是什么 |
|---|---|
overtone-captions |
该overtoneCLI:transcribe,recut,burn,export,validate,init,languages,providers。 |
videojs-overtone |
video.js 8.5+ 插件和五个样式包:clean,social,minimal,high-contrast,lumora。 |
overtone-format |
该.overtone.json格式:类型、JSON Schema、验证器,以及 WebVTT、SRT 和文本导出器。无运行时依赖。 |
在样式库中查看每个样式包。
基准测试
小而公开。方法、完整表格和注意事项:bench/RESULTS.md和bench/captions/RESULTS.md。
- 换行(三个英文片段,20.8 分钟,16:9,规则集 1):Overtone 的换行中有 0.3% 结束于 "the"、"of" 或 "and" 这类词且其后无停顿。将行填满到上限的做法,其换行中有 28.8% 如此,ElevenLabs 的 SRT 导出为 16.1%。Overtone 将说话人全部 47 处 0.5–1.5 秒的停顿都显示为换行;另外两者分别显示 28% 和 72%。
- 文本(四个语言的六个片段,20 分钟,3 次运行,2026-10-23):在所有引擎都返回文本的 5 个片段上,词错误率为 5.3%,而单独使用 gpt-transcribe 为 6.2%,单独使用 Azure Speech 为 7.7%。
- 静默失败:gpt-transcribe 在一场安静的会议中每次运行都返回空结果。Overtone 用其他引擎听到的语言重试,得分为 32.8%,而单独使用 Azure Speech 为 42.9%。
- 成本:在这些运行中,每分钟音频 $0.023–0.025,使用 ElevenLabs Scribe 为 $0.029(标价)。
限制
- 完整的断行和数字规则适用于英语和荷兰语。德语、法语、西班牙语、意大利语和葡萄牙语支持语言检测;其他语言使用中性规则。参见语言。
- 在没有空格的文字(中文、日文、泰文)中,“词”是一个完整短语:每个短语计一次时间,断行只发生在短语之间。
- 无翻译,无音效标签,例如
[music],无 GUI 编辑器。媒体最长 2 小时。
文档
- CLI 指南和CLI 参考:每条命令、选项和输出文件。
- 播放器指南:选项、样式包和主题。
- 格式规范。
- 智能体技能用于 Claude Code 和 Codex:复制
skills/overtone到.claude/skills/。 - 贡献:语言包、样式包和提供商。AI 编程智能体从AGENTS.md开始。