02 · 数字人
一门含 103 个视频的英文销售课程,变成中文课程影片:逐字稿、受术语表约束的翻译、Abby 的 Fish Audio 声音、与这段音频严丝合缝对口型的 HeyGen 数字人,以及一页 HyperFrames 笔记本页面,课程与英文原版并排播放。一条流水线,逐个视频运行。
Tony 的要求:用 HyperFrames,把转写出的英文和选定的 Fish Audio 中文声音做成动画视频;画面要让学习者爱上学习,而不是感到无聊。克制,胜过炫目。
流水线,按顺序
Trustworthy Selling 是一门含 103 个课程视频的英文课程。母版存放在工作室的渲染机上,供播放的副本存放在 SharePoint 库里,课程网站通过每位用户专属的链接播放每个视频,因此 SharePoint 自身的权限依然生效。中文版的设计,是与英文原版并排放在同一个课程页面上,而不是取代它。
trustworthy.apexfamilywealth.com · SharePoint KnowledgeBase / Trustworthy Selling / Mod N · scripts/upload-videos.mjs (resumable, 10 MiB chunks) · public/lessons/videos.json
Whisper 在渲染机上运行,为每个视频写出一份转写,含文本和逐字时间。英文句子在整条流水线里被一路保留:它成为屏幕上每一行中文后面的淡影行,也是翻译对齐所依据的锚点。
content/transcripts/v0NN.json · manifest.tsv (id → module, file, duration)
翻译代理使用固定的提示词和课程术语表,因此课程术语在每一课里译法一致。先盲译一课,逐句对照之后,才让九个代理并行跑完批量翻译。每一课都要通过解析与对齐检查,输出是一份由英文和中文配对组成的分段文件——这才是流水线真正的输入。
scripts/translate/PROMPT.md · GLOSSARY.md · content/transcripts/v0NN.zh.json
旁白工具把每一段中文用 Abby 的声音送去 Fish Audio,以 0.35 秒的间隔拼接各段,加上标题和片尾字卡的停顿,写出一个 WAV 和一份时间文件。合成同时从这同一份文件读取音频偏移和片段偏移,所以画面与声音不可能漂开。没有 API 密钥时,工具会退回到本地声音,这样流水线仍能端到端地跑通。
build/tts.py · assets/<id>/narration.wav + timings.json · Fish model s2.1-pro-free in development · fallback Kokoro zf_xiaobei
Abby 是 Tony 创建的一个 HeyGen 照片数字人。视频请求发送的是上传的音频资产,而不是脚本,所以 HeyGen 只负责让嘴唇动起来,Fish 的旁白与合成里已有的版本逐字节一致。两个引擎在同一段 13.7 秒的真实课程音频上做了对比,同一个形象、同样 1080p,一个接一个运行,让每次积分变化都对应一个任务。
写进流水线笔记的两个陷阱:照片数字人的 look id 等于 group id,而命令行工具没有说明;免费档会给每个片段加水印,并把 Avatar IV 限制在一分钟以内,所以正式运行是在 Pro 档上做的。口型同步的质量,只能靠看来判断,这由 Tony 说了算。
heygen asset create → audio_asset_id · heygen video create -d request.json --wait · videos/heygen-abby-test/run_test.py + results.json
HeyGen 返回片段里的音频,与上传的 WAV 在采样层面并不对齐。一次任务提前了 13 毫秒,另一次滞后了 23 毫秒,方向还不一样。构建会把片段的音频与上传的音频做互相关,把偏移写入文件,并让人声轨相应提前或推后,这样嘴唇和观众听到的声音,误差只在几毫秒之内。
assets/abby.offset.json · AUDIO_LEAD read by the build script · final voice vs lip-driving audio within 0–8 ms on the measured jobs
课程模板依据时间文件,为每个视频各实例化一份。外观与课程网站一致:深蓝画布、术语下的金色下划线标记、Noto Sans SC、每行中文后面低透明度的英文句子淡影、分段计数器,以及一条发丝般的进度线,让十二分钟的课程也不会让人迷失位置。Abby 位于固定区域,字幕条避开这个区域,所以文字永远不会跑到主讲人身下。
compositions/lesson.template.html · build/compose.mjs · build/proof.mjs · navy #001d69 · gold #F7E14D · paper #fbfaf8
一个运行器处理整个批次:如果时间文件缺失或供应商变了,就先做旁白;然后合成;运行 HyperFrames 检查,不通过就拒绝渲染;以 720p 把帧直接流式写入编码器;最后分流。不足 25 MiB 的渲染,会复制进网站供 Pages 使用;更大的,等待 SharePoint 上传器。无论哪条路,这一课在视频索引里的条目都会新增一个中文版本,记下大小、时长和配音供应商。运行器在磁盘余量不足时拒绝启动,因为磁盘写满曾让这台机器上的每个终端都卡死。
build/run.mjs v001 … v010 · npx hyperframes check . · render --quality looks --crf 24 · public/media/zh/<id>.mp4 · videos.json[mod][file].zh
发音审看、声音审看和各模块的审看,在项目里各有一个文件夹。Tony 把前十个版本评为“旁白的字幕”,他说得对:只是复述声音的文字,不是动画。下一版转向了一套场景语法:一张逐步生成的图示、一个渐渐清晰的切面、一次数字递增、增长条、一个仪表、几枚标签和一个落版;每个视频一份分镜脚本,旁白降级为字幕条。数字人的问题是这次审看之后才出现的,而不是在它之前。
pronunciation-review/ · voice-review/ · module1-review/ · module2-review/ · STORYBOARD.md · design-sample/ · source-led/
学习者看到之前的关卡
这条工作流教给工作室的事