批量生成前,先把分镜表检查一遍:模型是否支持这个时长和画面比例、取值是否正确、提示词是否过长或动作太多、是否涉及肖像和商标授权。 这篇做
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 |
在表格里改一个数字,比浪费一次生成便宜得多。