生成数字人视频前,先检查脚本长度、标题,并拦截常见冒充/转账诱导等模式。这篇
script_guard.py是预检,不是平台审核的替代。
先看清成品
- 培训样例 OK;冒充转账样例 FINDINGS。
- 3 项 pytest 通过。
合规提醒:定制以真人为原型的数字人必须取得本人同意,并按平台完成身份验证;不得用数字人冒充他人、从事欺诈或未披露的政治宣传。Video API 通常需 Pro 及以上(以官网为准);
test: true有水印且有每日测试限额。本文不编造价格与配额数字(除文档已写明的测试限额提示外,以你控制台为准)。
运行说明:无 Synthesia 正式密钥。A/C 本地合规检查;B 用 mock 创建+轮询到 complete。对官方主机无效 Authorization 实测 HTTP 403。2026-10-23(Asia/Shanghai)pytest 通过。
做完之后你会得到什么?
| 成果 | 说明 |
|---|---|
script_guard.py |
脚本预检 |
| 样例 txt | ok/bad |
test_100a.py |
测试 |
需要准备哪些环境?
| 项目 | 说明 |
|---|---|
| Python | 3.10+ |
关键事实
| 事实 | 来源 |
|---|---|
创建视频可把旁白放在 scriptText(Quickstart)或更丰富的 input 多场景 |
官方 Create / Quickstart |
test: true 不计入配额但有水印;文档提及测试日限额 |
官方 Video API / Quickstart |
| 内容可能被审核拒绝(status=rejected) | 官方 Videos 对象说明 |
文件结构
100-synthesia-A-src/
├── script_guard.py
├── sample_ok.txt
├── sample_bad.txt
└── test_100a.py
第 1 步:预检脚本
#!/usr/bin/env python3
"""Pre-flight checks for Synthesia avatar video scripts."""
from __future__ import annotations
import argparse
import json
import re
from pathlib import Path
# Soft practical limits for tutorial (not official hard caps).
MAX_CHARS = 5000
MIN_CHARS = 10
BANNED = [
r"我是\s*(总统|总理|CEO\s*本人)",
r"冒充",
r"deepfake",
r"未经授权",
r"transfer\s+all\s+your\s+money",
r"转账到此账户",
]
def check(script: str, *, title: str = "", test_mode: bool = True) -> list[str]:
errs = []
s = script.strip()
if len(s) < MIN_CHARS:
errs.append(f"脚本过短(<{MIN_CHARS})")
if len(s) > MAX_CHARS:
errs.append(f"脚本过长(>{MAX_CHARS}),建议拆成多场景 input[]")
if not title.strip():
errs.append("title 建议填写,便于分享页与检索")
for pat in BANNED:
if re.search(pat, s, re.I):
errs.append(f"命中风险模式: {pat}")
if re.search(r"https?://\S+", s) and "点击链接" in s:
errs.append("脚本含链接+诱导点击,注意钓鱼风险审核")
if not test_mode:
errs.append("提醒: test=false 会计入配额;教程默认建议先 test=true")
# blank-line scenes hint
if s.count("\n\n") >= 8 and len(s) > 1500:
errs.append("长脚本场景很多:考虑 API input 多 clip 而不是单 scriptText")
return errs
def main(argv=None) -> int:
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("script_file")
ap.add_argument("--title", default="Untitled")
ap.add_argument("--production", action="store_true", help="声明非 test 模式")
ap.add_argument("--json", action="store_true")
args = ap.parse_args(argv)
text = Path(args.script_file).read_text(encoding="utf-8")
errs = check(text, title=args.title, test_mode=not args.production)
# filter soft reminder when --production intentionally set
if args.production:
errs = [e for e in errs if not e.startswith("提醒: test=false")]
payload = {
"ok": not errs,
"chars": len(text.strip()),
"title": args.title,
"test_mode_recommended": not args.production,
"findings": errs,
}
if args.json:
print(json.dumps(payload, ensure_ascii=False, indent=2))
else:
print("OK" if not errs else "FINDINGS")
for e in errs:
print("-", e)
print(f"chars={payload['chars']}")
return 1 if errs else 0
if __name__ == "__main__":
raise SystemExit(main())
第 2 步:测试
from pathlib import Path
import subprocess
import sys
from script_guard import check
HERE = Path(__file__).resolve().parent
def test_ok():
t = (HERE / "sample_ok.txt").read_text()
assert check(t, title="安全培训", test_mode=True) == []
def test_bad():
t = (HERE / "sample_bad.txt").read_text()
errs = check(t, title="x", test_mode=True)
assert errs
def test_cli():
r = subprocess.run(
[
sys.executable,
str(HERE / "script_guard.py"),
str(HERE / "sample_ok.txt"),
"--title",
"安全培训",
],
capture_output=True,
text=True,
)
assert r.returncode == 0
第 3 步:运行
OK
chars=81
FINDINGS
- 命中风险模式: 我是\s*(总统|总理|CEO\s*本人)
- 命中风险模式: 转账到此账户
- 脚本含链接+诱导点击,注意钓鱼风险审核
chars=45
... [100%]
3 passed in 0.03s
怎么检查结果?
- 生产脚本仍需走平台审核与人工审阅。
- 长培训稿考虑拆成多 clip。
调试示例
预检通过 ≠ 平台通过。 Synthesia 仍可能 rejected。把 guard 当第一道闸,保留人工与法务闸。
常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
| 字数上限 | 教程软限制 | 以你账号与文档为准 |
| 多语言 | 脚本语言与配音匹配 | 在产品里选 voice |
| 要 SSML | 视套餐/端点 | 先查当前文档 |
模板规则
- 禁止冒充与欺诈脚本。
- 先 test 再生产。
- 定制形象必须授权。
项目资源
| 用途 | 地址 |
|---|---|
| API Quickstart(官方) | https://docs.synthesia.io/reference/synthesia-api-quickstart |
| Create a video(官方) | https://docs.synthesia.io/reference/create-video |
| Synthesia 官网 | https://www.synthesia.io/ |
脚本过关,再消耗生成配额。