首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Muse Video API 与 Muse Image API 实战:一张设定图生成同一角色的系列竖屏短视频,视频每秒 $0.037

Muse Video API 与 Muse Image API 实战:一张设定图生成同一角色的系列竖屏短视频,视频每秒 $0.037

原创
作者头像
用户7679731
发布于 2026-11-02 08:39:25
发布于 2026-11-02 08:39:25
4480
举报

做系列短视频的团队,比如品牌吉祥物、固定出镜的虚拟主播、连续几集的小剧情,最头疼的是同一个角色每条视频长得都不一样。纯文生视频每次都会重新"想象"一张脸;用首帧图生视频能锁住长相,但每条视频都要从同一张图、同一个构图开始,换个场景就得先另做一张首帧。

Muse Video 是 Meta 超级智能实验室(Meta Superintelligence Labs)的视频生成模型,生成 4–30 秒、720p 的横屏或竖屏视频,声音和画面一起生成;Muse Image 是同一实验室的图片模型 Muse Image 1.0。2026 年 7 月 7 日 Meta 发布了 Muse Image,同时放出 Muse Video 的早期预览,两者共用同一个预训练底座。Muse Video 除了首帧,还可以带最多 4 张参考图:模型保留图里的人物,但视频不从这些图开始,场景完全由提示词决定,正好对应上面的问题。

本文的做法是:先用 Muse Image 生成一张角色设定图,裁成"头像"和"三视图"两张参考图,再用 Muse Video 的参考图模式,批量生成同一个角色在不同场景里的竖屏短视频。

先说利益关系:文中用的接口是我们自己做的 apimodels.app,它与 Meta 没有隶属关系。

准备工作

  • Python 3.9 及以上,安装 requests 和 Pillow;第四步检查音轨用到 ffprobe(随 FFmpeg 安装)。
  • 一个 API key,下文用 YOUR_API_KEY 占位。
  • 图片和视频都是异步任务:创建时返回 taskId,再用同一个地址带上 task_id 查询。图片走 POST /v1/images/generations,视频走 POST /v1/video/generations,鉴权放在 Authorization: Bearer 头里。

先看清两个模型的边界

Muse 能调的参数比多数模型少,而且不支持的参数不会被悄悄忽略,会在创建任务时直接返回 400、不扣费。动手前先把边界记住,能省掉很多来回。

Muse Video(模型名 muse-video):

  • 分辨率只有 720p,画幅只有 16:9(1280×720,默认)和 9:16(720×1280)。方形、4:3、21:9 都不支持。
  • 时长是 4–30 的整数秒,默认 5 秒。5、6、8、10、15、20、25、30 秒精确出片,其他秒数向上取到下一档。
  • 图片二选一:1 张首帧,或 1–4 张参考图,不能同时传。支持 PNG、JPEG、WebP,每张最大 20 MB,公网 URL 或 base64 data URI 都可以。
  • 不支持尾帧、视频或音频输入、negative_prompt、seed,声音也关不掉(传 generate_audio: false 返回 400)。没有运镜参数,运镜写在提示词里。
  • 提示词最多 4000 个字符。

Muse Image(模型名 muse-image):

  • 一个请求出一张图(n 只能是 1),约 250 万像素。尺寸只决定比例:1:1 出 1600×1600,3:2 出 1920×1280,16:9 出 2048×1152,9:16 出 1152×2048。传 1024x1024 也交回 1600×1600;传 3840x2160 这类超过约 2.6MP 的尺寸返回 400,没有 4K。
  • aspect_ratio 可以是 auto(默认,由提示词决定形状),或 1:1、3:2、2:3、4:3、3:4、5:4、4:5、16:9、9:16、2:1、1:2、21:9、9:21。
  • 加 1–4 张参考图就是图生图,第 1 张是主图。不支持蒙版局部重绘、透明背景、negative_prompt、seed;quality 可以传,但不起作用。
  • 默认交付 JPEG(质量 95),output_format 可选 png 或 webp。

两个模型都没有 seed,同一个请求每次的结果都不一样。业务上需要可复现输出的,要提前考虑这一点。

第一步:用 Muse Image 生成角色设定图

角色设定图把同一个角色的头像和全身三视图画在一张图里。同一次生成里的人物天然是同一个人,比分开生成几张、再从里面挑长得一致的要省事。这里用 2:1 的宽幅,左边放头像,右边放三视图(示例):

代码语言:python
复制
import time, requests

API_KEY = "YOUR_API_KEY"
H = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
IMG = "https://api.apimodels.app/v1/images/generations"

def wait(url, task_id, interval):
    while True:
        d = requests.get(url, headers=H, params={"task_id": task_id}).json()["data"]
        if d["state"] == "completed":
            return d
        if d["state"] == "failed":
            raise RuntimeError(d.get("failMsg") or "failed")   # 失败不扣费
        time.sleep(interval)

r = requests.post(IMG, headers=H, json={
    "model": "muse-image",
    "prompt": (
        "Character reference sheet on a plain light grey background. "
        "Left third: a head-and-shoulders portrait of a 25-year-old woman with a short black bob, "
        "round glasses and a mustard yellow knit cardigan, facing the camera. "
        "Right two thirds: a full-body turnaround of the same woman, front, side and back views standing in a row. "
        "Even studio lighting, no text, no logos."
    ),
    "aspect_ratio": "2:1",
})
body = r.json()
if body["code"] != 200:
    raise SystemExit(body["msg"])          # 参数错误在这里返回,不建任务、不扣费
sheet = wait(IMG, body["data"]["taskId"], 5)
print(sheet["resultUrls"][0], sheet.get("images"))

任务完成后,resultUrls[0] 是图片地址,images 里带实际宽高。我们测试时每张约 35–70 秒;只有交付了图片才扣费,每张 $0.02。

习惯用 OpenAI SDK 的话,也可以一次调用直接拿到图:传 size 且不带 callback_url 时,同一个响应里就返回图片,不用轮询。

代码语言:python
复制
from openai import OpenAI

client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.apimodels.app/v1")
img = client.images.generate(model="muse-image", prompt="...", size="2048x1152")
print(img.data[0].url)

第二步:把设定图裁成两张参考图

整张设定图直接当参考图也能用,但头像在宽幅图里只占一小块。我们的做法是把头像和三视图裁开,分成两张传,测试的几组里,人物的脸、发型和衣着在视频里都和参考图一致。下面按左三分之一切开,转成 base64 data URI,这样不用另找地方托管图片(示例):

代码语言:python
复制
import base64, io
from PIL import Image

raw = requests.get(sheet["resultUrls"][0]).content
im = Image.open(io.BytesIO(raw)).convert("RGB")
w, h = im.size
cut = w // 3

def to_data_uri(part):
    buf = io.BytesIO()
    part.save(buf, format="JPEG", quality=92)
    return "data:image/jpeg;base64," + base64.b64encode(buf.getvalue()).decode()

refs = [
    to_data_uri(im.crop((0, 0, cut, h))),     # 参考图 1:头像
    to_data_uri(im.crop((cut, 0, w, h))),     # 参考图 2:三视图
]

模型不会严格按"左三分之一"排版,正式跑批之前打开设定图看一眼切口位置,偏了就调整 cut。

第三步:用参考图模式批量提交视频

参考图放在 images 数组里(写成 image_urls 或 reference_image_urls 也可以)。提示词开头点明"参考图里的这个人",再写新场景(示例):

代码语言:python
复制
VID = "https://api.apimodels.app/v1/video/generations"

scenes = {
    "cafe":  "sits by the window of a small cafe, wraps both hands around a latte, looks up at the camera and laughs",
    "park":  "walks through an autumn park, kicks up a few fallen leaves, then turns back toward the camera and waves",
    "books": "pulls a book from a shelf in an indie bookstore, flips it open and holds it up to show the cover",
}

tasks = {}
for name, action in scenes.items():
    r = requests.post(VID, headers=H, json={
        "model": "muse-video",
        "prompt": f"The same young woman from the reference images {action}. Handheld vertical shot, natural light.",
        "images": refs,                 # 1–4 张参考图;数组哪怕只有一项,也按参考图处理
        "duration": 10,
        "aspect_ratio": "9:16",         # 720x1280
        # "callback_url": "https://your-domain.example/hooks/video",
    })
    body = r.json()
    if body["code"] != 200:
        print(name, body["msg"])        # 400 在这里返回,不建任务
        continue
    tasks[name] = body["data"]["taskId"]

print(tasks)

写提示词的几条经验:

  • 超过 10 秒的片子分段写。 10 秒以上的视频会在 10 秒左右换镜头,按"前 10 秒……然后……"的顺序写,比一整段描述更可控。
  • 只写想要的,不写不要的。 Muse 没有反向提示词,Avoid ... 这类句子里的每个词它都会读进去,里面的敏感词同样可能触发内容安全检查。
  • 时长只用 duration 指定。 提示词里写了秒数,模型会照着去控时长,可能和 duration 对不上。
  • 运镜写进提示词。 比如 handheld、slow push-in、tracking shot,接口没有单独的运镜参数。

第四步:拿结果,顺便检查音轨

视频任务按 pending → processing → completed / failed 推进。10 秒以内的片子通常 1–2 分钟出片,15–30 秒通常 3–7 分钟,每 10–15 秒查一次就够了。成片是 H.264 MP4、24 fps,文件保留 30 天,要长期保存需要自己转存。

代码语言:python
复制
import subprocess

for name, tid in tasks.items():
    try:
        d = wait(VID, tid, 15)
    except RuntimeError as e:
        print(name, "failed:", e)
        continue
    url = d["resultUrls"][0]
    path = f"{name}.mp4"
    with open(path, "wb") as f:
        f.write(requests.get(url).content)
    # 不是每条都有声音:用 ffprobe 看有没有音频流
    out = subprocess.run(
        ["ffprobe", "-v", "error", "-select_streams", "a",
         "-show_entries", "stream=index", "-of", "csv=p=0", path],
        capture_output=True, text=True,
    ).stdout.strip()
    print(name, url, "audio" if out else "NO AUDIO")

之所以要查音轨:Meta 介绍 Muse Video 的声音和画面一起生成,但我们上线时测试的两条里有一条是无声的。流程里必须有声音的,逐条检查,没有声音就重试或者后期配乐。

批量任务也可以在创建时传 callback_url。任务到达 completed 或 failed 时,你会收到一个 POST;投递失败会在 30 分钟内按退避间隔重试,直到你的接口返回 2xx。回调里的视频地址放在 resultJson 这个字符串字段里,需要再 json.loads 一次。回调地址必须公网可达,填 localhost 或内网地址,创建时就会返回 400。

首帧和参考图怎么选

两种方式价格相同,区别在于视频从哪里开始:

  • 首帧:图片放在单图字段 image_url(也可以写成 first_frame_url、image、input_reference)。视频从这张图开始,提示词写接下来怎么动。适合手上已经有一张满意的画面、只想让它动起来。首帧图的横竖方向要和 aspect_ratio 一致。
  • 参考图:图片放在数组字段 images(也可以写成 image_urls、reference_image_urls)。模型保留人物、主体或风格,但视频不从任何一张图开始。适合同一个角色要出现在很多不同场景里。

两种不能放在同一个请求里,同时传会返回 400。最容易踩的坑是字段名:数组字段哪怕只放一张图,也一律按参考图处理;想要首帧效果,必须用单图字段。

算成本:按请求的秒数,不按成片时长

Muse Video 每秒 $0.037,按请求里的 duration 计费。成片因为向上取档可能比请求的长,多出来的部分不收费。常用时长的价格:

  • 5 秒:$0.185
  • 8 秒:$0.296
  • 10 秒:$0.37
  • 15 秒:$0.555
  • 30 秒:$1.11

请求 4 秒,出 5 秒的片、收 $0.148;请求 7 秒,出 8 秒的片、收 $0.259。三种输入方式(文生、首帧、参考图)同价。

本文这套流程:1 张设定图 $0.02,加 3 条 10 秒竖屏 3 × $0.37 = $1.11,合计 $1.13。之后同一个角色每多一条 10 秒视频,再加 $0.37,设定图可以一直复用。

失败的任务不扣费。每一单的实际扣费可以用 GET /v1/records/{task_id} 查,返回里的 credits 是实扣金额。这个查询本身不收费,适合逐单对账。

失败了怎么处理

两个模型的成功率都不是 100%。请求通过参数校验、建好任务之后,仍然可能失败,原因写在 data.failMsg 里:

  • 内容被拒:最常见的是 Muse Video 的内容安全检查。暴露的服装(内衣、泳装、透视面料)和带暗示性的措辞都容易触发,写在 Avoid 句子里也一样。这类失败原样重试通常没用,要把提示词改得更平实,或者换一张参考图。
  • 临时错误:稍后原样重试,通常就能成功。
  • 成片不合格:横竖方向不对、或者比请求的时长短的视频,会被作废而不是交付,重新提交即可。

实践中按"偶尔会失败"来设计流程:临时错误自动重试一两次,内容被拒的单子标记出来、人工改写提示词,不要假设第一次请求一定能拿到视频。

常见报错

下面这些都在创建任务时返回,不建任务、不扣费:

  • muse-video supports 16:9 (1280x720) or 9:16 (720x1280) only — set aspect_ratio to 16:9 or 9:16:传了 1:1、1920x1080 等其他比例或尺寸,或者 aspect_ratio 和 size 不一致。
  • muse-video outputs 720p only (resolution: 720p):resolution 传了 1080p 等其他值。去掉它,或者传 720p。
  • duration must be a whole number of seconds from 4 to 30:时长不在 4–30 之间,或者带了小数。
  • muse-video takes either a first frame (image_url) or reference images (images), not both:首帧和参考图同时传了,二选一。
  • muse-video takes at most 4 reference images (images / image_urls):参考图超过 4 张,挑最能代表这个角色的 4 张。
  • muse-video cannot turn sound off: the model decides whether a clip has sound:传了 generate_audio: false。需要无声视频,就在后期去掉音轨。
  • muse-image generates one image per request (got n=2); submit one request per image:图片的 n 大于 1。要多张就并行发多个请求。
  • muse-image does not support masks (mask): describe what to change in prompt instead:Muse Image 没有局部重绘,去掉蒙版,把要改的地方写进提示词。

什么时候别用 Muse

  • 需要 1080p、4K 视频,或者方形、4:3、21:9 视频:Muse Video 只有 720p 的横屏和竖屏。
  • 需要尾帧控制、视频编辑或续写、按自己的音频对口型:Muse Video 只接受提示词和图片。
  • 需要同一个请求每次结果一样:两个模型都没有 seed。
  • 需要透明背景、蒙版局部重绘、4K 或精确像素尺寸的图片:Muse Image 都不支持。
  • 需要稳定的无声视频:声音关不掉,只能后期去掉。

apimodels.app 在这套流程里的位置

apimodels.app 是一个多模型 API 网关:用一个 API key、一个 OpenAI 兼容端点调用图像、视频、语音和语言模型。在上面的流程里,Muse Image 和 Muse Video 用的是同一个 key、同一套异步任务格式,上文的 wait 函数图片和视频通用。

它在这套流程里做的几件具体的事:

  • 不支持的参数在创建时返回 400 并写明原因,不会被悄悄忽略,也不会排队几分钟后才发现结果不对。
  • 横竖方向不对或比请求时长短的视频会被作废,不会交付给你。
  • 失败不扣费,每一单的实扣金额可以单独查询。
  • 支持回调,投递失败会自动重试。

如果一共只做几条视频,在网页上手动生成就够了,没必要专门接接口。

限制

  • 本文的参数和价格以 2026-11-02 的接口文档为准,之后如有调整,以文档为准。
  • 我们不公布 Muse 的成功率,接入时请按"偶尔会失败"设计重试和人工处理。
  • 设定图的排版和参考图的一致性效果依赖提示词,文中的裁切比例要按实际出图调整。
  • 结果文件保留 30 天。

你在做系列短视频时,角色一致性是靠首帧、参考图,还是靠一段固定的人物描述?欢迎在评论区聊聊各自的做法。


接口文档:apimodels.app 的 Muse Video 接口文档;apimodels.app 的 Muse Image 接口文档。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 准备工作
  • 先看清两个模型的边界
  • 第一步:用 Muse Image 生成角色设定图
  • 第二步:把设定图裁成两张参考图
  • 第三步:用参考图模式批量提交视频
  • 第四步:拿结果,顺便检查音轨
  • 首帧和参考图怎么选
  • 算成本:按请求的秒数,不按成片时长
  • 失败了怎么处理
  • 常见报错
  • 什么时候别用 Muse
  • apimodels.app 在这套流程里的位置
  • 限制
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档