OpenMontage 接入 HeyGen Avatar 视频生成指南:`/v2/video/generate` 单场景与多场景工作流实战
本文基于开源仓库 OpenMontage 中 HeyGen/avatar-video 技能链路的参考文档(.agents/skills/heygen/references/video-generation.md,同内容亦维护在 .agents/skills/avatar-video/references/video-generation.md)编写。它系统讲解 HeyGen /v2/video/generate 端点的请求字段、单/多场景编排、三种配音输入、状态轮询、透明背景 WebM 合成等完整生产流程,并结合仓库中对应的技能定义与源码佐证调用关系。读完本文,你将掌握在不依赖本地 GPU 的前提下,通过 HeyGen Avatar API 精确生成「指定形象 + 指定文案 + 指定音色 + 逐场景背景」的数字人视频,并能把透明背景头像无缝叠加进屏幕录制或 Remotion 合成画面。
一、为什么需要 Avatar API 精确生成:先看它在本仓库技能体系中的定位
在深入字段细节前,有必要先厘清仓库里 HeyGen 相关技能的分工。OpenMontage 将 HeyGen 能力拆成了三个技能目录(见 .agents/skills/heygen/SKILL.md):
heygen:历史遗留技能,Frontmatter 中已明确标记[DEPRECATED],仅作向后兼容保留;create-video:面向「给定一段描述、让 AI 全自动出片」的 Video Agent / prompt 式生成;avatar-video:面向「我要让头像 Y 逐字说台词 Z、每个场景换背景」的精确控制路径,其默认工作流第一条就是POST /v2/video/generate。
技能文档给出了清晰的选用决策表:只有当用户明确需要"逐字脚本不被打断、指定 voice_id、每场景不同 avatar/background、精确的单场景节奏、批量按规格生成"时,才走 /v2/video/generate 这条链路;否则优先使用 .agents/skills/create-video/SKILL.md。这一点决定了本篇文章的适用范围:本指南是"精密仪器"而非"傻瓜相机",它服务的是有精确控片需求的生产流程。
二、视频输出格式:先选对端点
| 端点 | 格式 | 适用场景 |
|---|---|---|
/v2/video/generate |
MP4 | 标准(推荐)——带背景的视频,最常见 |
/v1/video.webm |
WebM | 透明背景——仅在需要把头像内容叠在别的画面背后时使用 |
绝大多数情况应使用带背景的 MP4。WebM 只在需要"透过头像看到背后的内容"时使用(例如把数字人主播叠加在屏幕录制画面上)。透明背景视频的成本更高、兼容面更窄,详见下文第八节。
三、最基本的视频生成请求(curl 起手式)
以一个最小可运行请求开始,先拿到能出片的骨架:
curl -X POST "https://api.heygen.com/v2/video/generate" \
-H "X-Api-Key: $HEYGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"video_inputs": [
{
"character": {
"type": "avatar",
"avatar_id": "josh_lite3_20230714",
"avatar_style": "normal"
},
"voice": {
"type": "text",
"input_text": "Hello! Welcome to HeyGen.",
"voice_id": "1bd001e7e50f421d891986aad5158bc8"
}
}
],
"dimension": {
"width": 1920,
"height": 1080
}
}'
这个请求的核心逻辑是:一个 video_inputs 条目 = 一"景" =「谁来说(character)+ 说什么/怎么发声(voice)+ 背后是什么(background)」。请求成功后会返回一个 video_id,后续靠它轮询状态、取回下载地址(见 视频状态轮询)。
四、请求字段全解
/v2/video/generate 是异步任务提交语义,字段分三层:顶层字段、video_inputs[] 内的 character / voice / background 子对象。
4.1 顶层字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
video_inputs |
array | ✓ | 视频输入对象数组,可容纳 1–50 个(即最多 50 景) |
dimension |
object | 视频尺寸 {width, height} |
|
title |
string | 视频标题,用于账号内组织管理 | |
test |
boolean | 测试模式:输出带水印、不消耗额度 | |
caption |
boolean | 是否启用自动字幕 | |
callback_id |
string | 自定义 ID,用于 Webhook 追踪 | |
callback_url |
string | 完成通知回调地址 | |
folder_id |
string | 存储目录 ID(视频归入指定文件夹) |
4.2 video_inputs[].character 字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
type |
string | ✓ | "avatar" 或 "talking_photo" |
avatar_id |
string | ✓* | Avatar ID(type="avatar" 时必填) |
talking_photo_id |
string | ✓* | 照片 ID(type="talking_photo" 时必填) |
avatar_style |
string | "normal"、"closeUp" 或 "circle" |
|
scale |
number | 头像缩放系数 | |
offset |
object | 位置偏移 {x, y} |
4.3 video_inputs[].voice 字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
type |
string | ✓ | "text"(TTS)、"audio"(上传音频)或 "silence"(静默) |
voice_id |
string | ✓* | 音色 ID(type="text" 时必填) |
input_text |
string | ✓* | 台词文本(type="text" 时必填) |
audio_url |
string | ✓* | 音频 URL(type="audio" 时必填) |
duration |
number | ✓* | 时长秒数(type="silence" 时必填) |
speed |
number | 语速 0.5–2.0(默认 1.0) | |
pitch |
number | 音高 −20~20(默认 0) |
4.4 video_inputs[].background 字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
type |
string | "color"、"image" 或 "video" |
|
value |
string | 十六进制色值(type="color" 时使用) |
|
url |
string | 图片/视频 URL(type="image"/"video" 时使用) |
|
fit |
string | "cover" 或 "contain" |
4.5 TypeScript 类型定义(含必填逻辑)
// Required fields have no '?' - optional fields have '?'
interface VideoInput {
character: {
type: "avatar" | "talking_photo"; // Required
avatar_id?: string; // Required when type="avatar"
talking_photo_id?: string; // Required when type="talking_photo"
avatar_style?: "normal" | "closeUp" | "circle";
scale?: number;
offset?: { x: number; y: number };
};
voice: {
type: "text" | "audio" | "silence"; // Required
input_text?: string; // Required when type="text"
voice_id?: string; // Required when type="text"
audio_url?: string; // Required when type="audio"
duration?: number; // Required when type="silence"
speed?: number;
pitch?: number;
};
background?: {
type?: "color" | "image" | "video";
value?: string;
url?: string;
fit?: "cover" | "contain";
};
}
interface VideoGenerateRequest {
video_inputs: VideoInput[]; // Required
dimension?: { width: number; height: number };
test?: boolean;
title?: string;
caption?: boolean;
callback_id?: string;
callback_url?: string;
folder_id?: string;
}
interface VideoGenerateResponse {
error: null | string;
data: {
video_id: string;
};
}
async function generateVideo(config: VideoGenerateRequest): Promise<string> {
const response = await fetch("https://api.heygen.com/v2/video/generate", {
method: "POST",
headers: {
"X-Api-Key": process.env.HEYGEN_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify(config),
});
const json: VideoGenerateResponse = await response.json();
if (json.error) {
throw new Error(json.error);
}
return json.data.video_id;
}
4.6 Python 等价实现
import requests
import os
def generate_video(config: dict) -> str:
response = requests.post(
"https://api.heygen.com/v2/video/generate",
headers={
"X-Api-Key": os.environ["HEYGEN_API_KEY"],
"Content-Type": "application/json"
},
json=config
)
data = response.json()
if data.get("error"):
raise Exception(data["error"])
return data["data"]["video_id"]
鉴权方式说明:以上请求均通过请求头
X-Api-Key: $HEYGEN_API_KEY完成鉴权。仓库内该技能的前置条件是在环境中配置HEYGEN_API_KEY(见.agents/skills/heygen/SKILL.md的 metadata 声明及 鉴权文档)。OpenMontage 的 API 侧封装同样遵循此约定——见 tools/video/heygen_video.py 中install_instructions对HEYGEN_API_KEY的要求。
五、完整配置示例与多场景视频
5.1 一条请求写满全部字段
const fullConfig: VideoGenerateRequest = {
// Test mode (no credits consumed, watermarked output)
test: false,
// Video title (for organization)
title: "Product Demo Video",
// Video dimensions
dimension: {
width: 1920,
height: 1080,
},
// Video scenes/inputs
video_inputs: [
{
// Avatar configuration
character: {
type: "avatar",
avatar_id: "josh_lite3_20230714",
avatar_style: "normal",
},
// Voice configuration
voice: {
type: "text",
input_text: "Welcome to our product demonstration!",
voice_id: "1bd001e7e50f421d891986aad5158bc8",
speed: 1.0,
pitch: 0,
},
// Background configuration
background: {
type: "color",
value: "#FFFFFF",
},
},
],
};
5.2 多场景:一次提交一整支"分镜"
video_inputs 数组支持 1–50 个场景条目,每一条都是独立的一"幕",可分别指定头像运镜风格、台词与背景。这比多次生成后拼接更省事,也更容易控制节奏——尤其适合"开场 → 特性演示 → 收尾"式的口播结构:
const multiSceneConfig = {
video_inputs: [
// Scene 1: Introduction
{
character: {
type: "avatar",
avatar_id: "josh_lite3_20230714",
avatar_style: "normal",
},
voice: {
type: "text",
input_text: "Hello! Today I'll show you three key features.",
voice_id: "1bd001e7e50f421d891986aad5158bc8",
},
background: {
type: "color",
value: "#1a1a2e",
},
},
// Scene 2: Feature 1
{
character: {
type: "avatar",
avatar_id: "josh_lite3_20230714",
avatar_style: "closeUp",
},
voice: {
type: "text",
input_text: "First, let's look at our dashboard.",
voice_id: "1bd001e7e50f421d891986aad5158bc8",
},
background: {
type: "image",
url: "https://example.com/dashboard-bg.jpg",
},
},
// Scene 3: Conclusion
{
character: {
type: "avatar",
avatar_id: "josh_lite3_20230714",
avatar_style: "normal",
},
voice: {
type: "text",
input_text: "Thanks for watching! Try it today.",
voice_id: "1bd001e7e50f421d891986aad5158bc8",
},
background: {
type: "color",
value: "#1a1a2e",
},
},
],
dimension: { width: 1920, height: 1080 },
};
值得注意的实践点:同一 avatar 在多场景间通过 avatar_style(如 normal→closeUp)切换景别,既能保持人物身份连续,又能制造画面的节奏变化——这正符合 avatar-video 技能默认工作流中"每场景一概念"的编排建议(参考 脚本撰写指南)。
六、两种角色类型与三种配音输入
6.1 角色类型
标准 Avatar(真人数字分身)
{
character: {
type: "avatar",
avatar_id: "josh_lite3_20230714",
avatar_style: "normal"
}
}
Talking Photo(照片说话)——用一张静态人像照片生成会开口的 presenter:
{
character: {
type: "talking_photo",
talking_photo_id: "your_talking_photo_id"
}
}
talking_photo_id 需预先通过照片头像流程创建,参见 照片头像文档。
6.2 配音类型:text / audio / silence
Text-to-Speech(最常用)——直接喂台词:
{
voice: {
type: "text",
input_text: "Your script here",
voice_id: "1bd001e7e50f421d891986aad5158bc8",
speed: 1.0, // 0.5 - 2.0
pitch: 0 // -20 to 20
}
}
Custom Audio(自定义音频)——配音已由外部工具(如仓库 skills 中 ElevenLabs / Fish Audio / Azure TTS 等本地音色管线)生成时,直接给音频 URL,HeyGen 负责做口型同步:
{
voice: {
type: "audio",
audio_url: "https://example.com/your-audio.mp3"
}
}
Silence(静默)——type="silence" 配合 duration,用于需要"人物不发声但保持画面/口型自然停顿"的场景。
七、完整工作流:提交 → 轮询 → 下载
HeyGen 的视频生成是异步的,POST 只返回 video_id,真正的成片需要轮询状态接口 GET /v2/videos/{video_id} 直到 status = "completed"。以下是一套完整的"生成→等待→取回 URL"代码:
async function createVideo(script: string, avatarId: string, voiceId: string) {
// 1. Generate video
console.log("Starting video generation...");
const videoId = await generateVideo({
video_inputs: [
{
character: {
type: "avatar",
avatar_id: avatarId,
avatar_style: "normal",
},
voice: {
type: "text",
input_text: script,
voice_id: voiceId,
},
background: {
type: "color",
value: "#FFFFFF",
},
},
],
dimension: { width: 1920, height: 1080 },
});
console.log(`Video ID: ${videoId}`);
// 2. Poll for completion
console.log("Waiting for video completion...");
const videoUrl = await waitForVideo(videoId);
console.log(`Video ready: ${videoUrl}`);
return videoUrl;
}
// Helper function for polling
async function waitForVideo(videoId: string): Promise<string> {
const maxAttempts = 60;
const pollInterval = 10000; // 10 seconds
for (let i = 0; i < maxAttempts; i++) {
const response = await fetch(
`https://api.heygen.com/v2/videos/${videoId}`,
{ headers: { "X-Api-Key": process.env.HEYGEN_API_KEY! } }
);
const { data } = await response.json();
if (data.status === "completed") {
return data.video_url;
} else if (data.status === "failed") {
throw new Error(data.failure_message || "Video generation failed");
}
await new Promise((r) => setTimeout(r, pollInterval));
}
throw new Error("Video generation timed out");
}
状态接口的四态语义与超时策略在仓库参考文档 视频状态与轮询 中有完整展开:pending(排队)→ processing(生成中)→ completed(可取件)→ failed(失败,含 failure_code / failure_message)。经验值:单支视频通常 5–15 分钟,高峰期或长脚本可能超过 20 分钟。因此推荐:
- 超时设 15–20 分钟(即 900,000–1,200,000 ms);
- 演讲稿超过 2 分钟时预期 15 分钟以上;
- 长视频优先"异步检查"而非长驻轮询——保存
video_id,稍后回来查状态。
八、错误处理与开发期加速
8.1 常见失败的分诊模式
async function generateVideoSafe(config: VideoGenerateRequest) {
try {
const videoId = await generateVideo(config);
return { success: true, videoId };
} catch (error) {
// Common errors
if (error.message.includes("quota")) {
console.error("Insufficient credits");
} else if (error.message.includes("avatar")) {
console.error("Invalid avatar ID");
} else if (error.message.includes("voice")) {
console.error("Invalid voice ID");
} else if (error.message.includes("script")) {
console.error("Script too long or invalid");
}
return { success: false, error: error.message };
}
}
8.2 Test Mode:免费试错开关
把 test: true 打开,就能以带水印、不消耗额度的方式验证整套配置是否合法、出片节奏是否满意——开发期应当默认开启,仅最终出片时关闭:
const config = {
test: true, // Watermarked output, no credits consumed
video_inputs: [...],
};
8.3 脚本长度与停顿控制
不同套餐对单场景台词长度有限制,规划脚本时应先按档位预估:
| 套餐档位 | 最大字符数 |
|---|---|
| Free | ~500 |
| Creator | ~1,500 |
| Team | ~3,000 |
| Enterprise | ~5,000+ |
想要控制口播节奏,可在台词中插入 SSML 风格的 <break> 停顿标签:
const script = "Welcome to our demo. <break time=\"1s\"/> Let me show you the features.";
- 格式:
<break time="Xs"/>,其中 X 为秒数(如1s、1.5s、0.5s); - 关键约束:标签前后必须留有空格(
word <break time="1s"/> word),直接粘连会导致标签不被识别; - 连续多个
<break>会被自动合并为总时长的一次停顿; - 停顿节奏与情感化音色的更多规则见 配音与音色指南。
九、生产级工作流:自动选用头像默认音色
直接硬编码 avatar_id / voice_id 只适合验证。生产环境中更稳的做法是:先列头像 → 取该头像的 default_voice_id(官方预匹配音色)→ 再生成,从而避免"男像配女声"之类的低级错误;若头像没有默认音色,再按性别人工配对(配音指南 给出了完整的配对策略与多语言示例)。
interface VideoGenerationResult {
videoId: string;
videoUrl: string;
duration: number;
avatarId: string;
voiceId: string;
avatarName: string;
}
async function generateAvatarVideo(
script: string,
options: {
avatarId?: string; // Specific avatar, or will pick first available
width?: number;
height?: number;
} = {}
): Promise<VideoGenerationResult> {
const { width = 1920, height = 1080 } = options;
let { avatarId } = options;
// 1. List avatars if no specific one provided
if (!avatarId) {
console.log("Listing available avatars...");
const listResponse = await fetch("https://api.heygen.com/v2/avatars", {
headers: { "X-Api-Key": process.env.HEYGEN_API_KEY! },
});
const listData = await listResponse.json();
if (!listData.data?.avatars?.length) {
throw new Error("No avatars available");
}
avatarId = listData.data.avatars[0].avatar_id;
}
// 2. Get avatar details including default_voice_id
console.log(`Getting details for avatar: ${avatarId}`);
const detailsResponse = await fetch(
`https://api.heygen.com/v2/avatar/${avatarId}/details`,
{ headers: { "X-Api-Key": process.env.HEYGEN_API_KEY! } }
);
const { data: avatar } = await detailsResponse.json();
if (!avatar.default_voice_id) {
throw new Error(`Avatar ${avatar.name} has no default voice - select voice manually`);
}
console.log(`Using avatar: ${avatar.name} with default voice: ${avatar.default_voice_id}`);
// 3. Generate video using avatar's default voice
const videoId = await generateVideo({
video_inputs: [{
character: {
type: "avatar",
avatar_id: avatar.id, // from details response
avatar_style: "normal",
},
voice: {
type: "text",
input_text: script,
voice_id: avatar.default_voice_id, // pre-matched default voice
speed: 1.0,
},
background: {
type: "color",
value: "#1a1a2e",
},
}],
dimension: { width, height },
});
console.log(`Video ID: ${videoId}`);
// 3. Wait for completion (20 minute timeout - generation can take 15+ min)
console.log("Waiting for video generation (typically 5-15 minutes, can be longer)...");
const result = await waitForVideo(
videoId,
process.env.HEYGEN_API_KEY!,
(status, elapsed) => {
console.log(` [${Math.round(elapsed / 1000)}s] ${status}`);
},
1200000 // 20 minute timeout for safety
);
return {
videoId,
videoUrl: result.video_url!,
duration: result.duration!,
avatarId: avatar.id,
voiceId: avatar.default_voice_id,
avatarName: avatar.name,
};
}
// Usage - let it pick an avatar automatically
const result = await generateAvatarVideo(
"Hello! Welcome to our product demonstration."
);
console.log(`Video ready: ${result.videoUrl}`);
// Or specify a known avatar_id
const result2 = await generateAvatarVideo(
"Hello! Welcome to our product demonstration.",
{ avatarId: "josh_lite3_20230714" }
);
十、透明背景视频(WebM):何时用、怎么用
10.1 决策依据:别为不需要透明的地方付代价
不需要 WebM 的场景(请直接用 MP4):
- 只需在头像上方叠加动效文字/图形;
- 带纯色背景的画中画(PiP);
- 标准主讲人出镜视频。
必须用 WebM 的场景:
- 头像叠加在屏幕录制上(Loom 风格);
- 头像"漂浮"在视频背景之上;
- 需要真实 alpha 通道做合成的场景。
端点注意:WebM 端点
/v1/video.webm的请求结构与/v2/video/generate不同,且 WebM 仅支持normal与closeUp两种风格——circle圆形风格不支持。想要圆形头像请在后处理阶段(Remotion / 视频编辑器)做圆形遮罩。
10.2 WebM 请求字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
avatar_pose_id |
string | ✓ | Avatar 姿势 ID(取自 avatar 详情) |
avatar_style |
string | ✓ | 仅 "normal" 或 "closeUp"(不支持 circle) |
input_text |
string | ✓* | 台词文本(不使用 input_audio 时必填) |
voice_id |
string | ✓* | 音色 ID(与 input_text 搭配时必填) |
input_audio |
string | ✓* | 音频 URL(不使用 input_text 时必填) |
dimension |
object | {width, height}(默认 1280×720) |
二选一约束:必须提供 input_text + voice_id,或 input_audio,两者不可同时提供。
10.3 curl 示例
curl -X POST "https://api.heygen.com/v1/video.webm" \
-H "X-Api-Key: $HEYGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"avatar_pose_id": "josh_lite3_20230714",
"avatar_style": "normal",
"input_text": "Hello! This video has a transparent background.",
"voice_id": "1bd001e7e50f421d891986aad5158bc8",
"dimension": {
"width": 1920,
"height": 1080
}
}'
10.4 TypeScript 封装
interface WebMVideoRequest {
avatar_pose_id: string; // Required
avatar_style: "normal" | "closeUp"; // Required (no circle support)
input_text?: string; // Required if not using input_audio
voice_id?: string; // Required with input_text
input_audio?: string; // Required if not using input_text
dimension?: { width: number; height: number };
}
async function generateTransparentVideo(
script: string,
avatarPoseId: string,
voiceId: string
): Promise<string> {
const response = await fetch("https://api.heygen.com/v1/video.webm", {
method: "POST",
headers: {
"X-Api-Key": process.env.HEYGEN_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
avatar_pose_id: avatarPoseId, // Required
avatar_style: "normal", // Required: "normal" or "closeUp"
input_text: script, // Required (with voice_id)
voice_id: voiceId, // Required (with input_text)
dimension: { width: 1920, height: 1080 },
}),
});
const { data } = await response.json();
return data.video_id;
}
10.5 MP4 vs WebM 速查
| 场景 | 格式 | 原因 |
|---|---|---|
| 头像上叠加动效文字 | MP4 | 叠加层在头像之上,无需透明 |
| 标准主讲人视频 | MP4 | 更简单、兼容性更好 |
| Loom 风格(头像盖在屏幕录制上) | WebM + normal/closeUp |
需要透明,后期裁成圆形 |
| 头像浮于视频内容上 | WebM | 需要透出头像背后的内容 |
10.6 生产案例:Loom 风格叠加 + Remotion 圆形遮罩
先生成透明 WebM(此处选择 closeUp 近景,更接近真人主播窗效果):
// Generate avatar with transparent background
const videoId = await fetch("https://api.heygen.com/v1/video.webm", {
method: "POST",
headers: { "X-Api-Key": apiKey, "Content-Type": "application/json" },
body: JSON.stringify({
avatar_pose_id: avatarPoseId, // Required
avatar_style: "closeUp", // Required: "normal" or "closeUp" only
input_text: script, // Required (with voice_id)
voice_id: voiceId, // Required (with input_text)
dimension: { width: 1920, height: 1080 },
}),
}).then(r => r.json()).then(d => d.data.video_id);
再在 Remotion 合成里把它作为第二层 Video,用 CSS borderRadius: "50%" 圆角遮罩压成"悬浮圆窗":
import { Video, AbsoluteFill } from "remotion";
export const LoomStyleVideo: React.FC<{
screenRecordingUrl: string;
avatarWebmUrl: string;
}> = ({ screenRecordingUrl, avatarWebmUrl }) => {
return (
<AbsoluteFill>
{/* Screen recording as base layer */}
<Video src={screenRecordingUrl} style={{ width: "100%", height: "100%" }} />
{/* Avatar with circular mask applied in CSS */}
<Video
src={avatarWebmUrl}
style={{
position: "absolute",
bottom: 20,
left: 20,
width: 150,
height: 150,
borderRadius: "50%", // Circular mask
overflow: "hidden",
objectFit: "cover",
}}
/>
</AbsoluteFill>
);
};
WebM 产物与 MP4 共用同一状态查询端点,轮询到
completed后video_url指向的将是.webm文件,可直接喂给上面的<Video src>。若想在此基础上叠加字幕/文字层,参考 Remotion 集成、字幕 与 文字叠加;长任务不轮询而改用回调的,见 Webhooks。
十一、最佳实践清单(可直接对照自检)
- 生成前预览头像——下载
preview_image_url让用户看到形象后再花钱出片(参考 头像选择); - 优先用头像的默认音色——多数 avatar 带官方预匹配的
default_voice_id,出片自然度最高; - 兜底策略:人工按性别配对——无默认音色时保证 avatar 与 voice 的性别一致(配音指南);
- 先校验输入——生成前确认
avatar_id、voice_id真实存在(可分别通过/v2/avatars、/v2/voices拉取校验); - 开发期开 test mode——不消耗额度、出片带水印,用于全流程联调;
- 预留充足的超时——建议 15–20 分钟,因为常规生成 10–15 分钟、长脚本更久;
- 长视频走异步模式——保存
video_id稍后查状态,而不是长驻进程干等; - 优雅处理错误——对 quota / avatar / voice / script 四类错误分别分诊;
- 监控进度——轮询时输出耗时与状态,便于向用户反馈进度;
- 精简台词——脚本保持简洁自然,利于控制长度与节奏;
- 按用途定画幅——YouTube 16:9、短视频 9:16、信息流 1:1,720p 草稿/1080p 出片(画幅与分辨率)。
十二、回到仓库:Avatar 生成在 OpenMontage 里的源码呼应
理解了上面这套 API 契约后,再看 OpenMontage 源码中两处 HeyGen 相关实现,能帮你把"外部 API"与"本仓库工具体系"对应起来:
其一是 API 侧的工具封装 tools/video/heygen_video.py。它把 HeyGen 作为云端视频生成聚合入口(provider = "heygen",capability = "video_generation"),通过 tools/video/_shared.py 中的 HEYGEN_PROVIDERS 将 VEO 3.x、Sora、Kling、Runway、Seedance 等模型暴露为统一 provider_variant(如 veo_3_1、sora_v2_pro、kling_pro),并声明了成本估算(estimate_quality_cost)、运行时长估算、重试策略与"无 GPU、纯云端"的资源画像(ResourceProfile(cpu_cores=1, ...))。注意:该工具面向的是 HeyGen 的文生视频/图生视频工作流(text_to_video / image_to_video),与本文讲解的 Avatar 精确控片(/v2/video/generate)是两个不同的能力面——前者聚合视频大模型,后者编排数字人出镜。
其二是技能侧的编排入口 .agents/skills/avatar-video/SKILL.md。它的默认工作流五步为:列头像(/v2/avatars)→(按需)列音色(/v2/voices)→ 写脚本 → POST /v2/video/generate → 轮询 /v2/videos/{video_id}。这正是本文全部知识点的落地编排;当仓库工具连了 mcp__heygen__* MCP 时,建议优先使用 MCP 工具完成状态查询、视频列表与删除(它们会自动处理鉴权与请求格式化),而 Avatar 生成与头像/音色列举按技能约定走直接 API 调用。
追溯说明:本文引用的
.agents/skills/heygen/references/video-generation.md与 .agents/skills/avatar-video/references/video-generation.md 内容完全一致——前者所在的heygen技能已在.agents/skills/heygen/SKILL.md中标注弃用,avatar-video(精确控片)与create-video(提示词出片)是仓库当前推荐的替代入口。查阅本文提到的头像、音色、状态等补充文档时,两份副本均可读,建议以avatar-video目录下的为主。
结语
/v2/video/generate 是 HeyGen Avatar 能力中最具"制片人思维"的一个端点:一次请求携带 1–50 个场景,逐场景指定人物、台词、音色与背景,配合 /v1/video.webm 的透明通道输出,几乎可以覆盖"精确口播 → 多景切换 → 叠加合成"的全部常规制片需求。掌握字段语义、轮询节奏、test mode 与默认音色策略之后,你便可以在 OpenMontage 的 Agent 工作流中把它当作一个高确定性的"数字人出镜组件"来调用——让 AI 编码助手真正替你完成从脚本到成片的最后一公里。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00