Remotion @remotion/openai-whisper 详解:将 OpenAI Whisper 转写结果转换为 Captions 字幕数据 Remotion remotion/openai-whisper 详解将 OpenAI Whisper 转写结果转换为 Captions 字幕数据【免费下载链接】remotion Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotionremotion/openai-whisper是 Remotion 生态中处理语音转写字幕的轻量工具包其核心职责是接收 OpenAI Whisper API 返回的 verbose JSON 转写结果带逐词时间戳将其转换为 Remotion 标准Caption[]字幕数组供后续字幕时间轴处理与视频渲染使用。读完本篇你将掌握该包的完整安装方式、输入/输出数据结构、openAiWhisperApiToCaptions()的转换算法原理含标点归属、撇号变体、连字符拆词等边界处理以及一套可直接复制的 OpenAI SDK 调用示例与测试用例验证方式。包定位与安装该包的定位可以用一句话概括来自 READMEWork with the output of the OpenAI Whisper API即它不直接调用 Whisper API而是处理 API 的输出结果。包的元信息定义在 package.json包名为remotion/openai-whisper当前仓库版本为4.0.521MIT 协议运行时仅依赖remotion/captions用于Caption类型测试则基于bun test src运行。安装命令npm install remotion/openai-whisper --save-exactREADME 中特别强调了版本对齐原则安装 Remotion 包时必须让项目中所有remotion与remotion/*包保持同一版本去掉版本号前的^字符锁定为精确版本这也是上面使用--save-exact参数的原因。包入口 src/index.ts 对外导出 3 个 API 与 1 个类型export { OpenAiToCaptionsInput, OpenAiToCaptionsOutput, openAiWhisperApiToCaptions, } from ./openai-whisper-api-to-captions; export {OpenAiVerboseTranscription} from ./openai-format;输入格式OpenAiVerboseTranscription转换函数的输入类型在 openai-format.ts 中定义它对应 OpenAI Whisper API 在response_format: verbose_json且timestamp_granularities: [word]时的返回结构字段类型必填性说明durationnumber \| string必填音频时长API 可能返回字符串languagestring必填识别出的语言如englishtextstring必填完整转写文本转换算法以此为匹配基准tasktranscribe可选任务类型非 transcribe 时函数会抛错wordsTranscriptionWord[]可选本包实际必需逐词时间戳数组segmentsTranscriptionSegment[]可选分段信息本包转换未直接使用其中逐词结构TranscriptionWord只有三个字段时间单位为秒浮点数export interface TranscriptionWord { end: number; start: number; word: string; }TranscriptionSegment则包含 Whisper verbose 格式的完整分段元数据id、avg_logprob、compression_ratio、no_speech_prob、seek、temperature、tokens等从源码结构看它只是为类型完整性而声明转换逻辑并不消费分段数据。核心 APIopenAiWhisperApiToCaptions函数签名定义在 openai-whisper-api-to-captions.tsexport type OpenAiToCaptionsInput { transcription: OpenAiVerboseTranscription; }; export type OpenAiToCaptionsOutput { captions: Caption[]; }; export const openAiWhisperApiToCaptions ({ transcription, }: OpenAiToCaptionsInput): OpenAiToCaptionsOutput { // ... };端到端使用示例测试文件 get-and-convert.test.ts 中给出了真实的 API 调用路径该用例在 CI 环境外会实际调用 OpenAI API使用仓库内 dialogue.wav 作为音频素材整理后完整流程如下import fs from fs; import OpenAI from openai; import {openAiWhisperApiToCaptions} from remotion/openai-whisper; const openai new OpenAI(); // 1. 调用 Whisper API必须要求 word 级时间戳 const transcription await openai.audio.transcriptions.create({ file: fs.createReadStream(./dialogue.wav), model: whisper-1, response_format: verbose_json, prompt: Hello, welcome to my lecture., timestamp_granularities: [word], // 关键缺少此参数本包无法工作 }); // 2. 转换为 Remotion Caption[] const {captions} openAiWhisperApiToCaptions({transcription});timestamp_granularities: [word]是硬性前提如果不带words字段转换函数会直接抛出The transcription does need to be been generated with timestamp_granularities: [word]错误见 源码 L34-L44。转换结果示例基于测试夹具 output.ts 中一段 170 秒的播客真实转写转换结果的前几条为{ captions: [ {confidence: null, endMs: 7039.999961853027, startMs: 6519.999980926514, text: Whats, timestampMs: 6779.9999713897705}, {confidence: null, endMs: 7559.999942779541, startMs: 7039.999961853027, text: up,, timestampMs: 7299.999952316284}, {confidence: null, endMs: 7880.000114440918, startMs: 7619.999885559082, text: everybody?, timestampMs: 7750}, {confidence: null, endMs: 8300.000190734863, startMs: 8239.999771118164, text: This, timestampMs: 8269.999980926514}, // ... ], }注意一个易被忽略的细节Whisper 的words只有秒级起止时间而text字段完整转写文本承载了标点信息。转换算法的工作就是把两者对齐让每条Caption的text带上它拥有的标点如Whats后的逗号归到up,。输出结构Caption 类型输出元素的类型Caption来自依赖包remotion/captions定义在 caption.tsexport type Caption { text: string; startMs: number; endMs: number; timestampMs: number | null; confidence: number | null; pageBreakAfter?: boolean; };本包的填充规则见 源码 L70-L76startMs/endMsword.start、word.end乘以 1000从秒转为毫秒timestampMs取(start end) / 2的中点时刻毫秒用于在渲染层定位字幕显示时机confidence固定为null——Whisper 的逐词数据本身不携带逐词置信度分段级的avg_logprob未被采用因此该字段留空text不是直接取word.word而是匹配算法从完整文本中切出的片段含标点见下节。转换算法原理剩余文本扫描与标点归属理解这个包的关键在于它不是简单地一个 word 生成一条 Caption。完整算法在 openai-whisper-api-to-captions.ts 中可以拆解为五步1. 前置校验if (!transcription.words) { if (transcription.task transcription.task ! transcribe) { throw new Error(The transcription does need to be a transcribe task. ...); } throw new Error(The transcription does need to be been generated with timestamp_granularities: [word]); }先区分任务类型错误与缺少词级时间戳两种错误给出可诊断的报错信息。2. 首词修剪issue #5031if (firstWord) { word.word word.word.trimStart(); }某些第三方/兼容型Whisper API 会在第一个词前面多带一个空格如 Hello。测试文件 foreign-api.test.ts 就是针对这一类输入每个词都带前导空格的转写结果最终首条 Caption 的text被规整为Hello而非 Hello。3. 逐词构建正则在剩余文本中匹配算法维护一个remainingText初始为transcription.text对每个词构造如下正则见 源码 L56-L68const punctuation \\?,\\.\\%\\–\\!\\;\\:\\\\\\\-\\_\\(\\)\\[\\]\\{\\}\\\\#\\$\\^\\\\*\\\\\\/\\|\\\\\\~\\\u2018\\u2019\\u02bc\\uff07; const wordToMatch word.word.replace(new RegExp(^[${punctuation}]), ); const match new RegExp( ^([\\s?${punctuation}]{0,4})${escapeWordForRegex(wordToMatch)}([${punctuation}]{0,3})?, ).exec(remainingText);正则的三个组成部分各有用意前导组([\s?标点]{0,4})允许词前最多 4 个空白/标点字符空格、逗号、连字符、货币符号等这些字符归属于当前词——例如 up,的前导空格、Its后面的词 up,携带的逗号词本体escapeWordForRegex对词做正则转义但有一个特殊处理——撇号的 5 种 Unicode 变体U0027直引号、U2018、U2019弯引号、U02BC修饰符撇号、UFF07全角在词与文本之间互相等价匹配见 源码 L16-L27。这解决了 issue #7298Whisper 有时在words里用弯引号Lets在text里用直引号Letsregressions.test.ts 的 Issue 7298 - apostrophe variants 用例专门验证了这一点后缀组([标点]{0,3})?词后最多 3 个标点归入该词的text——如句末的.、?、!、百分号%回归用例 it is 99% better 中99的 Caption 文本是 99%。匹配成功后remainingText从匹配片段末尾继续保证每个词只消费一次文本且整体是顺序推进的。4. 匹配失败即抛错如果某个词在剩余文本中找不到函数会抛出携带上下文的错误源码 L61-L65提示词是什么、剩余文本前 100 字符是什么并引导用户提交 issue。这是快速失败设计宁可直接报错也不产出时间戳错位的字幕。5. 生成 Caption 并推进匹配片段match[0]直接作为text写入 Caption时间字段按前文规则换算为毫秒。边界情况与测试证据包内 7 个测试文件src/test/恰好覆盖了转换算法的所有难点分支是验证各边界行为最直接的证据测试文件覆盖场景关键断言issue-50069.test.ts连字符拆词Like-minded.、千分位数字50,000.Like与-minded.各自成条50,与000.各自成条——前导-、,通过前导标点组归入后续词partial-word.test.ts词间时间间隙、句末标点massive的 Caption 为 massive.句号由后缀组捕获regressions.test.ts99%、real-time连字符、撇号变体99%中%归后缀real后跟-时-归入后续time词LetsU2019能匹配文本中的LetsU0027special-chars.test.ts货币符号$500$经前导标点组归入当前词最终文本为 $500foreign-api.test.ts第三方 API 词带前导空格首词trimStart后输出Hello其余词的空格被前导组吸收get-and-convert.test.ts完整真实转写170 秒播客 真实 API 调用前 10 条 Caption 精确断言非 CI 环境实际请求whisper-1并断言captions.length 60这些用例说明该函数设计目标非常明确容错地吸收 Whisper含兼容 API输出中的空格、标点、Unicode 变体差异但拒绝在无法确定归属时静默产出错误数据。与 Remotion 字幕体系的衔接Caption[]是 Remotion 字幕体系的通用中间格式本包通过remotion/captionspackage.json 中声明的 workspace 依赖导入该类型保证输出与remotion/captions的时间轴工具如字幕分句、分页、时间轴计算类型兼容。一条典型的数据流是音频文件 → OpenAI Whisper API (verbose_json word 时间戳) → openAiWhisperApiToCaptions() → Caption[] (毫秒级, 带标点) → remotion/captions 时间轴工具 / 你的 React 组件渲染使用前提与限制结合源码与测试使用该包时需要满足以下前提必须带词级时间戳API 调用需设置response_format: verbose_json与timestamp_granularities: [word]且任务为transcribe否则函数抛错text与words必须来自同一次转写算法依赖两者字符级对齐文本对不上会触发匹配失败异常置信度不可得输出的confidence恒为null若需要置信度应另行使用分段级数据版本锁定与项目中其他remotion/remotion/*包保持同一精确版本如当前仓库版本4.0.521。关键文件索引packages/openai-whisper/README.md — 包说明与安装方式packages/openai-whisper/package.json — 版本、依赖与测试脚本packages/openai-whisper/src/index.ts — 导出入口packages/openai-whisper/src/openai-format.ts — 输入类型定义packages/openai-whisper/src/openai-whisper-api-to-captions.ts — 核心转换实现packages/captions/src/caption.ts —Caption输出类型packages/openai-whisper/src/test/ — 边界行为测试用例【免费下载链接】remotion Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotion创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

最新新闻

BMC固件工程师:服务器健康系统的底层调度者

BMC固件工程师:服务器健康系统的底层调度者

1. BMC固件工程师不是“写BIOS的”,而是服务器健康系统的总调度员很多人第一次听说BMC(Baseboard Management Controller),下意识会把它和主板BIOS划等号——毕竟都跑在板子上、都带“固件”俩字、都能进底层。但这种类比就像把消…

2026/9/8 22:50:54
基于Qt5与hidapi的USB HID调试助手实现与避坑指南

基于Qt5与hidapi的USB HID调试助手实现与避坑指南

简介:基于Qt5框架与hidapi库开发的一款Windows 10环境下的USB调试助手,定位为轻量级上位机工具,主要面向嵌入式开发者、硬件测试人员以及HID协议学习者,用于解决个人电脑与USB设备之间数据收发、设备枚举和可视化交互不便的问题。…

2026/9/8 22:50:54
树莓派Pico USB详解:从RP2040硬件原理到MicroPython实战

树莓派Pico USB详解:从RP2040硬件原理到MicroPython实战

第一次把树莓派 Pico 插上电脑,很多人会被那个突然弹出的 RPI-RP2 磁盘骗到,以为它就是个 U 盘。实际上,这块板子上的 Micro-USB 口背后,是一整套 USB 1.1 设备控制器,而 MicroPython 固件默认把它做成了“虚拟串口 大…

2026/9/8 22:50:54
RetroArch 在 Switch 上闪退报 0x4A8?Atmosphère 三步修复完整指南

RetroArch 在 Switch 上闪退报 0x4A8?Atmosphère 三步修复完整指南

RetroArch 在 Switch 上闪退报 0x4A8?Atmosphre 三步修复完整指南 【免费下载链接】Atmosphere Atmosphre is a work-in-progress customized firmware for the Nintendo Switch. 项目地址: https://gitcode.com/GitHub_Trending/at/Atmosphere 你是不是也遇…

2026/9/8 22:50:54
Omarchy Arch 镜像源调优指南:3 步恢复快速 Pacman 更新

Omarchy Arch 镜像源调优指南:3 步恢复快速 Pacman 更新

Omarchy Arch 镜像源调优指南:3 步恢复快速 Pacman 更新 【免费下载链接】omarchy Beautiful, Modern & Opinionated Linux 项目地址: https://gitcode.com/GitHub_Trending/om/omarchy 凌晨两点,pacman -Syu 卡在 linux 内核的下载进度条上&…

2026/9/8 22:50:54
DiskWarrior:macOS 磁盘工具修不动时,这个修复工具登场

DiskWarrior:macOS 磁盘工具修不动时,这个修复工具登场

DiskWarrior:macOS 磁盘工具修不动时,这个修复工具登场 【免费下载链接】awesome-macOS  A curated list of awesome applications, softwares, tools and shiny things for macOS. 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-macO…

2026/9/8 22:45:54