接入方式
RESTful 风格接口,兼容主流图像 / 视频生成 API 的请求结构。把 base_url 指向本站、 把 Authorization 换成统一 KEY 即可,其余参数照常填写。
配置环境变量
export RELAY_BASE_URL = "http://ai.beiangou.com"
export RELAY_API_KEY = "<平台方提供的统一 KEY>"生成图片(同步)
curl -sS -X POST "http://ai.beiangou.com/v1/images/generations" \
-H "Authorization: Bearer $RELAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "image-2.5-flash",
"prompt": "晨光透过白色纱帘洒在极简客厅,空气中漂浮着微尘,胶片质感",
"size": "2K",
"ratio": "16:9",
"extra_body": { "response_format": "url" }
}'返回路径 data[0].url。 文生图必填 model / prompt,可选 n(张数,最多 6)、seed;ratio 取 1:1 / 3:4 / 4:3 / 16:9 / 9:16 / 2:3 / 3:2 / 21:9,size 支持档位(1K–4K)或 宽x高 精确写法;URL 输出务必写在 extra_body.response_format, 不能放在请求体顶层。建议客户端超时 60–360 秒(4K 更久),本站上限 300 秒。
兼容主流 SDK:像 quality / background 这类 SDK 默认携带、但本通道不接受的字段会被自动忽略,size:"auto" 归到默认档, 实际改动通过响应头 x-relay-compat 如实回传,不影响出图。
并发提交:生图支持一次性整批并发发出, 无需在客户端自行限速或错峰,排队与调度由平台侧完成。瞬时并发过高时个别请求可能返回 429(relay_overloaded / relay_queue_timeout),此类响应未进入生成、不产生费用, 直接重试即可。
图生图 / 多图合成
curl -sS -X POST "http://ai.beiangou.com/v1/images/generations" \
-H "Authorization: Bearer $RELAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "image-2.5-flash",
"prompt": "把这张照片改成赛博朋克夜景,保留主体构图",
"size": "1K",
"ratio": "4:3",
"extra_body": {
"image": ["https://example.com/source.jpg"],
"response_format": "url"
}
}'图生图不需要 tags;Base64 输出用 extra_body.response_format: "b64_json", 返回路径 data[0].b64_json。 写在顶层的 image / images 也会自动归到 extra_body.image,两种写法都能用。
参考图可以是 https:// 公网地址、 data:image/...;base64, 内联,也可以直接复用生图接口返回的 url(无需你自己转存)。纯内网 / localhost 落地址取不到, 返回 400 bad_request 并说明原因。
创建视频任务(异步)
curl -sS -X POST "http://ai.beiangou.com/v1/videos" \
-H "Authorization: Bearer $RELAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "video-2.5-flash",
"prompt": "雨后的未来城市街道,霓虹灯倒映在地面,一辆银色跑车缓慢驶过,电影级运镜",
"mode": "text",
"seconds": "5",
"size": "720P",
"aspect_ratio": "16:9"
}'从响应中保存 video_id。seconds 为时长("4"–"12",写成数字如 5 也会自动归一为字符串);画幅用 aspect_ratio(见右侧 720P 画幅表,共 6 档)。 生图与生视频均固定使用对应的免费模型(image-2.5-flash / video-2.5-flash),传其他模型名会被归一到该免费模型,并在响应头 x-relay-model-override 中告知;视频分辨率固定 "720P",请求 1080P 会返回 400。
并发提交:多个视频任务可以一次性并发发出, 无需在客户端自行限速或错峰,排队与调度都在平台侧完成。并发量较大时,个别任务可能返回 429,按 Retry-After 重试即可。 注意「创建任务」这一步在整批并发下会被摊开发出(响应可能较慢,实测可达 100s+), 客户端对 POST /v1/videos 的超时应给足(建议 ≥180s), 不要设得太短导致任务其实已创建、客户端却先超时。
图视混发:生图与生视频可以在同一批里混着并发发出, 两种任务互不阻塞、各走各的处理通道,无需拆分成先后两批。
首尾帧 / 参考视频模式
curl -sS -X POST "http://ai.beiangou.com/v1/videos" \
-H "Authorization: Bearer $RELAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "video-2.5-flash",
"prompt": "镜头缓缓推进,人物转身走向霓虹深处",
"mode": "keyframe",
"first_frame": "https://example.com/first.jpg",
"last_frame": "https://example.com/last.jpg",
"seconds": "8",
"size": "720P",
"aspect_ratio": "16:9"
}'
# 也接受数组写法(等价): "images": ["https://…/first.jpg", "https://…/last.jpg"]keyframe 把传入图片锁成第一帧(可再给尾帧锁成最后一帧),动画严格从这一帧开始; 首尾两个位置至少给一个,推荐 first_frame / last_frame,数组写法 images:[首帧, 尾帧] 等价可用(≤2 张)。reference 语义不同——只把素材当参考(构图由模型自行决定),支持 images(≤5)/ videos /audios(≤3,音视频同步)。 可选 callback_url,任务完成时会回调。
查询可用模型
curl -sS "http://ai.beiangou.com/v1/models" \
-H "Authorization: Bearer $RELAY_API_KEY"
# { "object": "list", "data": [ { "id": "image-2.5-flash", ... }, { "id": "video-2.5-flash", ... } ] }返回 data[].id 即可直接用于model 参数;加 ?kind=image 或 ?kind=video 只要某一类。
轮询视频结果
curl -sS "http://ai.beiangou.com/v1/videos/VIDEO_ID" \
-H "Authorization: Bearer $RELAY_API_KEY"建议每 2–5 秒查询一次,直到 status 为 completed 或 failed, 视频地址在顶层 url 字段, 可直接下载或内联播放,支持 Range 分段。
SDK 接入
from openai import OpenAI
import httpx, time
BASE = "http://ai.beiangou.com"
KEY = "<统一 KEY>"
client = OpenAI(base_url=f"{BASE}/v1", api_key=KEY, timeout=300)
# 1) 生图
img = client.images.generate(
model="image-2.5-flash",
prompt="晨光透过白色纱帘洒在极简客厅,胶片质感",
n=1, size="1024x1024",
extra_body={"ratio": "16:9", "response_format": "url"},
)
print(img.data[0].url)
# 2) 生视频:建任务 + 轮询
def gen_video(prompt: str, model: str = "video-2.5-flash") -> str:
h = {"Authorization": f"Bearer {KEY}"}
task = httpx.post(
f"{BASE}/v1/videos", headers=h, timeout=180,
json={"model": model, "prompt": prompt, "mode": "text",
"seconds": "5", "size": "720P", "aspect_ratio": "16:9"},
).json()
vid = task["video_id"]
for _ in range(360): # 最长约 30 分钟
st = httpx.get(f"{BASE}/v1/videos/{vid}", headers=h, timeout=30).json()
if st["status"] == "completed":
return st["url"]
if st["status"] == "failed":
raise RuntimeError(st.get("error", {}).get("message", "生成失败"))
time.sleep(3)
raise TimeoutError(vid)import OpenAI from "openai";
const BASE = "http://ai.beiangou.com";
const KEY = process.env.RELAY_API_KEY;
const client = new OpenAI({ baseURL: BASE + "/v1", apiKey: KEY, timeout: 300_000 });
// 生图
const img = await client.images.generate({
model: "image-2.5-flash",
prompt: "雨后的未来城市街道,霓虹倒映在地面",
n: 1,
size: "1024x1024",
});
console.log(img.data[0].url);
// 生视频(SDK 未覆盖,用 fetch)
const auth = { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" };
const task = await (await fetch(BASE + "/v1/videos", {
method: "POST", headers: auth,
body: JSON.stringify({ model: "video-2.5-flash", prompt: "镜头缓慢推进", mode: "text",
seconds: "5", size: "720P", aspect_ratio: "16:9" }),
})).json();
for (;;) {
const st = await (await fetch(BASE + "/v1/videos/" + task.video_id, { headers: auth })).json();
if (st.status === "completed") { console.log(st.url); break; }
if (st.status === "failed") throw new Error(st.error?.message ?? "生成失败");
await new Promise((r) => setTimeout(r, 3000));
}错误与重试
错误体统一为 OpenAI 风格: { "error": { "message", "type", "code" } }, 响应头带 x-request-id,反馈问题时请附上它。
| HTTP | code | 处理建议 |
|---|---|---|
| 400 | bad_json / missing_prompt / bad_mode / bad_size / missing_frame / too_many_images | 参数不合法或素材张数超上限(图像 n≤6、首尾帧≤2、参考≤5、音频≤3),修正请求体后重发,不要原样重试 |
| 401 | missing_api_key / invalid_api_key | 未带 KEY 或 KEY 无效(已吊销 / 复制不完整),核对后重发 |
| 403 | api_key_disabled / capability_denied | KEY 已停用或未开通该能力(生图 / 生视频),联系发放方 |
| 403 | quota_exceeded | 日或累计配额用满,未进入生成、不计费,联系发放方调整 |
| 404 | query_failed / bad_media_token | video_id 不存在或已过期,或资源 token 无效,勿重试 |
| 429 | rate_limited | 请求过于频繁,按 Retry-After 头退避后重试 |
| 429 | relay_overloaded | 服务瞬时繁忙,未进入生成、不计费,可立即重试 |
| 429 | relay_queue_timeout | 排队超时,稍后重试即可 |
| 429 | upstream_capacity | 该能力瞬时繁忙,按 Retry-After 稍后重试 |
| 429 | upstream_no_quota | 该能力暂时不可用,稍后重试或联系发放方 |
| 502 / 504 | upstream_error / all_keys_failed / media_fetch_failed | 服务处理异常或超时,带 request_id 反馈 |
| 503 | no_upstream_key | 服务暂时不可用,带 request_id 联系发放方 |
该重试:429(带 Retry-After 头时按其秒数退避,指数退避上限 30s)、502/503/504。不该重试:400(参数错)、401/403(KEY 问题)、 403 配额或能力不足——重试只会继续消耗额度。 429 relay_overloaded 与 quota_exceeded 都未进入生成流程、不产生费用。