HappyHorse 1.1 图生视频:API 调用方法和实测片段
一个脚本上传静图、轮询任务、保存 MP4。字段、水印和配乐的意外表现,加上 2026 年 11 月 2 日跑出的 5 条片段。

本页内容
用 HappyHorse 1.1 图生视频,把静图作为 first_frame POST 到 https://api.omniakey.com/v1/media/tasks,模型 ID 用 happyhorse-1.1-i2v,然后轮询任务、下载 MP4。2026 年 11 月 2 日,我们跑了 5 条 5 秒 720P 的片段,每条用时 92 到 158 秒。每条都带了没要求过的音乐,默认还会加一个 "Happy Horse" 水印。
简短回答
- 请求:模型
happyhorse-1.1-i2v,操作image_to_video,input.media里正好一个first_frame。 - 画面比例:片段跟随静图,因为没有
ratio字段。 - 时长和分辨率:3 到 15 秒,480P、720P 或 1080P。
resolution每次都要传,阿里云的默认值是 1080P。 - 水印:默认开启,传
watermark: false关闭。 - 声音:我们 5 条片段都有音乐,阿里云的 API 没有音频开关,可以用
ffmpeg去掉音轨。
第一次调用 HappyHorse 1.1 图生视频要准备什么?
需要三样东西:一个 key、Python 3,以及一张符合阿里云规则的静图。
- key 放在
OMNIAKEY_API_KEY。脚本把它作为 Bearer token 发送,代码里不留明文。 - Python 3,不用装任何东西。脚本只用标准库。
- 静图要符合 阿里云的图生视频 API 参考:JPEG、JPG、PNG 或 WEBP;宽高至少 300 像素;不超过 20 MB;宽高比 1:2.5 到 2.5:1。阿里云没有写像素上限。
麻烦在体积:内联静图跟着请求体一起走,整个请求含 Base64 必须小于 1 MiB(OmniaKey 媒体 API 概览,2026 年 11 月 2 日核对)。脚本超过 700 KB 就停下;再大就压缩静图,或者传公开的 HTTPS 链接。我们的 2K 静图是 2,254,819 字节,下面这条 macOS 命令把它压到 92,212 字节:
sips -s format jpeg -s formatOptions 85 -Z 1280 still.jpg --out still-small.jpg
请求里有哪些字段?
九个字段决定任务:顶层三个,input 里两个,parameters 里四个。
| 字段 | 取值 | 说明 |
|---|---|---|
model | happyhorse-1.1-i2v | 1.1 图生视频的模型 ID |
type | video | 任务产出的文件类型 |
operation | image_to_video | 不带前缀的名字 |
input.prompt | 文本 | OmniaKey 要求必填,阿里云的 API 视为可选;最多 5,000 个非中文字符或 2,500 个中文字符,超出会被截断 |
input.media | 正好一个 {"type": "first_frame", "url": ...} | 公开的 HTTPS 链接或 data URI |
parameters.resolution | 480P、720P 或 1080P | 每次都传:阿里云默认 1080P |
parameters.duration | 整数秒,3 到 15 | OmniaKey 上必填 |
parameters.watermark | true(默认)或 false | false 去掉 "Happy Horse" 文字 |
parameters.seed | 0 到 2147483647 | 同一个 seed 也不保证同一条片段 |
有四个细节容易漏。
- 没有
ratio字段:片段保持静图的宽高比(阿里云图生视频 API 参考,2026 年 11 月 2 日核对)。 - 阿里云的页面没有负向提示词字段。
- 每次创建任务都要带
Idempotency-Key请求头。同一个 body 重放会返回原来的任务,不会重复扣费;body 不同会得到409 idempotency_key_reused(OmniaKey 的 视频 API 文档,2026 年 11 月 2 日核对)。 - 输出尺寸会变:OmniaKey 的文档里,1200×630 的静图用 720P 生成,回来是 1324×696。
Python 脚本
下面是实际运行的完整文件,只用标准库。
"""Animate one still with HappyHorse 1.1 image-to-video through the OmniaKey media API.
Usage:
export OMNIAKEY_API_KEY="your-omniakey-api-key"
python3 hh_i2v.py still.jpg "The camera slowly orbits the headphones." clip.mp4
The still can be a local JPEG or PNG (sent inline as a data URL) or a public https:// URL.
"""
import base64
import json
import mimetypes
import os
import sys
import time
import urllib.error
import urllib.request
import uuid
API = "https://api.omniakey.com/v1/media/tasks"
HEADERS = {
"Authorization": "Bearer " + os.environ["OMNIAKEY_API_KEY"],
"Content-Type": "application/json",
"User-Agent": "happyhorse-i2v-example/1.0",
}
POLL_SECONDS = 10
GIVE_UP_AFTER = 15 * 60 # most clips finish in 1-5 minutes
def call(method, url, body=None, extra_headers=None):
data = json.dumps(body).encode() if body is not None else None
req = urllib.request.Request(url, data=data, method=method, headers={**HEADERS, **(extra_headers or {})})
for attempt in range(3):
try:
with urllib.request.urlopen(req, timeout=60) as resp:
return json.load(resp)
except urllib.error.HTTPError as err:
sys.exit(f"HTTP {err.code}: {err.read().decode(errors='replace')}")
except (urllib.error.URLError, TimeoutError, ConnectionError) as err:
if attempt == 2:
raise
print("network error, retrying:", err) # a retried POST keeps its Idempotency-Key
time.sleep(5)
def first_frame_url(image):
if image.startswith("https://"):
return image
raw = open(image, "rb").read()
if len(raw) > 700_000: # Base64 adds a third, and the whole request must stay under 1 MiB
sys.exit("The still is over 700 KB. Resize it or pass a public https:// URL instead.")
mime = mimetypes.guess_type(image)[0] or "image/jpeg"
return f"data:{mime};base64,{base64.b64encode(raw).decode()}"
def main(image, prompt, out_path):
task = call("POST", API, {
"model": "happyhorse-1.1-i2v",
"type": "video",
"operation": "image_to_video",
"input": {"prompt": prompt, "media": [{"type": "first_frame", "url": first_frame_url(image)}]},
"parameters": {"resolution": "720P", "duration": 5, "watermark": False}, # watermark is on by default
}, {"Idempotency-Key": str(uuid.uuid4())})
print("task", task["id"], task["status"])
start = time.time()
while task["status"] in ("queued", "processing"):
if time.time() - start > GIVE_UP_AFTER:
sys.exit(f"Still {task['status']} after 15 minutes. Do not submit it again; "
f"check it later with GET {API}/{task['id']}")
time.sleep(POLL_SECONDS)
task = call("GET", f"{API}/{task['id']}")
print(task["status"], "after", round(time.time() - start), "s")
if task["status"] != "succeeded":
sys.exit(json.dumps(task.get("error") or task))
# The signed download URL is short-lived, so save the file right away.
req = urllib.request.Request(task["assets"][0]["url"], headers={"User-Agent": HEADERS["User-Agent"]})
with urllib.request.urlopen(req, timeout=300) as resp, open(out_path, "wb") as f:
f.write(resp.read())
print("saved", out_path)
if __name__ == "__main__":
main(*sys.argv[1:4])
保存为 hh_i2v.py,然后运行:
export OMNIAKEY_API_KEY="your-omniakey-api-key"
python3 hh_i2v.py still.jpg "The camera slowly orbits the headphones." clip.mp4
我们那次 watermark: false 的运行打印了这些:
task task_QqK3ZdAd72vmK1DSOuOxXSytBSaJ244v queued
succeeded after 91 s
saved data/clips/c5-orbit-nowm.mp4
脚本里有五处值得注意。
- 每 10 秒轮询一次。
- 15 分钟后放弃,并提示不要再提交。
- 网络错误会重试。重试的创建请求保留
Idempotency-Key,拿回原来的任务,不会多扣一次费。 - 任务成功后马上保存文件,因为签名下载链接的有效期很短。
- 每个请求都带 User-Agent:2026 年 10 月 29 日我们测 Kling 3.0 API 时,Python 默认的 User-Agent 被 Cloudflare 以
error code: 1010返回 HTTP 403。
我们跑的五条片段
我们用 Nano Banana 2.1 生成了四张静图,又把耳机那张跑了两次来测水印。2026 年 11 月 2 日一共得到五条片段,都是 5 秒、720P。人像、湖面和狐狸三条用了默认设置,所以画面里带水印。
耳机环绕
The camera slowly orbits about 90 degrees to the right around the headphones while a soft band of light sweeps across the ear cups. The headphones stay perfectly still on the pedestal. Smooth, steady product-commercial camera move.

镜头从耳机一侧转到另一侧,耳机始终留在石台上。中间几帧里,耳机后面出现静图中没有的弧形背景边缘;提示词要的那道光带很难看出来。
同一张静图、同一段提示词,我们跑了两次:一次默认设置,一次 watermark: false。右下角能看到差别。

雨中人像
She slowly turns her head toward the camera and gives a small smile while light rain keeps falling. The neon signs behind her flicker softly and the camera pushes in a little.

她从向左看转为面向镜头并微笑,顺序和提示词一致,每一帧都带水印。提示词要求轻微推进,画面从半身变成脸部特写。
湖面推进
Slow aerial push-in over the water toward the rowboat. Mist drifts across the lake, the boat rocks gently and small ripples spread from its hull, and the golden light grows a little brighter.

镜头向小船推进,和提示词一致。到结尾时小船占了大部分画面,船身周围散开水波。
狐狸插画
The fox turns a page of the book with its paw and its ears twitch. A few orange leaves drift down from the tree and the branches sway gently. Keep the flat illustration style.

从第一帧到最后一帧,扁平插画风格都保持住了,橙色叶子不断飘落。镜头从整棵树推近到狐狸特写,这一点提示词没有要求;书页翘了起来,不过画面不能确认爪子翻了页。

我们 4 段提示词里有 2 段,镜头动得比要求的多,所以先跑一条短片确认取景。文档里最短、最低的一档是 3 秒 480P(阿里云图生视频 API 参考,2026 年 11 月 2 日核对)。
文件实测数据
| 片段 | 比例 | 像素 | 帧数 | 耗时 | 字节 |
|---|---|---|---|---|---|
| 环绕,默认 | 16:9 | 1286×716 | 123 | 128 秒 | 1,486,548 |
环绕,watermark: false | 16:9 | 1286×716 | 121 | 98 秒 | 1,320,527 |
| 雨中人像 | 9:16 | 716×1286 | 123 | 158 秒 | 2,108,577 |
| 湖面 | 16:9 | 1286×716 | 123 | 131 秒 | 2,691,558 |
| 狐狸 | 1:1 | 960×960 | 123 | 92 秒 | 2,405,557 |
每个文件标的时长都是 5.16 秒,虽然我们要的是 5 秒:那是音频流的长度,视频流 123 帧时是 5.13 秒,121 帧时是 5.04 秒。五条都是 24 fps 的 H.264,带一条双声道 AAC 音轨,切镜检测脚本没有发现任何剪切点。
我们的片段从提交到下载用了 92 到 158 秒。阿里云文档给图生视频任务的时间是 1 到 5 分钟(阿里云图生视频 API 参考,2026 年 11 月 2 日核对)。我们没有测试 480P、1080P、其它时长、seed、公开图片链接、HappyHorse 1.0,以及阿里云自己的接口地址。要比较模型,看 HappyHorse 1.1 对比 Seedance 2.0 和 HappyHorse 1.1 对比 Kling 3.0。不想写代码,也可以在 AI 视频生成器 里直接用 HappyHorse 1.1 重跑。
为什么片段里有声音?
HappyHorse 1.1 给五条片段都加了配乐,虽然我们的提示词都没要求。没有人试听:我们通过 OmniaKey API 让 Gemini 3.8 Flash 描述每条音轨。
| 片段 | 模型的描述 | 平均响度 |
|---|---|---|
| 环绕,默认 | “有节奏的嘻哈鼓点,带切分打击乐、拍手和柔和的合成器和弦。” | −19.5 dB |
环绕,watermark: false | “舒缓而有节奏的电子音乐,稳定的节拍和旋律化的合成器音色” | −20.5 dB |
| 雨中人像 | “缓慢、忧郁而轻柔的钢琴旋律,配柔和的环境氛围声” | −22.6 dB |
| 湖面 | “缓慢、轻柔而抒情的钢琴旋律” | −20.2 dB |
| 狐狸 | “用柔和铃音演奏的平静环境旋律”,加上“砾石上的脚步声” | −27.4 dB |
Gemini 3.8 Flash 在五条音轨里都没有报告人声。同样的提示词和静图跑两次,得到两条不同的音轨。
阿里云的图生视频参考里没有音频字段,也没有静音选项,不过 1.1 的发布说明提到音画同步(阿里云的新发布模型页面,2026 年 11 月 2 日核对)。要得到无声文件,下载后去掉音轨:
ffmpeg -i clip.mp4 -an -c:v copy silent.mp4
我们在 watermark: false 那条上跑了这条命令,结果有视频流、没有音频流。画面完全不变,因为 -c:v copy 直接复制视频流,不重新编码。
结果能保留多久?
在 OmniaKey 上,MP4 的签名链接大约有效 1 小时,任务记录保留 24 小时;再轮询一次任务就能拿到新链接(OmniaKey 媒体 API 概览,2026 年 11 月 2 日核对)。在阿里云自己的 API 上,视频链接和任务 ID 都保留 24 小时,之后查询返回 UNKNOWN,文件已经删除。任务成功就尽快下载。
会遇到哪些错误?
我们五次运行都没有失败,所以这份列表来自 OmniaKey 的视频 API 文档,2026 年 11 月 2 日核对。
| 状态 | 含义 | 处理 |
|---|---|---|
400 invalid_request | 请求体格式不对,或者任务没有 input.prompt | 对照上面的请求结构检查 |
400 model_price_error | 时长超出模型范围,或者分辨率没有定价 | 换支持的时长和分辨率 |
403 model_not_allowed | key 或分组没有这个模型 | 检查 key 的模型权限 |
409 idempotency_key_reused | 同一个键已经用不同的 body 发过 | 只在完全相同的重试里复用键 |
503 no_available_channel | 当前没有渠道提供这个模型或操作 | 稍后再试,或者看控制台 |
任务以 failed 结束时自动退款,所以失败的渲染不花钱,只耽误时间(OmniaKey 媒体 API 概览,2026 年 11 月 2 日核对)。
别把自己这边的超时当成任务失败。继续轮询同一个任务 ID;重新提交会开第二个任务,也会再扣一次费。如果确实要重发,保持同一个 Idempotency-Key 和同样的 body,就能拿回原来的任务。
一条 HappyHorse 1.1 片段多少钱?
一条 5 秒 720P 片段按阿里云新加坡的标价是 $0.70。下面是阿里云的每秒价格,来自它的价格页,2026 年 11 月 2 日核对:
| 分辨率 | 新加坡 | 北京和 Global |
|---|---|---|
| 480P | $0.07 | $0.0618845 |
| 720P | $0.14 | $0.123769 |
| 1080P | $0.18 | $0.165026 |
账单是每秒价格乘以输出秒数。失败的请求不计费。新加坡还有 10 秒的免费额度,有效期 90 天。价格页里,Global 价格适用于法兰克福、弗吉尼亚和东京。
OmniaKey 按渲染输出的秒数计费,创建任务时预扣,失败或取消的任务自动退款;当前价格见 HappyHorse 1.1 页面。
能直接调用阿里云吗?
可以。HappyHorse 在阿里云 Model Studio 上提供服务,新加坡、美国(弗吉尼亚)、北京、法兰克福和东京都有区域接口地址(阿里云图生视频 API 参考,2026 年 11 月 2 日核对)。我们的运行都走 OmniaKey 的 API,下面的内容来自阿里云的文档。
- 新加坡用
POST https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api/v1/services/aigc/video-generation/video-synthesis创建。 - 带上
X-DashScope-Async: enable请求头,否则请求会以 "current user api does not support synchronous calls" 失败。 - 每 15 秒左右轮询
GET .../api/v1/tasks/{task_id};状态依次是PENDING、RUNNING、SUCCEEDED、FAILED、CANCELED、UNKNOWN。 - 模型、接口地址和 key 放在同一个区域,跨区域调用会失败。
- 一个 key 每秒 5 个请求、5 个并发任务(阿里云的限流页面,2026 年 11 月 2 日核对)。
价格页列出了东京,限流页没有东京的 1.1 图生视频条目,所以东京这一项还没有确认。
国内怎么用
OmniaKey 支持人民币直充(支付宝、微信支付),一个 key 就能调用多家模型,包括 HappyHorse 1.1 和我们用来生成静图的 Nano Banana 2.1,不用自己再去申请阿里云的账号。上面的 Python 脚本就是我们实际跑的请求,把你自己的 key 填进 OMNIAKEY_API_KEY 就能用。
常见问题
用 HappyHorse 图生视频必须写提示词吗?
在 OmniaKey 上必须写:没有 input.prompt 的任务会得到 400 invalid_request(OmniaKey 视频 API 文档,2026 年 11 月 2 日核对)。阿里云自己的 API 把提示词视为可选,只用第一帧也能生成。无论哪种,都写清动作和镜头运动,像上面几段提示词那样。
怎么去掉 Happy Horse 水印?
传 parameters.watermark: false。默认的 true 会在右下角画上白色小字 "Happy Horse";我们第二条环绕片段传了 false,回来是干净的。
怎么设置画面比例?
裁静图。图生视频没有 ratio 字段,片段跟随第一帧的形状,所以 16:9 的静图得到 16:9 的片段,竖图得到 9:16 的片段。裁切比例保持在 1:2.5 到 2.5:1 之间。
有 HappyHorse 1.5 吗?
截至 2026 年 11 月 2 日,阿里云的模型列表、价格表和生命周期页面里都没有 1.1 之后的版本。这些页面上的最新版本是 happyhorse-1.1-i2v,发布于 2026 年 6 月 16 日。有些站点用了 "Happy Horse 1.5" 这个名字。
图生视频选 HappyHorse 1.1 还是 1.0?
阿里云说 1.1 提升了画质、动态表现和片段间一致性,价格页也给 1.1 单独列了 480P 档。1.1 在 2026 年 6 月 16 日发布,1.0 在 2026 年 4 月 22 日发布。按阿里云新加坡的价格,1.1 的 1080P 每秒 $0.18,1.0 是 $0.24。
参考来源
- 阿里云:HappyHorse 图生视频 API 参考,2026 年 11 月 2 日核对
- 阿里云:模型价格,2026 年 11 月 2 日核对
- 阿里云:模型列表,2026 年 11 月 2 日核对
- 阿里云:新发布模型,2026 年 11 月 2 日核对
- 阿里云:限流,2026 年 11 月 2 日核对
文中提到的模型
相关文章
HappyHorse 1.1 vs Seedance 2.0:同一提示词实测对比与价格
三条提示词、同一天:Seedance 2.0 出片更好,HappyHorse 1.1 快一倍。
HappyHorse 1.1 vs 可灵 3.0:同一提示词实测对比与价格
三条提示词:HappyHorse 1.1 赢了夜市和香水瓶,可灵 3.0 把滑板动作做对了。
Kling 3.0 API:文生视频的请求代码和实测片段
一次 POST、模型填 kling-3.0,就是一条文生视频任务。下面是请求代码、请求体里的字段,以及我们 2026 年 10 月 29 日实跑并测量过的两条 5 秒片段。

