AI 工具

PixVerse 批量生成前检查分镜表:校验时长、画幅与提示词

批量生成前,先把分镜表检查一遍:模型是否支持这个时长和画面比例、取值是否正确、提示词是否过长或动作太多、是否涉及肖像和商标授权。 这篇做 shotlist.py:把 CSV 分镜表转换成 PixVerse 文生视频请求体(plan.json),提交前发现问题,不花积分。

BINBHO · 图文教程

批量生成前,先把分镜表检查一遍:模型是否支持这个时长和画面比例、取值是否正确、提示词是否过长或动作太多、是否涉及肖像和商标授权。 这篇做 shotlist.py:把 CSV 分镜表转换成 PixVerse 文生视频请求体(plan.json),提交前发现问题,不花积分。

先看清成品

  • 6 个镜头中 2 个有错误(v5.6 不支持 6 秒;v5 不支持 21:9),4 个可以提交。
  • 提醒:大写取值已改为小写;一个镜头里动作太多;提示词含“明星”需要确认授权。
  • 发现并修复:错误提示“可选 5–10”会让人以为 6 秒可以。pytest 5 项通过。

合规提醒:只上传你有权使用的图片和视频;不生成真实人物的误导性内容,不做未经同意的换脸;发布时按平台规则标注 AI 生成;商用前确认所用套餐的授权范围(以 PixVerse 官方条款为准)。本文只使用 PixVerse 官方网页/App 和官方 API。API key 只放在服务端,不放进前端代码或日志。本文不列价格,积分消耗以控制台为准。

运行说明:本篇不调用 API,不花积分。规则来自 PixVerse 官方 Model Capability Map 和 Text-to-Video 接口页面(2026-10-21 查阅);账号实际可用的组合以控制台和接口返回为准。分镜表是我写的示例。

做完之后你会得到什么?

成果 说明
shotlist.py 检查分镜并生成 plan.json
shots.csv 6 个镜头的示例分镜
test_shotlist.py 5 项测试

需要准备哪些环境?

项目 说明
Python 3.9 以上,pip install pytest

关键事实

事实 来源
C1、V6:1~15 秒,支持 16:9 / 9:16 / 4:3 / 3:4 / 1:1 / 2:3 / 3:2 / 21:9 官方 Model Capability Map
V5.6:只支持 5 / 8 / 10 秒;V5:只支持 5 / 8 秒;这两个模型只支持 16:9 / 9:16 / 4:3 / 3:4 / 1:1 同上
quality 取值 360p / 540p / 720p / 1080p;prompt 最长 5000 字符 官方 Text-to-Video
能力、时长和分辨率还受账号权限影响,以接口页面为准 官方 Model Capability Map

文件结构

72-pixverse-B-src/
├── shotlist.py
├── shots.csv
└── test_shotlist.py

第 1 步:分镜表

shot,model,duration,quality,aspect_ratio,seed,prompt
1,v6,5,540p,16:9,12345,一只橘猫趴在窗台上晒太阳,尾巴轻轻摆动,窗外树叶随风晃动,镜头缓慢推近,暖色调
2,v5.6,6,720p,16:9,,咖啡从壶中缓缓倒入白色瓷杯,蒸汽上升,俯拍,自然光
3,v6,5,720p,21:9,,海边日落,海浪拍打礁石,镜头横移,电影感
4,v5,8,720p,21:9,,城市夜景延时摄影,车流光轨
5,V6,4,1080P,9:16,,一个人走进咖啡馆,然后点单,接着坐下打开电脑,之后开始打字
6,v6,5,720p,1:1,,某位明星在红毯上微笑挥手

第 2 步:检查脚本

"""把分镜表(CSV)检查一遍,再转成 PixVerse 文生视频请求体(plan.json),提交前就发现参数错误。
规则来自 PixVerse 官方 Model Capability Map 和 Text-to-Video 接口页面(2026-10-21 查阅);账号可用的组合以控制台和接口返回为准。
本脚本不调用 API、不花积分;提交请用 72A 的 pixverse_job.py。"""
import csv, json, re, sys

ASPECT_ALL = {"16:9", "9:16", "4:3", "3:4", "1:1", "2:3", "3:2", "21:9"}
ASPECT_5 = {"16:9", "9:16", "4:3", "3:4", "1:1"}
QUALITY = {"360p", "540p", "720p", "1080p"}
MODELS = {"c1": (set(range(1, 16)), ASPECT_ALL), "v6": (set(range(1, 16)), ASPECT_ALL),
          "v5.6": ({5, 8, 10}, ASPECT_5), "v5": ({5, 8}, ASPECT_5)}
RIGHTS = ["明星", "名人", "真人", "celebrity", "logo", "商标", "迪士尼", "disney", "marvel", "漫威"]   # 需要先确认授权的词(可自行补充)

def check_row(r):
    errs, warns = [], []
    m = r["model"].strip().lower(); d = r["duration"].strip(); q = r["quality"].strip().lower(); a = r["aspect_ratio"].strip(); p = r["prompt"].strip()
    if r["model"].strip() != m or r["quality"].strip() != q: warns.append(f"已改为小写:{m} / {q}(接口取值都是小写)")
    if m not in MODELS: errs.append(f"model {m!r} 不在 {sorted(MODELS)} 中")
    if not re.fullmatch(r"\d+", d): errs.append(f"duration {d!r} 必须是整数秒")
    elif m in MODELS and int(d) not in MODELS[m][0]:
        ok = sorted(MODELS[m][0])
        # 只有连续取值才写成范围;5/8/10 写成“5–10”会让人以为 6 也可以
        errs.append(f"{m} 不支持 {d} 秒(可选 {ok[0]}–{ok[-1]} 秒)" if m in ("c1", "v6") else f"{m} 不支持 {d} 秒(只能选 {'/'.join(map(str, ok))} 秒)")
    if q not in QUALITY: errs.append(f"quality {q!r} 不在 {sorted(QUALITY)} 中")
    if m in MODELS and a not in MODELS[m][1]: errs.append(f"{m} 不支持画面比例 {a}")
    if not p: errs.append("prompt 为空")
    if len(p) > 5000: errs.append(f"prompt {len(p)} 字,超过 5000")
    hit = [w for w in RIGHTS if w.lower() in p.lower()]
    if hit: warns.append(f"提示词含 {hit}:确认已取得肖像/商标授权,否则改写")
    if len(re.findall(r"然后|接着|之后|then", p)) >= 2: warns.append("一个镜头里动作太多,容易变形:拆成多个镜头")
    return errs, warns

def build(rows):
    plan, problems = [], []
    for i, r in enumerate(rows, 1):
        errs, warns = check_row(r); sid = r.get("shot") or str(i)
        problems += [(sid, "错误", e) for e in errs] + [(sid, "提醒", w) for w in warns]
        if not errs:
            body = {"model": r["model"].strip().lower(), "prompt": r["prompt"].strip(), "duration": int(r["duration"]),
                    "quality": r["quality"].strip().lower(), "aspect_ratio": r["aspect_ratio"].strip()}
            if r.get("seed", "").strip(): body["seed"] = int(r["seed"])
            plan.append({"shot": sid, "body": body})
    return plan, problems

def main(argv=None):
    argv = argv or sys.argv[1:]
    rows = list(csv.DictReader(open(argv[0], encoding="utf-8-sig")))
    plan, problems = build(rows)
    for sid, kind, msg in problems: print(f"镜头 {sid} [{kind}] {msg}")
    secs = sum(p["body"]["duration"] for p in plan)
    json.dump(plan, open("plan.json", "w", encoding="utf-8"), ensure_ascii=False, indent=1)
    print(f"{len(plan)}/{len(rows)} 个镜头可以提交,共 {secs} 秒;写入 plan.json(积分消耗以控制台显示为准)")
    return 1 if any(k == "错误" for _, k, _ in problems) else 0

if __name__ == "__main__":
    sys.exit(main())

第 3 步:测试

import csv, shotlist as S

ROWS = list(csv.DictReader(open("shots.csv", encoding="utf-8-sig")))

def test_plan():
    plan, probs = S.build(ROWS)
    assert [p["shot"] for p in plan] == ["1", "3", "5", "6"]
    assert plan[0]["body"] == {"model": "v6", "prompt": ROWS[0]["prompt"], "duration": 5, "quality": "540p", "aspect_ratio": "16:9", "seed": 12345}
    assert plan[2]["body"]["quality"] == "1080p" and plan[2]["body"]["model"] == "v6"

def test_discrete_durations_message():
    # 调试时发现:旧提示“可选 5–10”会让人以为 6 秒也可以
    e, _ = S.check_row(ROWS[1])
    assert e == ["v5.6 不支持 6 秒(只能选 5/8/10 秒)"]
    e, _ = S.check_row(dict(ROWS[0], duration="16"))
    assert e == ["v6 不支持 16 秒(可选 1–15 秒)"]

def test_aspect_per_model():
    assert S.check_row(ROWS[2])[0] == [] and S.check_row(ROWS[3])[0] == ["v5 不支持画面比例 21:9"]

def test_warnings():
    _, w5 = S.check_row(ROWS[4]); _, w6 = S.check_row(ROWS[5])
    assert any("已改为小写" in w for w in w5) and any("动作太多" in w for w in w5)
    assert any("授权" in w for w in w6)

def test_prompt_limit():
    assert S.check_row(dict(ROWS[0], prompt="猫" * 5001))[0] == ["prompt 5001 字,超过 5000"]

第 4 步:提交

检查通过后,用 72A 的 pixverse_job.py 逐条提交 plan.json 中的请求;在网页版中也可以按 plan.json 的参数手动生成。

第 5 步:运行

$ python shotlist.py shots.csv
镜头 2 [错误] v5.6 不支持 6 秒(只能选 5/8/10 秒)
镜头 4 [错误] v5 不支持画面比例 21:9
镜头 5 [提醒] 已改为小写:v6 / 1080p(接口取值都是小写)
镜头 5 [提醒] 一个镜头里动作太多,容易变形:拆成多个镜头
镜头 6 [提醒] 提示词含 ['明星']:确认已取得肖像/商标授权,否则改写
4/6 个镜头可以提交,共 19 秒;写入 plan.json(积分消耗以控制台显示为准)
$ python -m pytest -q
5 passed

怎么检查结果?

  • 有“错误”时退出码为 1,可以接在提交脚本之前。
  • “提醒”不阻止提交,但要人工确认,尤其是授权类提醒。
  • 积分消耗以控制台显示为准,脚本只统计总秒数。

调试示例

范围写法误导。 第一版对不支持的时长统一提示“可选 最小–最大”。v5.6 的镜头写了 6 秒,提示是:

镜头 2 [错误] v5.6 不支持 6 秒(可选 5–10:[5, 8, 10])

6 明明在“5–10”之间,提示自相矛盾。修复:C1、V6 是连续取值,显示范围;V5.6、V5 是离散取值,只列出可选值(“只能选 5/8/10 秒”)。

另外,第一版把模型名 V6 静默转成小写,但 1080P 却报错,处理不一致。现在两者都转为小写,并给出提醒。

常见问题

现象 原因 处理
全部报 model 错误 模型名写成了网页版的显示名 使用接口中的取值,例如 v6、v5.6
授权提醒太多 词表太宽 按需要修改 RIGHTS 列表
接口仍然报参数错误 账号没有某项能力权限 以接口返回为准,联系 PixVerse

模板规则

  • 提交前先检查分镜表。
  • 授权类提醒必须人工确认。
  • 规则表要随官方文档更新。

项目资源

用途 地址
PixVerse 官网 https://pixverse.ai/
PixVerse API:Start Here(官方) https://docs.platform.pixverse.ai/start-here-2394989m0
PixVerse API:错误码(官方) https://docs.platform.pixverse.ai/error-codes-2394992m0
PixVerse API:Model Capability Map(官方) https://docs.platform.pixverse.ai/model-capability-map-2394982m0
PixVerse API:Text-to-Video(官方) https://docs.platform.pixverse.ai/text-to-video-13016634e0

在表格里改一个数字,比浪费一次生成便宜得多。