happyhorse-1.1-i2v
欢喜马 HappyHorse · 图生视频
接口模型名称:happyhorse-1.1-i2v(请求体 model 必须与此完全一致)
| 项 | 值 |
|---|---|
| 类型 | 图生视频(首帧) |
| 调用方式 | 异步(先创建任务,再查询结果) |
先看这几条
- 计费:按秒 × 清晰度档,单价见控制台
- 耗时:视频生成通常较慢(常见数分钟,复杂任务可能更久),请耐心等待
- 调用:异步——创建成功后用
tid轮询/v1/tasks/query查看进度,不要反复提交同一任务 - 结果链接:
resp_content下载地址约 24 小时内有效,请及时保存到本地 - 输入素材:图片/视频 URL 须 公网可访问
- 通用说明:视频模型 API
最小可跑通请求
复制下面 JSON,替换密钥与素材 URL 后即可创建任务:
{
"model": "happyhorse-1.1-i2v",
"content": {
"prompt": "一只橘猫在窗台上缓缓走动,午后阳光洒落,镜头缓慢推进,写实电影感",
"media": [
{ "type": 2, "url": "https://example.com/first.png", "role": "first_frame" }
]
},
"parameters": {
"duration": 5,
"watermark": false
}
}
调用地址
| 步骤 | 方法 | 地址 |
|---|---|---|
| 创建任务 | POST | https://mass.gogpu.cn/v1/videos/completions |
| 查询任务 | POST | https://mass.gogpu.cn/v1/tasks/query |
鉴权:X-API-Key: sk-你的密钥 或 Authorization: Bearer sk-你的密钥。
参数说明
顶层字段
| 字段 | 必传 | 类型 | 说明 |
|---|---|---|---|
model | 是 | string | 接口模型名称(见页首) |
content | 是 | object | 含 prompt / media |
parameters | 否 | object | 生成控制参数,见下表 |
conversation_id | 否 | number | 可选会话 ID |
content
| 字段 | 必传 | 类型 | 说明 |
|---|---|---|---|
prompt | 是 | string | 正向提示词 |
negative_prompt | 否 | string | 反向提示词 |
media | 是 | array | 首帧图,见下表 |
content.media[]
| 字段 | 必传 | 类型 | 可选值 | 说明 |
|---|---|---|---|---|
type | 是 | int | 2 | 图片 |
url | 是 | string | 公网 URL | 首帧图 |
role | 是 | string | first_frame | 首帧 |
parameters
| 字段 | 必传 | 类型 | 可选值 / 范围 | 推荐示例 | 说明 |
|---|---|---|---|---|---|
duration | 否 | int | 以控制台该模型允许范围为准 | 5 | 输出时长(秒) |
resolution | 否 | string | "480P" / "720P" / "1080P" | — | 字符串 |
aspect_ratio | 否 | string | "16:9" 等 | — | 比例 |
watermark | 否 | bool | true / false | false | 水印 |
seed | 否 | int | 整数 | — | 种子 |
任务查询
创建成功只表示任务已受理,不代表视频已生成完成。请用返回的 tid(平台任务号) 轮询查询进度;创建响应里的 task_id 一般可忽略。
视频类任务耗时通常较长:常见需等待数分钟,分辨率更高、带参考素材或视频编辑时可能更久。请保持轮询,不要因「一时查不到结果」就重复创建。
{ "model": "<同上 model>", "tid": 164 }
| 字段 | 必传 | 说明 |
|---|---|---|
model | 是 | 与创建时相同 |
tid | 是 | 创建响应里的 data.tid |
建议每 10~15 秒查询一次;客户端总等待建议 ≥ 15~30 分钟(编辑类可更长)。成功后请尽快下载 resp_content(约 24 小时有效)。
成功响应示例
创建成功(示意)
{
"code": 0,
"data": {
"tid": 164,
"output": { "task_id": "cgt-xxxxxxxx", "task_status": "PENDING" }
},
"msg": "操作成功"
}
记下 data.tid,用于查询。
查询成功(示意)
{
"code": 0,
"data": {
"tid": 164,
"task_status": "SUCCEEDED",
"complete_status": 2,
"resp_content": "https://example.com/result.mp4",
"quantity": 5,
"billing_metric": "480P",
"total_token": 50638,
"total_amount": 2.33,
"fail_reason": ""
},
"msg": "操作成功"
}
| 字段 | 说明 |
|---|---|
task_status | SUCCEEDED 表示成功 |
resp_content | 视频下载地址(约 24 小时内有效,请及时保存) |
quantity | 计费用量;按秒计费时多为秒数 |
billing_metric | 清晰度档,如 480P / 720P |
total_token | Token 用量(按 Token 计费时关注) |
total_amount | 本次金额(元,按量时) |
fail_reason | 失败原因(成功时可为空) |
代码示例
点击右上角标签切换 curl / Python / Node.js / Go(含创建 + 轮询):
curl -sS https://mass.gogpu.cn/v1/videos/completions \
-H "Content-Type: application/json" \
-H "X-API-Key: sk-你的密钥" \
-d '{
"model": "happyhorse-1.1-i2v",
"content": {
"prompt": "一只橘猫在窗台上缓缓走动,午后阳光洒落,镜头缓慢推进,写实电影感",
"media": [{"type": 2, "url": "https://example.com/first.png", "role": "first_frame"}]
},
"parameters": {"duration": 5, "watermark": false}
}'
import json, time, urllib.request
BASE, KEY, MODEL = "https://mass.gogpu.cn", "sk-你的密钥", "happyhorse-1.1-i2v"
def api(path, body):
req = urllib.request.Request(
f"{BASE}{path}",
data=json.dumps(body).encode(),
method="POST",
headers={"Content-Type": "application/json", "X-API-Key": KEY},
)
with urllib.request.urlopen(req, timeout=180) as r:
return json.loads(r.read().decode())
c = api("/v1/videos/completions", {
"model": MODEL,
"content": {
"prompt": "一只橘猫在窗台上缓缓走动,午后阳光洒落,镜头缓慢推进,写实电影感",
"media": [{"type": 2, "url": "https://example.com/first.png", "role": "first_frame"}],
},
"parameters": {"duration": 5, "watermark": False},
})
assert c.get("code") == 0, c
tid = c["data"]["tid"]
print("tid=", tid)
while True:
d = api("/v1/tasks/query", {"model": MODEL, "tid": tid})["data"]
print(d.get("task_status"), d.get("resp_content"), d.get("quantity"), d.get("billing_metric"), d.get("total_amount"), d.get("total_token"))
if d.get("task_status") in ("SUCCEEDED", "FAILED", "CANCELED", "UNKNOWN"):
break
time.sleep(10)
const BASE = "https://mass.gogpu.cn";
const KEY = "sk-你的密钥";
const MODEL = "happyhorse-1.1-i2v";
const api = (path, body) =>
fetch(`${BASE}${path}`, {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": KEY },
body: JSON.stringify(body),
}).then((r) => r.json());
const c = await api("/v1/videos/completions", {
model: MODEL,
content: {
prompt: "一只橘猫在窗台上缓缓走动,午后阳光洒落,镜头缓慢推进,写实电影感",
media: [{ type: 2, url: "https://example.com/first.png", role: "first_frame" }],
},
parameters: { duration: 5, watermark: false },
});
if (c.code !== 0) throw new Error(JSON.stringify(c));
const tid = c.data.tid;
console.log("tid=", tid);
for (;;) {
const d = (await api("/v1/tasks/query", { model: MODEL, tid })).data;
console.log(d.task_status, d.resp_content, d.quantity, d.billing_metric, d.total_amount, d.total_token);
if (["SUCCEEDED", "FAILED", "CANCELED", "UNKNOWN"].includes(d.task_status)) break;
await new Promise((r) => setTimeout(r, 10000));
}
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
const (
base = "https://mass.gogpu.cn"
apiKey = "sk-你的密钥"
model = "happyhorse-1.1-i2v"
)
func api(path string, body any) (map[string]any, error) {
b, err := json.Marshal(body)
if err != nil {
return nil, err
}
req, err := http.NewRequest(http.MethodPost, base+path, bytes.NewReader(b))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-API-Key", apiKey)
client := &http.Client{Timeout: 180 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
raw, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var out map[string]any
if err := json.Unmarshal(raw, &out); err != nil {
return nil, err
}
return out, nil
}
func main() {
var createBody any
if err := json.Unmarshal([]byte(`{
"model": "happyhorse-1.1-i2v",
"content": {
"prompt": "一只橘猫在窗台上缓缓走动,午后阳光洒落,镜头缓慢推进,写实电影感",
"media": [
{ "type": 2, "url": "https://example.com/first.png", "role": "first_frame" }
]
},
"parameters": {
"duration": 5,
"watermark": false
}
}`), &createBody); err != nil {
panic(err)
}
c, err := api("/v1/videos/completions", createBody)
if err != nil {
panic(err)
}
fmt.Printf("%v\n", c)
if fmt.Sprint(c["code"]) != "0" {
panic(fmt.Sprintf("create failed: %v", c))
}
data := c["data"].(map[string]any)
tid := data["tid"]
fmt.Println("tid=", tid)
for {
q, err := api("/v1/tasks/query", map[string]any{"model": model, "tid": tid})
if err != nil {
panic(err)
}
d := q["data"].(map[string]any)
status, _ := d["task_status"].(string)
fmt.Println(status, d["resp_content"], d["quantity"], d["billing_metric"], d["total_amount"], d["total_token"])
switch status {
case "SUCCEEDED", "FAILED", "CANCELED", "UNKNOWN":
return
}
time.Sleep(10 * time.Second)
}
}
计费说明
按 视频时长(秒)× 清晰度档 计费,单价以控制台为准。成功后可在任务查询结果中核对用量与金额。
常见错误
| 现象 | 处理 |
|---|---|
| 模型不可用或不存在 | 核对 model 是否与控制台「接口模型名称」/ GET /v1/models 的 id 完全一致 |
| 余额不足 / 套餐额度不足 | 前往控制台充值或购买/更换套餐后重试 |
| 创建成功但一直轮询不到结束 | 视频生成本身较慢,属正常情况:保持轮询(建议间隔 10~15 秒),客户端总等待建议 ≥ 15~30 分钟;视频编辑可能更久。勿重复创建同一任务 |
| 媒体相关失败 / 无法读取素材 | 确认图片或视频 URL 公网可访问(勿用内网或需登录的地址) |
| 参数错误 / role 或 type 不对 | 严格按本页 media 要求填写;文生请传 media: [] |
