用Codex+TTS制作PPT配音视频

一、缘起

前段时间帮一位朋友做 PPT,顺手试了一下 TTS 配音。

原本以为这件事会非常简单:把讲稿丢进去,生成音频,贴到 PPT 上,收工。结果一圈试下来发现,事情远没有这么美好。普通 TTS 的问题不是“不能用”,而是“一听就知道它是 TTS”,声音特别平淡、古板。最后试下来,还是豆包语音效果最好,尤其是中文语境下的停顿、语气和自然度。正好马上要在半年度交流会上做一次关于 AI 应用的分享,于是,既然已经帮别人折腾过一遍,不如把自己的汇报也用同一套流程做成“PPT + 自己音色配音 + 自动合成视频”。

别人都是上去讲,我上去直接播放视频,岂不美哉?而且也契合 AI 的主题。有了 Codex,做到这些并不困难。

P.S. 本文内容基于 Windows + Microsoft Office + Codex 环境。

二、古法手写大纲

这一步不能偷懒。做一个汇报,你脑子里总得要有想法、有内容吧。大纲肯定要自己写,但不用苛求格式,甚至无所谓结构性,把零散的想法陈列出来也行。这一步建议用语音输入,比如 Typeless,可以充分解放双手。

三、让 Codex 生成分页讲稿初稿

接下来把大纲交给 Codex,让它生成分页讲稿。

这里的关键是要约束时长和页数。例如:请根据 @大纲.txt 生成一份 15 分钟汇报的分页讲稿。要求总页数控制在 20 页左右。

因为后面要做配音视频,音频必须和 PPT 页切换对齐,所以在讲稿的格式中必须以明确的页数逐页分隔。如果讲稿是一整篇散文,后面就会陷入“这句话到底该出现在第 7 页还是第 8 页”的泥潭。分页讲稿相当于先把视频时间轴切成一段一段的小香肠,后面好加工。

正常中文汇报语速大约每分钟 220 到 280 字。TTS 的语速不要轻易调太多,调快会像赶高铁,调慢会像在念经。更稳妥的方法是改文字长度,而不是调语速。通常你提供一个目标时长后,AI 会自主控制一个合理的字数。

四、手动修改讲稿,并把案例素材扔进文件夹

这时候,Codex 生成的讲稿仍然只是初稿。你只提供了主题和想要表达的思想,但一次成功的汇报离不开案例。所以,我们要为它补充案例。暂不需要自己编辑PPT和讲稿,你只需要提供案例的原始素材就行,解读它的事情完全可以交给 Codex。

在项目文件夹内创建“cases”子目录。每个案例分别再创建子目录,子目录的名称就用案例的简称就好了。文件夹内可以放每个案例的代码、提示词、截图、word说明……等等都可以。Codex 的优势就在这里:它可以自己读取文件夹,提炼“这个案例说明了什么”。人类只需要保证素材是真的,不要把无关文件塞得太离谱。

案例素材准备好后,在讲稿中需要引用案例的地方加个括号,大致写明这里需要引用哪个案例,要突出什么优点、提炼什么内容即可。这些括号中的提示很快就会用到。

五、用 presentations 插件生成 PPT 初稿

接下来需要用到 Codex 的 presentations 插件。

presentations 插件的作用,是让 Codex 直接生成可编辑的 PowerPoint 文件,而不是只给你一堆“第 1 页写什么、第 2 页写什么”的建议。它的原理大致是:Codex 先把汇报内容整理成叙事主线,再用结构化的幻灯片描述生成 PPTX。每一页的标题、文本框、图表、图片、版式元素,都不是截图糊上去,而是尽量保持为 PPT 里的可编辑对象。

可编辑很重要,因为 PPT 初稿一定要改。如果工具给你的只是图片(就像 NotebookLM),那后面每改一个字都像在拆炸弹。可编辑 PPTX 才适合真实工作流。

给 Codex 的指令可以这样写:

根据 @讲稿.txt 制作 PPT。注意讲稿中的括号部分是案例提示,请根据提示读取 cases 文件夹中的案例素材,根据括号中的要求增加 PPT 中案例相关的内容。
PPT比例使用 16:9。

如果需要背景图,可以要求 Codex 使用 Image Gen 插件来制作。

Image Gen 可以调用 Image 2 的原生能力。我们用它来生成或编辑位图素材,比如背景图、插图、示意场景、透明素材。它的原理不是在 PPT 里画矢量图,而是调用图像生成模型生成 PNG/JPG 这类图片,再嵌入 PPT 或视频画面中。适合做“抽象但有氛围”的图,例如 AI 工作流背景、语音波形概念图、文档自动化示意图。但它不适合做严肃图表、真实软件界面、单位 Logo,后者最好用真实截图或可编辑图形。

Codex 通常会自动 review 每一页 PPT 的内容,结合内容来生成相应的图片。

如果是背景图,注意半透明处理。背景图可以铺满页面,再加一层半透明矩形遮罩,例如深色遮罩 30% 到 45%,或者浅色遮罩 50% 左右。文字区域再用轻微模糊或低透明底板兜一下。原则是:背景负责氛围,不能喧宾夺主。这些都可以交给 Codex 来搞定。

这一步完成后,PPT就接近成品了。

六、手动改 PPT,调整汇报节奏

PPT 初稿出来之后,一定要手动改。首先是复核整体 PPT 的节奏:各部分内容的篇幅是否与主题重心吻合;有没有需要进一步展开的细节或过分冗长的内容;是否有案例引用错误,或案例提炼不当的地方。

其次是调整行距(我发现 Codex 总是喜欢用 1 倍行距,显得太紧)、删除备注性文字(Codex 有时会把你的制作要求直接写在 PPT 上)、补充说明(一些辅助信息)。如果前序工作比较扎实,这一步工作量很小。

这一步完成后,PPT 就已经基本成型了。

七、让 Codex 根据新版 PPT 重写讲稿

把修改后的 PPT 再交给 Codex,让它重新读取每页内容,生成最终讲稿。这一步的目的是,让讲稿与 PPT 对齐(而不是相反)。一旦 PPT 成型,那么讲稿是要以 PPT 为中心的,特别是当你手动对 PPT 作了较大调整之后。

这一步可以要求 Codex 把每页的讲稿拆成 1-4 个 TTS 段落,每段不超过 180 字。为什么要拆段?因为 TTS 一次合成太长时,稳定性会下降。我的经验是逐页合成不如逐段合成,逐段合成不如逐句或两三句合成。尤其是自定义音色,长文本偶发失败时,重跑一小段比重跑一整页省心很多。

每段音频生成后,Codex 会用 ffprobe 或 Python 读取时长,得到一个清单:

slide_01_01.mp3 12.4s
slide_01_02.mp3 18.7s
slide_01_pause 0.5s
slide_02_01.mp3 31.2s

后面视频时间轴就靠这张表对齐。

八、豆包语音:注册、复制声音、准备 API

接下来进入 TTS。

TTS 是 Text to Speech,也就是文字转语音。传统 TTS 更像“根据字词发音”,现在的大模型 TTS 会结合上下文判断语气、停顿和情绪,所以听感自然很多。豆包语音比较适合中文汇报,尤其是正式但不死板的场景。

火山引擎控制台入口在这里:https://console.volcengine.com/speech/new/experience/clone?projectName=default

注册账号后,可以领取豆包语音 TTS 2.0 的免费额度(2万字)。免费额度不够就少量充值,很便宜,28元/10万字,绰绰有余(除非你一上来就生成 40 个版本)。我原本以为,TTS 声音复制很容易进入“怎么都感觉不像自己”的循环,但实测表明,豆包语音的声音复制实力强劲,一次通过,我很满意。录的时候按平时汇报语气读,不要端播音腔。你录进去的是一个“说话习惯样本”,如果样本像新闻联播,生成出来也会努力向新闻联播靠拢。

声音复制完成后,记下两个东西:API Key;音色 ID,通常是一个自定义 speaker id。

这里有一个坑:使用声音复刻 2.0 的自定义音色时,X-Api-Resource-Id 要用 seed-icl-2.0,不是 seed-tts-2.0。普通豆包 TTS 2.0 音色才对应 seed-tts-2.0。这点在火山引擎文档里有说明,用错以后接口会失败,而且失败信息不一定温柔。

API Key 不要明文写进代码。更推荐在本机设置环境变量,当然这些 Codex 都会帮你考虑到。

Python 脚本的核心逻辑很简单(注意下面只是代码示意):

api_key = os.environ["DOUBAO_API_KEY"]
speaker = os.environ["DOUBAO_SPEAKER_ID"]

headers = {
"X-Api-Key": api_key,
"X-Api-Resource-Id": "seed-icl-2.0",
"Content-Type": "application/json",
}

payload = {
"req_params": {
"speaker": speaker,
"text": text,
"audio_params": {
"format": "mp3",
"sample_rate": 24000
}}}

实际字段以火山引擎当前 V3 文档为准,但原则不变:逐段请求、保存 mp3、记录时长、失败重试。

九、处理多音字、停顿和失败音频

TTS 最麻烦的不是生成,而是微调。

多音字不要指望模型永远懂你。比如“行”“重”“数”“长”这类字,如果读错,可以优先改句子上下文,而不是硬塞拼音。比如“这个行业”比“这个行当”更稳,“重新处理”比“重处理”更稳。如果接口和音色支持 SSML,再考虑用 <phoneme> 或 <sub> 之类的标记;但声音复刻 2.0 对 SSML 目前还不支持,解决方案是故意用错别字解决。比如,我的 PPT 中有“转蛋”,TTS 会把“转”念成第三声“转身”的“转”,但正确的发音是第四声“到处转转”的“转”。解决方案是直接把讲稿写成“赚”,立刻解决。

要考虑必要的停顿。有三种做法:句内停顿:用逗号、分号、顿号;页内停顿:合成多个 mp3 后,中间插入 0.2 到 0.5 秒静音;分页停顿,中间插入 1 秒左右静音;章节停顿:章节页前后插入 2 秒左右静音。这样节奏感会好不少。

不要疯狂调语速。语速参数调到 1.15 以上,声音很容易开始“不像本人”。如果总时长超了,优先删稿;如果短了,优先加停顿或补一句解释。

还要检测长静音。TTS 偶发失败时,有可能生成一个很短、很空、或者中间长时间无声的 mp3。可以让 Codex 调用 ffmpeg 检测:

ffmpeg -i slide_05_02.mp3 -af silencedetect=noise=-45dB:d=2 -f null -

如果某段出现超过 3 秒的异常静音,就自动标记重生成。每段生成后也要用 ffprobe 取时长:

ffprobe -v error -show_entries format=duration -of default=nw=1:nk=1 slide_05_02.mp3

最后得到一份 audio_manifest.json,里面记录每页每段音频、时长、停顿和累计时间。这个文件就是视频合成的地基。

十、用 Office COM 导出 PPT 图片

PPT 做完后,Codex 会调用 Office COM 把每一页导出成 PNG。它相当于让真正的 PowerPoint 打开文件并逐页导出,比一些第三方转换工具更接近最终显示效果。

导出时建议固定 1920x1080,实践表明用 Full HD 还会偶尔有轻微模糊。如果机器性能较好,用 4K 分辨率是比较稳妥的。

十一、用 hyperframes 合成视频

最后用 hyperframes 插件。

hyperframes 插件的作用,是用 HTML/CSS/GSAP 来描述视频画面、动画、音频和时间轴。它的原理可以理解为:每个画面元素都是网页元素,每段音频、图片、字幕都有 data-start 和 data-duration,再通过浏览器逐帧渲染,最后编码成视频。好处是可控、可复现、适合把 PPT 页图、mp3 配音、转场动画整合在一起。

对于这个任务,最简单的结构是:

video_project/
index.html
slides/
slide_001.png
slide_002.png
audio/
slide_001_001.mp3
slide_001_002.mp3
audio_manifest.json

每一页 PPT 是一个场景。场景时长等于这一页所有 mp3 时长之和,再加页内停顿和转场时间。例如第 3 页音频总长 42.3 秒,页尾停顿 0.5 秒,转场 0.4 秒,那么这一页可以设置为 43.2 秒。

页切换对齐的关键是累计时间:

slide_01 start = 0.0
slide_01 duration = 38.6
slide_02 start = 38.6
slide_02 duration = 44.1
slide_03 start = 82.7

音频也按同样的累计时间放进去。这样 PPT 切页一定发生在对应配音结束之后,不会出现“声音还在讲上一页,画面已经冲到下一页”的尴尬场面。

转场不需要花哨。会议汇报最适合 0.25 到 0.5 秒的淡入淡出,或者轻微推移。每一页都飞来飞去,会显得像模板网站在展示肌肉。hyperframes 里可以用 GSAP 做:

tl.from(".slide", { opacity: 0, duration: 0.35, ease: "power2.out" }, start);

更复杂一点,可以让章节页用慢一点的淡入,案例页用轻微横向滑入。但不要每页随机一种动画。视频不是转场特效展销会。

十二、最终检查

合成前后 Codex 会自动(或者你要求它)做一张检查表:

PPT 是否每页都成功导出 PNG;每段 mp3 是否存在,时长是否正常;是否有超过 3 秒的异常静音;每页开始时间是否等于上一页结束时间;总视频时长是否接近预期;章节停顿是否足够;多音字是否已经修正;背景图是否压住了正文;字幕或页码是否被裁切;最终视频是否为目标分辨率,帧率一般 30fps 即可。

如果总时长要微调,不要去全局改语速。差 10 秒以内,可以调页间停顿;差 30 秒以上,就回去改讲稿。真正影响时长的永远是废话,不是参数。

十三、总结

这套流程跑下来,感觉 Codex 最适合做的不是“替我创作”,而是“替我维护流程”。

人负责判断内容是否成立,Codex 负责把讲稿、素材、PPT、音频、视频脚本这些东西接起来。presentations 插件解决 PPT 初稿,image gen 插件补视觉素材,豆包语音解决自然配音,hyperframes 解决时间轴和视频输出。每一个环节都不是完全自动,但每一个环节都比纯手工省力。

最后成品的效果也很有意思:画面是 PPT,声音是自己的音色,节奏是提前排好的。它不像录屏那样容易口误,也不像纯 TTS 那样没有人格。唯一的问题是,听到“自己”用非常稳定的语气讲完一整套汇报,会有一种微妙的错位感。

未来投标好像再也不需要董事长亲自出马配音了(温馨提示:声音复制需要本人授权)。