GPT-6 Sol、Claude Opus 5.5 已上线GPT-6 Sol 价格仅为 5.6 Sol 的一半

Seedance 2.0 对口型:台词口型同步和 4 段实测

口型跟着提示词走,我们自己的录音也回到了输出音轨里。

Kiki, OmniaKey COO11 分钟阅读
本页内容

Seedance 2.0 口型由提示词驱动:只差音频开关的两条片,嘴都从闭口张到最大。我们 1.8 秒的录音经 reference_to_video 传进去,音轨回到了那句话。只传音频会被上游拒绝,720P 每秒 $0.15,5 秒 $0.75。

先说结论

  • 口型来自提示词。同一条提示词、两个 5 秒 720P 视频,一个开音频一个关音频,都出现闭口 → 微张 → 张大。
  • 只传音频会被拒。2.0 系列至少要带一张参考图或一段参考视频(BytePlus 建任务接口,2026 年 11 月 3 日核对)。
  • 参考音频最多 3 段,每段 2–15 秒,合计 15 秒,格式 wav 或 mp3,每段 15 MB。
  • 音频会被用上。我们 1.8 秒的 mp3 回到了输出音轨里,台词是完整的。
  • 按 BytePlus 的秒价,720P 每秒 $0.15,5 秒 $0.75。
  • 同一天的 4 条片:720P 有声、720P 无声、方形 720P 图生视频、480P 参考音频。

Seedance 2.0 能对口型吗?

官方文档里找不到「对口型」这个词。文档写的是画面和声音一起生成,再加一句把台词放进双引号的建议。

ByteDance 的 Seed 页面说 Seedance 2.0 是「a unified multimodal audio-video joint generation architecture that supports text, image, audio, and video inputs」(2026 年 11 月 3 日核对)。BytePlus ModelArk 的指南重复了这一点,能力列表里写着「Generate videos with audio」(页面更新于 2026 年 9 月 29 日)。

在这几页里搜关键词:「lip sync」和「talking」一次都没出现。「mouth」只出现在一条示例提示词里,「dialogue」出现两次,两次都在讲音频生成。最接近操作的是一句建议:「It is recommended to put dialogue content in double quotes to optimize the audio generation effect」(建任务接口,更新于 2026 年 10 月 28 日)。

所以这项能力落在两者的空隙里:模型会出画面也会出音轨,官方页面没讲过嘴唇对上每个音节。我们这次 4 条片,开音频和关音频都能看到嘴在动,符合「提示词说有人在说话」的画面模型行为。

也有人一直在试。2026 年 2 月 18 日的一条 Hacker News 评论把歌和视频一起传进去,结论是「the model did reference the singing music I provided, but it reinterpreted it on its own」(评论)。2026 年 6 月 3 日的 GitHub issue 把「Mouth movements match phoneme timing」写成通过条件,这个测量官方文档里没有(issue)。

台词怎么写进提示词?

先写角色,再把台词放进双引号,最后写嘴和脸怎么动。我们的提示词写了角色和口型,漏了双引号,所以那句台词是模型自己编的。

我们这次用的写法,分五步:

  1. 一句话交代角色:定格黏土、大圆眼镜、针织围巾、坐在厨房桌边。
  2. 说明他在做什么:对镜头说一句短台词。
  3. 把台词原样放进双引号,这是 BytePlus 的建议。
  4. 写嘴和脸:嘴跟着词开合,眉毛跟着句子动,重音处头略偏。
  5. 锁住镜头和灯光,画面里只剩表演在动。

下面是 4 条片共用的提示词,原样照抄:

A stop-motion clay character with big round glasses and a knitted scarf sits at a kitchen table, looks straight into the camera, and speaks one short line to the viewer. The mouth opens and closes in time with the words, the eyebrows move with the sentence, and the head tilts slightly on the stressed word. Fixed camera, warm lamp light, a mug of tea in front of them, gentle 24 fps stop-motion feel.

少的就是台词本身。提示词只说了「一句短台词」,所以词是模型挑的。打开音频后,音轨里说的是「You look like you could use a warm hug.」,这句在请求里一个字都没有。想控制台词,第 3 步必须在提交前补上。

口型我们按每 0.5 秒一帧抽出来看。有声那条从闭口开始,第 2 到第 7 帧微张,第 8 帧张大,然后微张再闭上。无声那条是闭口、微张、张大、微张、张大,最后两帧微张。

十帧黏土角色的脸部特写,戴圆眼镜和围巾,每半秒一帧:第一帧和最后一帧闭嘴,中间张口,第 8 帧张得最大。
开了音频,每半秒一帧:第 1 帧闭嘴,第 2 到 7 帧微张,第 8 帧张大,到第 10 帧又闭上。Seedance 2.0 经 OmniaKey,文生视频,5 秒,720P,2026 年 11 月 3 日生成。
十帧橙色黏土角色的脸部特写,围深绿色围巾,每半秒一帧,嘴一张一合,来自一条没有音轨的视频。
关掉音频、同一条提示词:嘴照样一张一合,第 5、6、8 帧张得最大,文件里完全没有音轨。5 秒,720P,2026 年 11 月 3 日生成。

同一段话也会选到不同角色:无声那条回来是橘色身体、灰棕分头、深绿围巾。角色那句话当成建议来写就好。两条的镜头都没动,这是「Fixed camera」换来的。

能传自己的音频吗?

能,同一次请求里带一张参考图或一段参考视频就行。我们 1.8 秒的 mp3 作为参考音频传了进去,词回到了输出音轨。

这次用的是 reference_to_video,请求里有三样东西:黏土角色的静帧作为参考图,我们的录音作为参考音频,还有上面那段提示词。参数是 480P、5 秒、打开生成音频。OmniaKey 返回 202,任务 task_3Ay0Ktf2mbYXh9GNZpZ5j9kGyOIzz8Pv 成功。120.2 秒后拿到 MP4,864×496,音轨 5.06 秒,编码 aac。

音轨的听写结果是一整句:「Why tow it? I told you the keys were in the drawer.」后半句就是我们录的那句,一个词不差。前面三个词不在我们传的文件里;听写分不清它是我们的气口还是模型新说的话,所以只把听到的原句写在这里。

十帧褐色黏土角色戴帽子、围橙色围巾坐在木桌后,嘴闭上、张开、再闭上又张开,杯口的热气在动。
用我们自己的录音当参考:嘴在动,杯口的热气也在飘,输出音轨里带着我们传的那句话。5 秒,480P,2026 年 11 月 3 日生成。

10 帧、每 0.5 秒一帧,能看到的只是嘴在动。逐音节对齐要看更密的帧和专门的测量,这次没有做,所以不能说嘴唇对上了每个音。

限制来自 BytePlus 的建任务接口(2026 年 11 月 3 日核对)。音频最多 3 段,每段 2–15 秒,合计 15 秒,格式 wav 或 mp3,每段 15 MB。音频可以用公网 URL、Base64 字符串或素材 ID。只有音频不行,原文是「Audio-only input is not supported; include at least one reference image or video.」

别把真人放进请求。2.0 系列的参考图或参考视频里不能有真人脸,拍说话镜头就用黏土、插画或 CG 角色。

图生视频会自己换镜头

我们的图生视频从站姿全身镜头,在第 4 帧直接切到坐着的厨房近景,提示词里没有要求剪辑,也没有要求镜头运动。

首帧是这次专门出的静帧:黏土角色站在暖白色墙前,双手垂下,全身入画,1254×1254 像素。提示词就是上面那条,里面写的是坐在厨房桌边。第 1 到第 3 帧还是站姿,第 4 帧跳到桌前坐下的近景,之后一直保持。嘴到第 7 帧都是闭的,第 8 帧微张,第 9、10 帧张大。音轨里是一句「Well, what do you think?」,还有布料摩擦声。

十帧方形成片:前几帧是站着的黏土角色,后面切成坐在厨房桌边的角色,嘴张开。
图生视频:站姿首帧只停了一小会,随后切到提示词要求、图片里却没有的厨房坐姿。5 秒,720P,2026 年 11 月 3 日生成。

这里要看的是构图,不是嘴。这个模型上,角色在哪、镜头怎么走由提示词决定,首帧主要决定角色长什么样。哪个镜头重要,就写进提示词。

成片是 960×960,不是 1280×720。原因是我们用方图做首帧、没传比例,而接口默认跟随画面。想要哪个画幅就自己写 ratio,别拿分辨率标签去猜。

国内怎么用

充值用支付宝或微信支付,按人民币直接充,不用先换美元。一个 key 就能调我们目录里的多个视频模型,换模型只改 model 字段,轮询和下载的代码不动。Seedance 2.0 的模型 ID 是 dreamina-seedance-2-0-260128,现价和额度看 Seedance 2.0 模型页,不想写代码也可以在那一页直接试。

Python 请求

建任务、轮询任务 ID、下载 MP4,三步三个请求。只用标准库,同一个 helper 服务三个操作。

python
import base64
import json
import os
import time
import urllib.error
import urllib.request
import uuid

API = "https://api.omniakey.com/v1/media/tasks"
KEY = os.environ["OMNIAKEY_API_KEY"]
MODEL = "dreamina-seedance-2-0-260128"

PROMPT = (
    "A stop-motion clay character with big round glasses and a knitted scarf sits at a kitchen table, "
    "looks straight into the camera, and speaks one short line to the viewer. The mouth opens and closes "
    "in time with the words, the eyebrows move with the sentence, and the head tilts slightly on the "
    "stressed word. Fixed camera, warm lamp light, a mug of tea in front of them, gentle 24 fps "
    "stop-motion feel."
)

MIME = {".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg",
        ".webp": "image/webp", ".mp3": "audio/mpeg", ".wav": "audio/wav"}


def call(method, url, body=None, idempotency_key=None):
    headers = {"Authorization": f"Bearer {KEY}", "User-Agent": "omniakey-example/1"}
    data = None
    if body is not None:
        headers["Content-Type"] = "application/json"
        data = json.dumps(body).encode()
    if idempotency_key:
        headers["Idempotency-Key"] = idempotency_key
    req = urllib.request.Request(url, data=data, headers=headers, method=method)
    with urllib.request.urlopen(req, timeout=120) as resp:
        return json.load(resp)


def data_url(path, limit_mb):
    raw = open(path, "rb").read()
    if len(raw) > limit_mb * 1024 * 1024:  # 图片 30 MB,音频 15 MB
        raise ValueError(f"{path} is over {limit_mb} MB, the limit for this input type")
    mime = MIME[os.path.splitext(path)[1].lower()]
    return f"data:{mime};base64," + base64.b64encode(raw).decode()


def wait(task_id, timeout=900, step=5):
    deadline = time.time() + timeout
    while time.time() < deadline:
        state = call("GET", f"{API}/{task_id}")
        if state["status"] not in ("queued", "processing"):
            return state
        time.sleep(step)
    raise TimeoutError(f"{task_id} is still running: poll it again, do not resubmit")


def run(body, out_path):
    task_id = call("POST", API, body, str(uuid.uuid4()))["id"]
    print("task", task_id, flush=True)
    state = wait(task_id)
    if state["status"] != "succeeded":
        raise RuntimeError(state.get("error") or state["status"])
    signed = state["assets"][0]["url"]  # 链接会过期,拿到就下载
    req = urllib.request.Request(signed, headers={"User-Agent": "omniakey-example/1"})
    with urllib.request.urlopen(req, timeout=300) as resp, open(out_path, "wb") as f:
        f.write(resp.read())
    return task_id


def reference_to_video(prompt, image_path, audio_path, out_path):
    body = {
        "model": MODEL,
        "type": "video",
        "operation": "reference_to_video",
        "input": {
            "prompt": prompt,
            "media": [
                {"type": "reference_image", "url": data_url(image_path, 30)},
                {"type": "reference_audio", "url": data_url(audio_path, 15)},
            ],
        },
        "parameters": {"duration": 5, "resolution": "480P", "ratio": "16:9",
                       "generate_audio": True, "watermark": False},
    }
    return run(body, out_path)


if __name__ == "__main__":
    print("done", reference_to_video(PROMPT, "character.png", "line.mp3", "line-clip.mp4"))

这段代码有三处值得留着。每次请求带一个新的 Idempotency-Key,重放拿到的是原任务,不会扣两次钱。等待循环 15 分钟后报错退出,因为超时说明片子还在渲染,重新提交等于再买一条。下载放在第一次成功的那一刻,因为 assets[0].url 是会过期的签名链接。

另外两个操作只换请求体,helper 不动:

python
def text_to_video(prompt, out_path):
    body = {
        "model": MODEL,
        "type": "video",
        "operation": "text_to_video",
        "input": {"prompt": prompt},
        "parameters": {"duration": 5, "resolution": "720P", "ratio": "16:9",
                       "generate_audio": True, "watermark": False},
    }
    return run(body, out_path)


def image_to_video(prompt, image_path, out_path):
    body = {
        "model": MODEL,
        "type": "video",
        "operation": "image_to_video",
        "input": {"prompt": prompt,
                  "media": [{"type": "first_frame", "url": data_url(image_path, 30)}]},
        "parameters": {"duration": 5, "resolution": "720P", "ratio": "adaptive",
                       "generate_audio": True, "watermark": False},
    }
    return run(body, out_path)

字段就这些:model、type、operation、input.prompt、input.media[](type 写 first_frame、reference_image、reference_video 或 reference_audio),以及 parameters.duration、resolution、ratio、generate_audio、watermark。同样的形状写在 OmniaKey 的 视频 API 文档 里,建任务、查询、下载的流程见 媒体 API 概览。模型对应 Seedance 2.0 模型页。

多少钱

BytePlus 按秒计费。5 秒、16:9、不带视频输入的官方价格是这样(ModelArk 价格页,2026 年 11 月 3 日核对):

输出每秒5 秒
480p$0.07$0.35
720p$0.15$0.76
1080p$0.37$1.87
4K$0.78$3.89

用秒价自己乘一遍,结果和表里差一分钱:5 秒 × $0.15 = $0.75,表里写的是 $0.76。我们两条文生视频都是 720P、5 秒,按 BytePlus 的价每条约 $0.75。

带视频输入的请求按另一种方式计费,价格更高。参考视频的任务套不上上面这张表(ModelArk 价格页,2026 年 11 月 3 日核对)。OmniaKey 按生成的秒数扣费,任务以失败或取消结束时退回(媒体 API 概览,2026 年 11 月 3 日核对);现价看 模型页。

容易出问题的地方

  • 只传音频会被拒。音轨旁边至少要配一张参考图或一段参考视频。
  • 真人脸不行。参考图或参考视频里有真人就会被挡,角色用黏土、手绘或 CG。
  • 生成音频默认是开的。要静音文件就显式关掉;要台词就保持默认,并在提示词里写明有人在说话。
  • 开音频的请求可能因输出音频的内容策略在上游被拒。我们三次开音频的请求都过了;真被拒时,把同一份请求的 generate_audio 改成 false 再试。
  • 成片尺寸跟着比例走。720P 文生视频给的是 1280×720,方形首帧没传比例给的是 960×960,480P 配 16:9 给的是 864×496。
  • 速度没有规律。同样 5 秒的四条,用了 259.0、202.0、155.3 和 120.2 秒,按两到五分钟准备,用轮询等。
  • 成片时长只能选 4–15 秒,参考片段每段 2–15 秒、合计 15 秒。四条文件的帧率都是 24 fps。

常见问题

传一段 WAV 上去,嘴会跟着我的录音动吗?

可以,和一张参考图一起传,模型会用它:我们自己的录音回到了输出音轨。嘴能不能对准文件里的每个音,我们的截帧看不出来;每 0.5 秒一帧只能看到嘴在动,没有测过对齐精度。

为什么只传音频的请求被拒了?

2.0 系列不接受音频作为唯一输入。同一次请求里加一张参考图或一段参考视频,音频就能一起传。

要台词的话,生成音频是开还是关?

保持开启,这是默认值。关掉之后文件里没有音轨,但只要提示词说角色在说话,嘴还是会动,我们那条无声片就是这样。

参考音频能有多长?

每段 2–15 秒,最多 3 段,合计 15 秒,wav 或 mp3,每段 15 MB。这些数字来自 BytePlus 建任务接口,2026 年 11 月 3 日核对。我们传的 1.8 秒比这个下限还短,以 Base64 数据链接发送,照样成功了。

来源

更新记录

  • 2026 年 11 月 3 日:第一版,4 条视频都是当天生成的。

文中提到的模型

Seedance 2.0对口型AI 视频参考音频视频 APIPython

相关文章

最新文章

热门指南