主题
视频 API
ModelGate 提供强大的 AI 视频生成 API,支持主流视频生成模型。通过文本描述即可生成高质量的视频内容。
API 概览
ModelGate 视频 API 采用异步任务模式,适合视频生成这类耗时操作。
- 统一接口: 一个 API 端点访问所有视频生成模型
- 多模型支持: 支持 OpenAI Sora 2 系列模型
- 灵活配置: 支持自定义分辨率、时长等参数
- 异步任务: 异步生成模式,支持任务查询和进度跟踪
API 端点
| 端点 | 方法 | 说明 |
|---|---|---|
/api/v1/videos/generations | POST | 创建视频生成任务 |
/api/v1/videos/query | GET | 查询任务状态 |
/api/v1/videos/download | GET | 下载生成的视频 |
注意
如果您使用 modelgate 网页端,Host 为: https://mg.aid.pub
如果您使用 modelgate 客户端,Host 为: http://localhost:13148
生成视频
创建一个视频生成任务。
请求参数
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| model | string | 是 | - | 模型名称,如 openai/sora-2 |
| prompt | string | 是 | - | 视频描述文本 |
| seconds | string | 是 | "4" | 视频时长,支持 "4"、"8"、"12" 秒 |
| size | string | 是 | "1280x720" | 视频分辨率,格式为 "宽x高"。openai/sora-2 模型支持:1280x720, 720x1280; openai/sora-2-pro 模型支持:1280x720, 720x1280, 1024x1792, 1792x1024 |
| images | string[] | 否 | - | 图像参考,用于指导生成,URL 数组格式 |
代码示例
bash
curl --location 'https://mg.aid.pub/api/v1/videos/generations' \
--header 'Authorization: Bearer your-modelgate-key' \
--header 'Content-Type: application/json' \
--data '{
"model": "openai/sora-2",
"prompt": "一只开飞机的小猫",
"seconds": "8",
"size": "1280x720"
}'python
import requests
import json
url = "https://mg.aid.pub/api/v1/videos/generations"
headers = {
"Authorization": "Bearer your-modelgate-key",
"Content-Type": "application/json"
}
payload = {
"model": "openai/sora-2",
"prompt": "一只开飞机的小猫",
"seconds": "8",
"size": "1280x720"
}
response = requests.post(url, headers=headers, json=payload)
data = response.json()
print(f"任务ID: {data['task_id']}")
print(f"状态: {data['status']}")typescript
interface VideoGenerationRequest {
model: string;
prompt: string;
seconds?: string;
size?: string;
}
interface VideoGenerationResponse {
task_id: string;
status: string;
completed_at: number;
created_at: number;
error: {
code: string;
message: string;
};
expires_at: number;
model: string;
object: string;
progress: number;
prompt: string;
seconds: string;
size: string;
}
const url = 'https://mg.aid.pub/api/v1/videos/generations';
const payload: VideoGenerationRequest = {
model: 'openai/sora-2',
prompt: '一只开飞机的小猫',
seconds: '8',
size: '1280x720'
};
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': 'Bearer your-modelgate-key',
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
const data: VideoGenerationResponse = await response.json();
console.log('任务ID:', data.task_id);
console.log('状态:', data.status);javascript
const url = 'https://mg.aid.pub/api/v1/videos/generations';
const payload = {
model: 'openai/sora-2',
prompt: '一只开飞机的小猫',
seconds: '8',
size: '1280x720'
};
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': 'Bearer your-modelgate-key',
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
const data = await response.json();
console.log('任务ID:', data.task_id);
console.log('状态:', data.status);go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
type VideoRequest struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
Seconds string `json:"seconds,omitempty"`
Size string `json:"size,omitempty"`
}
type VideoResponse struct {
TaskID string `json:"task_id"`
Status string `json:"status"`
CompletedAt int64 `json:"completed_at"`
CreatedAt int64 `json:"created_at"`
Error struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
ExpiresAt int64 `json:"expires_at"`
Model string `json:"model"`
Object string `json:"object"`
Progress int `json:"progress"`
Prompt string `json:"prompt"`
Seconds string `json:"seconds"`
Size string `json:"size"`
}
func main() {
url := "https://mg.aid.pub/api/v1/videos/generations"
payload := VideoRequest{
Model: "openai/sora-2",
Prompt: "一只开飞机的小猫",
Seconds: "8",
Size: "1280x720",
}
jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer your-modelgate-key")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result VideoResponse
json.Unmarshal(body, &result)
fmt.Printf("任务ID: %s\n", result.TaskID)
fmt.Printf("状态: %s\n", result.Status)
}java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import org.json.JSONObject;
public class VideoGeneration {
public static void main(String[] args) throws Exception {
String url = "https://mg.aid.pub/api/v1/videos/generations";
JSONObject payload = new JSONObject();
payload.put("model", "openai/sora-2");
payload.put("prompt", "一只开飞机的小猫");
payload.put("seconds", "8");
payload.put("size", "1280x720");
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer your-modelgate-key")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload.toString()))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
JSONObject data = new JSONObject(response.body());
System.out.println("任务ID: " + data.getString("task_id"));
System.out.println("状态: " + data.getString("status"));
}
}响应格式
json
{
"task_id": "video_692830be5f348190b726277ba9689c63",
"status": "queued",
"completed_at": 0,
"created_at": 1764241598,
"error": {
"code": "",
"message": ""
},
"expires_at": 0,
"model": "openai/sora-2",
"object": "video",
"progress": 0,
"prompt": "一只开飞机的小猫",
"seconds": "8",
"size": "1280x720"
}响应字段说明:
| 字段名 | 类型 | 说明 |
|---|---|---|
| task_id | string | 任务ID,用于查询状态和下载视频 |
| status | string | 任务状态: queued(排队中)、processing(生成中)、completed(已完成)、failed(失败) |
| completed_at | integer | 完成时间戳,未完成时为 0 |
| created_at | integer | 创建时间戳 |
| error.code | string | 错误码 |
| error.message | string | 错误信息 |
| expires_at | integer | 过期时间戳,未完成时为 0 |
| model | string | 使用的模型 |
| object | string | 对象类型,固定为 "video" |
| progress | integer | 生成进度,0-100 |
| prompt | string | 视频描述文本 |
| seconds | string | 视频时长 |
| size | string | 视频分辨率 |
查询任务状态
使用任务ID查询视频生成状态。
代码示例
bash
curl --location 'https://mg.aid.pub/api/v1/videos/query?task_id=video_692830be5f348190b726277ba9689c63' \
--header 'Authorization: Bearer your-modelgate-key'python
import requests
task_id = "video_692830be5f348190b726277ba9689c63"
url = f"https://mg.aid.pub/api/v1/videos/query?task_id={task_id}"
headers = {
"Authorization": "Bearer your-modelgate-key"
}
response = requests.get(url, headers=headers)
data = response.json()
print(f"状态: {data['status']}")
print(f"进度: {data['progress']}%")typescript
const taskId = 'video_692830be5f348190b726277ba9689c63';
const url = `https://mg.aid.pub/api/v1/videos/query?task_id=${taskId}`;
const response = await fetch(url, {
headers: {
'Authorization': 'Bearer your-modelgate-key'
}
});
const data = await response.json();
console.log('状态:', data.status);
console.log('进度:', data.progress + '%');javascript
const taskId = 'video_692830be5f348190b726277ba9689c63';
const url = `https://mg.aid.pub/api/v1/videos/query?task_id=${taskId}`;
const response = await fetch(url, {
headers: {
'Authorization': 'Bearer your-modelgate-key'
}
});
const data = await response.json();
console.log('状态:', data.status);
console.log('进度:', data.progress + '%');go
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
taskID := "video_692830be5f348190b726277ba9689c63"
url := fmt.Sprintf("https://mg.aid.pub/api/v1/videos/query?task_id=%s", taskID)
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer your-modelgate-key")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result map[string]interface{}
json.Unmarshal(body, &result)
fmt.Printf("状态: %s\n", result["status"])
fmt.Printf("进度: %.0f%%\n", result["progress"])
}java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import org.json.JSONObject;
public class VideoQuery {
public static void main(String[] args) throws Exception {
String taskId = "video_692830be5f348190b726277ba9689c63";
String url = "https://mg.aid.pub/api/v1/videos/query?task_id=" + taskId;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer your-modelgate-key")
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
JSONObject data = new JSONObject(response.body());
System.out.println("状态: " + data.getString("status"));
System.out.println("进度: " + data.getInt("progress") + "%");
}
}响应格式
生成中:
json
{
"task_id": "video_692830be5f348190b726277ba9689c63",
"status": "processing",
"completed_at": 0,
"created_at": 1764241598,
"error": {
"code": "",
"message": ""
},
"expires_at": 0,
"model": "MaaS_Sora_2",
"object": "video",
"progress": 0,
"prompt": "",
"seconds": "8",
"size": "1280x720"
}生成完成:
json
{
"task_id": "video_692830be5f348190b726277ba9689c63",
"status": "completed",
"completed_at": 1764241714,
"created_at": 1764241598,
"error": {
"code": "",
"message": ""
},
"expires_at": 1764327998,
"model": "MaaS_Sora_2",
"object": "video",
"progress": 100,
"prompt": "",
"seconds": "8",
"size": "1280x720"
}下载视频
任务完成后,使用任务ID下载生成的视频。
代码示例
bash
curl -o output.mp4 "https://mg.aid.pub/api/v1/videos/download?task_id=video_692830be5f348190b726277ba9689c63"python
import requests
task_id = "video_692830be5f348190b726277ba9689c63"
url = f"https://mg.aid.pub/api/v1/videos/download?task_id={task_id}"
headers = {
"Authorization": "Bearer your-modelgate-key"
}
response = requests.get(url, headers=headers, stream=True)
with open("output.mp4", "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
print("视频下载完成: output.mp4")typescript
import fs from 'fs';
const taskId = 'video_692830be5f348190b726277ba9689c63';
const url = `https://mg.aid.pub/api/v1/videos/download?task_id=${taskId}`;
const response = await fetch(url, {
headers: {
'Authorization': 'Bearer your-modelgate-key'
}
});
const buffer = await response.arrayBuffer();
fs.writeFileSync('output.mp4', Buffer.from(buffer));
console.log('视频下载完成: output.mp4');javascript
const taskId = 'video_692830be5f348190b726277ba9689c63';
const url = `https://mg.aid.pub/api/v1/videos/download?task_id=${taskId}`;
const response = await fetch(url, {
headers: {
'Authorization': 'Bearer your-modelgate-key'
}
});
const blob = await response.blob();
const urlObject = URL.createObjectURL(blob);
// 在浏览器中触发下载
const a = document.createElement('a');
a.href = urlObject;
a.download = 'output.mp4';
a.click();
console.log('视频下载完成');go
package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
taskID := "video_692830be5f348190b726277ba9689c63"
url := fmt.Sprintf("https://mg.aid.pub/api/v1/videos/download?task_id=%s", taskID)
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer your-modelgate-key")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
out, _ := os.Create("output.mp4")
defer out.Close()
io.Copy(out, resp.Body)
fmt.Println("视频下载完成: output.mp4")
}java
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class VideoDownload {
public static void main(String[] args) throws Exception {
String taskId = "video_692830be5f348190b726277ba9689c63";
String url = "https://mg.aid.pub/api/v1/videos/download?task_id=" + taskId;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer your-modelgate-key")
.GET()
.build();
HttpResponse<InputStream> response = client.send(request,
HttpResponse.BodyHandlers.ofInputStream());
try (FileOutputStream fos = new FileOutputStream("output.mp4")) {
response.body().transferTo(fos);
}
System.out.println("视频下载完成: output.mp4");
}
}完整工作流示例
以下是完整的视频生成、查询和下载流程:
python
import requests
import time
API_KEY = "your-modelgate-key"
BASE_URL = "https://mg.aid.pub/api/v1/videos"
def generate_video(prompt: str, seconds: str = "8", size: str = "1280x720"):
"""创建视频生成任务"""
url = f"{BASE_URL}/generations"
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
payload = {
"model": "openai/sora-2",
"prompt": prompt,
"seconds": seconds,
"size": size
}
response = requests.post(url, headers=headers, json=payload)
return response.json()
def query_status(task_id: str):
"""查询任务状态"""
url = f"{BASE_URL}/query?task_id={task_id}"
headers = {
"Authorization": f"Bearer {API_KEY}"
}
response = requests.get(url, headers=headers)
return response.json()
def download_video(task_id: str, output_path: str = "output.mp4"):
"""下载生成的视频"""
url = f"{BASE_URL}/download?task_id={task_id}"
headers = {
"Authorization": f"Bearer {API_KEY}"
}
response = requests.get(url, headers=headers, stream=True)
with open(output_path, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
return output_path
def main():
# 1. 创建视频生成任务
print("创建视频生成任务...")
result = generate_video("一只开飞机的小猫", seconds="8")
task_id = result["task_id"]
print(f"任务ID: {task_id}")
print(f"状态: {result['status']}")
# 2. 轮询查询状态
print("\n等待视频生成...")
while True:
status = query_status(task_id)
print(f"进度: {status['progress']}% - 状态: {status['status']}")
if status["status"] == "completed":
print("\n视频生成完成!")
break
elif status["status"] == "failed":
print(f"\n生成失败: {status['error']['message']}")
return
time.sleep(5) # 每5秒查询一次
# 3. 下载视频
print("\n下载视频...")
output_file = download_video(task_id)
print(f"视频已保存到: {output_file}")
if __name__ == "__main__":
main()typescript
const API_KEY = 'your-modelgate-key';
const BASE_URL = 'https://mg.aid.pub/api/v1/videos';
interface VideoTask {
task_id: string;
status: string;
progress: number;
error: {
code: string;
message: string;
};
}
async function generateVideo(
prompt: string,
seconds: string = '8',
size: string = '1280x720'
): Promise<VideoTask> {
const url = `${BASE_URL}/generations`;
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'openai/sora-2',
prompt,
seconds,
size
})
});
return await response.json();
}
async function queryStatus(taskId: string): Promise<VideoTask> {
const url = `${BASE_URL}/query?task_id=${taskId}`;
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${API_KEY}`
}
});
return await response.json();
}
async function downloadVideo(taskId: string, outputPath: string = 'output.mp4') {
const url = `${BASE_URL}/download?task_id=${taskId}`;
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${API_KEY}`
}
});
const buffer = await response.arrayBuffer();
// Node.js 环境
const fs = await import('fs');
fs.writeFileSync(outputPath, Buffer.from(buffer));
return outputPath;
}
async function main() {
// 1. 创建视频生成任务
console.log('创建视频生成任务...');
const result = await generateVideo('一只开飞机的小猫', '8');
const taskId = result.task_id;
console.log(`任务ID: ${taskId}`);
console.log(`状态: ${result.status}`);
// 2. 轮询查询状态
console.log('\n等待视频生成...');
while (true) {
const status = await queryStatus(taskId);
console.log(`进度: ${status.progress}% - 状态: ${status.status}`);
if (status.status === 'completed') {
console.log('\n视频生成完成!');
break;
} else if (status.status === 'failed') {
console.log(`\n生成失败: ${status.error.message}`);
return;
}
await new Promise(resolve => setTimeout(resolve, 5000)); // 每5秒查询一次
}
// 3. 下载视频
console.log('\n下载视频...');
const outputFile = await downloadVideo(taskId);
console.log(`视频已保存到: ${outputFile}`);
}
main();错误处理
API 可能返回以下错误码:
| 错误码 | 说明 |
|---|---|
| 400 | 请求参数错误 |
| 401 | API Key 无效或未提供 |
| 402 | 余额不足 |
| 429 | 请求频率超限 |
| 500 | 服务器内部错误 |
| 503 | 服务暂时不可用 |
错误响应示例:
json
{
"task_id": "video_692830be5f348190b726277ba9689c63",
"status": "failed",
"error": {
"code": "invalid_parameter",
"message": "Invalid size format. Expected format: WIDTHxHEIGHT"
}
}最佳实践
轮询间隔: 建议每 3-5 秒查询一次任务状态,避免过于频繁的请求
超时处理: 视频生成通常需要 1-3 分钟,建议设置合理的超时时间
错误重试: 对于临时性错误(429, 5xx),建议实现指数退避重试机制
视频下载: 生成的视频有过期时间(expires_at),建议及时下载并存储
详细的提示词: 提供清晰、详细的描述可以获得更好的生成效果:
- 场景描述(环境、光照、氛围)
- 动作和运动(镜头移动、角色动作)
- 风格和质感(电影感、动画风格等)
合理设置时长:
- 短视频预览: 4 秒
- 标准内容: 8 秒
- 完整叙事: 12 秒
内容审核: 对用户提供的提示词进行内容审核,避免生成违规内容
