edge-tts
—— 开启语音合成之旅1.1 文本转语音 (TTS) 技术概述
文本转语音(Text-to-Speech, TTS),顾名思义,是一种将输入的文本信息转换成可听的语音波形的技术。它是人机语音交互的关键组成部分,使得计算机能够像人一样“说话”。
1.1.1 TTS 的发展简史与重要性
TTS 技术的研究可以追溯到上世纪中叶,早期的 TTS 系统通常基于参数合成或拼接合成的方法,声音机械、不自然。
TTS 技术的重要性体现在:
1.1.2 现代 TTS 系统的关键组成部分
一个现代的 TTS 系统通常包含以下几个核心模块:
文本预处理 (Text Preprocessing / Normalization):
语言学分析 (Linguistic Analysis):
声学模型/韵律模型 (Acoustic Model / Prosody Model):
声码器 (Vocoder) / 波形生成 (Waveform Generation):
edge-tts
本身并不直接实现这些复杂的模块,而是作为客户端,将文本(或 SSML)发送给微软的云端 TTS 服务,由微软的后端服务完成上述所有处理流程,并返回合成的音频流。
1.2 微软 Edge 浏览器的 TTS 能力与 edge-tts
的渊源
微软在其 Edge 浏览器中内置了强大的“大声朗读”(Read Aloud) 功能,允许用户方便地听取网页内容。这项功能背后依赖的是微软认知服务 (Microsoft Cognitive Services) 中的语音服务 (Speech Service) 或类似的技术栈。
1.2.1 Edge 浏览器“大声朗读”功能的特点
1.2.2 edge-tts
的诞生:解锁云端能力
edge-tts
库的作者发现 Edge 浏览器进行语音合成时,会通过 WebSocket 与微软的某个语音合成服务API进行通信。这个API虽然没有被微软作为公开的开发者API直接推广给所有Python开发者(微软有其官方的 Azure Speech SDK),但其存在为 edge-tts
提供了可能性。
edge-tts
通过模拟 Edge 浏览器与此服务之间的通信协议(主要是 WebSocket 连接和特定格式的消息传递,通常涉及 SSML),使得 Python 程序也能够利用这个高质量的语音合成引擎。
关键点:
edge-tts
本质上是一个非官方的客户端,它利用了 Edge 浏览器使用的后端 TTS 服务。edge-tts
的功能和稳定性在一定程度上会受到微软对其内部 API 策略调整的影响。如果微软更改 API 端点、通信协议或认证方式,edge-tts
可能需要更新才能继续工作。1.2.3 edge-tts
的核心优势
edge-tts
使用该服务通常是免费的,这对于个人项目和小规模应用非常有吸引力。(但用户应意识到这可能随时改变,且应遵守合理使用原则)。asyncio
,可以方便地进行异步操作,适合构建高并发应用。1.3 edge-tts
与微软官方 Azure Speech SDK 的关系
理解 edge-tts
和 Azure Speech SDK 之间的区别非常重要:
Azure Speech SDK:
edge-tts
:
edge-tts
可能会失效,需要库作者更新。选择考量:
edge-tts
是一个极具吸引力的选择,因为它提供了极高质量的语音而无需复杂的账户设置和费用。可以认为 edge-tts
是一个“取巧”的、轻量级的解决方案,它让更广泛的开发者能够便捷地接触到微软高质量的神经元语音。
1.4 安装 edge-tts
安装 edge-tts
非常简单,主要通过 Python 的包管理器 pip
。
1.4.1 环境准备
Python 版本: edge-tts
通常需要 Python 3.7 或更高版本,因为它依赖于 asyncio
以及一些现代的 Python 特性。建议使用较新的 Python 3 版本(例如 3.8+)。
你可以通过以下命令检查你的 Python 版本:
python --version
# 或者,如果你的系统上有多个Python版本
python3 --version
如果未安装 Python 或版本过低,请先从 Python 官方网站 (python.org) 下载并安装合适的版本。
pip
包管理器: pip
通常随 Python 一起安装。你可以检查其版本:
pip --version
# 或者
pip3 --version
如果需要,可以升级 pip
:
python -m pip install --upgrade pip
# 或者
python3 -m pip install --upgrade pip
虚拟环境 (推荐): 为了避免不同项目之间的库版本冲突,强烈建议在 Python 项目中使用虚拟环境。
venv
为例):# 在你的项目目录下
python -m venv .venv
# python -m venv: 使用 venv 模块创建虚拟环境
# .venv: 虚拟环境的名称 (一个常用的名称,可以自定义)
.venv\Scripts\activate
.venv\Scripts\Activate.ps1
# 如果遇到执行策略问题,可能需要先运行: Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
source .venv/bin/activate
(.venv) user@hostname:...$
。之后通过 pip install
安装的库将仅位于此虚拟环境中。deactivate
1.4.2 使用 pip
安装 edge-tts
在激活了虚拟环境(如果使用的话)的命令行或终端中,运行以下命令:
pip install edge-tts
# pip install: pip命令,用于安装Python包
# edge-tts: 要安装的包的名称
pip
会自动从 Python Package Index (PyPI) 下载 edge-tts
及其所有依赖项(例如 aiohttp
, websockets
等)并进行安装。
1.4.3 安装特定版本或升级
edge-tts
(例如,为了兼容性或避免某个新版本的bug),可以指定版本号:pip install edge-tts==1.2.3 # 替换为实际的版本号
# edge-tts==1.2.3: 指定安装版本号为 1.2.3 的 edge-tts
edge-tts
,想升级到最新的稳定版本:pip install --upgrade edge-tts
# --upgrade: pip 的选项,用于升级已安装的包
1.4.4 验证安装
安装完成后,你可以通过几种方式验证 edge-tts
是否成功安装:
命令行工具检查: edge-tts
提供了一个命令行工具。你可以尝试列出可用的语音:
edge-tts --list-voices
# edge-tts: 调用 edge-tts 命令行工具
# --list-voices: 该工具的选项,用于列出所有可用的语音
如果命令成功执行并输出了一个语音列表,则表明命令行工具部分安装正确。
Python 解释器中导入: 打开 Python 解释器 (直接输入 python
或 python3
命令),然后尝试导入 edge_tts
模块:
import edge_tts
print(edge_tts.VoicesManager) # 尝试访问库中的一个对象
# import edge_tts: 导入 edge_tts 库
# print(edge_tts.VoicesManager): 打印库中的 VoicesManager 类,检查是否能成功访问
如果没有出现 ModuleNotFoundError
或其他导入错误,则表明库本身已成功安装并可以被 Python 代码使用。
1.4.5 潜在的安装问题与解决
pip install
需要从互联网下载包。如果你的网络连接有问题,或者需要通过代理访问互联网,可能会导致安装失败。
pip
使用代理:pip install --proxy <PROXY_ADDRESS>:<PROXY_PORT> edge-tts
# --proxy: pip 的选项,用于指定代理服务器地址和端口
# :: 替换为你的代理服务器实际地址和端口
或者设置环境变量 HTTP_PROXY
和 HTTPS_PROXY
。sudo pip install edge-tts
(这会将包安装到系统Python,可能引发问题)。在 Windows 上,以管理员身份运行命令提示符。edge-tts
的依赖项可能与你环境中已有的其他库版本冲突。虚拟环境可以最大限度地减少这类问题。如果发生冲突,错误消息通常会给出提示,你可能需要手动调整相关库的版本或寻求社区帮助。edge-tts
的某些依赖项(特别是底层的网络库,如 aiohttp
可能依赖 yarl
和 multidict
,它们可能有C扩展)在某些平台上安装时可能需要C编译器。大多数情况下,PyPI 会提供预编译的二进制轮子 (wheels),用户无需编译。但如果你的平台或Python版本没有对应的轮子,pip
会尝试从源码编译,这时如果缺少编译器(如 GCC for Linux, MSVC for Windows),安装会失败。
sudo apt install build-essential python3-dev
;在 Windows 上可能需要安装 Microsoft C++ Build Tools。不过,对于 edge-tts
及其核心依赖,这种情况相对少见,因为它们通常有良好的轮子支持。1.5 edge-tts
的基本命令行用法
edge-tts
不仅是一个 Python 库,还附带了一个非常方便的命令行工具 (CLI),也叫做 edge-tts
。这使得你可以不编写任何 Python 代码就能快速地将文本转换为语音文件。
1.5.1 查看帮助信息
要了解命令行工具的所有可用选项和功能,可以使用 -h
或 --help
参数:
edge-tts --help
# --help: 显示命令行工具的帮助信息和可用选项
这将输出详细的用法说明,包括所有支持的参数及其解释。
1.5.2 基本的文本到语音文件转换
最基本的功能是将一段文本转换成一个音频文件。
edge-tts --text "你好,世界!这是一个来自 edge-tts 的测试。" --write-media hello_world_cli.mp3
# --text "内容": 指定要转换为语音的文本内容
# --write-media hello_world_cli.mp3: 指定输出的音频文件名,这里是 hello_world_cli.mp3
执行完毕后,当前目录下会生成一个名为 hello_world_cli.mp3
的音频文件,内容就是 “你好,世界!这是一个来自 edge-tts 的测试。” 的语音。
1.5.3 选择语音 (Voice Selection)
edge-tts
支持多种语言和多种发音人。你可以使用 --list-voices
来查看所有可用的语音:
edge-tts --list-voices
# --list-voices: 列出所有可用的语音及其属性,如 Name, ShortName, Gender, Locale
输出会是类似这样的列表(部分示例):
Name: Microsoft Server Speech Text to Speech Voice (en-US, AriaNeural)
ShortName: en-US-AriaNeural
Gender: Female
Locale: en-US
Name: Microsoft Server Speech Text to Speech Voice (en-US, GuyNeural)
ShortName: en-US-GuyNeural
Gender: Male
Locale: en-US
Name: Microsoft Server Speech Text to Speech Voice (zh-CN, XiaoxiaoNeural)
ShortName: zh-CN-XiaoxiaoNeural
Gender: Female
Locale: zh-CN
Name: Microsoft Server Speech Text to Speech Voice (zh-CN, YunxiNeural)
ShortName: zh-CN-YunxiNeural
Gender: Male
Locale: zh-CN
... (更多语音)
每一条记录都包含了语音的 Name
(完整名称)、ShortName
(短名称,用于在命令行中指定语音)、Gender
(性别) 和 Locale
(语言地区代码)。
要使用特定的语音,可以使用 --voice
或 -v
参数,后跟语音的 ShortName
:
edge-tts --text "Hello world, this is a test from edge-tts." --voice "en-US-AriaNeural" --write-media hello_aria.mp3
# --voice "en-US-AriaNeural": 指定使用 ShortName 为 en-US-AriaNeural 的语音 (美国英语,Aria,女性)
edge-tts --text "早上好,今天天气真不错。" --voice "zh-CN-XiaoxiaoNeural" --write-media morning_xiaoxiao.mp3
# --voice "zh-CN-XiaoxiaoNeural": 指定使用 ShortName 为 zh-CN-XiaoxiaoNeural 的语音 (简体中文,晓晓,女性)
如果你不指定 --voice
,edge-tts
通常会使用一个默认的英语语音(具体哪个可能会随版本变化)。
1.5.4 控制语速 (Rate) 和音量 (Volume)
你可以调整合成语音的语速和音量。
语速 (--rate
):
语速可以指定为百分比(相对于默认语速)或预定义的词语(如 x-slow
, slow
, medium
, fast
, x-fast
)。
通常格式是 +n%
(提高n%) 或 -n%
(降低n%)。 0%
代表默认语速。
# 较慢的语速
edge-tts --text "This is spoken slowly." --voice "en-US-GuyNeural" --rate="-20%" --write-media slow_speech.mp3
# --rate="-20%": 将语速降低20%
# 较快的语速
edge-tts --text "This is spoken quickly." --voice "en-US-GuyNeural" --rate="+30%" --write-media fast_speech.mp3
# --rate="+30%": 将语速提高30%
注意:百分比前的 +
号有时可以省略,但为了清晰,建议写上。语速调整的确切效果和支持范围可能因语音和服务端实现而异。
音量 (--volume
):
音量也可以指定为百分比(相对于默认音量)。
格式与语速类似:+n%
(提高n%) 或 -n%
(降低n%)。 0%
代表默认音量。
# 较大的音量
edge-tts --text "This is spoken loudly." --voice "en-US-AriaNeural" --volume="+20%" --write-media loud_speech.mp3
# --volume="+20%": 将音量提高20%
# 较小的音量
edge-tts --text "This is spoken softly." --voice "en-US-AriaNeural" --volume="-50%" --write-media soft_speech.mp3
# --volume="-50%": 将音量降低50%
音量的调整范围通常在 0%
(静音) 到 100%
(最大音量) 之间,但这里的百分比是相对调整。
1.5.5 控制音高 (Pitch)
你还可以调整语音的音高。
--pitch
):x-low
, low
, medium
, high
, x-high
)表示。+n%
(提高n%) 或 -n%
(降低n%)。0%
代表默认音高。# 较低的音高
edge-tts --text "My voice is low." --voice "en-US-GuyNeural" --pitch="-20%" --write-media low_pitch.mp3
# --pitch="-20%": 将音高降低20%
# 较高的音高
edge-tts --text "My voice is high." --voice "en-US-GuyNeural" --pitch="+30%" --write-media high_pitch.mp3
# --pitch="+30%": 将音高提高30%
过度调整音高可能会导致声音失真或听起来不自然。1.5.6 从文件读取文本 (--text-file
)
如果你的文本内容很长,或者已经保存在一个文件中,可以使用 --text-file
参数来指定输入的文本文件。文件应为 UTF-8 编码。
# 首先创建一个文本文件,例如 story.txt
# 内容:
# Once upon a time, in a land far, far away, there lived a brave knight.
# He embarked on a quest to find a legendary dragon.
echo "Once upon a time, in a land far, far away, there lived a brave knight. He embarked on a quest to find a legendary dragon." > story.txt
# echo ... > story.txt: 创建一个名为 story.txt 的文件并写入内容
edge-tts --text-file story.txt --voice "en-US-AriaNeural" --write-media story_audio.mp3
# --text-file story.txt: 从名为 story.txt 的文件中读取文本内容
如果同时指定了 --text
和 --text-file
,通常 --text
参数会优先。
1.5.7 使用 SSML (--ssml
)
对于更高级的语音控制,例如插入停顿、改变特定词语的发音方式、混合不同语音等,可以使用 SSML (语音合成标记语言)。你需要将 SSML 内容保存在一个 .xml
或 .ssml
文件中,然后通过 --ssml-file
(或者如果库支持直接命令行传递SSML,可能是 --ssml
参数,但通常是通过文件) 来指定。
注意:较新版本的 edge-tts
CLI 可能直接支持 --ssml "..."
参数来传递SSML字符串,或者依然主要通过文件。请用 edge-tts --help
确认。假设这里我们使用文件方式。
创建一个 SSML 文件,例如 speech_control.ssml
:
<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="en-US">
<voice name="en-US-AriaNeural">
<prosody rate="slow">Hello world!prosody>
<break time="500ms"/>
I will now speak faster.
<prosody rate="fast">This part is quick.prosody>
<break strength="medium"/>
And now, let's try a different pitch.
<prosody pitch="high">This is high pitched.prosody>
voice>
speak>
解释这个 SSML 文件:
: SSML 文档的根元素。xml:lang="en-US"
: 指定文档的主要语言。
: 选择一个特定的语音。注意,这里用的 name
可能需要是 ShortName
,具体取决于 edge-tts
如何解析。在 Python 库中,通常用 ShortName
。...
: 将 “Hello world!” 以较慢的语速说出。
: 插入一个 500 毫秒的停顿。...
: 将 “This part is quick.” 以较快的语速说出。
: 插入一个中等强度的停顿。...
: 将 “This is high pitched.” 以较高的音调说出。然后使用命令行:
# 假设 speech_control.ssml 在当前目录
edge-tts --ssml-file speech_control.ssml --write-media ssml_output.mp3
# --ssml-file speech_control.ssml: 从名为 speech_control.ssml 的文件中读取 SSML 内容
# 注意:这里没有指定 --voice,因为 SSML 文件内部已经通过 指定了。
# 如果 SSML 内部没有指定 voice,或者你想覆盖它,可能需要命令行配合 --voice。
# 行为细节需查阅最新文档或通过实验确认。
SSML 提供了非常强大的控制能力,我们将在后续章节中详细探讨。
1.5.8 输出到标准输出 (Piping)
有时你可能不想将音频保存到文件,而是希望将其通过管道传递给其他命令进行处理(例如,用 ffplay
或 mpv
直接播放)。
如果 edge-tts
支持将原始音频数据输出到 stdout,通常是将 --write-media
的文件名指定为 -
(一个横杠,常用于表示标准输出)。
# 尝试输出到标准输出并用 ffplay 播放 (需要安装 ffmpeg)
# 这个命令的可用性取决于 edge-tts 是否支持输出原始音频到 stdout 以及其格式
# edge-tts --text "Playing directly." --voice "en-US-AriaNeural" --write-media - | ffplay -nodisp -autoexit -
# --write-media - : 尝试将输出写入标准输出
# | ffplay ... : 将标准输出通过管道传递给 ffplay 命令进行播放
# -nodisp: ffplay 选项,不显示视频窗口
# -autoexit: ffplay 选项,播放完毕后自动退出
# 最后的 - : ffplay 从标准输入读取数据
# 如果直接输出到 stdout 不支持或格式不兼容,另一种方法是先生成临时文件
# edge-tts --text "Playing via temp file." --voice "en-US-AriaNeural" --write-media temp_audio.mp3 && ffplay -nodisp -autoexit temp_audio.mp3 && rm temp_audio.mp3
# &&: Shell操作符,前一个命令成功执行后才执行后一个
# rm temp_audio.mp3: 删除临时文件
edge-tts
的 CLI 是否直接支持将编码后的音频(如MP3)流式输出到 stdout 以便管道传输,需要查阅其最新文档或通过 edge-tts --help
中关于 --write-media
的说明确认。如果它主要设计为写入完整文件,那么直接流式播放可能需要通过 Python 库结合其他工具实现。
1.5.9 指定代理 (--proxy
)
如果你的网络环境需要通过代理服务器访问互联网,可以使用 --proxy
参数。
edge-tts --text "Testing with proxy." --voice "en-US-AriaNeural" --proxy "http://your_proxy_server:port" --write-media proxy_test.mp3
# --proxy "http://your_proxy_server:port": 指定使用的HTTP代理服务器地址和端口
# 例如: --proxy "http://127.0.0.1:8080"
# 支持的代理格式可能包括 http, https, socks5 等,具体需看 `aiohttp` 的支持。
1.5.10 其他可能的选项
edge-tts
的命令行工具可能还包含其他选项,例如:
--locale LOCALE
: 仅列出特定语言环境的语音,配合 --list-voices
使用。edge-tts --list-voices --locale zh-CN
# --locale zh-CN: 仅列出中文(中国)的语音
-V
或 --verbose
) 用于输出更详细的日志信息,方便调试。始终建议通过 edge-tts --help
来获取最准确和最新的命令行选项信息。
通过这些命令,你可以方便地在不写代码的情况下使用 edge-tts
的核心功能。这对于快速测试语音、生成少量音频文件或在 shell 脚本中集成 TTS 非常有用。对于更复杂的逻辑和应用程序集成,我们接下来将转向 Python 库的使用。
1.6 使用 edge-tts
Python 库
虽然命令行工具非常便捷,但要在应用程序中集成 TTS 功能、处理复杂逻辑、进行流式传输或自定义更多行为,就需要使用 edge-tts
提供的 Python API。edge-tts
库是基于 asyncio
构建的,这意味着它的核心操作是异步的,这对于网络I/O密集型的 TTS 任务来说非常高效。
1.6.1 核心类与异步概念
在使用 edge-tts
库之前,需要对 Python 的 asyncio
有基本的了解。asyncio
是 Python 用于编写并发代码的库,使用 async/await
语法。
async def
: 用于定义一个协程 (coroutine),这是一种可以暂停和恢复执行的特殊函数。await
: 用于暂停协程的执行,等待一个 awaitable
对象(通常是另一个协程或返回 Future
的操作)完成。在等待期间,事件循环可以运行其他任务。asyncio
的核心,负责调度和执行协程。edge-tts
的主要交互通常围绕以下几个核心类或概念:
Communicate
类: 这是进行实际文本到语音转换的核心类。你需要实例化它,并调用其方法来生成语音。VoicesManager
类: 用于获取和管理可用的语音列表。1.6.2 基本的文本到语音文件 (异步)
让我们看一个最基本的例子:将文本转换为 MP3 文件并保存。
import asyncio # 导入 asyncio 库,用于异步编程
import edge_tts # 导入 edge_tts 库
TEXT = "Hello World! This is a test from the edge-tts Python library." # 要转换的文本
# VOICE = "en-US-AriaNeural" # 指定要使用的语音,这里是美国英语的Aria Neural语音
VOICE = "zh-CN-XiaoxiaoNeural" # 更换为中文语音,晓晓 Neural
# OUTPUT_FILE = "hello_world_python.mp3" # 指定输出的MP3文件名
OUTPUT_FILE = "你好世界_python.mp3" # 指定输出的MP3文件名
async def amain() -> None: # 定义一个异步主函数 amain
"""Main function"""
communicate = edge_tts.Communicate(TEXT, VOICE) # 创建 Communicate 类的实例,传入文本和语音名称
# Communicate(text, voice, rate, volume, pitch, proxy)
# text: 要合成的文本
# voice: 语音的 ShortName
# rate: 语速 (可选, 例如 "+10%")
# volume: 音量 (可选, 例如 "-5%")
# pitch: 音高 (可选, 例如 "high")
# proxy: 代理服务器地址 (可选, 例如 "http://localhost:8080")
# 调用 save 方法异步保存音频到文件
# 这个方法内部会处理与服务器的通信、接收音频数据并写入文件
await communicate.save(OUTPUT_FILE)
# await: 等待 communicate.save 操作完成
# OUTPUT_FILE: 保存音频的文件路径
print(f"音频文件已保存到: {
OUTPUT_FILE}") # 打印保存成功的消息
if __name__ == "__main__": # 当脚本作为主程序运行时
# Python 3.7+ 可以使用 asyncio.run()
asyncio.run(amain()) # 运行异步主函数 amain
# 对于 Python 3.6 及更早版本,需要手动获取和运行事件循环:
# loop = asyncio.get_event_loop_policy().new_event_loop()
# asyncio.set_event_loop(loop)
# try:
# loop.run_until_complete(amain())
# finally:
# loop.close()
代码解释:
import asyncio
和 import edge_tts
: 导入必要的库。TEXT
, VOICE
, OUTPUT_FILE
: 定义了输入文本、选择的语音(这里使用了微软的 en-US-AriaNeural
,一个高质量的女性英文语音,以及zh-CN-XiaoxiaoNeural
,一个中文女性语音)和输出文件名。你可以从 edge-tts --list-voices
的输出中选择你喜欢的 ShortName
。async def amain():
: 定义了一个异步函数 amain
。所有 edge-tts
的核心操作都应该是异步的,所以它们需要在一个异步函数内部被 await
。communicate = edge_tts.Communicate(TEXT, VOICE)
: 创建 edge_tts.Communicate
类的一个实例。构造函数接收文本和语音名称作为基本参数。它还有可选参数如 rate
, volume
, pitch
和 proxy
,我们稍后会看到。await communicate.save(OUTPUT_FILE)
: 这是执行 TTS 并保存到文件的关键步骤。save()
是一个协程方法,所以我们使用 await
来等待它完成。它会连接到微软的 TTS 服务,发送文本,接收音频数据,然后将其写入到指定的 OUTPUT_FILE
。asyncio.run(amain())
: 这是在 Python 3.7+ 中运行顶层异步函数的标准方式。它负责创建事件循环,运行 amain()
协程直到完成,然后关闭事件循环。运行此脚本:
保存代码为例如 tts_basic.py
,然后在命令行中运行:
python tts_basic.py
执行成功后,你会在脚本所在的目录下找到 你好世界_python.mp3
(或 hello_world_python.mp3
) 文件,播放它就能听到合成的语音。
1.6.3 获取和选择语音 (VoicesManager
)
如果你想在代码中动态地获取可用的语音列表,而不是硬编码 ShortName
,可以使用 VoicesManager
类。
import asyncio
import edge_tts
async def list_available_voices(): # 定义一个异步函数来列出可用语音
"""Lists available voices."""
voices_manager = await edge_tts.VoicesManager.create() # 异步创建 VoicesManager 实例
# VoicesManager.create() 是一个异步类方法,用于初始化并获取语音列表
all_voices = voices_manager.voices # 获取所有语音的列表,每个元素是一个包含语音信息的字典
print(f"找到 {
len(all_voices)} 种可用语音:\n") # 打印找到的语音数量
# 遍历并打印每种语音的详细信息
for i, voice_info in enumerate(all_voices):
print(f"语音 {
i+1}:") # 打印语音序号
print(f" Name: {
voice_info['Name']}") # 打印语音的完整名称
print(f" ShortName: {
voice_info['ShortName']}") # 打印语音的短名称 (用于API调用)
print(f" Gender: {
voice_info['Gender']}") # 打印语音的性别
print(f" Locale: {
voice_info['Locale']}") # 打印语音的语言地区代码
# voice_info 中可能还有其他字段,如 SuggestedCodec, FriendlyName, Status 等
print("-" * 20) # 打印分隔线
# 按条件查找语音,例如:查找所有中文普通话女声
print("\n查找所有中文(中国)女声 (zh-CN, Female):")
chinese_female_voices = voices_manager.find(Gender="Female", Locale="zh-CN")
# voices_manager.find(): 根据提供的条件筛选语音
# Gender="Female": 筛选条件,性别为女性
# Locale="zh-CN": 筛选条件,语言地区为中文(中国)
if chinese_female_voices: # 如果找到了匹配的语音
for voice_info in chinese_female_voices:
print(f" ShortName: {
voice_info['ShortName']}, Name: {
voice_info['Name']}")
else:
print(" 未找到匹配的中文女声。") # 如果没有找到,打印提示
# 查找特定 ShortName 的语音 (虽然通常直接用 ShortName,但也可以这样验证)
target_short_name = "en-US-AriaNeural"
found_specific = voices_manager.find(ShortName=target_short_name)
if found_specific:
print(f"\n找到了 ShortName 为 '{
target_short_name}' 的语音: {
found_specific[0]['Name']}")
else:
print(f"\n未找到 ShortName 为 '{
target_short_name}' 的语音。")
async def generate_speech_with_selected_voice(): # 定义一个异步函数,使用筛选出的语音生成音频
"""Generates speech using a selected voice after filtering."""
voices_manager = await edge_tts.VoicesManager.create() # 创建 VoicesManager
# 示例:选择第一个可用的简体中文女声
target_locale = "zh-CN"
target_gender = "Female"
selected_voices = voices_manager.find(Locale=target_locale, Gender=target_gender)
if not selected_voices: # 如果没有找到匹配的语音
print(f"错误:未找到语言为 '{
target_locale}' 且性别为 '{
target_gender}' 的语音。")
# 尝试备选:选择任意一个简体中文语音
print("尝试选择任意一个简体中文语音...")
selected_voices = voices_manager.find(Locale=target_locale)
if not selected_voices:
print(f"错误:也未找到任何语言为 '{
target_locale}' 的语音。将使用默认语音(如果有)。")
# 在这种情况下,如果不指定 voice 给 Communicate,它可能会使用一个内置的默认值(通常是英文)
# 或者你可以选择抛出异常或使用一个已知的安全默认值
selected_voice_shortname = "en-US-AriaNeural" # 使用一个已知的英文语音作为后备
else:
selected_voice_shortname = selected_voices[0]["ShortName"] # 选择列表中的第一个
print(f"已选择备用语音: {
selected_voice_shortname}")
else:
selected_voice_shortname = selected_voices[0]["ShortName"] # 选择列表中的第一个
print(f"已选择语音: {
selected_voice_shortname} ({
selected_voices[0]['Name']})")
text_to_speak = "这是通过Python代码动态选择语音后生成的音频。"
output_filename = "dynamic_voice_selection_example.mp3"
communicate = edge_tts.Communicate(text_to_speak, selected_voice_shortname)
# 使用上面选择的 selected_voice_shortname
await communicate.save(output_filename)
print(f"音频文件已保存到: {
output_filename}")
if __name__ == "__main__":
print("--- 列出所有可用语音 ---")
asyncio.run(list_available_voices()) # 运行列出语音的函数
print("\n--- 使用动态选择的语音生成音频 ---")
asyncio.run(generate_speech_with_selected_voice()) # 运行使用动态选择语音生成音频的函数
代码解释 (list_available_voices
):
voices_manager = await edge_tts.VoicesManager.create()
: VoicesManager.create()
是一个异步类方法,用于初始化管理器并从微软服务器获取最新的语音列表。必须 await
它。all_voices = voices_manager.voices
: 获取一个包含所有语音信息的列表。列表中的每个元素都是一个字典,包含了语音的 Name
, ShortName
, Gender
, Locale
等属性。voices_manager.find(Gender="Female", Locale="zh-CN")
: find()
方法允许你根据一个或多个条件来筛选语音。它返回一个匹配条件的语音信息字典的列表。代码解释 (generate_speech_with_selected_voice
):
VoicesManager
来动态选择一个语音。selected_voice_shortname
后,将其传递给 Communicate
实例。这种动态查找和选择语音的能力对于构建需要支持多语言或允许用户选择语音的应用非常有用。
1.6.4 控制语速、音量和音高 (Python API)
Communicate
类的构造函数接受 rate
, volume
, 和 pitch
参数来控制这些语音属性。这些参数的格式与命令行工具中的类似(例如 "+10%"
, "-20%"
)。
import asyncio
import edge_tts
TEXT = "Let's try adjusting rate, volume, and pitch using the Python API."
VOICE = "en-US-GuyNeural" # 使用 GuyNeural 语音,一个男性英文语音
async def generate_with_prosody_controls(): # 定义异步函数来演示韵律控制
"""Generates speech with different prosody controls."""
# 示例1: 较慢的语速,较大的音量,较高的音高
output_file_1 = "prosody_control_1.mp3"
communicate_1 = edge_tts.Communicate(
TEXT,
VOICE,
rate="-25%", # 语速降低 25%
volume="+10%", # 音量增加 10%
pitch="+15%" # 音高增加 15%
)
await communicate_1.save(output_file_1)
print(f"已生成音频 (慢速、大声、高音): {
output_file_1}")
# 示例2: 较快的语速,默认音量,较低的音高
output_file_2 = "prosody_control_2.mp3"
communicate_2 = edge_tts.Communicate(
TEXT,
VOICE,
rate="+40%", # 语速增加 40%
# volume 使用默认值
pitch="-20%" # 音高降低 20%
)
await communicate_2.save(output_file_2)
print(f"已生成音频 (快速、默认音量、低音): {
output_file_2}")
# 示例3: 使用预定义的词语 (如果支持,具体支持的词语需查文档或SSML规范)
# 注意:Communicate 的构造函数参数通常期望百分比字符串。
# 要使用 "x-slow", "loud" 等词,通常需要通过 SSML 实现。
# 这里我们还是用百分比,但可以模拟这些效果。
output_file_3 = "prosody_control_3_simulated_keywords.mp3"
text_for_keywords = "This simulates x-slow rate, and medium pitch."
communicate_3 = edge_tts.Communicate(
text_for_keywords,
VOICE,
rate="-50%", # 模拟 "x-slow"
pitch="0%" # 模拟 "medium" (默认音高)
)
await communicate_3.save(output_file_3)
print(f"已生成音频 (模拟 x-slow, medium pitch): {
output_file_3}")
if __name__ == "__main__":
asyncio.run(generate_with_prosody_controls())
代码解释:
Communicate
实例时,直接通过 rate
, volume
, pitch
关键字参数传递期望的调整值。"-25%"
表示降低25%,"+40%"
表示增加40%。"0%"
通常表示默认值。edge-tts
内部转换为相应的 SSML
标签属性,然后发送给微软的 TTS 服务。1.6.5 流式传输音频 (stream()
方法)
Communicate.save()
方法是一次性将所有音频数据写入文件。但在某些场景下,你可能希望以数据块 (chunks) 的形式逐步获取音频数据,例如:
edge-tts
提供了 Communicate.stream()
方法来实现这一点。stream()
是一个异步生成器 (async generator),它会 yield
音频数据块。
import asyncio
import edge_tts
# 你可能需要一个播放库,例如 playsound, simpleaudio, pydub, หรือ pygame
# 这里我们只是将数据块写入一个文件,模拟流式处理
# 在实际播放场景中,你会将这些数据块送入播放器的缓冲区
TEXT_STREAM = "This audio is being streamed chunk by chunk. You could play it as it arrives."
VOICE_STREAM = "en-GB-SoniaNeural" # 使用英国英语女声 Sonia
OUTPUT_STREAM_FILE = "streamed_audio_python.mp3"
async def stream_audio_to_file(): # 定义异步函数来演示流式音频处理
"""Streams audio data and writes it to a file chunk by chunk."""
communicate = edge_tts.Communicate(TEXT_STREAM, VOICE_STREAM)
print(f"开始流式传输音频到 {
OUTPUT_STREAM_FILE}...")
# 'wb' 表示以二进制写模式打开文件
with open(OUTPUT_STREAM_FILE, "wb") as audio_file: # 打开输出文件
# communicate.stream() 是一个异步生成器
async for chunk in communicate.stream(): # 异步迭代 communicate.stream() 返回的音频块
if chunk["type"] == "audio": # 检查块的类型是否为 "audio"
print(f"接收到音频数据块,大小: {
len(chunk['data'])} bytes") # 打印接收到的数据块大小
audio_file.write(chunk["data"]) # 将音频数据写入文件
elif chunk["type"] == "WordBoundary": # 检查块的类型是否为 "WordBoundary" (词边界信息)
print(f"词边界: Text='{
chunk['text']}', Offset={
chunk['offset']}, Duration={
chunk['duration']}")
# chunk['text']: 当前词语的文本
# chunk['offset']: 当前词语在整个音频中的开始时间 (通常是相对于音频流开始的字节偏移或时间偏移,具体看库的实现)
# chunk['duration']: 当前词语的持续时间
elif chunk["type"] == "SentenceBoundary": # 检查块的类型是否为 "SentenceBoundary" (句子边界信息)
print(f"句子边界: Text='{
chunk['text']}', Offset={
chunk['offset']}, Duration={
chunk['duration']}")
print(f"音频流传输完成。文件已保存: {
OUTPUT_STREAM_FILE}")
if __name__ == "__main__":
asyncio.run(stream_audio_to_file())
代码解释:
async for chunk in communicate.stream():
: communicate.stream()
返回一个异步生成器。我们使用 async for
来迭代它。在每次迭代中,chunk
是一个字典,包含了该数据块的信息。chunk["type"]
: 这个键表示数据块的类型。
"audio"
: 表示 chunk["data"]
包含的是实际的音频字节数据 (例如 MP3 数据的一部分)。"WordBoundary"
: 表示这是一个词边界事件。chunk
中会包含关于当前识别到的词的信息,如 text
(词文本), offset
(在音频流中的偏移量,单位可能是字节或毫秒,取决于 edge-tts
的实现和服务器返回的信息), 和 duration
(词的持续时间,单位可能是毫秒)。这对于实现字幕同步或语音高亮非常有用。"SentenceBoundary"
: 类似于词边界,但表示句子结束的事件。audio_file.write(chunk["data"])
: 如果块是音频数据,我们将其写入文件。在实际播放应用中,你会将此数据送入音频播放库的缓冲区。流式播放示例 (概念性,需要音频播放库):
假设你有一个名为 player
的音频播放对象,它有一个 feed(data)
方法来接收音频数据块并播放。
# 这是一个概念性的例子,实际代码需要具体的播放库
import asyncio
import edge_tts
# from some_audio_player_library import Player # 假设有一个播放库
# async def play_audio_stream_concept():
# player = Player() # 初始化播放器
# await player.start() # 启动播放器
# communicate = edge_tts.Communicate("Streaming directly to player.", "en-US-JennyNeural")
# async for chunk in communicate.stream():
# if chunk["type"] == "audio":
# await player.feed(chunk["data"]) # 将音频数据块送入播放器
# elif chunk["type"] == "WordBoundary":
# print(f"Playing word: {chunk['text']}") # 可以在这里做一些同步UI更新
# await player.stop() # 播放完毕后停止播放器
我们将在后续章节中更详细地探讨如何结合具体音频库实现流式播放。
1.6.6 使用代理 (proxy
参数)
与命令行工具类似,Communicate
类的构造函数也接受一个 proxy
参数,用于在需要通过代理服务器访问微软 TTS 服务时进行配置。
import asyncio
import edge_tts
TEXT_PROXY = "Testing TTS via a proxy server using Python."
VOICE_PROXY = "en-AU-NatashaNeural" # 澳大利亚英语女声
OUTPUT_PROXY_FILE = "proxy_test_python.mp3"
# 替换为你的实际代理服务器地址和端口
# 支持的格式通常是 "http://user:pass@host:port" 或 "socks5://user:pass@host:port"
# 具体支持的格式取决于底层的 aiohttp 库
PROXY_SERVER = "http://localhost:8080" # 假设本地有一个HTTP代理在8080端口
async def generate_with_proxy(): # 定义异步函数来演示使用代理
"""Generates speech using a proxy server."""
try:
communicate = edge_tts.Communicate(
TEXT_PROXY,
VOICE_PROXY,
proxy=PROXY_SERVER # 传入代理服务器信息
)
await communicate.save(OUTPUT_PROXY_FILE)
print(f"通过代理 '{
PROXY_SERVER}' 生成音频成功: {
OUTPUT_PROXY_FILE}")
except Exception as e: # 捕获可能发生的异常
# 例如,代理服务器不可用,或者代理配置错误
print(f"通过代理 '{
PROXY_SERVER}' 生成音频失败: {
e}")
print("请确保代理服务器正在运行并且配置正确。")
print("如果不需要代理,请将 PROXY_SERVER 设置为 None 或移除 proxy 参数。")
if __name__ == "__main__":
# 重要提示:要测试此代码,你需要一个实际在 PROXY_SERVER 地址上运行的代理服务器。
# 如果你没有运行代理,可以将 PROXY_SERVER 设置为 None,或者直接调用不带 proxy 参数的 Communicate。
# 例如,如果无代理:
# communicate = edge_tts.Communicate(TEXT_PROXY, VOICE_PROXY)
# 为了演示,我们假设代理可能不存在,所以用 try-except 包裹
asyncio.run(generate_with_proxy())
代码解释:
Communicate
实例时,将代理服务器的 URL 字符串传递给 proxy
参数。edge-tts
底层使用 aiohttp
进行网络请求,aiohttp
会处理代理连接。try-except
块来捕获可能因代理问题(如代理不可达、认证失败等)引发的异常。PROXY_SERVER
设置为 None
或直接省略 proxy
参数。1.6.7 错误处理和异常
网络请求和外部服务交互总是有可能出现问题。edge-tts
在遇到问题时会抛出异常。你的代码应该准备好处理这些异常,以确保健壮性。
常见的异常可能包括:
edge_tts.exceptions.NoAudioReceivedError
: 未能从服务器接收到任何音频数据。可能是因为文本过短、包含不支持的字符、或者服务器临时问题。edge_tts.exceptions.UnknownResponseError
: 服务器返回了未知的或错误格式的响应。edge_tts.exceptions.VoicesManagerError
: 在获取语音列表时发生错误。aiohttp
异常,例如 aiohttp.ClientConnectorError
(无法连接到服务器)、aiohttp.ClientProxyConnectionError
(代理连接问题)、aiohttp.ClientTimeout
(请求超时) 等。import asyncio
import edge_tts
from edge_tts.exceptions import NoAudioReceivedError, VoicesManagerError # 导入特定的异常类
import aiohttp # 导入 aiohttp 以便捕获其特定异常
TEXT_ERROR_HANDLING = "Testing error handling capabilities."
VOICE_ERROR_HANDLING = "en-IN-PrabhatNeural" # 印度英语男声
OUTPUT_ERROR_HANDLING_FILE = "error_handling_test.mp3"
async def generate_with_error_handling(): # 定义异步函数来演示错误处理
"""Generates speech with error handling."""
try:
print(f"尝试获取语音列表...")
voices_manager = await edge_tts.VoicesManager.create(proxy="http://nonexistent.proxy:1234") # 故意使用无效代理
# voices_manager = await edge_tts.VoicesManager.create() # 正常情况
available_voices = voices_manager.find(Locale="en-IN")
if not available_voices:
print("警告: 未找到指定的 en-IN 语音,将尝试使用默认语音或可能失败。")
selected_voice = VOICE_ERROR_HANDLING # 即使找不到也继续尝试,看Communicate的行为
else:
selected_voice = available_voices[0]["ShortName"]
print(f"选择的语音: {
selected_voice}")
print(f"\n尝试生成语音: '{
TEXT_ERROR_HANDLING}'")
# 故意制造一个可能导致 NoAudioReceivedError 的情况 (例如,非常规字符或空文本)
# text_to_send = "@@@###$$$"
text_to_send = TEXT_ERROR_HANDLING # 正常文本
# 模拟网络不通的情况,可以临时修改 Communicate 内部连接的 URL,但这不推荐直接做
# 更实际的测试是断开网络或使用无效代理
communicate = edge_tts.Communicate(
text_to_send,
selected_voice,
# proxy="http://nonexistent.proxy:1234" # 也可以在这里设置无效代理
)
await communicate.save(OUTPUT_ERROR_HANDLING_FILE)
print(f"音频生成成功: {
OUTPUT_ERROR_HANDLING_FILE}")
except VoicesManagerError as vme: # 捕获 VoicesManager 相关的错误
print(f"获取语音列表时发生错误: {
vme}")
print("请检查网络连接和代理设置(如果使用)。")
except NoAudioReceivedError as nare: # 捕获未收到音频的错误
print(f"错误: 未能从服务器接收到音频数据。 {
nare}")
print("这可能是因为文本内容不被支持、文本过短、或者服务器端问题。")
except aiohttp.ClientConnectorError as cce: # 捕获 aiohttp 连接错误
print(f"网络连接错误: 无法连接到语音服务。 {
cce}")
print("请检查你的网络连接。")
except aiohttp.ClientProxyConnectionError as cpce: # 捕获 aiohttp 代理连接错误
print(f"代理连接错误: 无法通过代理连接到语音服务。 {
cpce}")
print("请检查代理服务器的地址、端口、用户名和密码是否正确,以及代理服务器是否正常运行。")
except aiohttp.ClientTimeout as cto: # 捕获 aiohttp 超时错误
print(f"请求超时: 连接到语音服务或接收数据超时。 {
cto}")
print("网络可能不稳定,或者服务器响应缓慢。可以尝试增加超时设置(如果库支持)。")
except edge_tts.exceptions.UnknownResponseError as ure: # 捕获未知响应错误
print(f"服务器返回未知响应: {
ure}")
except Exception as e: # 捕获所有其他未预料到的异常
print(f"发生未知错误: {
type(e).__name__} - {
e}")
# 在实际应用中,你可能还想记录堆栈跟踪
# import traceback
# print(traceback.format_exc())
finally:
print("\n错误处理演示结束。")
if __name__ == "__main__":
# 要触发 VoicesManagerError 或 ClientProxyConnectionError,
# 你可以在 VoicesManager.create() 或 Communicate() 中提供一个无效的代理地址。
# 要触发 NoAudioReceivedError,可以尝试传递非常短的或包含大量非语音字符的文本。
# 要触发 ClientConnectorError,可以尝试在没有网络连接的情况下运行。
asyncio.run(generate_with_error_handling())
代码解释:
try...except
块来包裹可能抛出异常的 edge-tts
操作。edge_tts
自定义的几个主要异常,如 VoicesManagerError
, NoAudioReceivedError
, UnknownResponseError
。aiohttp
客户端异常,如 ClientConnectorError
(网络连接问题), ClientProxyConnectionError
(代理问题), ClientTimeout
(超时)。except Exception as e:
来捕获任何其他未预料到的错误。except
块中,我们打印错误信息,并可以根据错误类型给用户提供有用的反馈或执行回退逻辑。VoicesManagerError
/ ClientProxyConnectionError
: 在 VoicesManager.create()
或 Communicate()
中传入一个无效的代理地址,例如 proxy="http://nonexistent.proxy:1234"
。NoAudioReceivedError
: 尝试给 Communicate
传递非常短的文本(如单个特殊字符)或完全空的字符串。ClientConnectorError
: 在运行脚本前断开你的网络连接。ClientTimeout
: 如果网络非常慢,或者服务器响应慢,可能会触发。aiohttp
有默认超时,edge-tts
可能也允许配置。良好的错误处理对于构建可靠的应用程序至关重要。
第二章:精通 SSML —— 驾驭语音合成的艺术
SSML (Speech Synthesis Markup Language) 是一种基于 XML 的标记语言,旨在为语音合成应用提供一种标准化的方式来控制语音输出的各个方面,如发音、音量、音高、语速、停顿、强调等等。通过使用 SSML,开发者可以超越简单的纯文本输入,创造出更自然、更富有表现力、更符合特定场景需求的合成语音。
edge-tts
库(以及其背后的微软语音服务)对 SSML 提供了良好的支持。当你向 Communicate
类提供 SSML 格式的输入时,你可以解锁许多通过纯文本参数难以实现或无法实现的控制能力。
2.1 SSML 基础回顾
在深入 edge-tts
的具体应用之前,我们先快速回顾一下 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">
Your text content and SSML tags go here.
speak>
元素:
标签内。version="1.0"
: 指定使用的 SSML 版本。xmlns="http://www.w3.org/2001/10/synthesis"
: 标准的 SSML 命名空间。xmlns:mstts="http://www.w3.org/2001/mstts"
(可选,但对于微软特定功能常用): 微软 TTS 特有的命名空间,用于支持一些微软扩展的 SSML 功能,如情感表达、特定说话风格等。xml:lang="en-US"
: 指定文档内容的主要语言和地区。这个属性非常重要,它会影响发音、词汇选择和默认语音(如果在内部没有用
标签明确指定)。例如,zh-CN
代表中国大陆的普通话,ja-JP
代表日语。2.2 在 edge-tts
Python 库中使用 SSML
要在 edge-tts
的 Python API 中使用 SSML,你需要将完整的 SSML 字符串作为 text
参数传递给 Communicate
类的构造函数。此时,voice
参数(以及 rate
, volume
, pitch
等基本参数)的行为会有些不同:
标签指定了语音,那么 Communicate
构造函数中的 voice
参数通常会被忽略,或者其作用可能取决于 edge-tts
内部处理 SSML 的逻辑(例如,是否作为未指定语音时的后备)。通常建议在 SSML 中明确指定语音。Communicate
构造函数中的 voice
参数(如果提供)将被用作整个 SSML 文档的默认语音。rate
, volume
, pitch
等参数,如果它们在 Communicate
构造函数中设置,并且 SSML 文本本身(不在任何
标签内)也包含纯文本,这些参数可能会应用于那些纯文本部分。但是,SSML 内部的
标签会覆盖这些全局设置。最佳实践是:当使用 SSML 时,尽可能在 SSML 内部通过相应的标签来控制语音、语速、音量等属性,以获得最精确和可预测的结果。
让我们看一个使用 SSML 的基本 Python 示例:
import asyncio
import edge_tts
# VOICE_FOR_SSML = "en-US-AriaNeural"
VOICE_FOR_SSML = "zh-CN-XiaoxiaoNeural" # 使用晓晓 Neural 语音
# SSML 字符串
# 注意:xml:lang 应该与你选择的语音的语言匹配
SSML_TEXT = f"""
{
VOICE_FOR_SSML} ">
你好,世界!
这是一个使用 SSML 的测试。
这句话的语速会比较慢,音调也会稍低一些。
而这句话会说得很快,音调也比较高!
再会!
"""
# f-string 用于方便地将 VOICE_FOR_SSML 变量插入到 SSML 字符串中
# OUTPUT_SSML_FILE = "ssml_example_python.mp3"
OUTPUT_SSML_FILE = "ssml_示例_python.mp3"
async def generate_from_ssml(): # 定义异步函数从 SSML 生成音频
"""Generates audio from an SSML string."""
# 当text参数是SSML时,Communicate 会自动识别
# voice 参数在这里是可选的,因为SSML内部已经指定了voice
# 如果SSML内部没有标签,这里的voice参数会作为默认
communicate = edge_tts.Communicate(SSML_TEXT, VOICE_FOR_SSML)
# 即使SSML中指定了voice,Communicate 的 voice 参数也最好提供一个匹配的,
# 以免 edge-tts 内部对语言或元数据处理产生困惑。
# 或者,如果 SSML 内部已完整定义,可以将 Communicate 的 voice 参数设为 None 或省略,
# 但需要测试具体版本的行为。通常提供一个与 xml:lang 匹配的 voice 是安全的。
await communicate.save(OUTPUT_SSML_FILE)
print(f"SSML 音频文件已保存到: {
OUTPUT_SSML_FILE}")
print("\n使用的 SSML 内容:")
print(SSML_TEXT)
if __name__ == "__main__":
asyncio.run(generate_from_ssml())
代码解释:
VOICE_FOR_SSML
: 定义了我们想在 SSML 中使用的语音的 ShortName
。SSML_TEXT
: 这是一个多行 f-string,包含了完整的 SSML 文档。
xml:lang="zh-CN"
: 表明 SSML 内容是中文。
: 明确指定了要使用的语音。
: 插入一个持续 500 毫秒的停顿。...
: 将内部文本的语速减慢,音高降低10%。
: 插入一个中等时长的停顿(具体时长由 TTS 引擎根据上下文决定)。
: 这是一个微软特定的标签 (mstts
命名空间),在它后面的 “再会!” 文本之前插入 300ms 的静音。
: 在 “再会!” 文本之后插入 1 秒的静音。communicate = edge_tts.Communicate(SSML_TEXT, VOICE_FOR_SSML)
: 我们将整个 SSML_TEXT
字符串作为第一个参数(通常是纯文本的 text
参数)传递给 Communicate
。edge-tts
能够识别输入是否为有效的 XML/SSML 字符串。我们仍然传递了 VOICE_FOR_SSML
作为第二个参数,虽然 SSML 内部已经指定了语音,但这通常是一个好的做法,可以帮助 edge-tts
正确设置与该语音相关的元数据或进行兼容性检查。如果 SSML 中没有
标签,这里的 voice
参数将成为必需。运行此脚本后,生成的 ssml_示例_python.mp3
文件将包含根据 SSML 指令精确控制的语音输出。
2.3 常用 SSML 标签详解及其在 edge-tts
中的应用
下面我们将详细介绍一些常用的 SSML 标签,并提供如何在 edge-tts
中使用它们的示例。
2.3.1
- 选择语音、语言和性别
voice
标签用于在 SSML 文档的不同部分使用不同的语音,或者明确指定要使用的语音。
name
(必需): 指定要使用的语音的 ShortName
(例如, "en-US-AriaNeural"
, "zh-CN-XiaoxiaoNeural"
). 你可以从 edge-tts --list-voices
或 VoicesManager
获取这些名称。gender
(可选): 指定期望的性别 ("male"
, "female"
, "neutral"
). 如果同时提供了 name
,则 name
优先。如果只提供 gender
和 xml:lang
(或外部 voice
参数的语言),TTS 服务会尝试选择一个匹配的语音。xml:lang
(可选,但强烈推荐在
级别或更高级别
明确指定): 指定该
标签内文本的语言和地区代码。如果
标签的 xml:lang
与其父元素(如
)的 xml:lang
不同,则会发生语言切换。示例:在同一段语音中切换中英文,并使用不同语音
import asyncio
import edge_tts
# 语音选择
CHINESE_VOICE = "zh-CN-YunxiNeural" # 云希 (男声)
ENGLISH_VOICE = "en-US-GuyNeural" # Guy (男声)
SSML_MULTI_VOICE = f"""
{
CHINESE_VOICE} ">
你好,我将说一段中文。
{
ENGLISH_VOICE} " xml:lang="en-US">
Now, I will speak some English. This voice is different.
{
CHINESE_VOICE} ">
现在我又说回中文了。
如果您有任何问题,请随时提出。
"""
# mstts:express-as style="customerservice" styledegree="0.8" : 尝试使用微软特定的客服说话风格,强度为0.8
# 并非所有语音都支持所有风格,支持程度也可能变化
OUTPUT_MULTI_VOICE_FILE = "ssml_multi_voice_python.mp3"
async def generate_multi_voice_ssml(): # 定义异步函数来生成多语音SSML音频
# 当 SSML 中包含 时,Communicate 的第二个 voice 参数可以省略或设为 None,