Skip to content

视频 API

ModelGate 提供强大的 AI 视频生成 API,支持主流视频生成模型。通过文本描述即可生成高质量的视频内容。

API 概览

ModelGate 视频 API 采用异步任务模式,适合视频生成这类耗时操作。

  • 统一接口: 一个 API 端点访问所有视频生成模型
  • 多模型支持: 支持 OpenAI Sora 2 系列模型
  • 灵活配置: 支持自定义分辨率、时长等参数
  • 异步任务: 异步生成模式,支持任务查询和进度跟踪

API 端点

端点方法说明
/api/v1/videos/generationsPOST创建视频生成任务
/api/v1/videos/queryGET查询任务状态
/api/v1/videos/downloadGET下载生成的视频

注意

如果您使用 modelgate 网页端,Host 为: https://mg.aid.pub
如果您使用 modelgate 客户端,Host 为: http://localhost:13148

生成视频

创建一个视频生成任务。

请求参数

参数名类型必填默认值说明
modelstring-模型名称,如 openai/sora-2
promptstring-视频描述文本
secondsstring"4"视频时长,支持 "4"、"8"、"12" 秒
sizestring"1280x720"视频分辨率,格式为 "宽x高"。
openai/sora-2 模型支持:1280x720, 720x1280;
openai/sora-2-pro 模型支持:1280x720, 720x1280, 1024x1792, 1792x1024
imagesstring[]-图像参考,用于指导生成,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_idstring任务ID,用于查询状态和下载视频
statusstring任务状态: queued(排队中)、processing(生成中)、completed(已完成)、failed(失败)
completed_atinteger完成时间戳,未完成时为 0
created_atinteger创建时间戳
error.codestring错误码
error.messagestring错误信息
expires_atinteger过期时间戳,未完成时为 0
modelstring使用的模型
objectstring对象类型,固定为 "video"
progressinteger生成进度,0-100
promptstring视频描述文本
secondsstring视频时长
sizestring视频分辨率

查询任务状态

使用任务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请求参数错误
401API Key 无效或未提供
402余额不足
429请求频率超限
500服务器内部错误
503服务暂时不可用

错误响应示例:

json
{
  "task_id": "video_692830be5f348190b726277ba9689c63",
  "status": "failed",
  "error": {
    "code": "invalid_parameter",
    "message": "Invalid size format. Expected format: WIDTHxHEIGHT"
  }
}

最佳实践

  1. 轮询间隔: 建议每 3-5 秒查询一次任务状态,避免过于频繁的请求

  2. 超时处理: 视频生成通常需要 1-3 分钟,建议设置合理的超时时间

  3. 错误重试: 对于临时性错误(429, 5xx),建议实现指数退避重试机制

  4. 视频下载: 生成的视频有过期时间(expires_at),建议及时下载并存储

  5. 详细的提示词: 提供清晰、详细的描述可以获得更好的生成效果:

    • 场景描述(环境、光照、氛围)
    • 动作和运动(镜头移动、角色动作)
    • 风格和质感(电影感、动画风格等)
  6. 合理设置时长:

    • 短视频预览: 4 秒
    • 标准内容: 8 秒
    • 完整叙事: 12 秒
  7. 内容审核: 对用户提供的提示词进行内容审核,避免生成违规内容

ModelGate 产品文档