首页
/ OpenMontage Avatar Video 技能深度解析:HeyGen 语音(Voices)配置、语速音调调节与 SSML 停顿控制实战

OpenMontage Avatar Video 技能深度解析:HeyGen 语音(Voices)配置、语速音调调节与 SSML 停顿控制实战

2026-09-05 23:38:01作者:郁楠烈Hubert

OpenMontage 的 avatar-video 技能通过 HeyGen v2 API 实现"数字人+配音"的精准视频生产,其中 references/voices.md 是该技能中负责语音链路的核心参考文档。本文完整覆盖该文档的全部内容——语音列表接口、多语言支持、speed/pitch 参数调节、SSML 风格 <break> 停顿标签的语法规则与最佳实践、自定义音频替代 TTS、语音筛选与数字人配对策略,并结合 OpenMontage 仓库中的工具实现(如 heygen_video 工具)补充说明这套语音配置在真实生产流水线中的落地位置。读完本文,你可以独立完成 HeyGen 语音的选择、参数化调优与脚本级节奏控制。

一、文档定位:avatar-video 技能中的语音链路

voices.md 位于 avatar-video 技能的参考资料目录下,与 avatars.mdscripts.mdvideo-generation.md 等参考文件共同构成该技能的完整知识体系。技能主文件 SKILL.md 定义了默认工作流:

  1. 列出数字人GET /v2/avatars)——选定数字人并记录 avatar_iddefault_voice_id
  2. 列出语音GET /v2/voices,即本文档主题)——为数字人挑选性别/语言匹配的语音;
  3. 撰写脚本——按场景组织内容;
  4. 生成视频POST /v2/video/generate)——为每个场景传入数字人、语音、脚本与背景;
  5. 轮询完成状态——直到状态变为 completed

语音配置就发生在第 2 步与第 4 步之间:先通过列表接口获取可用语音,再把 voice_id(可附加 speedpitch 参数)填入生成请求的 video_inputs[].voice 中。所有请求都需要 X-Api-Key 请求头,密钥来自环境变量 HEYGEN_API_KEY——这一点与仓库中 heygen_video 工具的鉴权方式一致,见 heygen_video.pyget_status()HEYGEN_API_KEY 环境变量的检查,以及 PROVIDERS.md 中对该密钥的配置说明。

二、列出可用语音(GET /v2/voices)

curl 调用

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

TypeScript 实现

文档给出了完整的类型定义与调用封装:

interface Voice {
  voice_id: string;
  name: string;
  language: string;
  gender: "male" | "female";
  preview_audio: string;
  support_pause: boolean;
  emotion_support: boolean;
}

interface VoicesResponse {
  error: null | string;
  data: {
    voices: Voice[];
  };
}

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

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

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

  return json.data.voices;
}

每个 Voice 对象的核心字段含义:

字段 说明
voice_id 语音唯一标识,生成视频时填入 voice.voice_id
name 语音名称(如 Sara、Paul)
language 语言/地域(如 "English"),可用于筛选
gender 性别,male / female,应与数字人性别匹配
preview_audio 试听音频 URL,选语音前建议先试听
support_pause 是否支持 <break> 停顿标签
emotion_support 是否支持情感表达

Python 实现

import requests
import os

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

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

    return data["data"]["voices"]

响应格式示例

{
  "error": null,
  "data": {
    "voices": [
      {
        "voice_id": "1bd001e7e50f421d891986aad5158bc8",
        "name": "Sara",
        "language": "English",
        "gender": "female",
        "preview_audio": "https://files.heygen.ai/...",
        "support_pause": true,
        "emotion_support": true
      },
      {
        "voice_id": "de8b5d78f2e0485f88d1e9f5c8e7f9a6",
        "name": "Paul",
        "language": "English",
        "gender": "male",
        "preview_audio": "https://files.heygen.ai/...",
        "support_pause": true,
        "emotion_support": false
      }
    ]
  }
}

三、支持的语言与地域

HeyGen 提供多语言语音覆盖。文档列出的支持语言清单(实际可用集合以接口返回为准):

语言 代码 说明
英语(美国) en-US 多语音可选
英语(英国) en-GB 英式口音
西班牙语 es-ES 西班牙本土
西班牙语(拉丁) es-MX 墨西哥西语
法语 fr-FR 法国法语
德语 de-DE 标准德语
葡萄牙语 pt-BR 巴西葡语
中文(普通话) zh-CN 简体中文
日语 ja-JP 标准日语
韩语 ko-KR 标准韩语
意大利语 it-IT 标准意大利语
荷兰语 nl-NL 标准荷兰语
波兰语 pl-PL 标准波兰语
阿拉伯语 ar-SA 沙特阿拉伯语

选型要点:地域要与目标受众匹配(例如面向巴西市场应选 pt-BR 而非欧洲葡语)。这一建议也体现在文档最佳实践第 4 条"Consider locale"中。

四、在视频生成中使用语音

语音配置位于 POST /v2/video/generate 请求体的 video_inputs[].voice 中,与 character(数字人)、background(背景)平级。

基础用法(text 类型)

const videoConfig = {
  video_inputs: [
    {
      character: {
        type: "avatar",
        avatar_id: "josh_lite3_20230714",
        avatar_style: "normal",
      },
      voice: {
        type: "text",
        input_text: "Hello! Welcome to our presentation.",
        voice_id: "1bd001e7e50f421d891986aad5158bc8",
      },
    },
  ],
};

语速调节(speed)

const videoConfig = {
  video_inputs: [
    {
      character: {
        type: "avatar",
        avatar_id: "josh_lite3_20230714",
        avatar_style: "normal",
      },
      voice: {
        type: "text",
        input_text: "This is spoken at a faster pace.",
        voice_id: "1bd001e7e50f421d891986aad5158bc8",
        speed: 1.2, // 1.0 is normal, range: 0.5 - 2.0
      },
    },
  ],
};
  • 取值范围0.52.0,默认 1.0
  • 推荐区间:文档最佳实践建议日常使用 0.91.1x 保持自然节奏。配套的 scripts.md 进一步细分:0.8–0.9 适合复杂主题与年长观众,1.1–1.2 适合节奏明快的内容,1.3+ 需谨慎使用以免影响清晰度。

音调调节(pitch)

const videoConfig = {
  video_inputs: [
    {
      character: {
        type: "avatar",
        avatar_id: "josh_lite3_20230714",
        avatar_style: "normal",
      },
      voice: {
        type: "text",
        input_text: "This has a higher pitch.",
        voice_id: "1bd001e7e50f421d891986aad5158bc8",
        pitch: 10, // Range: -20 to 20
      },
    },
  ],
};
  • 取值范围-2020,默认 0(默认值与取值范围在 video-generation.md 的字段表中有交叉印证:speed 0.5-2.0 默认 1.0,pitch -20 到 20 默认 0)。

speedpitch 是两个相互独立的微调旋钮:语速影响整体时长(可按 150 词/分钟 × speed 估算),音调影响音色明暗,二者组合使用可以在不换 voice_id 的前提下适配不同内容风格。

五、用 SSML 风格 break 标签添加停顿

HeyGen 支持在脚本文本中嵌入 SSML 风格的 <break> 标签,实现精确的停顿控制。

标签格式

<break time="Xs"/>

其中 X 为秒数(如 1s1.5s0.5s)。

书写规则

规则 示例
秒数必须带 "s" 后缀 <break time="1.5s"/>
标签前必须有空格 word <break time="1s"/>
标签后必须有空格 <break time="1s"/> word
必须是自闭合标签 <break time="1s"/>

错误写法word<break time="1s"/>word(标签紧贴文字,无空格) 正确写法word <break time="1s"/> word

停顿示例

// Single pause
const script1 = "Hello and welcome. <break time=\"1s\"/> Let me introduce our product.";

// Multiple pauses
const script2 = "First point. <break time=\"1.5s\"/> Second point. <break time=\"1s\"/> Third point.";

// Pause at start (dramatic opening)
const script3 = "<break time=\"0.5s\"/> Welcome to our presentation.";

// Longer pause for emphasis
const script4 = "And the winner is... <break time=\"2s\"/> You!";

完整示例:带停顿的产品演示脚本

const scriptWithPauses = `
Welcome to our product demo. <break time="1s"/>
Today I'll show you three key features. <break time="0.5s"/>
First, let's look at the dashboard. <break time="1.5s"/>
As you can see, it's incredibly intuitive.
`;

const videoConfig = {
  video_inputs: [
    {
      character: {
        type: "avatar",
        avatar_id: "josh_lite3_20230714",
        avatar_style: "normal",
      },
      voice: {
        type: "text",
        input_text: scriptWithPauses,
        voice_id: "1bd001e7e50f421d891986aad5158bc8",
      },
    },
  ],
};

连续 break 的合并规则

多个连续 break 标签会被自动合并为一个停顿:

// These two breaks:
"Hello <break time=\"1s\"/> <break time=\"0.5s\"/> world"

// Are treated as a single 1.5s pause

停顿最佳实践

  1. 用于强调——在重要观点前加停顿;
  2. 保持时长合理——0.5s2s 是常见区间,更长会显得不自然;
  3. 贴合人类语流——在人类会呼吸或停顿的位置添加;
  4. 试听验证——生成后收听音频,确认节奏是否合适。

此外,只有 support_pause: true 的语音才支持该特性,筛选语音时可以把这一字段作为过滤条件(见下一节的 filterByFeatures)。

六、用自定义音频替代 TTS

除了文本转语音,voice.type 可以直接传 audio 并附带音频 URL,由数字人对口型播放你自己的音频:

const videoConfig = {
  video_inputs: [
    {
      character: {
        type: "avatar",
        avatar_id: "josh_lite3_20230714",
        avatar_style: "normal",
      },
      voice: {
        type: "audio",
        audio_url: "https://example.com/my-audio.mp3",
      },
    },
  ],
};

从源码结构看,voice.type 完整支持三种取值:text(TTS)、audio(自定义音频)、silence(静音,需传 duration 秒数)——完整的字段约束见 video-generation.md 中的 video_inputs[].voice Fields 表格。audio 类型适用于真人录音、既有播客源或需要完全不受 TTS 音色限制的场景;此时 speed/pitch 参数不适用,音频本身的节奏就是最终节奏。

七、语音筛选(Filtering)

拿到 listVoices() 返回的完整列表后,通常按语言、性别、能力三个维度做客户端筛选。

按语言筛选

function filterByLanguage(voices: Voice[], language: string): Voice[] {
  return voices.filter((v) =>
    v.language.toLowerCase().includes(language.toLowerCase())
  );
}

const englishVoices = filterByLanguage(voices, "english");
const spanishVoices = filterByLanguage(voices, "spanish");

按性别筛选

function filterByGender(voices: Voice[], gender: "male" | "female"): Voice[] {
  return voices.filter((v) => v.gender === gender);
}

const femaleVoices = filterByGender(voices, "female");

按能力特征筛选

function filterByFeatures(
  voices: Voice[],
  options: { supportPause?: boolean; emotionSupport?: boolean }
): Voice[] {
  return voices.filter((v) => {
    if (options.supportPause !== undefined && v.support_pause !== options.supportPause) {
      return false;
    }
    if (options.emotionSupport !== undefined && v.emotion_support !== options.emotionSupport) {
      return false;
    }
    return true;
  });
}

const expressiveVoices = filterByFeatures(voices, { emotionSupport: true });

八、语音选择助手(组合条件一次到位)

三个维度筛选的组合版本,返回第一个满足全部条件的语音:

interface VoiceSelectionCriteria {
  language?: string;
  gender?: "male" | "female";
  supportPause?: boolean;
  emotionSupport?: boolean;
}

async function findVoice(criteria: VoiceSelectionCriteria): Promise<Voice | null> {
  const voices = await listVoices();

  const filtered = voices.filter((v) => {
    if (criteria.language && !v.language.toLowerCase().includes(criteria.language.toLowerCase())) {
      return false;
    }
    if (criteria.gender && v.gender !== criteria.gender) {
      return false;
    }
    if (criteria.supportPause !== undefined && v.support_pause !== criteria.supportPause) {
      return false;
    }
    if (criteria.emotionSupport !== undefined && v.emotion_support !== criteria.emotionSupport) {
      return false;
    }
    return true;
  });

  return filtered[0] || null;
}

// Usage
const voice = await findVoice({
  language: "english",
  gender: "female",
  emotionSupport: true,
});

findVoice 的返回值为 null 表示条件过严(例如指定了不存在的语言+性别组合),调用方应做好回退处理,例如放宽 emotionSupport 或更换语言再查一次。

九、多语言视频:每个场景使用不同语言的语音

video_inputs 是一个数组(1–50 个场景),每个场景拥有独立的 charactervoice,因此同一条视频里可以混合使用不同语言、不同 voice_id 的场景:

const multiLanguageConfig = {
  video_inputs: [
    {
      character: {
        type: "avatar",
        avatar_id: "josh_lite3_20230714",
        avatar_style: "normal",
      },
      voice: {
        type: "text",
        input_text: "Hello! Welcome to our global product launch.",
        voice_id: "english_voice_id",
      },
    },
    {
      character: {
        type: "avatar",
        avatar_id: "josh_lite3_20230714",
        avatar_style: "normal",
      },
      voice: {
        type: "text",
        input_text: "Hola! Bienvenidos al lanzamiento global de nuestro producto.",
        voice_id: "spanish_voice_id",
      },
    },
  ],
};

这个模式同样适用于"同一数字人、不同语言、逐场景切换背景"的多场景制作,背景配置规则参考 backgrounds.md

十、语音与数字人的配对策略

首选:使用数字人的默认语音(default_voice_id)

很多数字人带有预匹配的 default_voice_id这是文档明确推荐的首选方案,因为配对经过官方验证,性别必然一致、口型同步最自然、代码也最简单。

// Using v2 API to get avatar with default voice
const response = await fetch(
  "https://api.heygen.com/v2/avatar_group.list?include_public=true",
  { headers: { "X-Api-Key": process.env.HEYGEN_API_KEY! } }
);
const { data } = await response.json();

// Find avatar with a default voice
const avatar = data.avatar_group_list.find((a: any) => a.default_voice_id);

if (avatar) {
  const videoConfig = {
    video_inputs: [{
      character: { type: "avatar", avatar_id: avatar.id },
      voice: {
        type: "text",
        input_text: script,
        voice_id: avatar.default_voice_id, // Pre-matched voice
      },
    }],
  };
}

更细致的推荐流程记录在 avatars.md:先 GET /v2/avatars 获取 avatar_id 列表,再 GET /v2/avatar/{id}/details 拿到该数字人的 default_voice_id,最后 POST /v2/video/generate。完整示例可参考 avatars.md 中的 generateWithAvatarDefaultVoice 函数。

回退方案:手动按性别匹配

当数字人没有默认语音时,手动选择同性别(且语言匹配)的语音:

interface AvatarVoicePair {
  avatarId: string;
  voiceId: string;
  gender: "male" | "female";
}

async function findMatchingAvatarAndVoice(
  preferredGender?: "male" | "female"
): Promise<AvatarVoicePair> {
  const [avatars, voices] = await Promise.all([
    listAvatars(),
    listVoices(),
  ]);

  // Default to male if no preference
  const gender = preferredGender || "male";

  // Find avatar with matching gender
  const avatar = avatars.find((a) => a.gender === gender);
  if (!avatar) {
    throw new Error(`No ${gender} avatar available`);
  }

  // Find voice with matching gender AND language
  const voice = voices.find(
    (v) => v.gender === gender && v.language.toLowerCase().includes("english")
  );
  if (!voice) {
    throw new Error(`No ${gender} English voice available`);
  }

  return {
    avatarId: avatar.avatar_id,
    voiceId: voice.voice_id,
    gender,
  };
}

注意示例中 listAvatars() 的接口封装在 avatars.md 中定义(GET /v2/avatars,返回体含 avatarstalking_photos 两个数组)。

十一、最佳实践汇总

文档给出的 7 条生产建议,可直接作为上线前 checklist:

  1. 语音性别与数字人匹配——男声配男数字人、女声配女数字人,首选 default_voice_id
  2. 语音与内容匹配——商务内容选专业音色;
  3. 先试听再定稿——收听 preview_audio 后再确认 voice_id
  4. 匹配受众地域口音——如面向拉美用户选 es-MX
  5. 使用自然语速——speed 通常控制在 0.9–1.1x;
  6. 添加停顿——用 SSML <break> 标签获得更自然的语流(前提是 support_pause: true);
  7. 验证可用性——生成前务必确认 voice_id 存在于列表接口返回中。

十二、在 OpenMontage 工具链中的落点

voices.md 是写给 Agent 的技能参考资料,而 OpenMontage 仓库中的可执行工具则覆盖 HeyGen 的另一条链路。从源码结构看:

  • heygen_video.py 定义了 HeyGenVideo 工具(provider = "heygen"),其 input_schema 只暴露 promptoperationprovider_variantaspect_ratio 等视频生成参数——它走的是 POST /v1/workflows/executions 的 VEO/Sora/Kling 等通用视频生成工作流(见 shared helpers 中的 generate_heygen_videopoll_heygen),并不直接承载 avatar + voice 配置
  • 因此,"指定数字人+指定语音+精确脚本"的 avatar 视频生产在 OpenMontage 中由 avatar-video 技能(allowed-tools: mcp__heygen__*)按本文档描述的 v2 API 直接编排完成,SKILL.md 也明确了分工:视频状态查询优先使用 HeyGen MCP 工具,而 avatar/voice 列表与 POST /v2/video/generate 走直接 API 调用。

理解这一分工有助于正确选择实现路径:需要"文本提示词生成通用视频"时可用 heygen_video 工具;需要"数字人口播+精确语音控制"时应遵循本技能文档的 v2 接口链路。

十三、关键要点速查

主题 端点/字段 要点
列出语音 GET /v2/voices 返回 voice_idlanguagegendersupport_pauseemotion_support
语言覆盖 language 字段 14 种语言/地域,选与受众匹配的地域口音
语速 voice.speed 0.5–2.0,默认 1.0,推荐 0.9–1.1
音调 voice.pitch -20 到 20,默认 0
停顿 脚本内 <break time="Xs"/> 前后必须有空格、秒数带 s、自闭合;连续 break 自动合并
自定义音频 voice.type: "audio" + audio_url 跳过 TTS,直接对口型既有音频
配对策略 default_voice_id 优先 无默认语音时按性别+语言手动匹配
鉴权 X-Api-Key 来自环境变量 HEYGEN_API_KEY

以上所有接口与参数均以当前仓库 .agents/skills/avatar-video/references/voices.md 为准;端点字段约束可交叉核对 video-generation.md,脚本写作与语速/时长估算可继续参考 scripts.md

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

项目优选

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