小二爱编程·头像
关注
用 Codex 从零搭一套 AI 短视频流水线:提示词 + 批量脚本 + 真实踩坑封面图

用 Codex 从零搭一套 AI 短视频流水线:提示词 + 批量脚本 + 真实踩坑

单人日产 10-14 条、单条 3-6 分钟、风格还不飘。提示词、配音、合成、批处理四段全公开,代码复制就能跑。

一、先给结论:三条路线我全跑过

2026 年用 AI 做短视频早就不稀奇了。真正卡住人的地方已经变了——不是"能不能生成",而是"能不能日产 10 条以上、风格还不飘"。

一周时间,三条路线,单人实测均值:

方案单条耗时日产量(单人)风格一致性成本可控性上手难度推荐指数
纯在线工具(可灵 / 即梦等)8-15 分钟4-6 条★★★
纯 ComfyUI 本地10-20 分钟3-5 条极高★★★★
Codex + 本地工具链3-6 分钟10-14 条极低★★★★★

三条都趟过,说几句实话:

  1. 纯在线工具上手最快,但它是黑盒。同一个提示词,今天出冷调、明天出暖调,做系列号必翻车。
  2. ComfyUI 一致性最好,但环境能把人劝退——装一天、报错两天是常态。
  3. Codex + 本地工具链是我最后留下的方案:把胶水代码、批处理脚本交给 Codex 写,人只负责定风格和抽检。

下面就是第三种路线拆开后的全部内容。

二、四步跑通

先定目录结构,后面代码都按这个放:

ai-shorts/
├── prompts/       # 提示词模板
├── scripts/       # narration.txt,每行一条旁白
├── videos/        # 分镜视频(务必英文路径)
├── audios/        # 配音音频
├── output/        # 合成成片
├── tts_batch.py
├── merge_batch.py
└── main.py

2.1 提示词:把「风格锚点」写死

整套流程里最值钱的一步。风格漂移的根因,90% 就出在提示词每次都不一样。

直接复制下面这段:

你是一位有 5 年以上短视频实战经验的导演兼爆款文案写手。
请严格按以下格式输出,不要添加任何额外解释。

主题:程序员深夜改 Bug 的真实日常
目标时长:50 秒
目标受众:25-35 岁程序员与打工人
风格要求:真实、有共鸣、微幽默,杜绝鸡汤和 AI 味

【旁白文案】
(口语化;前 3 秒必须强钩子;总字数 170-190 字;长句短句交替)

【分镜表】
镜头 1(0-8 秒):
- 画面描述:
- 镜头运动:
- 文生视频关键词(必须包含统一风格前缀「电影感,冷色调,真实光影,浅景深,禁止人物变形」):
- 字幕重点:

镜头 2(8-16 秒):
...
(按时间顺序继续到结束)

【BGM 建议】
【整体色调关键词】

关键就一句话:「统一风格前缀」这个字段每次都要一字不改地带上,它是抗漂移的锚点。改主题可以,改锚点不行。

2.2 配音批处理(Edge-TTS)

先装依赖:

pip install edge-tts
# tts_batch.py
import asyncio
from pathlib import Path

import edge_tts

# 旁白推荐云希(偏年轻)或晓晓(偏亲和);
# 云扬是新闻腔,别用在短视频里,一听就"官方"
VOICE = "zh-CN-YunxiNeural"
RATE = "+8%"        # 比默认语速稍快,完播率会更好
OUT_DIR = Path("audios")


async def generate_voices(texts: list[str], out_dir: Path = OUT_DIR,
                          voice: str = VOICE, rate: str = RATE) -> None:
    out_dir.mkdir(parents=True, exist_ok=True)

    for i, text in enumerate(texts, 1):
        output_file = out_dir / f"narration_{i:03d}.mp3"

        # 偶发的 403 / 空文件,重试两次基本就过
        for attempt in range(3):
            try:
                communicate = edge_tts.Communicate(text, voice, rate=rate)
                await communicate.save(str(output_file))
                break
            except Exception as exc:
                if attempt == 2:
                    raise
                print(f"第 {i} 条失败({exc}),1.5s 后重试")
                await asyncio.sleep(1.5)

        print(f"已生成:{output_file}")
        await asyncio.sleep(0.5)     # 串行 + 间隔,避免被限流


if __name__ == "__main__":
    texts = [
        "凌晨两点,屏幕上的红字还在跳。",
        "你以为改完这个 Bug 就能睡了?太天真了。",
    ]
    asyncio.run(generate_voices(texts))

文件名用 narration_001.mp3 这种三位补零的格式,是为了后面排序时不会出现 10 排在 2 前面。

2.3 视频合成:先标准化,再批量合并

这一步 80% 的翻车都不是 ffmpeg 的锅,是素材本身不统一。 先做一次标准化(竖屏 1080×1920 / 25fps / 44100Hz):

ffmpeg -i raw.mp4 \
  -r 25 \
  -vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2" \
  -c:v libx264 -pix_fmt yuv420p -crf 20 \
  -c:a aac -ar 44100 -b:a 192k \
  videos/std_001.mp4

再批量合并:

# merge_batch.py
import subprocess
from pathlib import Path


def batch_merge(video_dir: str, audio_dir: str, output_dir: str,
                dry_run: bool = False) -> None:
    video_dir, audio_dir, output_dir = map(Path, (video_dir, audio_dir, output_dir))
    output_dir.mkdir(parents=True, exist_ok=True)

    videos = sorted(video_dir.glob("*.mp4"))
    audios = sorted(audio_dir.glob("*.mp3"))

    # 数量不一致时别硬跑,否则音画会整条错位
    if len(videos) != len(audios):
        raise ValueError(f"数量不匹配:视频 {len(videos)} 个 / 音频 {len(audios)} 个")

    for i, (video, audio) in enumerate(zip(videos, audios), 1):
        output = output_dir / f"final_{i:03d}.mp4"
        cmd = [
            "ffmpeg", "-y",
            "-i", str(video),
            "-i", str(audio),
            "-c:v", "copy",
            "-c:a", "aac", "-b:a", "192k", "-ar", "44100",
            "-shortest",
            "-movflags", "+faststart",
            str(output),
        ]

        if dry_run:
            print(" ".join(cmd))
            continue

        subprocess.run(cmd, check=True,
                       stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
        print(f"合成完成:{output}")


if __name__ == "__main__":
    batch_merge("videos", "audios", "output")

-c:v copy 不重编码,秒出;-shortest 让成片以较短的一轨为准,避免尾部黑屏;+faststart 让平台侧边加载边播。

2.4 一条命令串完全流程

# main.py
import argparse
import asyncio
from pathlib import Path

from merge_batch import batch_merge
from tts_batch import generate_voices

ROOT = Path(__file__).parent


def load_scripts(path: Path) -> list[str]:
    return [ln.strip() for ln in path.read_text("utf-8").splitlines() if ln.strip()]


def main() -> None:
    parser = argparse.ArgumentParser(description="AI 短视频流水线")
    parser.add_argument("--scripts", default=str(ROOT / "scripts/narration.txt"),
                        help="每行一条旁白文案")
    parser.add_argument("--skip-tts", action="store_true", help="跳过配音,只做合成")
    args = parser.parse_args()

    if not args.skip_tts:
        asyncio.run(generate_voices(load_scripts(Path(args.scripts))))

    batch_merge(ROOT / "videos", ROOT / "audios", ROOT / "output")


if __name__ == "__main__":
    main()

之后每天只做两件事:往 narration.txt 里贴文案,把生成好的分镜丢进 videos/,然后 python main.py

三、高频踩坑与解决方案

1. 风格严重漂移

  • 原因:关键词没有强制统一风格前缀,每次描述都是"新的一版"。
  • 解决:固定前缀一字不改,并且每批成品人工抽检 3 条——抽检不是为了改,是为了及早发现锚点失效。

2. 口型对不齐 / 音画不同步

  • 原因:音频采样率和视频帧率不匹配(44.1k vs 48k、24fps vs 25fps 混着来)。
  • 解决:全链路统一 44100Hz + 25fps,在 2.3 的标准化命令里一次做掉。

3. 批量处理时 FFmpeg 随机失败

  • 原因:路径含中文、并发过高、某些源的编码不兼容。
  • 解决:全英文路径 + 串行执行;-c:v copy 报错的那一条,单独改成重编码试试:
ffmpeg -y -i bad.mp4 -i bad.mp3 \
  -c:v libx264 -pix_fmt yuv420p -c:a aac -shortest fixed.mp4

4. 完播率低

  • 原因:前 3 秒钩子太弱,节奏拖沓。
  • 解决:在提示词里就写死"前 3 秒必须出现冲突或强烈共鸣点"。节奏问题要在文案阶段解决,剪辑阶段只能补救。

5. Edge-TTS 偶发空文件 / 403

  • 原因:短时间请求过密被限流。
  • 解决:串行生成 + 每条间隔 0.5s + 失败重试(2.2 的代码里已经带上了)。

四、真实效率数据

跑通之后的实际数字:

  • 单人稳定日产 10-14 条可直接发布的视频;
  • 单条均摊 3-6 分钟,其中人工只占 1 分钟左右;
  • 综合效率比纯在线工具提升约 2.5 倍,边际成本接近为零。

一句话总结:这套流程的价值不在"生成",在于把不可控的创意劳动,变成了可控的工业流程。


转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/weixin_52208686/article/details/166130930

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--