mcpField
T
tts-voiceover

tts-voiceover

github.com/microsoft创意与媒体1.6k45 次安装今天更新
代码仓库

关于 tts-voiceover

tts-voiceover 从 PowerPoint 内容目录的 YAML speaker_notes 生成逐页 WAV 旁白,并可将音频嵌入 PPTX。它面向需要为幻灯片制作合成讲解音频的团队,支持 SSML 发音控制和无需凭据的预演模式。

主要功能

  1. 01从 speaker_notes 生成逐页 WAV
  2. 02使用 Azure AI Speech 神经语音
  3. 03通过 SSML 别名控制术语发音
  4. 04支持无凭据 dry-run 验证
  5. 05将旁白音频嵌入 PPTX

适用场景

  1. 01为演示文稿生成逐页旁白
  2. 02预览 SSML 模板而不生成音频
  3. 03为技术缩写配置发音别名
  4. 04为 PPTX 添加旁白和播放计时

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/microsoft/hve-core --skill tts-voiceover

安装后在 Claude Code 中输入/tts-voiceover确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

pip-audit-known-vulnerabilities.txt
pyproject.toml
SECURITY.md
uv.lock
scripts/
embed_audio.py
embed-audio.sh
generate_voiceover.py
generate-voiceover.sh
Invoke-EmbedAudio.ps1
Invoke-GenerateVoiceover.ps1
scripts/Modules/
TtsVoiceoverHelpers.psm1
tests/
conftest.py
fuzz_harness.py
Invoke-GenerateVoiceover.Tests.ps1
test_embed_audio_integrity.py
test_embed_audio.py
test_generate_voiceover_boundaries.py
test_generate_voiceover.py
TtsVoiceoverHelpers.Tests.ps1
tests/corpus/
0_acronym_text
0_empty
0_ssml_fragment
0_valid_yaml

详细介绍

TTS 旁白技能

使用 Azure AI Speech 神经语音,根据 YAML speaker_notes 生成每张幻灯片对应的 WAV 旁白文件,并通过 SSML 控制发音。

概述

此技能会读取 PowerPoint 技能内容目录中的 content.yaml 文件,提取 speaker_notes 字段,为缩略词添加别名以确保技术术语发音正确,并为每张幻灯片生成一个 WAV 文件。支持试运行模式,可在无需 Azure 凭据的情况下验证 SSML 模板。

语音合成使用 Azure AI Speech 神经语音,包括 en-US-Andrew:DragonHDLatestNeural 等 HD 语音。HD 语音仅在部分 Azure 区域提供;选择 SPEECH_REGION 前,请查看语音服务区域。

此技能生成的旁白为合成语音。请告知听众该语音由 AI 生成,并遵循 Microsoft 的合成语音披露设计指南。HVE 演示材料 CI 不会合成语音,而是生成静音视频。

前置条件

  • Azure Speech 资源:有关免费层额度和 HD 语音费率,请参阅 Azure AI Speech 定价。
  • 身份验证:Microsoft Entra ID(SPEECH_RESOURCE_ID,推荐)或资源密钥(SPEECH_KEY)。
  • 区域:合成时必须设置 SPEECH_REGION,且没有默认值。试运行模式无需设置。
  • Python 3.11+,并使用 uv 管理虚拟环境。
  • 数据处理说明:旁白备注内容会传输到配置的 SPEECH_REGION 进行合成。对于预生成的神经语音,Microsoft 声明输入文本和输出音频都不会存储在 Microsoft 日志中;请参阅文本转语音的数据、隐私和安全。运营人员仍须设置获批的区域,并避免发送受监管或机密的旁白内容。
Microsoft Entra ID 身份验证(推荐)

Entra ID 无需存储长期有效的密钥。此方式要求 Speech 资源具有自定义域,并为已登录的身份分配 Cognitive Services Speech User 角色。脚本通过 DefaultAzureCredential 解析身份,因此 az login 会话、托管身份或通过 azure/login 进行的 GitHub Actions OIDC 登录均可使用。

export SPEECH_RESOURCE_ID="/subscriptions/.../Microsoft.CognitiveServices/accounts/your-resource"
export SPEECH_REGION="eastus"
基于密钥的身份验证
export SPEECH_KEY="your-speech-key"
export SPEECH_REGION="eastus"

如果同时设置了 SPEECH_KEY 和 SPEECH_RESOURCE_ID,脚本会发出警告并使用密钥。取消设置 SPEECH_KEY 即可使用 Entra ID。

安装依赖项:

# run from this skill folder
uv sync

快速入门

无需生成音频即可验证 SSML 模板:

uv run scripts/generate_voiceover.py --dry-run --content-dir path/to/content

生成旁白 WAV 文件:

uv run scripts/generate_voiceover.py --content-dir path/to/content --output-dir voice-over

将音频嵌入 PPTX 演示文稿:

uv run scripts/embed_audio.py --input deck.pptx --audio-dir voice-over --output deck-narrated.pptx

参数参考

对于不同的演讲者,可在每次调用时使用重复的 --slide <number> 参数,为一位演讲者合成指定幻灯片的语音。只会读取这些规范的 slide-NNN 文件夹并替换其中的 WAV 文件;其他演讲者的输出不受影响。 省略 --slide 可合成整套演示文稿。

generate_voiceover.py
参数类型默认值说明
--dry-run标志false打印 SSML,不生成音频
--voice字符串en-US-Andrew:DragonHDLatestNeuralAzure AI Speech 语音名称
--rate字符串+10%语音韵律速率
--content-dir路径content幻灯片内容目录的路径
--output-dir路径voice-overWAV 输出目录的路径
--slide整数所有幻灯片可重复指定,仅合成所选的规范幻灯片编号
--lexicon路径(自动检测)自定义 acronyms.yaml 路径
--collapse-newlines标志false合成前,将演讲者备注中的换行和连续空白折叠为单个空格
--verbose / -v标志false启用详细(DEBUG)日志输出
embed_audio.py

将 WAV 文件嵌入到对应的 PPTX 幻灯片中,并添加旁白时间 XML, 使 PowerPoint 能够通过 文件 > 导出 > 创建视频 > 使用录制的计时和旁白 识别音频,以便导出视频。

参数类型默认值说明
--input路径(必需)源 PPTX 文件路径
--audio-dir路径voice-over包含 slide-NNN.wav 的目录
--output路径*-narrated.pptx输出 PPTX 文件路径
--verbose / -v标志false启用详细(DEBUG)日志输出

每个 WAV 文件根据其名称中的编号映射到一张幻灯片,因此 slide-1.wav 和 slide-001.wav 都会映射到第 1 张幻灯片。如果两个文件映射到同一张幻灯片,嵌入过程会报错并停止,且不会写入输出文件。编号超过最后一张幻灯片的 WAV 文件会被忽略,并显示警告。如果 WAV 文件无法读取,系统会报告该文件,其对应的幻灯片保持不变,同时继续嵌入其余幻灯片。

脚本参考

使用自定义语音和速率生成:

uv run scripts/generate_voiceover.py \
  --content-dir content \
  --output-dir voice-over \
  --voice "en-US-Jenny:DragonHDLatestNeural" \
  --rate "+5%"

使用自定义词典:

uv run scripts/generate_voiceover.py \
  --content-dir content \
  --lexicon custom-acronyms.yaml

折叠演讲者备注中的换行(建议用于块标量 | 备注,否则换行会被读作停顿):

uv run scripts/generate_voiceover.py \
  --content-dir content \
  --collapse-newlines

嵌入生成的音频:

uv run scripts/embed_audio.py \
  --input slide-deck/presentation.pptx \
  --audio-dir voice-over \
  --output slide-deck/presentation-narrated.pptx

缩略词词典

词典用于控制缩略词和技术术语的 SSML <sub alias> 替换。创建一个 acronyms.yaml 文件:

acronyms:
  HVE-Core: "H V E Core"
  OWASP: "Oh wasp"
  SBOM: "S Bomb"
  SLSA: "Salsa"
  CI/CD: "C I C D"

词典解析顺序:

  1. 通过 --lexicon 参数指定的路径。
  2. 内容目录中的 acronyms.yaml。
  3. 内置的常见技术缩略词默认值。

SSML 模板

每张幻灯片都会生成一份 SSML 文档:

<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis"
 xmlns:mstts="http://www.w3.org/2001/mstts" xml:lang="en-US">
  <voice name="en-US-Andrew:DragonHDLatestNeural">
    <prosody rate="+10%">
      Text with <sub alias="Oh wasp">OWASP</sub> aliases applied.
    </prosody>
  </voice>
</speak>

与 PowerPoint Skill 集成

此 Skill 会读取 PowerPoint Skill 的内容目录结构:

content/
├── slide-001/
│   └── content.yaml    # Must include speaker_notes: field
├── slide-002/
│   └── content.yaml
└── ...

每个 content.yaml 都应包含带有旁白文本的 speaker_notes: 字段。生成的 WAV 文件会命名为 slide-NNN.wav,与目录名称相匹配。

故障排除

问题解决方案
Set SPEECH_KEY ... or SPEECH_RESOURCE_ID设置 SPEECH_KEY(密钥认证)或 SPEECH_RESOURCE_ID(Entra ID),并设置 SPEECH_REGION。
SPEECH_REGION must be set将 SPEECH_REGION 设置为已获批准的 Azure 区域。语音合成没有默认区域。
Multiple WAV files map to slide N删除重复的 WAV 文件(例如,与 slide-001.wav 并列的 slide-1.wav),然后重新运行 embed_audio.py。
使用 Entra ID 认证时出现 401 错误检查 Speech 资源上的自定义域和 Cognitive Services Speech User 角色。RBAC 最多需要 5 分钟才能生效。
WAV 文件为空或幻灯片被跳过确认 content.yaml 中存在非空的 speaker_notes:。
首字母缩略词发音错误在 acronyms.yaml 中添加带有语音别名的条目。
azure-cognitiveservices-speech package is required在技能目录中运行 uv sync。
PPTX 中显示音频图标嵌入后,在 PowerPoint 中重新定位或调整音频对象的大小。
嵌入后原先添加的幻灯片动画消失embed_audio.py 会用旁白计时替换现有的 p:timing;嵌入音频后,在 PowerPoint 中重新应用动画。
嵌入后幻灯片不再响应单击而前进embed_audio.py 会将 advClick="0" 设为自动前进。若要重新启用,请在 PowerPoint 中选中所有幻灯片,并在“切换”选项卡中勾选 推进幻灯片 > 单击鼠标时。
导出视频时显示“未记录计时”使用更新后的 embed_audio.py 重新嵌入音频,该脚本会自动添加旁白计时 XML。

评论

支持 Markdown