happyhorse-1.0-video-edit
欢喜马 HappyHorse · 视频编辑
接口模型名称:happyhorse-1.0-video-edit(请求体 model 必须与此完全一致)
| 项 | 值 |
|---|---|
| 类型 | 视频编辑(指令 + 源视频 + 可选参考图) |
| 调用方式 | 异步(先创建任务,再查询结果) |
先看这几条
- 计费:按输入+输出时长(秒)× 清晰度档,单价见控制台
- 耗时:视频生成通常较慢(常见数分钟,复杂任务可能更久),请耐心等待
- 调用:异步——创建成功后用
tid轮询/v1/tasks/query查看进度,不要反复提交同一任务 - 结果链接:
resp_content下载地址约 24 小时内有效,请及时保存到本地 - 输入素材:图片/视频 URL 须 公网可访问
- 通用说明:视频模型 API
最小可跑通请求
复制下面 JSON,替换密钥与素材 URL 后即可创建任务:
{
"model": "happyhorse-1.0-video-edit",
"content": {
"prompt": "让视频中的主体穿上参考图中的服装",
"media": [
{ "type": 3, "url": "https://example.com/source.mp4", "role": "video_source" },
{ "type": 2, "url": "https://example.com/ref.png", "role": "reference_image" }
]
},
"parameters": {
"resolution": "720P",
"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 | 编辑指令(要改什么) |
media | 是 | array | 必须含源视频;参考图可选 |
content.media[]
| 字段 | 必传 | 类型 | 可选值 | 说明 |
|---|---|---|---|---|
type | 是 | int | 视频 3 / 图 2 | 与 role 匹配 |
url | 是 | string | 公网 URL | 源视频或参考图 |
role | 是 | string | 源视频 video_source;参考图 reference_image(可选,最多约 5 张) | 与 type 对应填写 |
parameters
| 字段 | 必传 | 类型 | 可选值 / 范围 | 推荐示例 | 说明 |
|---|---|---|---|---|---|
resolution | 建议传 | string | "720P" / "1080P" 等 | "720P" | 字符串;影响计费档 |
watermark | 否 | bool | true / false | false | 水印 |
seed | 否 | int | 整数 | — | 种子 |
duration | 禁止 | — | — | — | 不要传;输出时长跟随输入视频(一般 ≤ 15s) |
aspect_ratio | 一般不传 | string | — | — | 编辑通常跟随源视频 |
源视频必填;参考图可选但做换装/风格参考时建议带上。
任务查询
创建成功只表示任务已受理,不代表视频已生成完成。请用返回的 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.0-video-edit",
"content": {
"prompt": "让视频中的主体穿上参考图中的服装",
"media": [
{"type": 3, "url": "https://example.com/source.mp4", "role": "video_source"},
{"type": 2, "url": "https://example.com/ref.png", "role": "reference_image"}
]
},
"parameters": {"resolution": "720P", "watermark": false}
}'
import json, time, urllib.request
BASE, KEY, MODEL = "https://mass.gogpu.cn", "sk-你的密钥", "happyhorse-1.0-video-edit"
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": 3, "url": "https://example.com/source.mp4", "role": "video_source"},
{"type": 2, "url": "https://example.com/ref.png", "role": "reference_image"},
],
},
"parameters": {"resolution": "720P", "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"))
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.0-video-edit";
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: 3, url: "https://example.com/source.mp4", role: "video_source" },
{ type: 2, url: "https://example.com/ref.png", role: "reference_image" },
],
},
parameters: { resolution: "720P", 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);
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.0-video-edit"
)
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.0-video-edit",
"content": {
"prompt": "让视频中的主体穿上参考图中的服装",
"media": [
{ "type": 3, "url": "https://example.com/source.mp4", "role": "video_source" },
{ "type": 2, "url": "https://example.com/ref.png", "role": "reference_image" }
]
},
"parameters": {
"resolution": "720P",
"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)
}
}
计费说明
按 输入视频时长 + 输出视频时长(秒),并结合清晰度档计费,单价以控制台为准。成功后可在任务查询中核对用量与金额。
常见错误
| 现象 | 处理 |
|---|---|
| 媒体 type / role 不匹配 | 源视频须 type:3 + role:video_source;参考图须 type:2 + role:reference_image |
| 传了 duration 异常 | 编辑类不要传 duration |
| 模型不可用或不存在 | 核对 model 是否与控制台「接口模型名称」/ GET /v1/models 的 id 完全一致 |
| 余额不足 / 套餐额度不足 | 前往控制台充值或购买/更换套餐后重试 |
| 创建成功但一直轮询不到结束 | 视频生成本身较慢,属正常情况:保持轮询(建议间隔 10~15 秒),客户端总等待建议 ≥ 15~30 分钟;视频编辑可能更久。勿重复创建同一任务 |
| 媒体相关失败 / 无法读取素材 | 确认图片或视频 URL 公网可访问(勿用内网或需登录的地址) |
| 参数错误 / role 或 type 不对 | 严格按本页 media 要求填写;文生请传 media: [] |
