首页
/ OpenMontage Avatar Video 技能实战:HeyGen v2 视频模板与批量个性化视频生成完全指南

OpenMontage Avatar Video 技能实战:HeyGen v2 视频模板与批量个性化视频生成完全指南

2026-09-06 11:01:30作者:鲍丁臣Ursa

本文基于 OpenMontage 仓库中 avatar-video 技能的模板参考文档 templates.md,系统讲解 HeyGen v2 模板 API 的完整用法:模板列表与详情查询、变量替换生成、三类变量(文本/图像/音频)、批量个性化生成与请求前校验,并结合仓库源码说明该能力在 OpenMontage 智能体生产体系中的定位与配套机制。读完本文,你可以直接照抄命令与代码,用 HeyGen 模板 API 构建可复制、可批量、可校验的个性化视频生产线。

1. 技能定位:模板在 OpenMontage avatar-video 技能中的角色

OpenMontage 把 AI 视频生产能力组织为一组 agent 技能文件。其中 avatar-video 技能 基于 HeyGen v2 API,提供对虚拟人、语音、脚本、场景与背景的精确控制,其默认工作流是:

  1. 列出虚拟人GET /v2/avatars,选定 avatar_iddefault_voice_id(详见 avatars.md);
  2. 列出语音GET /v2/voices(详见 voices.md);
  3. 编写脚本 — 每个场景一个概念(详见 scripts.md);
  4. 生成视频POST /v2/video/generate(详见 video-generation.md);
  5. 轮询完成状态GET /v2/videos/{video_id}(详见 video-status.md)。

在上述"逐帧精确控制"的路线之外,HeyGen 提供了另一条模板化路线:预先设计好带占位变量的视频结构,之后只需替换变量即可大规模生成个性化视频。技能文件的 Quick Reference 表中明确将"Use templates"映射到本文所讲解的 templates.md。两条路线的取舍在技能文件中有清晰说明——"描述一个视频想法让 AI 全权处理"用 create-video 技能;"指定虚拟人精确说出指定台词、批量按精确规格生成"则属于本技能范畴。

1.1 认证与环境变量

所有请求都需要 X-Api-Key 请求头,统一通过环境变量 HEYGEN_API_KEY 提供。技能元数据声明了 HEYGEN_API_KEY 为必需环境变量(见 SKILL.md 的 metadata.openclaw.requires.env)。在 OpenMontage 的工具层,heygen_video.py 同样遵循该约定:get_status() 检查 HEYGEN_API_KEY 是否存在,缺失时返回 ToolStatus.UNAVAILABLE,并提示到 https://app.heygen.com/settings/api 获取密钥;同时定义了 RetryPolicy(max_retries=2, backoff_seconds=10.0, retryable_errors=["rate_limit", "timeout", "server_error"]) 的容错策略,这正是第 8 节批量生成中"请求间加延迟"实践的仓库级印证。

1.2 MCP 工具优先原则

技能文件强调:若 HeyGen MCP 工具可用(mcp__heygen__*),优先使用而非直接 HTTP 调用——它们自动处理认证与请求格式。不过模板相关端点(/v2/templates)与视频生成(POST /v2/video/generate)走的是直接 API 调用,这也是本文所有示例的形式。

2. 模板数据模型

HeyGen 模板允许创建带变量占位符的可复用视频结构,从而支持大规模个性化视频生成。参考文档定义了三层 TypeScript 类型,完整刻画了模板的数据结构:

interface Template {
  template_id: string;
  name: string;
  thumbnail_url: string;
  variables: TemplateVariable[];
}

interface TemplateVariable {
  name: string;
  type: "text" | "image" | "audio";
  properties?: {
    max_length?: number;
    default_value?: string;
  };
}

interface TemplatesResponse {
  error: null | string;
  data: {
    templates: Template[];
  };
}

三个关键设计点值得注意:

  • 变量三态:每个 TemplateVariabletype 限定为 "text" | "image" | "audio",与第 5 节三类变量示例一一对应;
  • 约束内嵌于模板properties.max_lengthproperties.default_value 由模板定义方声明,调用方应在生成前据此校验(见第 7 节);
  • 统一错误信封:所有响应都用 { error: null | string, data: ... } 包裹,error 非空即代表请求级失败。

3. 列出模板(Listing Templates)

3.1 curl

curl -X GET "https://api.heygen.com/v2/templates" \
  -H "X-Api-Key: $HEYGEN_API_KEY"

3.2 TypeScript

listTemplates() 封装了列表请求、错误检查与结果提取:

async function listTemplates(): Promise<Template[]> {
  const response = await fetch("https://api.heygen.com/v2/templates", {
    headers: { "X-Api-Key": process.env.HEYGEN_API_KEY! },
  });

  const json: TemplatesResponse = await response.json();

  if (json.error) {
    throw new Error(json.error);
  }

  return json.data.templates;
}

3.3 Python

import requests
import os

def list_templates() -> list:
    response = requests.get(
        "https://api.heygen.com/v2/templates",
        headers={"X-Api-Key": os.environ["HEYGEN_API_KEY"]}
    )

    data = response.json()
    if data.get("error"):
        raise Exception(data["error"])

    return data["data"]["templates"]

3.4 响应格式

列表接口的完整响应结构(含一个带 3 个变量的"Product Announcement"模板示例):

{
  "error": null,
  "data": {
    "templates": [
      {
        "template_id": "template_abc123",
        "name": "Product Announcement",
        "thumbnail_url": "https://files.heygen.ai/...",
        "variables": [
          {
            "name": "product_name",
            "type": "text",
            "properties": {
              "max_length": 50
            }
          },
          {
            "name": "presenter_script",
            "type": "text",
            "properties": {
              "max_length": 500
            }
          },
          {
            "name": "product_image",
            "type": "image"
          }
        ]
      }
    ]
  }
}

从示例可以看到:presenter_scriptmax_length 为 500,说明脚本类变量通常被模板设计方赋予较宽松的字数上限,而 product_name 只有 50——这个约束就是第 7 节校验逻辑的输入依据。

4. 获取模板详情(Getting Template Details)

生成前必须知道模板定义了哪些变量。技能文件对此有明确提醒:"variables 对象的键必须与模板定义的变量名匹配,请查看模板详情确认定义了哪些变量"

curl

curl -X GET "https://api.heygen.com/v2/template/{template_id}" \
  -H "X-Api-Key: $HEYGEN_API_KEY"

TypeScript

async function getTemplate(templateId: string): Promise<Template> {
  const response = await fetch(
    `https://api.heygen.com/v2/template/${templateId}`,
    { headers: { "X-Api-Key": process.env.HEYGEN_API_KEY! } }
  );

  const json = await response.json();

  if (json.error) {
    throw new Error(json.error);
  }

  return json.data;
}

注意详情接口返回的 json.data 直接就是 Template 对象(不像列表那样多套一层 templates 数组),这是两个端点在响应结构上的差异,实现时不要混淆。

5. 从模板生成视频(Generating Video from Template)

5.1 请求字段

字段 类型 必填 说明
variables object 与模板变量一一对应的键值对
test boolean 测试模式(带水印,不消耗额度)
title string 用于组织归档的视频名称
callback_id string 自定义 ID,用于 webhook 追踪
callback_url string 完成通知的回调 URL

其中 test: true 的"带水印、不扣额度"语义与技能文件最佳实践第 4 条一致——开发阶段一律用测试模式验证,避免浪费额度;额度的完整规则参见技能配套的 quota.mdcallback_url / callback_id 则对接技能的 webhook 机制(见 webhooks.md),适合不想维持轮询连接的生产系统。

5.2 curl

curl -X POST "https://api.heygen.com/v2/template/{template_id}/generate" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "test": false,
    "variables": {
      "product_name": "SuperWidget Pro",
      "presenter_script": "Introducing our latest innovation!",
      "product_image": "https://example.com/product.jpg"
    }
  }'

5.3 TypeScript

interface TemplateGenerateRequest {
  variables: Record<string, string>;           // Required
  test?: boolean;
  title?: string;
  callback_id?: string;
  callback_url?: string;
}

interface TemplateGenerateResponse {
  error: null | string;
  data: {
    video_id: string;
  };
}

async function generateFromTemplate(
  templateId: string,
  variables: Record<string, string>,
  test: boolean = false
): Promise<string> {
  const response = await fetch(
    `https://api.heygen.com/v2/template/${templateId}/generate`,
    {
      method: "POST",
      headers: {
        "X-Api-Key": process.env.HEYGEN_API_KEY!,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ test, variables }),
    }
  );

  const json: TemplateGenerateResponse = await response.json();

  if (json.error) {
    throw new Error(json.error);
  }

  return json.data.video_id;
}

5.4 Python

def generate_from_template(template_id: str, variables: dict, test: bool = False) -> str:
    response = requests.post(
        f"https://api.heygen.com/v2/template/{template_id}/generate",
        headers={
            "X-Api-Key": os.environ["HEYGEN_API_KEY"],
            "Content-Type": "application/json"
        },
        json={
            "test": test,
            "variables": variables
        }
    )

    data = response.json()
    if data.get("error"):
        raise Exception(data["error"])

    return data["data"]["video_id"]

生成接口是异步的:立即返回 video_id,视频在后台渲染。后续状态查询、下载与轮询模式完整继承技能的 video-status.md,该文档给出的关键事实是:视频生成通常需要 5–15 分钟,高峰期或长脚本可能超过 20 分钟;建议轮询超时设置为 15–20 分钟(900,000–1,200,000 ms),并以指数退避重试方式下载最终视频。状态机为 pending → processing → completed | failed,失败时响应携带 failure_codefailure_message(例如 script_too_long)。

6. 三类变量的取值形态

6.1 文本变量(Text Variables)

用于动态文本内容:

const variables = {
  customer_name: "John Smith",
  product_name: "SuperWidget Pro",
  price: "$99.99",
  cta_text: "Order Now!",
};

6.2 图像变量(Image Variables)

用于动态图像(背景、产品图)——值为可公网访问的 URL:

const variables = {
  product_image: "https://example.com/product.jpg",
  logo: "https://example.com/logo.png",
  background: "https://example.com/bg.jpg",
};

6.3 音频变量(Audio Variables)

用于自定义音频内容:

const variables = {
  background_music: "https://example.com/music.mp3",
  custom_voiceover: "https://example.com/voiceover.mp3",
};

三类变量的共同规律是:非文本变量一律使用 URL 而非本地文件。如果手头是本地素材,需要先走技能的资产上传流程(assets.md)获得可访问地址。

7. 生成前校验:把错误挡在 API 之外

参考文档给出的 validateTemplateVariables 实现了三层防御:缺变量检测、文本长度上限检测(依据模板声明的 max_length)、图像 URL 合法性检测:

function validateTemplateVariables(
  template: Template,
  variables: Record<string, string>
): { valid: boolean; errors: string[] } {
  const errors: string[] = [];

  for (const templateVar of template.variables) {
    const value = variables[templateVar.name];

    // Check if required variable is provided
    if (!value) {
      errors.push(`Missing required variable: ${templateVar.name}`);
      continue;
    }

    // Check text length limits
    if (templateVar.type === "text" && templateVar.properties?.max_length) {
      if (value.length > templateVar.properties.max_length) {
        errors.push(
          `Variable "${templateVar.name}" exceeds max length of ${templateVar.properties.max_length}`
        );
      }
    }

    // Validate image URLs
    if (templateVar.type === "image") {
      try {
        new URL(value);
      } catch {
        errors.push(`Variable "${templateVar.name}" is not a valid URL`);
      }
    }
  }

  return {
    valid: errors.length === 0,
    errors,
  };
}

该校验的价值在于:一次生成可能要等待 5–15 分钟且消耗额度,而一次变量缺失或超长只会在渲染中途以 failed 状态暴露(如 script_too_long),前期校验能把这类浪费降到零。它同时呼应了技能文件最佳实践第 6 条——"生成前校验 avatar 与 voice ID 是否真实存在",校验思想贯穿整个 avatar-video 技能。

8. 批量个性化生成(Batch Generation)

模板的真正威力在于"一份模板 × N 份数据"。参考文档的批量生成实现包含两个生产级细节:逐条提交后收集 videoId请求间 1 秒限流延迟

interface PersonalizationData {
  name: string;
  email: string;
  company: string;
  customMessage: string;
}

async function batchGenerateVideos(
  templateId: string,
  recipients: PersonalizationData[]
): Promise<string[]> {
  const videoIds: string[] = [];

  for (const recipient of recipients) {
    const variables = {
      recipient_name: recipient.name,
      company_name: recipient.company,
      personalized_message: recipient.customMessage,
    };

    const videoId = await generateFromTemplate(templateId, variables);
    videoIds.push(videoId);

    // Rate limiting: add delay between requests
    await new Promise((r) => setTimeout(r, 1000));
  }

  return videoIds;
}

// Usage
const recipients = [
  {
    name: "John Smith",
    email: "john@example.com",
    company: "Acme Inc",
    customMessage: "Thanks for your interest in our product!",
  },
  {
    name: "Jane Doe",
    email: "jane@example.com",
    company: "Tech Corp",
    customMessage: "We'd love to show you a demo!",
  },
];

const videoIds = await batchGenerateVideos("template_abc123", recipients);

这里的限流策略与 OpenMontage 工具层的实现相互印证:heygen_video.pyrate_limit 列为可重试错误、退避间隔 10 秒,说明 HeyGen API 对高频请求存在真实的限流约束,批量场景必须主动控速。批量任务还应配合第 5.1 节的 callback_id:为每位收件人分配不同 ID,webhook 回调即可精确定位是哪条视频完成,避免轮询 N 个 video_id

9. 完整模板工作流(Complete Template Workflow)

参考文档将上述所有环节组装成一条端到端管线:拉详情 → 校验 → 生成 → 等待完成:

async function createPersonalizedVideo(
  templateId: string,
  personalization: Record<string, string>
): Promise<string> {
  // 1. Get template details
  const template = await getTemplate(templateId);
  console.log(`Using template: ${template.name}`);

  // 2. Validate variables
  const validation = validateTemplateVariables(template, personalization);
  if (!validation.valid) {
    throw new Error(`Validation errors: ${validation.errors.join(", ")}`);
  }

  // 3. Generate video
  console.log("Generating video...");
  const videoId = await generateFromTemplate(templateId, personalization);
  console.log(`Video ID: ${videoId}`);

  // 4. Wait for completion
  const videoUrl = await waitForVideo(videoId);
  console.log(`Video ready: ${videoUrl}`);

  return videoUrl;
}

// Usage
const videoUrl = await createPersonalizedVideo("template_abc123", {
  customer_name: "John Smith",
  product_name: "SuperWidget Pro",
  offer_details: "Get 20% off your first order!",
});

其中第 4 步的 waitForVideo(videoId) 即技能 video-status.md 提供的轮询实现(默认 10 分钟超时、5 秒轮询间隔,超时抛 "Video generation timed out")。生产环境建议按该文推荐把超时放宽到 15–20 分钟,并对 completed 后的下载加指数退避重试——因为视频 URL 在状态变为 completed 后可能不会立即可用。长任务还可采用文档中的"断点续查"模式:生成后立即保存 video_id 到本地状态文件,进程退出,后续再检查状态,避免长时间挂起一个等待进程。

10. 最佳实践与典型用例

参考文档总结的 7 条最佳实践:

  1. 为灵活性设计 — 用通用占位符创建模板;
  2. 设置合理上限 — 为文本变量定义 max_length
  3. 校验输入 — 生成前检查变量值(第 7 节);
  4. 使用测试模式 — 先用 test: true 验证再进入生产(水印、不扣额度);
  5. 实现限流 — 批量生成时请求间加延迟(第 8 节);
  6. 缓存模板数据 — 减少重复的模板详情 API 调用;
  7. 处理错误 — 优雅地处理生成失败。

典型用例覆盖:

  • 销售触达 — 面向潜在客户的个性化视频;
  • 客户入职 — 带客户姓名的欢迎视频;
  • 产品更新 — 含动态内容的发布公告;
  • 培训 — 定制化培训模块;
  • 营销campaign — 定向促销视频。

11. 小结:模板路线与精确控制路线如何互补

在 OpenMontage 的 avatar-video 技能体系中,templates.md 所代表的模板路线与 POST /v2/video/generate 的逐场景精确控制路线互补:前者以"变量替换"换取规模化与一致性,适合销售触达、客户入职等数据驱动场景;后者以显式的 avatar/voice/script/background 配置换取逐场景艺术控制。两者共享同一套工程底座——HEYGEN_API_KEY 认证(技能元数据强制声明)、video_id 异步状态机(pending → processing → completed | failed)、5–15 分钟量级的生成时长预期,以及技能配套的 quota.md(额度规则)与 webhooks.md(完成回调)。仓库工具层 heygen_video.py 中"密钥缺失即 UNAVAILABLE、rate_limit 可重试、退避 10 秒"的声明,为本文所有限流与容错建议提供了来自实际运行代码的佐证。按本文顺序实现——列表 → 详情 → 校验 → 生成 → 轮询下载——即可搭起一条可复制、可批量、可观测的 HeyGen 模板化视频生产线。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388