论坛 图像/语音/视频 查看主题

数字人口播视频流水线:架构、踩坑与提示词工程

S sixchu · 1781834619 · 浏览 2 · 回复 0
分享
楼主 1 小时前

一份从零跑通到稳定出片的工程笔记。文稿一键生成竖屏数字人口播视频(背景视频 + 右下角圆形数字人 + 逐句字幕 + 配音),分享设计思路、踩过的坑、以及关键的提示词原则。

关键词:ComfyUI · IndexTTS2 · WhisperX · InfiniteTalk · Wan2.2 · LTX-2 · ffmpeg · 数字人


一、做了个什么东西

输入:一段口播文稿(txt) + 一张人物图 + 一段参考音色
输出:竖屏成片(720×1280)—— 全屏背景视频 + 右下角圆形数字人 + 逐句字幕 + 配音

一句话:文稿 → 自动分镜 → 配音 → 数字人口播 → 背景空镜 → 合成成片,全程一条命令。

跑下来体验:改文稿只重跑受影响的阶段;数字人没变就直接复用之前的 mp4;某一环出问题,单独调那一环。


二、整体架构:三方分工

判断每个步骤归谁,只问两件事:要不要 GPU?要不要动态编排 / 逐句对齐?

角色 干什么 为什么是它
ComfyUI(GPU 工人) ① IndexTTS2 配音 ② InfiniteTalk 数字人 ③ WhisperX 强制对齐 只有这几步真正需要 GPU 大模型
云端 LLM API 文稿→分镜、写 video_prompt、文生图 语义理解 / 生成式出图
T2V 视频生成服务(独立 HTTP) 文生视频(基于 LTX-2),生成背景空镜 专门的视频生成服务
Python + ffmpeg 编排、调度、测时长、逐句对齐、2D 合成、运镜、圆形叠加、字幕、音轨 mux 有状态流程 + 动态段数 + 时间轴,确定性强、无 GPU、好调试

结论:ComfyUI 只负责「真要 GPU 的三件事」,背景拼接与合成全部 Python+ffmpeg,分镜与出图走云端 API。


三、八阶段流水线

storyboard → images → tts → align → durations → human → background → compose
# 阶段 产物 谁做 说明
1 storyboard storyboard.json LLM 文稿切 N 段,每段 text + image_prompt
2 images images/seg_NN.png 文生图 API T2V 模式自动跳过
3 tts full_voice.wav IndexTTS2 整篇连续配音,保证语流
4 align timestamps.json WhisperX 整条音频强制对齐,反推每句时间轴
5 durations durations.json ffprobe 每句精确秒数(B 对齐命根子)
6 human digital_human.mp4 InfiniteTalk 用整条 full_voice 跑一次,口型对整条音频
7 background background.mp4 ffmpeg / T2V / Wan 背景视频,4 种模式可选
8 compose final.mp4 ffmpeg 背景 + 圆形数字人 + 字幕 + 音轨

每作品独立目录,所有中间产物落盘,断点续跑。

背景生成的 4 种模式

模式 实现 速度 效果 适用
kenburns ffmpeg 2D 运镜(zoompan 缩放/平移) 秒出,纯 CPU 静图动起来 快速验证 / 无 GPU
wan_i2v Wan 14B 图生视频(ComfyUI 逐段) 真实动态 要质量、有 GPU
wan_flf Wan 首尾帧生视频 首尾帧过渡 特定过渡需求
t2v LTX-2 文生视频(跳过生图) 直接出空镜 推荐默认

四、五条非协商方针

方针一:中间产物全部落盘,可断点续跑

每个阶段产物写到固定文件名,支持 --from <阶段> / --only <阶段>

为什么:AI 生成慢且贵(数字人几分钟、T2V 一个镜头三四分钟)。中途失败或要调某一环,绝不能从头再来。落盘 = 每一步可单独验证、可复用。

延伸阶段内部也要做断点续跑。比如背景生成 12 个镜头,跑到第 7 个断了,续跑时只提交缺失的 5 个,已下载的不重做。

方针二:B 逐句对齐 —— 音频连续生成,时间轴反推

  1. 配音一次性连续生成整条,不靠后期拼接制造节奏
  2. WhisperX 对整条音频做强制对齐,反推每句起止时间戳
  3. 不切音频 —— 音频始终是完整一条,切的只是「时间轴标记」
  4. 背景切换、字幕、数字人口型,三者全部由同一份 durations.json 驱动

为什么:先按句切音频再拼,停顿和语气连贯性会断裂。连续音频 + 反推时间轴,既保住自然语流,又拿到帧级精确的同步点。

这是非协商项。任何「为了省事先切音频」的想法都会破坏听感。

方针三:ComfyUI 当函数调 —— 模板 + patch

把工作流当成「可调用的函数」:

  1. 在 UI 里调好工作流,导出 API 格式 json
  2. Python 读模板,只 patch 关心的输入节点(文本、音频文件名、帧数、输出前缀),其余参数(分辨率/步数/attention)全继承模板
  3. POST /prompt → 监听 WS 完成事件 → 读 /history/{id} 取真实产物文件名 → 归档

参数调优在 UI 里做(可视化、即时反馈),调好导出即可,脚本永远不用动那些参数。patch 节点 id 写在脚本顶部常量区,工作流改了节点结构只改这几个常量。

方针四:配置与密钥分离,环境可切换

  • config.example.yaml:模板,key 留空,提交到仓库
  • config.dev.yaml / config.prod.yaml:实际配置含密钥,不提交
  • --env dev|prod 切换。dev 用 human_resolution=320 提速,prod 用 640

方针五:提示词用正面描述,不用负面约束

要画面「不出现某东西」时,描述想要的画面,而不是罗列「不要 X、不要 Y」。原因详见第六节「白熊效应」。


五、十大踩坑(按症状索引)

#1 背景运镜抖动(zoompan 整数取整)

现象:kenburns 模式缓慢缩放/平移,肉眼可见高频抖动/频闪。

根因:ffmpeg 的 zoompan 滤镜每帧把 x/y 坐标取整。缓慢缩放每帧步进很小(亚像素级),被整数取整放大成了高频跳变。

解法:在远大于输出的画布上做 zoompan,最后降采样回目标尺寸。画布放大到输出的 4 倍,则 1 像素取整 = 输出 0.25 像素,肉眼不可见。1.3 倍不够,4 倍彻底消除。

#2 数字人头顶被切

ImageResizeKJv2 节点的 crop_position 默认 center。人物图通常头在上方,center 裁剪会切掉头顶。改 top

#3 IndexTTS2 的 speech_speed 是「时长倍率」

源码 infer_v2.py:695

target_lengths = code_lens * 1.72 * speed_scale

speed_scale 越大 → 目标音频越长 → 语速越慢。要慢一点设 >1(如 1.15),要快设 <1。记反了就南辕北辙

#4 Wan 模型格式坑(最容易踩)

Wan 系列有一堆「看起来一样实际不通用」的格式陷阱:

文本编码器(umt5-xxl)有两种格式,互不兼容

  • WanVideoWrapper 自定义 key(blocks.X.attn.q.weight):只能给 WanVideoWrapper 用
  • 原生 CLIPLoader 需要标准 T5 格式(encoder.block.X.layer.0.SelfAttention.q.weight
  • 原生节点(I2V/FLF)唯一兼容源:官方 Repackaged 仓库的 umt5_xxl_fp16.safetensors
  • 官方原始 .pth 也不行(key 前缀不匹配)

VAE 通道数不通用

  • 2.2 VAE 输出 48 通道,2.1 VAE 输出 16 通道,混用直接报错

LoRA 维度不匹配

  • lightx2v LoRA 是给 14B 训练的,5B 维度不匹配,5B 流程要 bypass

5B 架构限制

  • Wan2.2 5B 没有图像交叉注意力层,WanVideoWrapper 里只支持 T2V
  • I2V 要用 ComfyUI 原生节点,不能用 WanVideoWrapper
  • FLF(首尾帧)5B 不支持(架构限制),只能 14B + WanVideoWrapper

#5 字幕换行与去标点

ASS 头加 WrapStyle: 0 自动换行不溢出。逗号顿号 → 空格(保留停顿可读性),句末符号(。!?:等)直接删除。字幕距底边 90px 避开圆形数字人。

#6 LTX-2 分辨率必须 32 倍数

LTX-2 的 latent patch 要求宽高是 32 的倍数(two-stage 流程是 64)。常用预设:

  • landscape = 1280×736
  • portrait = 736×1280
  • cinematic = 1536×640

输出后用 ffmpeg scale 到目标尺寸(如 736→720,2.2% 差异可忽略)。帧数公式 1+8k(不同于 Wan 的 1+4k),传 seconds 让服务自动对齐。

#7 画面乱码(白熊效应)

视频里出现伪字幕、乱码招牌?看第六节。这是最重要的一坑

#8 横转竖(blur-fill 填充)

T2V 横屏生成质量比竖屏好(训练数据 16:9 为主),但最终要竖屏。1280×736 塞进 720×1280:

[0:v]split=2[orig][blur];
[blur]scale=W:H:force_original_aspect_ratio=increase,crop=W:H,boxblur=20:20[bg];
[orig]scale=W:414[fv];
[bg][fv]overlay=(W-w)/2<img src="static/image/smiley/default/sad.gif" smilieid="2" border="0" alt="" />H-h)/2[out]

干净的横屏画面缩放居中(720×414),上下用同源画面的模糊扩展填满(720×1280)。

#9 断点续跑:只提交缺失的 shot

早期续跑逻辑「只要不是全部存在就重新提交全部」,浪费算力。

正确做法:

missing = [i for i, f in enumerate(seg_files) if not os.path.exists(f)]
if len(missing) < len(segs):
    clear_mem = False          # 续跑不清 Memory Bank,保持风格连续
sub_shots = [shots[i] for i in missing]
# submit_batch 返回的 index 要映射回原始段号:
# orig_idx = missing[shot_info["index"]]

#10 后台长任务(nohup + disown)

nohup python run.py --project myproj --from background > bg.log 2>&1 &
disown
  • nohup ... &:忽略 SIGHUP
  • disown:从 job 表移除,关 SSH 不影响
  • 查进度:tail -f bg.log

六、白熊效应:最反直觉的提示词坑

「不要想白熊」—— 结果你满脑子都是白熊。扩散模型也一样。

现象

T2V 生成的视频里出现大量乱码文字、伪字幕、招牌乱码。直觉上加一句 no text / 无字幕结果适得其反,乱码更多了

根因

扩散模型没有真正的「否定」能力。提示词进 cross-attention,模型看到的是一个个 token 的视觉概念。写 no text / no subtitle / 无字幕

  • text / subtitle / 字幕 这些 token 照样被编码进注意力
  • 模型不理解「no」是要排除 —— 它只看到「文字」的概念被反复强调
  • 结果:越强调不要文字,画面越容易出文字

同样的陷阱也藏在不显眼的地方,比如 style_prompt: "...无文字水印"

解法:只描述想要的,不说不要的

(负面罗列,激活概念):

no signage, no posters, no banners, no text, no subtitle, 无字幕水印

(正面描述,画面自然干净):

Pure natural landscape with organic surfaces only: stone, wood, water,
foliage, sky, fabric. Clean photographic frame, unadorned, raw nature.

记一个反直觉原则:要画面没有某东西,就把画面描述得丰满到没有它的位置,而不是去「禁止」它。


七、video_prompt:让 LLM 输出有层次的电影感长描述

T2V 模式跳过生图,直接文生视频。video_prompt 的质量 = 视频的质量。最容易出废片的一环。

踩过的坑:LLM 偷懒输出短句

早期 prompt 只说「80-150 词英文」,LLM 看到中文输入就偷懒,输出 1-2 句中文混英文术语:

镜头从脚下的土层缓缓向上摇,locked-off固定停在开阔大地远景,暖柔自然光,风吹动草叶轻轻晃动

对比官方优质 prompt(100+ 词纯英文,层次丰富),差距巨大,生成出来的视频空洞、单调。

解法:强约束 + 反面例子 + 感官清单

重写后的 system prompt 加了三样东西:

1. 强制感官清单 —— 每个 shot 必须包含全部 7 项:

# 维度 要求
1 场景 & 主体 具体视觉细节:不是「mountains」而是「jagged snow-capped peaks with dark granite ridges」
2 动作 At normal speed, 开头,按时间顺序的缓慢运动
3 风格 调色板名 + 光线质感 + 情绪 + 胶片参考(Kodak Portra / ARRI Alexa)
4 镜头 精确英文术语:slow push-in / gentle dolly-in / locked-off tripod,描述运动揭示了什么
5 背景 分层景深:前景 / 中景 / 远景,各层光线
6 声音 具体的环境音(diegetic),分层
7 音乐 匹配情绪的乐器床

2. 反面例子 —— 直接把上面那种短句作为「NEVER OUTPUT」示范。

3. 硬约束

  • 每段 100-180 英文词,「If under 100, it is WRONG」
  • 必须全英文,中文/拼音/混合直接 REJECTED
  • 偏好缓慢运动(漂浮、摇曳、波动),避免快速复杂动作(模型会畸变)
  • 全程风格/调色板一致,序列才统一

优质 prompt 长什么样

一个达标的 shot:

A vast ancient mountain landscape at dawn, tiered limestone peaks receding into layers of blue-grey haze, a silver ribbon river winding through the deep valley far below, pine forests clinging to rocky slopes... At normal speed, thin clouds drift slowly across the valley while the first golden sunlight gradually spreads over the highest ridges... A very slow aerial push-in glides gently toward the river bend... The foreground shows silhouetted pine branches framing the top edge, the midground reveals layered mountain silhouettes, the deep background fades into atmospheric haze. Soft wind rustles through pine needles, distant birdsong echoes across the valley... A soft orchestral bed plays low beneath the scene.

注意它怎么做到「丰满」的:每个名词都带形容词和材质,动作有时间推进,景深分三层,声音分层,连音乐都指定了乐器。


八、关键模型与节点

配音:IndexTTS2

  • 工作流核心节点 IndexTTS2Advanced(不是 Simple,需要可调参数)
  • 参数:speech_speed(时长倍率)、interval_silence_ms(句间停顿)、emotion_control_weight、temperature
  • 整篇文稿一次性生成(保证语流),不要逐句生成再拼接

数字人:InfiniteTalk

  • 用 full_voice.wav 整条音频驱动整张人物图
  • 输出方形视频,再通过 ffmpeg 圆形遮罩叠加到右下角
  • 避坑:ImageResizeKJv2crop_position 必须改 top

强制对齐:WhisperX

  • 输入:full_voice.wav + 全文 text
  • 输出:每句的 [start, end, dur]
  • 不切音频,只做时间轴标注
  • SRT 输出在 PreviewAny 节点的 outputs["text"][0],不落文件

背景视频:Wan2.2 / LTX-2 二选一

  • Wan2.2-TI2V-5B:图生视频,效果真实但慢,需要 ComfyUI 原生节点
  • LTX-2:文生视频,跳过生图,速度中等,画面更稳

九、可视化前端(可选)

工程跑通后,加了个简洁的 Web 控制台(FastAPI + Vanilla JS):

  • 项目列表 / 8 阶段卡片 / 文稿编辑 / 分镜编辑(缩略图 + 文本)
  • SSE 实时日志流,自动着色
  • 产物预览(图片网格 / 视频播放器 / 音频播放器)
  • 一键启动 / 续跑 / 单跑某阶段
  • 端口 8189,与 ComfyUI 8188 错开

后端不修改 run.py,通过 subprocess.Popen 调命令行,复用现有断点续跑逻辑。前端单文件 HTML,零构建工具。


十、几个关键经验总结

  1. AI 生成贵 → 必须断点续跑:阶段间 + 阶段内都要做
  2. 音频是基准 → 时间轴一律反推,不靠拼接造节奏
  3. GPU 只干必须 GPU 的活:运镜、合成、字幕这种确定性 2D 用 ffmpeg
  4. ComfyUI 当 HTTP 服务调:UI 调参 + API 调用,参数永远在 UI 里
  5. 提示词用正面描述:白熊效应是真的,禁止只会激活
  6. 格式陷阱必查 key:Wan / LTX / Whisper 模型源不通用,别只看文件名
  7. 本地查代码 + 服务器跑:本地无 GPU 跑不动,但查代码比 SSH 快

十一、参考链接


工程沉淀的几个原则其实都很朴素:慢的步骤要可续跑单一数据源驱动同步确定性的活别用 GPU提示词描述想要的而不是不要的
希望对在做类似工程的朋友有帮助。

#1

登录后即可发表回复

立即登录