pyttsx3
库:从入门到精通的终极文本转语音指南pyttsx3
简介与核心概念pyttsx3
概览pyttsx3
?pyttsx3
是一个跨平台的文本转语音 (Text-To-Speech, TTS) Python 库。它的显著特点是它完全离线运行,不需要互联网连接即可将文本转换为语音。pyttsx3
作为一个封装层,可以与多种操作系统底层的TTS引擎进行交互。这意味着它本身并不包含语音合成的算法,而是调用操作系统提供的或已安装的TTS服务。
pyttsx3
可以在 Windows、macOS 和 Linux 等多种操作系统上工作。pyttsx3
本身是开源免费的,其依赖的底层TTS引擎(如Windows SAPI5, macOS NSSpeechSynthesizer, Linux espeak)通常也是操作系统自带或可免费获取的。pyttsx3
的历史版本支持它)。我们这里的讨论将聚焦于Python 3。pyttsx3
?在众多的TTS解决方案中,选择pyttsx3
通常基于以下原因:
pyttsx3
提供了非常简洁的API,几行代码就可以实现基本的文本转语音功能,非常适合快速集成到项目中或用于教学。pyttsx3
是一个理想的选择。例如,桌面应用程序、嵌入式系统(如果支持其依赖的TTS引擎)或对数据隐私有较高要求的场合。pyttsx3
及其依赖的本地引擎无需支付额外费用。espeak
或espeak-ng
。然而,也需要注意pyttsx3
的局限性:
espeak
的默认语音听起来可能比较机械化(尽管espeak-ng
有所改善)。pyttsx3
在声音选择、语音风格调整(如情感、语速微调)等高级定制方面能力有限。pyttsx3
支持的TTS引擎pyttsx3
通过不同的驱动程序 (drivers) 来支持各个平台上的TTS引擎:
SAPI5 (Microsoft Speech API version 5):
pyttsx3
通过 sapi5
驱动程序使用它。NSSpeechSynthesizer:
pyttsx3
通过 nsss
驱动程序使用它。espeak / espeak-ng:
pyttsx3
在这些平台上会优先使用SAPI5和NSSpeechSynthesizer)。espeak
是一个开源的、小巧的命令行文本转语音合成器,支持多种语言。espeak-ng
(Next Generation) 是其一个积极维护和改进的分支。pyttsx3
通过 espeak
驱动程序使用它。pyttsx3
工作,通常需要确保espeak
或espeak-ng
已安装。pyttsx3
在初始化时会自动检测当前操作系统并尝试加载合适的驱动程序。
pyttsx3
的核心组件理解pyttsx3
的几个核心概念有助于更好地使用它:
引擎 (Engine):
pyttsx3
的中心对象,代表了一个TTS引擎的实例。pyttsx3.init()
创建。语音 (Voice):
属性 (Properties):
rate
: 语速(每分钟的单词数)。volume
: 音量(通常在0.0到1.0之间)。voice
: 当前选择的语音ID。voices
: 可用语音对象的列表。engine.getProperty(name)
获取属性值,通过 engine.setProperty(name, value)
设置属性值。事件与回调 (Events and Callbacks):
pyttsx3
允许注册回调函数来响应TTS过程中的特定事件,例如:
started-utterance
: 开始朗读一段文本。finished-utterance
: 完成朗读一段文本。started-word
: 开始朗读一个单词(某些引擎支持)。error
: 发生错误。pyttsx3
安装与环境设置在开始使用 pyttsx3
之前,我们需要确保开发环境已正确配置并且库已成功安装。
支持的操作系统:
Python版本:
pyttsx3
支持 Python 2.7 以及 Python 3.x (推荐使用Python 3.6及更高版本)。底层TTS引擎:
Windows: 通常不需要额外操作,SAPI5是系统组件。可以通过 “控制面板” -> “语音识别” -> “文本到语音转换” 来查看和配置已安装的SAPI5语音。
# PowerShell中检查SAPI5语音的一种方式 (可能需要管理员权限或调整执行策略)
# Add-Type -AssemblyName System.Speech # 加载System.Speech程序集
# $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer # 创建语音合成器对象
# $synth.GetInstalledVoices() | ForEach-Object { $_.VoiceInfo.Name } # 获取并列出已安装的语音名称
上面的PowerShell代码片段可以帮助你了解系统中有哪些SAPI5语音。pyttsx3
会自动发现这些。
macOS: NSSpeechSynthesizer 是系统内置的。可以通过 “系统偏好设置” -> “辅助功能” -> “语音” (或“朗读内容”) 来配置系统语音。
# macOS终端中列出可用语音的一种方式
say -v '?' # 列出所有可用的语音及其语言代码
Linux: 大多数情况下需要手动安装 espeak
或 espeak-ng
。
espeak-ng
:sudo apt update # 更新包列表
sudo apt install espeak-ng # 安装espeak-ng
espeak
:sudo apt update # 更新包列表
sudo apt install espeak # 安装espeak
espeak-ng
:sudo dnf install espeak-ng # 安装espeak-ng
espeak-ng
:espeak-ng "Hello, world" # 使用espeak-ng朗读文本
如果 pyttsx3
在Linux上找不到 espeak
或 espeak-ng
,它将无法工作。
pip
安装 pyttsx3
安装 pyttsx3
最常见和推荐的方式是使用 Python 的包管理器 pip
。
打开终端或命令提示符:
cmd
或 PowerShell
。Terminal.app
。执行安装命令:
pip install pyttsx3 # 执行pip安装pyttsx3命令
如果你同时安装了 Python 2 和 Python 3,或者使用了虚拟环境,请确保你使用的是对应 Python 3 的 pip
(通常是 pip3
):
pip3 install pyttsx3 # 使用pip3安装pyttsx3命令 (如果pip默认指向Python 2)
在某些系统中,可能需要管理员权限来安装包到全局Python环境 (不推荐直接安装到系统Python,建议使用虚拟环境):
sudo pip3 install pyttsx3 # (Linux/macOS) 使用sudo进行全局安装 (请谨慎使用)
安装特定版本 (可选):
如果需要安装特定版本的 pyttsx3
,可以使用:
pip install pyttsx3==2.90 # 安装pyttsx3的2.90版本
(这里的 2.90
是一个示例版本号)
在虚拟环境中安装 (推荐):
为了避免不同项目之间的包依赖冲突,强烈建议在Python虚拟环境 (venv
或 conda env
) 中安装库。
venv
为例):python -m venv mytts_env # 创建名为mytts_env的虚拟环境 (python通常指python3)
# 或者 python3 -m venv mytts_env
mytts_env\Scripts\activate
source mytts_env/bin/activate
pyttsx3
:pip install pyttsx3 # 在虚拟环境中安装pyttsx3
deactivate
命令退出虚拟环境。安装完成后,可以通过一个简单的Python脚本来验证 pyttsx3
是否工作正常。
创建一个名为 test_pyttsx3.py
的Python文件,内容如下:
# test_pyttsx3.py
import pyttsx3 # 导入pyttsx3库
try:
engine = pyttsx3.init() # 初始化TTS引擎
except ImportError:
print("驱动程序导入错误:请确保已安装适合您操作系统的TTS引擎。") # 打印驱动程序导入错误信息
print("Windows: 确保SAPI5可用。") # Windows平台提示
print("macOS: 确保NSSpeechSynthesizer可用。") # macOS平台提示
print("Linux: 确保espeak或espeak-ng已安装 (例如: sudo apt install espeak-ng)。") # Linux平台提示
engine = None
except RuntimeError as e:
print(f"运行时错误:{
e}") # 打印运行时错误信息
print("这通常意味着没有找到可用的TTS引擎或驱动程序初始化失败。") # 对错误的解释
print("请检查您的TTS引擎配置。") # 提醒检查配置
engine = None
if engine: # 如果引擎成功初始化
print("pyttsx3 引擎成功初始化。") # 打印成功初始化信息
voices = engine.getProperty('voices') # 获取所有可用的语音
if voices: # 如果有可用的语音
print(f"找到 {
len(voices)} 个可用语音:") # 打印找到的语音数量
for voice in voices: # 遍历所有语音
print(f" - ID: {
voice.id}") # 打印语音ID
print(f" Name: {
voice.name}") # 打印语音名称
print(f" Lang: {
voice.languages}") # 打印语音支持的语言
print(f" Gender: {
voice.gender}") # 打印语音性别
print(f" Age: {
voice.age}") # 打印语音年龄
else:
print("警告:未找到可用语音。TTS功能可能受限。") # 打印未找到可用语音的警告
engine.say("Hello, pyttsx3 is working!") # 让引擎说出文本
print("正在尝试朗读 'Hello, pyttsx3 is working!'...") # 打印尝试朗读的信息
try:
engine.runAndWait() # 运行并等待语音播放完成
print("朗读完成。") # 打印朗读完成信息
except RuntimeError as e:
print(f"朗读时发生运行时错误: {
e}") # 打印朗读时的运行时错误
print("这可能与音频输出设备或引擎状态有关。") # 对错误的解释
# 演示更改属性
current_rate = engine.getProperty('rate') # 获取当前语速
print(f"当前语速: {
current_rate}") # 打印当前语速
engine.setProperty('rate', current_rate - 50 if current_rate > 100 else 150) # 设置新的语速 (降低50,或设为150)
engine.say("I am now speaking a bit slower, or at a default rate.") # 用新的语速朗读文本
engine.runAndWait() # 运行并等待
engine.setProperty('rate', current_rate) # 恢复原始语速 (可选)
current_volume = engine.getProperty('volume') # 获取当前音量
print(f"当前音量: {
current_volume}") # 打印当前音量
engine.setProperty('volume', max(0.1, current_volume - 0.3)) # 设置新的音量 (降低0.3,最小0.1)
engine.say("My volume is now lower.") # 用新的音量朗读文本
engine.runAndWait() # 运行并等待
engine.setProperty('volume', current_volume) # 恢复原始音量 (可选)
if voices and len(voices) > 1: # 如果有多个可用语音
print(f"当前语音 ID: {
engine.getProperty('voice')}") # 打印当前语音ID
original_voice_id = engine.getProperty('voice') # 获取原始语音ID
try:
# 尝试切换到列表中的另一个不同语音 (如果存在)
new_voice_id_to_try = None
for voice_obj in voices:
if voice_obj.id != original_voice_id:
new_voice_id_to_try = voice_obj.id
break
if new_voice_id_to_try:
print(f"尝试切换到语音 ID: {
new_voice_id_to_try}") # 打印尝试切换的语音ID
engine.setProperty('voice', new_voice_id_to_try) # 设置新的语音
engine.say("This is a different voice.") # 用新语音朗读
engine.runAndWait() # 运行并等待
engine.setProperty('voice', original_voice_id) # 切换回原始语音
print("已切换回原始语音。") # 打印已切换回原始语音
else:
print("只有一个可用语音,或未能找到不同的语音进行切换测试。") # 如果没有其他语音可切换
except Exception as e:
print(f"切换语音时发生错误: {
e}") # 打印切换语音时的错误
engine.setProperty('voice', original_voice_id) # 确保切换回原始语音
else:
print("只有一个或没有可用语音,跳过切换语音测试。") # 如果语音不足,跳过测试
print("pyttsx3 基础功能验证完毕。") # 打印验证完毕信息
else:
print("pyttsx3 引擎未能初始化。请检查上述错误信息。") # 打印引擎初始化失败信息
运行此脚本:
python test_pyttsx3.py
如果你能听到 “Hello, pyttsx3 is working!” 以及后续的语音,并且终端没有显示严重错误,那么pyttsx3
已基本正确安装和配置。脚本还会尝试列出可用的语音和调整语速、音量,帮助你了解当前环境下的能力。
ModuleNotFoundError: No module named 'pyttsx3'
pyttsx3
库没有被安装到你当前运行脚本的Python环境中。pip install pyttsx3
。pip3
或 python -m pip
)。sys.path
确保Python可以找到安装的包。ImportError: No module named 'comtypes'
(通常在Windows上)
pyttsx3
在Windows上使用 comtypes
库与SAPI5交互。这个依赖通常应该随 pyttsx3
自动安装。如果缺失,可能是 pip
安装过程中出现了问题。comtypes
:pip install comtypes # 安装comtypes库
RuntimeError: No K音声驱动程序found
或类似的引擎未找到错误
pyttsx3
无法找到或初始化任何底层的TTS引擎。pyttsx3
通常能处理好这个问题,但极端情况下可能出现不匹配。espeak
或 espeak-ng
没有安装,或者没有在系统的 PATH
中。sudo apt install espeak-ng
(或对应你的发行版的命令) 来安装。espeak-ng
命令可以在终端直接运行。pyttsx3
可能需要特定的 espeak
库文件路径,尽管它通常会自动检测。初始化引擎时出现 AttributeError
或其他底层库错误
pyttsx3
,以排除库冲突。pyttsx3
到最新版本 (pip install --upgrade pyttsx3
),或者如果最新版有问题,尝试降级到一个已知的稳定版本。语音质量差或发音奇怪 (尤其在Linux上)
espeak
的默认语音确实比较机械化。espeak-ng
,它通常比旧版 espeak
有所改进。espeak-ng
本身有很多命令行参数可以调整发音、语调等,但 pyttsx3
对这些高级参数的直接控制有限。你可能需要通过 engine.setProperty()
尝试可用的属性,或者接受 espeak-ng
的默认输出。gTTS
(需要网络)或安装更高质量的本地TTS引擎(如 Festival,但与pyttsx3
的直接集成可能需要额外工作)。engine.runAndWait()
卡住或不发声
espeak
无法正常输出声音。pyttsx3
脚本,看是否能发声。runAndWait()
没有阻塞主事件循环太久,或者考虑使用 engine.startLoop(False)
和外部事件循环集成。espeak-ng "test"
是否能从命令行正常发声。如果命令行可以,但Python不行,问题可能在Python与espeak
的接口或音频系统权限上。pyttsx3
核心功能与基本用法使用 pyttsx3
的第一步是初始化一个TTS引擎实例。这是通过 pyttsx3.init()
函数完成的。
import pyttsx3 # 导入pyttsx3库
# 初始化TTS引擎
try:
engine = pyttsx3.init() # 尝试初始化TTS引擎
# 可选:指定驱动程序名称 (driverName)
# engine = pyttsx3.init(driverName='sapi5') # 在Windows上显式使用SAPI5
# engine = pyttsx3.init(driverName='nsss') # 在macOS上显式使用NSSpeechSynthesizer
# engine = pyttsx3.init(driverName='espeak') # 在Linux上显式使用espeak
# 可选:设置初始化时的调试模式 (debug)
# engine = pyttsx3.init(debug=True) # 开启调试模式,会打印更多内部信息
print("TTS引擎成功初始化。") # 打印初始化成功信息
except Exception as e:
print(f"初始化TTS引擎失败: {
e}") # 打印初始化失败及其错误信息
print("请检查您的操作系统是否安装并配置了相应的TTS驱动程序:") # 提示检查驱动
print("- Windows: SAPI5") # Windows平台提示
print("- macOS: NSSpeechSynthesizer") # macOS平台提示
print("- Linux: espeak或espeak-ng (通常需要手动安装, 例如 sudo apt install espeak-ng)") # Linux平台提示
engine = None # 将引擎对象置为None,表示初始化失败
if engine is None: # 如果引擎未能初始化
exit("无法继续,因为TTS引擎未能初始化。") # 退出程序
pyttsx3.init(driverName=None, debug=False)
参数详解:
driverName
(可选, 字符串):
'sapi5'
: Microsoft SAPI5 (Windows)。'nsss'
: Apple NSSpeechSynthesizer (macOS)。'espeak'
: espeak/espeak-ng (Linux, 也可以在其他平台使用,但通常不作为首选)。driverName
为 None
(默认值),pyttsx3
会自动检测当前操作系统并尝试加载最合适的驱动程序。
sapi5
。nsss
。espeak
。driverName
?
driverName
无效或对应的引擎无法加载,init()
可能会失败并抛出异常。debug
(可选, 布尔值):
True
,pyttsx3
会在初始化和操作过程中打印更详细的调试信息到控制台。这对于排查问题非常有用。False
。引擎实例的生命周期:
pyttsx3.init()
返回的是一个 pyttsx3.engine.Engine
类的实例。这个引擎对象是你与TTS功能交互的主要接口。
通常情况下,在一个应用程序中,你只需要初始化一个引擎实例,并在整个应用程序的生命周期内使用它。频繁地创建和销毁引擎实例可能会导致不必要的开销或潜在的资源问题,尤其是在某些底层TTS引擎实现中。
虽然pyttsx3
没有显式的 engine.destroy()
或 engine.quit()
方法,但引擎通常会在Python脚本结束、引擎对象被垃圾回收时自动清理其占用的资源。然而,在某些复杂的应用或长时间运行的服务中,确保资源被正确释放仍然是一个需要考虑的问题,特别是当涉及到外部事件循环时(我们将在后面讨论 engine.startLoop()
)。
引擎最核心的功能就是将文本转换为语音并播放出来。这主要通过 engine.say()
和 engine.runAndWait()
方法实现。
import pyttsx3 # 导入pyttsx3库
engine = pyttsx3.init() # 初始化TTS引擎
# 要朗读的文本
text_to_speak = "Python is a versatile programming language." # 定义要朗读的英文文本
chinese_text = "你好,世界。欢迎使用pyttsx3。" # 定义要朗读的中文文本
# 1. 使用 engine.say() 将文本排入队列
# 这个方法是非阻塞的,它只是将文本添加到待朗读的队列中,然后立即返回。
engine.say(text_to_speak) # 将英文文本添加到朗读队列
engine.say(chinese_text) # 将中文文本添加到朗读队列
engine.say("This is the third sentence.") # 添加第三句英文文本
# 2. 使用 engine.runAndWait() 来处理队列中的所有命令并等待完成
# 这个方法是阻塞的。它会启动TTS引擎的事件循环(如果尚未运行),
# 处理所有已排队的命令(包括 say() 添加的文本),并等待所有语音播放完成。
# 在调用 runAndWait() 之前,任何 say() 的调用都只是将任务排队。
print("已将三段文本添加到队列,现在开始朗读...") # 打印提示信息
engine.runAndWait() # 启动事件循环,处理队列中的所有朗读任务,并阻塞直到所有任务完成
print("所有文本已朗读完毕。") # 打印朗读完成信息
# 再次朗读,证明引擎仍然可用
engine.say("One more time for a quick test.") # 再次添加文本到队列
engine.runAndWait() # 再次处理并等待
print("第二次朗读测试完成。") # 打印第二次测试完成信息
engine.say(text, name=None)
方法详解:
text
(字符串): 要转换为语音的文本内容。可以是任何字符串。name
(可选, 字符串): 为这段语音指定一个可选的名称。这个名称可以在事件回调中使用,以识别是哪段文本正在被处理(例如,在 started-utterance
或 finished-utterance
事件中)。如果未提供,pyttsx3
可能会分配一个默认名称或不使用名称。engine.say("This is sentence A.", name="SentenceA") # 为朗读任务命名为SentenceA
engine.say("This is sentence B.", name="SentenceB") # 为朗读任务命名为SentenceB
# (事件处理将在后面章节详细介绍)
engine.runAndWait()
方法详解:
say()
(以及其他命令,如 setProperty()
)排队的任务。say()
而不调用 runAndWait()
(或 startLoop()
,稍后讨论),你可能听不到任何声音,因为 say()
只是将任务放入队列,实际的处理和播放是在事件循环中发生的。runAndWait()
。每次调用都会处理当前队列中的所有任务。runAndWait()
是阻塞的,在它执行期间,你的Python脚本的其他部分(例如GUI更新)将无法运行。对于需要响应式用户界面的应用程序,这可能不是理想的方式。在这种情况下,需要使用非阻塞的事件循环集成(见第5章)。pyttsx3
允许你控制多个语音输出的属性,如语速、音量和使用的语音(发音人)。
engine.getProperty(name)
: 获取指定属性的当前值。engine.setProperty(name, value)
: 设置指定属性的新值。这些设置会影响后续通过 say()
添加到队列的文本。
import pyttsx3 # 导入pyttsx3库
engine = pyttsx3.init() # 初始化TTS引擎
# --- 1. 控制语速 (Rate) ---
default_rate = engine.getProperty('rate') # 获取默认/当前语速
print(f"默认/当前语速: {
default_rate} 字/分钟 (Words Per Minute)") # 打印默认语速
# 设置一个较慢的语速
slower_rate = default_rate - 70 if default_rate > 100 else 100 # 计算较慢的语速 (减少70,但不低于某个值)
engine.setProperty('rate', slower_rate) # 设置新的语速
print(f"设置语速为: {
slower_rate} 字/分钟") # 打印设置后的语速
engine.say("I am speaking at a slower pace now.") # 使用新语速朗读
engine.runAndWait() # 处理并等待
# 恢复默认语速 (或设置为一个更快的语速)
faster_rate = default_rate + 50 # 计算较快的语速 (增加50)
engine.setProperty('rate', faster_rate) # 设置更快的语速
print(f"设置语速为: {
faster_rate} 字/分钟") # 打印设置后的语速
engine.say("Now, I am speaking much faster!") # 使用更快的语速朗读
engine.runAndWait() # 处理并等待
engine.setProperty('rate', default_rate) # 恢复到初始获取的默认语速
print(f"语速已恢复到: {
default_rate}") # 打印恢复后的语速
# --- 2. 控制音量 (Volume) ---
default_volume = engine.getProperty('volume') # 获取默认/当前音量 (通常在 0.0 到 1.0 之间)
print(f"默认/当前音量: {
default_volume:.2f} (0.0 到 1.0)") # 打印默认音量
# 设置一个较低的音量
lower_volume = max(0.1, default_volume - 0.4) # 计算较低的音量 (减少0.4,但不低于0.1)
engine.setProperty('volume', lower_volume) # 设置新的音量
print(f"设置音量为: {
lower_volume:.2f}") # 打印设置后的音量
engine.say("My volume is now quite low.") # 使用新音量朗读
engine.runAndWait() # 处理并等待
# 设置一个较高的音量 (注意不要超过1.0)
higher_volume = min(1.0, default_volume + 0.3) # 计算较高的音量 (增加0.3,但不超过1.0)
engine.setProperty('volume', higher_volume) # 设置更高的音量
print(f"设置音量为: {
higher_volume:.2f}") # 打印设置后的音量
engine.say("Can you hear me clearly at this volume?") # 使用更高音量朗读
engine.runAndWait() # 处理并等待
engine.setProperty('volume', default_volume) # 恢复到初始获取的默认音量
print(f"音量已恢复到: {
default_volume:.2f}") # 打印恢复后的音量
print("属性控制演示完成。") # 打印完成信息
常用属性说明:
'rate'
(整数):
'volume'
(浮点数):
0.0
(静音) 到 1.0
(最大音量)。某些引擎可能支持大于1.0的值,但这可能导致音频削波或失真。1.0
。'voice'
(字符串):
engine.getProperty('voices')
返回的语音对象列表中的某个语音的 id
属性(一个字符串)。'voices'
(只读, 列表):
pyttsx3.voice.Voice
对象的列表。Voice
对象都有以下属性:
id
(字符串): 语音的唯一标识符,用于 setProperty('voice', voice_id)
。name
(字符串): 语音的可读名称 (例如, “Microsoft David Desktop”, “Alex”)。languages
(列表): 该语音支持的语言代码列表 (例如, ['en_US']
)。gender
(字符串): 语音的性别 (例如, “male”, “female”, “neutral”)。可能为空或不准确。age
(整数):