Documentation Index
Fetch the complete documentation index at: https://docs.apiyi.com/llms.txt
Use this file to discover all available pages before exploring further.
VEO 3.1 视频生成 — 新人接入说明
面向第一次接入的开发者,5 分钟跑通最小可用 demo,然后扩展到生产。
1. 准备
- 注册 / 拿到 apiyi 的 token,形如
sk-xxxxxxxx
- 设置环境变量
export BASE_URL="https://api.apiyi.com"
export API_TOKEN="sk-xxxxxxxx"
- 模型只有两个(按次计费,详见第 6 节):
veo-3.1-fast-generate-preview — 便宜,$0.3 / 次
veo-3.1-generate-preview — 标准,质感更好,$1.2 / 次
说明:接口走 OpenAI 兼容风格(Bearer 鉴权 + JSON / multipart),new-api 渠道类型选 openai。
2. 30 秒跑通(curl)
# 创建任务
RESP=$(curl -sS -X POST "$BASE_URL/v1/videos" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "veo-3.1-fast-generate-preview",
"prompt": "黄昏海边的灯塔,镜头缓慢推进,海浪轻拍礁石,电影级光影",
"duration": "4",
"size": "1280x720",
"metadata": {"resolution": "720p", "aspectRatio": "16:9"}
}')
TASK_ID=$(echo "$RESP" | python3 -c 'import sys,json;print(json.load(sys.stdin)["task_id"])')
echo "task_id=$TASK_ID"
# 轮询
while :; do
S=$(curl -sS -H "Authorization: Bearer $API_TOKEN" "$BASE_URL/v1/videos/$TASK_ID")
ST=$(echo "$S" | python3 -c 'import sys,json;print(json.load(sys.stdin)["status"])')
echo "status=$ST"
[ "$ST" = "completed" ] && break
[ "$ST" = "failed" ] && { echo "$S"; exit 1; }
sleep 8
done
# 下载
curl -sSL -H "Authorization: Bearer $API_TOKEN" \
"$BASE_URL/v1/videos/$TASK_ID/content" -o demo.mp4
⚠️ 注意 duration 必须传字符串("4"、"6"、"8")。传 number 会被服务端拒绝:
json: cannot unmarshal number into Go struct field ... duration of type string
3. Python 最小可用示例
import time, json, urllib.request
BASE = "https://api.apiyi.com"
KEY = "sk-..."
def req(method, path, body=None):
h = {"Authorization": f"Bearer {KEY}"}
data = None
if body is not None:
h["Content-Type"] = "application/json"
data = json.dumps(body).encode()
r = urllib.request.Request(BASE + path, data=data, method=method, headers=h)
return json.loads(urllib.request.urlopen(r, timeout=120).read())
create = req("POST", "/v1/videos", {
"model": "veo-3.1-fast-generate-preview",
"prompt": "傍晚海边的灯塔,镜头缓慢推进,稳定运镜",
"duration": "4",
"size": "1280x720",
"metadata": {"resolution": "720p", "aspectRatio": "16:9"},
})
tid = create["task_id"]
while True:
s = req("GET", f"/v1/videos/{tid}")
if s["status"] in {"completed", "succeeded"}:
break
if s["status"] == "failed":
raise RuntimeError(s)
time.sleep(8)
# 下载(content endpoint 偶尔会在 status=completed 后短暂返回 400,加重试)
import time as _t
for i in range(5):
try:
with urllib.request.urlopen(
urllib.request.Request(
f"{BASE}/v1/videos/{tid}/content",
headers={"Authorization": f"Bearer {KEY}"},
), timeout=180,
) as resp, open("demo.mp4", "wb") as f:
while chunk := resp.read(1 << 16):
f.write(chunk)
break
except urllib.error.HTTPError as e:
if i == 4:
raise
_t.sleep(4)
4. 参数速查
| 参数 | 必填 | 类型 | 取值 | 说明 |
|---|
model | ✅ | string | veo-3.1-fast-generate-preview / veo-3.1-generate-preview | 只支持这两个 |
prompt | ✅ | string | 自由文本 | 音频效果也写进 prompt(不要传 generateAudio) |
duration | ❌ | string | "4" / "6" / "8" | 默认 "8";1080p、4k 时必须 "8" |
size | ❌ | string | 1280x720 / 1920x1080 / 3840x2160 | 优先级低于 metadata.resolution |
metadata.resolution | ❌ | string | 720p / 1080p / 4k | 默认 720p;价格不随分辨率变化 |
metadata.aspectRatio | ❌ | string | 16:9 / 9:16 | 默认 16:9 |
metadata.seed | ❌ | int | 任意整数 | 复现/批量场景用 |
metadata.negativePrompt | ❌ | string | 自由文本 | 推荐传 |
参数识别优先级(server 会按这个顺序取):
- 秒数:
metadata.durationSeconds > duration > seconds > 8
- 分辨率:
metadata.resolution > size > 720p
5. 图生视频(image-to-video)
只支持 1 张参考图,字段名必须是 input_reference。
curl -X POST "$BASE_URL/v1/videos" \
-H "Authorization: Bearer $API_TOKEN" \
-F "model=veo-3.1-fast-generate-preview" \
-F "prompt=镜头从灯塔基座缓慢上升至塔顶" \
-F "input_reference=@./lighthouse.png;type=image/png" \
-F "seconds=8" \
-F "size=1280x720" \
-F "resolution=720p" \
-F "aspectRatio=16:9"
不支持的能力(虽然 Google 官方 Veo 3.1 有):
6. 计费
按模型名,按次计费;时长和分辨率都不影响单价。只对成功任务计费,失败 / 取消免费。
| 模型 | 单价 |
|---|
veo-3.1-fast-generate-preview | $0.3 / 次 |
veo-3.1-generate-preview | $1.2 / 次 |
也就是说,跑 4s 还是 8s,720p 还是 1080p,价格一样 —— 在预算允许时,直接挑画质更高的参数即可。
7. 错误与排查
| 现象 | 原因 / 处理 |
|---|
parse_request_failed + cannot unmarshal number into ... duration of type string | duration 必须传字符串 |
INVALID_ARGUMENT | 不要传 generateAudio;或检查 1080p/4k 是否配了非 8 秒 |
GET /v1/videos/{id}/content 偶发 400 | status=completed 后等几秒重试;实测重试一次即可 |
长时间 queued / in_progress | 4s fast 约 60-90s,标准 8s 视频可超 3 分钟,设 10-15 min 超时 |
| 401 | 检查 Authorization: Bearer <key> 没空格、key 没过期 |
8. 状态字段对照
| 接口 | 状态值 |
|---|
GET /v1/videos/{id} | queued / in_progress / completed / failed |
GET /v1/video/generations/{id} | queued / processing / succeeded / failed(响应里附 data.url) |
两套都通,建议日常用第一个轮询、需要拿 URL 走第二个。
9. 完整工程化客户端
仓库已经提供 veo_client.py,功能:
python3 veo_client.py preflight — 跑一次最小成本预检(fast/4s/720p)
python3 veo_client.py run --model fast --duration 8 --resolution 1080p — 自定义跑一次,自动保存视频 + 完整 metadata + append 到 outputs/_log.jsonl
- 完整测试矩阵 runner:
python3 run_matrix.py
输出目录:outputs/
<label>.mp4 — 视频
<label>.meta.json — 该次请求 body、每一次 poll、create/total 耗时、最终 status
_log.jsonl — 跨 run 汇总
10. 常见问题(FAQ)
Q1. fast 和 full 到底怎么选?
- 同等参数下渲染时长基本相同(实测 720p 8s:fast 83s,full 78s),“fast” 不是更快,而是更便宜。
- 默认用
veo-3.1-fast-generate-preview($0.3/次)。
- 出片要做最终交付、对画面细腻度 / 物理一致性敏感时,再切
veo-3.1-generate-preview($1.2/次)。
- 建议线上 AB:同 prompt + 同 seed 下,两个模型各跑一次,人工挑。
Q2. 为什么 duration 一定要传字符串?
后端用的 Go struct 把 duration 声明为 string;传 number 直接被解码层拒掉,报 parse_request_failed。这是上游强约束,不会改。写代码时记得加引号:"4" / "6" / "8"。
Q3. 任务什么时候才算完成?要不要 webhook?
- 目前没有 webhook,只能轮询
GET /v1/videos/{task_id}。
- 推荐轮询间隔:8 秒(实测够用,不会触发限流)。
- 实测耗时:720p / 1080p 60–115 秒,4K 5–6 分钟。客户端超时建议 720p/1080p 设 3 分钟,4K 设 10 分钟。
Q4. progress 字段为什么一直是 50%?
这个字段是粗粒度,只在 0 / 50 / 100 三档之间跳,不要拿来做百分比进度条。要展示进度,要么用旋转 loading,要么按”已等待秒数 / 预期秒数”自己算。
Q5. 视频生成失败会扣费吗?
不会。只对 status=completed 的任务计费,failed / 取消都免费。这点放心。
Q6. seed 到底有没有用?能不能复现一模一样的视频?
两个结论拆开看:
A. 字节级复现 —— 不行。 同 prompt + 同 seed(88888)+ 同参数,fast 跑两次:文件大小 9.81 MB vs 9.25 MB,md5 完全不同,渲染耗时 105s vs 64s。不能拿 seed 做精确重放,需要稳定输出请缓存生成的 mp4。
B. 但 seed 不是装饰品 —— 它真的会影响输出分布。 5 次实测(seed=88888 × 2,seed=99999 × 3,其他参数全一致):
| seed | 文件大小均值 | 组内跨度 |
|---|
88888 | 9.53 MB | 6.0% |
99999 | 13.03 MB | 5.0% |
| 组间差距 | +36.8%(~5.9 倍组内方差) | — |
→ 同 seed 的多次结果互相聚集;不同 seed 系统性偏移。
实战建议:
- 想要”挑一个稳定风格”的工作流:固定一个 seed,可以拿到风格相对一致的多次输出(但不字节一致)
- 想要”探索变体”:换 seed 比换 prompt 局部词便宜直观
- 想要”精确重放”:别想了,把 mp4 存下来
Q7. 能传多张参考图吗?能传首尾帧吗?
当前都不支持。 图生视频只能 1 张图,字段名固定 input_reference,而且必须是文件或 Base64,不接受远程 URL。Google 官方 Veo 3.1 有多参考图 / 首尾帧 / 视频扩展,本站尚未开放。
Q8. prompt 能写中文吗?语言对画质有影响吗?
能写中文,实测中文 prompt 出片正常(本测试报告里所有 prompt 都是中文)。模型对英文 prompt 训练样本多一些,如果要追求极致风格控制,可以英文写;一般场景中文足够。
Q9. 想要带对白 / 环境音 / BGM 怎么办?
VEO 3 / 3.1 是原生带音频的视频模型,但 generateAudio 这个参数不要传(传了会被上游回 INVALID_ARGUMENT)。要控制声音,把音频意图写进 prompt,比如:
“黄昏海边的灯塔,海浪声、远处海鸟叫声,低沉的风声,电影级氛围”
Q10. 横屏 / 竖屏怎么切?
传 metadata.aspectRatio:
也可以通过 size 推:1280x720 → 16:9;720x1280 → 9:16。两者都没传时默认 16:9。
Q11. 4K 值得用吗?
绝大多数场景不推荐。原因:
- 同价格(按次)拿到更高分辨率,听起来划算
- 但渲染慢 4–6 倍(720p 80s → 4K 350s)
- 文件大 ~10 倍(720p 4MB → 4K 40MB),带宽 / 存储成本翻倍
- 视觉上 1080p 已经够用,大部分播放场景看不出差别
除非是大屏投放 / 后期素材,默认用 1080p 即可。
确实需要 4K 时的完整 curl 示例(关键约束:duration 只能 "8",resolution=4k,size=3840x2160):
# 创建 4K 任务(注意:本轮实测耗时 5-6 分钟,先把超时调大)
RESP=$(curl -sS -X POST "$BASE_URL/v1/videos" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "veo-3.1-generate-preview",
"prompt": "黄昏海边的灯塔,镜头缓慢推进,海浪轻拍礁石,远处低沉的风声和海鸟声,电影级光影,稳定运镜",
"duration": "8",
"size": "3840x2160",
"metadata": {
"resolution": "4k",
"aspectRatio": "16:9",
"seed": 20260521,
"negativePrompt": "blurry, watermark, distorted, low quality"
}
}')
TASK_ID=$(echo "$RESP" | python3 -c 'import sys,json;print(json.load(sys.stdin)["task_id"])')
echo "task_id=$TASK_ID"
# 轮询(4K 建议 10 秒间隔 + 10 分钟硬超时)
START=$(date +%s)
while :; do
S=$(curl -sS -H "Authorization: Bearer $API_TOKEN" "$BASE_URL/v1/videos/$TASK_ID")
ST=$(echo "$S" | python3 -c 'import sys,json;print(json.load(sys.stdin)["status"])')
ELAPSED=$(( $(date +%s) - START ))
echo "[${ELAPSED}s] status=$ST"
[ "$ST" = "completed" ] && break
[ "$ST" = "failed" ] && { echo "$S"; exit 1; }
[ $ELAPSED -gt 600 ] && { echo "timeout"; exit 2; }
sleep 10
done
# 下载(status 刚翻 completed 偶发 400,等几秒再下;--retry 3 兜底)
sleep 4
curl -sSL --retry 3 --retry-delay 4 \
-H "Authorization: Bearer $API_TOKEN" \
"$BASE_URL/v1/videos/$TASK_ID/content" \
-o "veo_4k_${TASK_ID}.mp4"
ls -lh "veo_4k_${TASK_ID}.mp4" # 实测 25-40MB
同价格下要 4K 没问题,但务必:a) 模型用 veo-3.1-generate-preview(质感才匹配 4K);b) duration 必须 "8"(4K 不支持 4s/6s);c) 客户端超时 ≥ 10 分钟;d) 异步任务做好后台处理,不要阻塞用户请求线程。
Q12. 任务 / 视频留存多久?
官方文档没有明确给出留存期。建议生成完立刻下载落本地存储(GET /v1/videos/{task_id}/content),不要长期依赖远端 task_id 拿视频。
Q13. 视频带水印 / 溯源信息吗?
- 没有可视水印
- 但带 Google C2PA Content Credentials 签名(
urn:c2pa:...,Google C2PA Media Services 颁发),藏在 MP4 元数据里。终端用户肉眼看不到,用 C2PA 工具(如 Adobe Content Authenticity)可以验出”由 Veo 生成”。
- 如果业务要二创再分发,知情即可;一般不影响播放。
Q14. 一次能并发多少任务?有 QPS 限制吗?
本测试一口气提交 10 个任务全部成功入队,没遇到拒绝。具体上限官方没明示,建议生产侧自己限流(同时 in-flight ≤ 10),并对 429 / 5xx 加指数退避重试。
Q15. 失败重试要不要换 seed?
- 如果失败原因是 参数错误(400 类),改参数再发;别盲目重试。
- 如果失败原因是 上游瞬时(5xx /
INTERNAL / 网络抖动),保持同 seed 重试,这样如果是 seed 撞到 bad case 也能复现给上游。
- 单任务建议最多重试 2 次,再失败转人工。
Q16. 接 OpenAI SDK 能跑吗?
理论上可以,接口是 OpenAI 风格的(Bearer 鉴权 + /v1/...)。但 OpenAI 官方 SDK 没有 videos.create 这个方法(/v1/videos 是 new-api 自定义路径),所以多半要直接用 HTTP 调用,或者用 OpenAI SDK 的底层 client.post()。直接 HTTP 最省事。
Q18. prompt / 图片会被上游记录吗?
经 apiyi → new-api → Google Gemini Veo,上游 Google 侧有日志和滥用审计。涉及敏感内容(人脸、品牌、未授权角色)请走业务方的合规审查后再上线。
Q19. 提示词怎么写效果好?
经验法则:
- 场景 + 主体 + 动作 + 镜头 + 光影 + 风格,按这个顺序拼
- 加入”稳定运镜""电影级光影""真实质感”这类描述质量明显提升
- 用
metadata.negativePrompt 排除常见 artifacts:"blurry, watermark, distorted, low quality, deformed hands"
- 镜头语言关键词:推镜 / 拉镜 / 摇镜 / 跟镜 / 俯拍 / 仰拍
Q20. 出错了如何快速定位?
- 先看 HTTP 状态码(400 / 401 / 429 / 5xx 各有不同处理)
- 看响应 body 的
message 和 code 字段
- 用
task_id 去查 GET /v1/videos/{task_id},看 status 和 error(失败时上游会带 reason)
- 还是搞不定就把 task_id + 完整请求 + 完整响应贴给运维,渠道侧能查到 raw 日志