AI 短剧视频生产 Skill v2.0
概述
本 Skill 提供竖屏 AI 短剧从剧本到成片的完整自动化生产流水线。基于 EP01-EP03 实际生产中反复迭代的方法论,核心改进包括:FFmpeg 命令文档外置、Motion Prompt LLM 自动增强、速度/质量双模式拆分、结果交付标准化。
单集标准规格:18 场景 / 竖屏 1080x1920(9:16) / 约 3 分钟。
核心原则:
- 禁止 Ken Burns 作为主要视频来源:Ken Burns(ffmpeg zoompan)仅在 AI 图生视频 API 完全失败时作为最后降级方案
- 图片必须是真 PNG 1080x1920:JPEG 改扩展名为 .png 会导致视频 API 1210 参数错误
- 视频 API 和 TTS 是独立限流桶:TTS 恢复不代表视频 API 恢复
管线架构
分镜图生成 → TTS配音 → Motion Prompt增强 → 图生视频(z-ai video) → FFmpeg合成 → 字幕烧录 → 交付检查
↑ ↑ ↑ ↑ ↑
z-ai-generate z-ai TTS LLM增强器 batch_i2v.mjs ffmpeg-recipes.md
1080x1920真PNG SDK/CLI enhance_prompts.py speed/quality SRT生成+烧录
项目结构
reborn/
├── config.json # 剧目配置(角色、风格、分辨率)
├── SKILL.md # 核心技能知识库
├── pipeline.sh # 统一流水线入口(preview/quality双模式)
├── batch_i2v.mjs # 批量图生视频(speed/quality双模式)
├── deliver_episode.py # 标准化交付检查+自动合成
├── scripts/
│ ├── enhance_prompts.py # Motion Prompt LLM增强器
│ ├── generate_srt.py # SRT字幕生成(去角色名前缀,字幕提前0.2s)
│ ├── quality_check.py # 质量检查
│ ├── bible.md # 剧集圣经(人物/世界观)
│ ├── outline.md # 总大纲
│ └── ep01~ep03.md # 分集剧本
├── prompts/
│ └── {ep}/
│ ├── scenes.json # 场景prompt+dialogue数据
│ ├── scenes_enhanced.json # LLM增强后的prompt
│ └── sc01~sc18.json # 单场景独立文件
├── images/
│ ├── {ep}/sc01~sc18.png # 原始生成图片
│ └── {ep}_png/sc01~sc18.png # 真PNG 1080x1920(PIL转换后)
├── audio/
│ └── {ep}/
│ ├── e_sc01~sc18.mp3 # TTS音频
│ └── aligned/{ep}.srt # 生成的SRT字幕
├── videos/
│ └── {ep}_i2v/sc01~sc18.mp4 # 图生视频片段
├── skills/
│ └── ffmpeg-recipes.md # FFmpeg命令参考文档(外置)
├── references/ # 角色参考图
└── subtitles/ # SRT字幕文件
阶段 1:分镜图生成
使用 z-ai-generate CLI 生成分镜图,必须输出 1080x1920 竖屏:
# 生成图片(先用支持的尺寸)
z-ai-generate -p "PROMPT" -o output.png -s 1080x1344
# 转为1080x1920真PNG(关键步骤!)
python3 -c "
from PIL import Image
img = Image.open('output.png').resize((1080, 1920), Image.LANCZOS)
img.save('output.png', format='PNG')
print(f'Mode={img.mode} Format=PNG Size={img.size}')
"
Prompt 构成:角色外观(参考 config.json characters) + 场景环境 + 光影氛围 + 镜头语言 + 风格限定。config.json 结构示例:
{
"project": "短剧名称",
"resolution": "1080x1920",
"characters": [
{ "name": "角色名", "description": "外观描述", "traits": ["特征"], "reference_image": "references/角色图.png" }
]
}
批量转换整集 18 张:
python3 -c "
from PIL import Image, glob, os
for f in sorted(glob.glob('images/epXX/sc*.png')):
img = Image.open(f).resize((1080, 1920), Image.LANCZOS)
img.save(f, format='PNG')
print(f'{os.path.basename(f)}: 1080x1920 PNG OK')
"
可用生成尺寸:1024x1024 | 768x1344 | 1344x768 | 864x1152 | 1152x864 | 1440x720 | 720x1440
> 推荐尺寸:768x1344 → PIL 转为 1080x1920(竖屏),或直接用 864x1152 / 720x1440
429 限流处理:触发后等待 5-10 分钟冷却,串行生成每张间隔 10s+。
阶段 2:TTS 配音
使用 z-ai TTS SDK 生成:
const zai = await ZAI.create();
const response = await zai.audio.tts.create({
input: dialogue,
voice: 'xiaochen', // 男声
// voice: 'tongtong', // 女声
speed: 1.0,
response_format: 'wav',
stream: false
});
// WAV → MP3 转换
// ffmpeg -y -i input.wav -c:a libmp3lame -q:a 4 output.mp3
无台词场景:用 ffmpeg 生成静音占位:
ffmpeg -y -f lavfi -i anullsrc=r=24000:cl=mono -t 3 -c:a libmp3lame -q:a 9 silent.mp3
注意:TTS 和视频 API 是独立限流桶,互不影响。
阶段 3:Motion Prompt 增强
3.1 LLM 自动增强器(核心改进)
使用 LLM 将简短的画面描述增强为符合视频模型最佳实践的 motion prompt:
python3 scripts/enhance_prompts.py --ep EP03
python3 scripts/enhance_prompts.py --ep EP03 --dry-run # 预览不写文件
python3 scripts/enhance_prompts.py --ep EP03 --local-only # 仅用本地规则
增强原则:
- 保留原始画面核心元素(人物外观、场景、服装、道具)
- 添加 2-3 个具体镜头运动(slow dolly in, gentle pan left, subtle zoom out)
- 补充 1-2 个动态元素(灯光摇曳、衣角飘动、水波荡漾、烛光闪烁)
- 有台词时让角色表情与情绪匹配
- 结合台词情绪调整氛围(愤怒→光影更硬,温柔→光影更柔)
- 控制在 80-150 个英文单词
- 末尾固定添加:cinematic, smooth motion, 8k
- API 不可用时自动降级为本地规则增强
输出:prompts/{ep}/scenes_enhanced.json,在原 scenes.json 基础上添加 motion_prompt 字段。
阶段 4:图生视频
4.1 CLI 方式
z-ai video -i IMAGE.png -p "MOTION_PROMPT" -d 5 --poll -o result.json
4.2 SDK 方式(推荐,支持重试和状态管理)
const client = await ZAI.create();
const task = await client.video.generations.create({
prompt: motionPrompt,
image_url: imagePath, // 本地文件路径或base64 data URL
duration: 5
});
// 轮询结果
const result = await client.async.result.query(task.id);
4.3 速度/质量双模式(核心改进)
| 模式 | 参数 | 间隔 | 重试 | 适用场景 |
|---|---|---|---|---|
| speed | -q speed -d 5 |
60s | 4次 | 调试、检查镜头、快速预览 |
| quality | -q quality -d 5 --fps 30 |
90s | 8次 | 最终交付 |
4.4 批量生成脚本
# 批量生成(speed模式)
bun run batch_i2v.mjs --episode ep03 --mode speed
# 批量生成(quality模式)
bun run batch_i2v.mjs --episode ep03 --mode quality
# 指定场景
bun run batch_i2v.mjs --episode ep03 --mode speed --scenes sc01 sc02 sc03
# 限制数量
bun run batch_i2v.mjs --episode ep03 --mode speed --max 4
# 使用增强后的prompt
bun run batch_i2v.mjs --episode ep03 --mode quality --enhanced
batch_i2v.mjs 特性:
- 自动跳过已生成的场景(>50KB 视频文件)
- 429 限流时立即停止,等下次 cron 继续
- 1210 参数错误(假 PNG)不重试,直接标记失败
- 指数退避重试(30s → 60s → 120s → 300s)
- 全部完成后自动触发合成脚本
阶段 5:FFmpeg 合成
> 详细的 FFmpeg 命令模板参见外置文档 skills/ffmpeg-recipes.md(核心改进:文档外置)
5.1 视频片段按音频时长对齐
ADUR=$(ffprobe -v quiet -show_entries format=duration -of csv=p=0 audio.mp3)
ffmpeg -y -stream_loop -1 -i video.mp4 -i audio.mp3 \
-t "$ADUR" -c:v libx264 -c:a aac -shortest \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2,fps=30" \
-preset fast -crf 22 \
segment.mp4
关键参数:
- -stream_loop -1:视频循环播放匹配音频时长
- -shortest:以音频时长为准截断
- scale+pad:强制 1080x1920,不足部分黑边填充
- fps=30:统一帧率,避免 concat 兼容问题
5.2 片段拼接
# 生成 concat 列表
for i in $(seq 1 18); do
sc=$(printf "sc%02d" $i)
[ -f "${sc}_seg.mp4" ] && echo "file '${sc}_seg.mp4'" >> concat.txt
done
# concat demuxer(不重新编码)
ffmpeg -y -f concat -safe 0 -i concat.txt -c copy raw.mp4
5.3 字幕烧录
ffmpeg -y -i raw.mp4 \
-vf "subtitles='ep03.srt':force_style='FontSize=20,PrimaryColour=&HFFFFFF&,OutlineColour=&H000000&,Outline=2,MarginV=50'" \
-c:a copy output.mp4
5.4 GPU 加速(如可用)
ffmpeg -encoders 2>/dev/null | grep nvenc # 检测
ffmpeg -y -hwaccel cuda -i input.mp4 -c:v h264_nvenc -preset p4 -cq 23 -c:a aac output.mp4
阶段 6:SRT 字幕生成
python3 scripts/generate_srt.py \
--audio-dir audio/ep03 \
--scenes-json prompts/ep03/scenes.json \
--output audio/ep03/aligned/ep03.srt
逻辑:逐场景获取 mp3 时长,累加时间轴,台词作为字幕文本。自动去除角色名前缀。
阶段 7:标准化交付(核心改进)
7.1 交付检查脚本
# 完整检查 + 自动合成
python3 deliver_episode.py --episode ep03
# 仅检查不合成
python3 deliver_episode.py --episode ep03 --check-only
检查项:
- 图片:18/18 是否存在,是否真 PNG(file 命令检测 PNG image data)
- 音频:18/18 是否存在,真 TTS vs 静音占位(区分逻辑:(sz<6000 and dur>=2.5) or (5200<sz<5500))
- 视频:18/18 是否存在,是否 >50KB,ffprobe 检查是否损坏
- 字幕:自动生成 SRT
输出:
- 控制台打印检查报告
- videos/{ep}_report.json 结构化报告
- 全部就绪后自动触发 assemble_{ep}.sh 合成
7.2 统一流水线入口
# 高质量模式(默认)
bash pipeline.sh EP03 quality
# 快速预览模式
bash pipeline.sh EP03 preview
pipeline.sh 流程:
1. 前置检查(图片/音频/视频数量)
2. 图片格式验证与自动修复(PIL 转 1080x1920 真 PNG)
3. API 可用性测试(TTS + Video 独立检测)
4. 补全缺失 TTS
5. 批量图生视频(每 cron 最多 4 个)
6. 生成 SRT 字幕
7. FFmpeg 合成(片段对齐 → concat → 字幕烧录)
8. 质量检查(文件大小、时长、视频/音频流)
preview vs quality 模式差异:
| 项目 | preview | quality |
|---|---|---|
| 视频生成 | -q speed |
-q quality --fps 30 |
| 编码 | libx264, CRF 28, veryfast | libx264, CRF 20, medium |
| GPU | 不使用 | 自动检测 NVENC |
7.3 交付命名规范
输出到 /home/z/my-project/download/,命名:
{剧名}_EP{编号}_{模式}版.mp4
常见错误与修复
| 错误 | 原因 | 修复 |
|---|---|---|
| 1210 参数错误 | 图片非真 PNG(JPEG 改扩展名)或尺寸非 1080x1920 | PIL.resize((1080,1920)).save(format='PNG') |
| 429 限流 | API 请求过频 | 指数退避重试,等 cron 继续下一批 |
| concat 音画不同步 | 片段编码参数不一致 | 统一 libx264 + aac + fps 30 |
| 字幕乱码 | SRT 文件非 UTF-8 | iconv -f GBK -t UTF-8 |
| 视频黑边 | 原图比例非 9:16 | scale+pad 强制 1080x1920 |
| 静音误判 | 极短真 TTS(如"到了。"0.65s/4KB)被误判为静音 | 调整判断逻辑为 (sz<6000 and dur>=2.5) or (5200<sz<5500) |
踩坑备忘
- 真 PNG 是硬性要求:
z-ai-generate输出可能是 JPEG 内核仅改扩展名,视频 API 会返回 1210。必须用 PIL 检测img.format并重新save(format='PNG')。 - 视频 API 和 TTS 独立限流:TTS 恢复正常不代表视频 API 也恢复。两个 API 各自维护限流计数器,需分别检测。
- 429 时立即停止:不要继续重试,直接等下次 cron。指数退避最多到 5 分钟(300s),超过就放弃本轮。
- Ken Burns 禁止作为主力:用户明确禁止 zoompan 作为主要视频来源,仅在 AI 图生视频完全失败时作为 fallback。
- Motion Prompt 质量决定视频质量:简短的描述性 prompt 产出静态感视频,增强后的 prompt(含镜头运动+动态元素)产出明显更好的效果。
- concat 前统一编码参数:所有片段必须 libx264 + aac + 30fps,否则 concat demuxer 会出现音画不同步或播放器兼容问题。
- 竖屏字幕 MarginV=50:手机播放时底部有 UI 遮挡,字幕底边距需设 50-60。
效率参考
| 步骤 | 单场景耗时 | 备注 |
|---|---|---|
| 分镜图生成 | ~15s | 含 429 等待 |
| TTS 配音 | ~3s | 极快 |
| Motion Prompt 增强 | ~5s/场景 | LLM API |
| 图生视频(speed) | ~60s+等待 | 含轮询 |
| 图生视频(quality) | ~90s+等待 | 含轮询 |
| FFmpeg 合成(18场景) | ~3min | CPU |
| 单集总计(speed) | ~30-40min | 不含 429 等待 |
| 单集总计(quality) | ~60-90min | 不含 429 等待 |