跳转到主要内容

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. 参数速查

参数必填类型取值说明
modelstringveo-3.1-fast-generate-preview / veo-3.1-generate-preview只支持这两个
promptstring自由文本音频效果也写进 prompt(不要传 generateAudio)
durationstring"4" / "6" / "8"默认 "8";1080p、4k 时必须 "8"
sizestring1280x720 / 1920x1080 / 3840x2160优先级低于 metadata.resolution
metadata.resolutionstring720p / 1080p / 4k默认 720p;价格不随分辨率变化
metadata.aspectRatiostring16:9 / 9:16默认 16:9
metadata.seedint任意整数复现/批量场景用
metadata.negativePromptstring自由文本推荐传
参数识别优先级(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 stringduration 必须传字符串
INVALID_ARGUMENT不要传 generateAudio;或检查 1080p/4k 是否配了非 8 秒
GET /v1/videos/{id}/content 偶发 400status=completed 后等几秒重试;实测重试一次即可
长时间 queued / in_progress4s 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文件大小均值组内跨度
888889.53 MB6.0%
9999913.03 MB5.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:
  • 横屏:"16:9"(默认)
  • 竖屏:"9:16"
也可以通过 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. 出错了如何快速定位?

  1. 先看 HTTP 状态码(400 / 401 / 429 / 5xx 各有不同处理)
  2. 看响应 body 的 messagecode 字段
  3. task_id 去查 GET /v1/videos/{task_id},看 statuserror(失败时上游会带 reason)
  4. 还是搞不定就把 task_id + 完整请求 + 完整响应贴给运维,渠道侧能查到 raw 日志