本文记录我用 WorkBuddy 把"竖屏短视频 / 图文视频 / 口播混剪"做成一条可批量生产的本地流水线的完整过程。输入一份 JSON 脚本,输出指定比例(1080×1920 竖屏或 1920×1080 横屏)的 MP4。全程零积分、不依赖 ComfyUI,核心依赖只有三个免费组件:edge-tts(配音)、Pillow(程序化背景与文字)、ffmpeg(合成转场)。包含关键代码、架构设计,以及几个真实踩坑(转场时长夹紧、配音 rate 格式、BGM 空壳 bug)。适合想用本地方案做视频自动化的开发者参考。
做批量短视频内容(竖屏口播、图文视频、产品混剪等),主流方案要么上 ComfyUI 出图再剪,要么买云端配音和剪辑服务。我的约束是两个:
于是思路变成:把"出图、配音、合成"三步全用免费本地组件拼起来,任何外部渠道失败就回落到程序化兜底,保证出片不中断。通过 JSON 字段切换比例、字体、音色、背景来源,实现"一套流水线、全类型输出"。
最终架构是一条极简的流水线:
JSON 脚本 → 逐 scene 出背景图(PIL/免费图源) + 叠加标题/副标题文字 → 逐 scene 生成配音(edge-tts) → 每条 scene 用 zoompan 做 Ken Burns 运镜 → ffmpeg xfade 串联转场 + 混 BGM/音效 → 输出 指定比例 MP4(竖屏 1080×1920 / 横屏 1920×1080)

全类型视频自动生产线架构总览:JSON → Scene → PIL/edge-tts → zoompan → xfade → MP4,底部为 bg 路由键的多源降级策略。
整个流水线由一份 JSON 脚本驱动,每条 scene 生成"一张背景图 + 一段配音 + 一组文字层",scene 之间用转场串联。脚本示例:
{
"badge": "系列名 · 第01期",
"tag": "分类标签 · 一句话定位",
"voice": "zh-CN-YunxiNeural",
"ratio": "vertical",
"scenes": [
{
"big": "主标题文字",
"sub": "副标题 / 补充说明",
"voice": "这里是这一屏要配音的文案……",
"bg": "ink",
"big_font": "li"
}
]
}ratio 字段控制输出比例(vertical 竖屏 / horizontal 横屏),分辨率由它推导,改一行就能换画幅。
bg 字段是整套系统设计的重点——它不是一个单纯的文件路径,而是一个路由键,背后是一套可降级的多源取图策略:
关键约束:任何外部渠道失败都自动回落到 Pillow 程序化背景。这样哪怕 Pexels 限流、摄图网 cookie 过期,流水线也不会断。把"兜底"设为默认、把"增强"设为可选,是这套系统能稳定跑起来的设计根基。

水墨晕染风格(bg=ink)实际渲染效果:暖色调渐变背景 + 山峦剪影 + 红日 + 书法大字,由 Pillow 程序化生成。

青绿山水风格(bg=gradient)实际渲染效果:同一套代码仅改 bg 路由键即可切换背景风格。
edge-tts 的 Communicate 原生支持 rate / volume / pitch,但免费端点偶发 NoAudioReceived 抖动。下面是实际封装(含递增退避重试)——这部分看似简单,却是后面做多音色和情感化的基础:
async def tts(text, out_path, voice, rate="+0%", volume="+0%", pitch="+0Hz", style=None):
import edge_tts
backoff = [1, 2, 3, 5, 8]
for attempt in range(len(backoff)):
try:
if style:
ssml = build_ssml(text, voice, style, rate, volume, pitch)
comm = edge_tts.Communicate(ssml, voice=voice)
else:
comm = edge_tts.Communicate(text, voice=voice,
rate=rate, volume=volume, pitch=pitch)
await comm.save(out_path)
return
except Exception as e:
if "NoAudioReceived" not in str(e):
raise
await asyncio.sleep(backoff[attempt])
raise last_err情感风格(SSML 的 mstts:express-as)需要套一层 SSML 包裹,且中文音色支持度差异很大,后面踩坑章节会讲怎么优雅降级。
静帧背景要"有呼吸感",靠 ffmpeg 的 zoompan 做缓慢推进 + 轻微视差平移。难点是缓动——线性推近很机械,改用 sine ease-in-out:
eased = f"(0.5-0.5*cos(PI*on/{frames}))" # 先慢→快→慢
z_expr = f"1.0+0.14*{eased}" # 镜头推近 1.0 → 1.14
x_expr = f"iw/2-(iw/zoom/2)+({eased})*50-25"
y_expr = f"ih/2-(ih/zoom/2)+({eased})*30-15"
vf = (f"zoompan=z='{z_expr}':d={frames}:s={W}x{H}:fps={FPS}:"
f"x='{x_expr}':y='{y_expr}'")0.5-0.5*cos(PI*p) 这条表达式同时用在运镜和转场上,是整套"电影感"的来源。W×H 由 JSON 的 ratio 字段推导,竖屏取 1080×1920、横屏取 1920×1080,代码里一处切换即可。
多条 scene 用 ffmpeg xfade 串联。这里有个必须处理的实际问题:转场时长不能大于相邻任意一条 scene 的时长,否则 ffmpeg 直接报错。所以每条转场时长都要被相邻短镜头"夹紧":
xfades = []
for k in range(n - 1):
xf = min(xfade, min(durs[k], durs[k + 1]) - 0.15)
xfades.append(max(0.2, xf))offset 也要随拧紧后的转场时长重新累积,否则画面和配音会对不上。最后音频用 concat 串起来,BGM / 音效通过 amix 叠加。
整套命令最终是一个 -filter_complex 字符串,把视频 xfade 链、音频 concat 链、可选的 BGM 链和音效链拼在一起。
文档里写"支持语速",但 edge-tts 7.2.8 实际只接受 +N% / -N% 格式。写 "fast"、"slow" 这类标签,或者裸写 "50%",都会直接 ValueError。JSON 里必须严格写 "+20%"、"-15%"。这个坑第一次踩的时候,批量脚本整批挂掉,排查了半天才定位到是格式问题。
早期 concat_xfade 的函数签名声明了 bgm 参数,函数体却从未引用它——音频链只做了 concat 把各 scene 配音串起来,BGM 字段写了也完全无声。修复方式是真正接入 ffmpeg 混音链:
[bgm] aloop=loop=-1[bgml];
[bgml] atrim=0=TOTAL[bgmt];
[bgmt] volume=0.3[bgmm];
[bgmm] aformat=sample_rates=44100:channel_layouts=mono[bgmma];
[aout][bgmma] amix=inputs=2:duration=first[aout2]注意两个细节:① duration=first 以配音长度为准,BGM 不足则循环、超出则裁剪;② 配音是 44100 mono,BGM 进 amix 前必须 aformat 重采样归一,否则报错或音质异常。
SSML 的 mstts:express-as 不是所有音色都支持。实测(用脚本逐一对音色跑单句探测)结果很分裂:
如果盲信文档给不支持的音色指定风格,要么报错要么静默忽略。所以代码里做了一张支持度映射表,遇到不支持的组合直接 WARN 退回普通配音,而不是中断整条流水线。这对"同一套流水线要适配不同语种 / 不同音色"的场景尤其重要。
xfade 自带 slideup / wipeleft 这类方向性擦除,但用在图文静帧 / 口播截图上很生硬。最终默认只用一组"柔化类"交叉溶解(dissolve / fade / distance)循环混搭,方向性转场只在单条 scene 显式指定时才启用。视觉上顺滑很多,也更适合大多数短视频节奏。
再次强调设计根基:背景取图严格免费优先,绝不默认调积分生图。优先级从高到低:
任意一级失败自动回落上一级,最差情况也能用 Pillow 出片。把兜底做成默认,增强做成可选,是本地自动化系统稳定性最高的设计原则——这比追求"每一帧都精美"务实得多。

宣纸纹理风格(bg=paper)实际渲染效果:最轻量的纯色程序化背景,适合内容密度高的场景。
一条命令批量转出整个目录(竖屏、横屏脚本混在同一个目录也能分别推导比例):
python pipeline.py batch -i templates/ -o output/合规上也有红线:标题/配音避免"最 / 第一 / 绝对"等极限词;不宣称医疗功效、金融收益、算命改运等需资质的内容;涉及品牌 / 人物需确认授权。把内容定位在"知识分享 / 生活记录 / 产品介绍"等合规类目,规避需要特殊认证的赛道。
这套生产线的核心设计有三条,按重要性排序:
如果你也想搭类似的本地视频流水线,建议先只用 Pillow + edge-tts + ffmpeg 三个组件把单条跑通(含竖屏和横屏各一条),确认出片没问题,再加 Pexels / SD / BGM 这些增强层。一层一层加,比一步到位稳。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。