目标:跑通一条多模态内容生产管线——输入一部电影,输出一条带配音、字幕、封面的全自动粗剪解说视频。定位是技术项目而非内容运营,验收标准是管线能力,不是播放量。
1
素材获取 → 转录对齐 → 结构化拉片 → LLM文案 → TTS配音 → 音画对轴粗剪 → 字幕/封面 → 发布
原则:每个环节先找现成方案,只对”没有好轮子”的环节动手写——真正值得写的是结构化拉片和音画对轴两段,其余全部用轮子。
| 阶段 | 产出 | 预估(每周 8h) |
|---|---|---|
| M1 | 电影 → 带时间戳的场景索引 JSON | 2-3 周 |
| M2 | 场景索引 + 片型模板 → 带画面引用的解说词 | 2 周 |
| M3 | TTS + 对轴合成 → 第一条全自动粗剪视频 | 4-6 周 |
| M4 | 端到端跑通,出 3-5 条 | 持续 |
1
2
3
4
5
# Python 3.10+,建议独立 venv
pip install faster-whisper scenedetect[opencv] edge-tts pydantic moviepy
# ffmpeg 必须在 PATH 中(转录、抽帧、合成全靠它)
# LLM 用 API 调用,TTS 用 edge-tts(免费)起步
项目结构建议:
1
2
3
4
5
6
7
8
9
10
movie-pipeline/
├── cli.py # 命令行入口,串联各阶段
├── stage1_transcribe/ # 转录 + 镜头切分
├── stage2_index/ # 场景索引(LLM)
├── stage3_script/ # 文案生成(LLM + 模板)
├── stage4_tts/ # 配音
├── stage5_assemble/ # 音画对轴 + 合成
├── templates/ # 片型文案模板(惊悚/喜剧/爱情)
├── schemas/ # pydantic 模型
└── output/ # 各阶段中间产物,全部落盘可复跑
中间产物全部 JSON 落盘是关键设计:每个阶段可以单独重跑、人工检查、跳过重试,LLM 失败不用从头再来。
1
yt-dlp -f "bv*[height<=1080]+ba" -o "input.mp4" <URL>
不自动化这一段。人工下载、人工确认版权风险,管线只管处理已到位的文件。
faster-whisper 本地跑,输出逐句字幕 + 时间戳。SRT/JSON 是整条管线的骨架——每句台词、每个时间点都是后续 LLM 决策的坐标。
1
2
3
4
5
6
7
from faster-whisper import WhisperModel
model = WhisperModel("medium", device="auto", compute_type="int8")
segments, info = model.transcribe("input.mp4", language="zh", vad_filter=True)
for seg in segments:
print(seg.start, seg.end, seg.text) # → 落盘 transcript.json
镜头切分用 PySceneDetect(AdaptiveDetector 对电影更稳):
1
2
3
from scenedetect import detect, ContentDetector
scenes = detect("input.mp4", AdaptiveDetector()) # → 落盘 scenes.json
产出两份文件:transcript.json(句级时间戳)、scenes.json(镜头边界)。
合并逻辑:以镜头为容器,把时间上落入该镜头的字幕句挂进去;无字幕的镜头(纯动作戏)标 no_dialogue: true,M1 不深究视觉特征。
场景索引 JSON Schema:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"movie": "Fall 2",
"duration_sec": 5880,
"scenes": [
{
"id": 1,
"start_sec": 0,
"end_sec": 142,
"location": "塔顶平台",
"characters": ["Becky", "Hunter"],
"dialogue_summary": "两人登顶后自拍庆祝",
"emotion_intensity": 3,
"key_moment": false,
"cliffhanger": false
}
]
}
字段设计要点:emotion_intensity(1-5)供后续筛选高潮段落;key_moment 标记名场面;dialogue_summary 压缩对白信息量控制 token 成本。
LLM 提示词骨架:输入是合并后的场景序列(按 token 上限分批),要求做”结构化摘要”而非”剧情复述”——每场景输出固定字段,禁止自由发挥加形容词。分批处理时带前一批的场景 id 列表保持上下文连续性,最后本地合并,用 pydantic 校验 schema,不过则自动重试(同一输入最多 3 次,仍失败则该批标红人工介入)。
按片型注入不同模板(惊悚→悬念递进,喜剧→吐槽框架,爱情→情绪刀法),输入是场景索引,输出是自带画面引用的解说词:
1
2
3
4
5
6
7
8
9
10
{
"lines": [
{
"text": "600米高空,她们的手机掉下了塔底",
"ref": {"start_sec": 612, "end_sec": 625}
}
],
"hook": "前3秒钩子文案",
"title_candidates": ["标题A", "标题B", "标题C"]
}
画面引用是整条管线的枢纽——每句话标注该配哪段画面(引用场景 id + 起止秒),后面剪辑才能全自动。文案 prompt 中强制:每个 text 必须带合法 ref,ref 必须指向场景索引中存在的区间,pydantic 校验引用合法性,非法引用自动打回重写。
文案结构模板(解说词的”填表”框架):
1
钩子(前3秒)→ 主线剧情压缩(信息密度优先)→ 每个转折点抛新悬念 → 结尾留讨论点
1
2
3
4
import edge_tts
communicate = edge_tts.Communicate(解说词全文, "zh-CN-YunxiNeural")
await communicate.save("voiceover.mp3")
关键:逐句合成而非整篇合成,每句单独生成音频文件并记录实际时长——句子时长是对轴计算的输入,整篇合成拿不到句级时间点。
输入:解说词 + 画面引用 + 原片 + 句级音频。核心问题是每句话对应的画面时长 ≠ 句子音频时长,需要自动伸缩:
| 情况 | 策略 |
|---|---|
| 画面 > 语音 | 画面截取其中语音等长片段(优先保留动作起始帧) |
| 画面 < 语音 | 画面慢放至语音时长(0.8x-1.0x),或拼接相邻同场景镜头补足 |
| 两句引用同一段 | 第二句自动偏移引用区间的未使用部分 |
| 无可用画面 | 兜底:用前一句画面续播或黑屏字幕卡 |
工程实现:moviepy 组时间轴,ref 区间 → VideoFileClip.subclipped() → 按句级音频时长伸缩 → 逐句拼接 → 叠配音轨 + BGM(音量压低到 -18dB)。边界情况极多,接受”90% 自动 + 10% 人工精修”的定位,不为长尾情况过度设计。
字幕:从句级文案 + TTS 实际时长直接生成 SRT,ffmpeg 烧录:
1
ffmpeg -i out.mp4 -vf "subtitles=out.srt" -c:a copy final.mp4
封面:ffmpeg 在高潮时间点抽帧(emotion_intensity 最高的 key_moment)+ Pillow 排版模板(标题大字 + 顶部渐变遮罩)。
不自动化。平台无开放 API,模拟发布是风控高危区,手动发布 10 分钟的事。
按 Anthropic《Building Effective Agents》的区分:Workflow 是步骤固定、路径确定的流水线,LLM 只是其中某些步骤的”函数”;Agent 是由模型自己决定下一步调什么工具、何时结束。本管线 90% 的环节(转录、切分、TTS、对轴、字幕)是确定性的,只有环节 2/3 里有 LLM 决策——所以不要把整条管线做成 agent 自由发挥,让模型自己决定”接下来跑哪个环节”只会引入不稳定。
正确架构是三层:
1
2
3
4
5
6
7
8
┌─ 编排层(Agent)───────────────────────────────┐
│ Claude Code / Agent SDK 当 orchestrator │
│ 职责:调度各环节、处理失败重跑、人工审核点 │
├─ 环节层(Workflow,确定性)─────────────────────┤
│ stage1_transcribe → stage5_assemble,独立 CLI │
├─ 决策点(LLM,结构化输出)──────────────────────┤
│ 环节2 拉片 / 环节3 文案:schema 校验 + 重试循环 │
└─────────────────────────────────────────────────┘
引入 agent 的收益点是处理异常——某批拉片校验失败、ref 引用非法、对轴冲突需要选策略时才让 agent 决策,正常流程一律走 pipeline。”何时用 agent、何时不用”的判断力,本身就是这个项目要练的东西。
顺带地,这条管线几乎是教科书级的 agent harness 练手项目,各核心概念都有落点:
| Harness 概念 | 管线对应物 |
|---|---|
| 工具定义 | 每个 stage 独立 CLI 脚本,orchestrator 经 Bash 调用(进阶:包成 MCP 工具) |
| 上下文管理 | 环节 2 按 token 分批 + 只传 dialogue_summary 不传全文 |
| 校验-重试循环 | pydantic 校验不过自动打回重写——这就是最小 agent loop:输出→校验→回灌→再输出 |
| 权限 / human-in-the-loop | “标红人工介入”、M1/M2 产物人工检查点 |
| Checkpoints | 中间产物 JSON 落盘、单阶段可重跑 |
| 评测(evals) | 验收标准变成批量跑 + 打分脚本 |
编排的实施顺序:
cli.py 串联跑通 M1-M2,不引入 orchestrator(裸写阶段)while + pydantic + 消息回灌,不用框架cli.py