升级macOS Ventura后pyttsx3获取语音列表报KeyError: 'VoiceAge'求助
macOS Ventura下pyttsx3获取语音列表触发KeyError: 'VoiceAge'的解决方案
问题背景
原代码在macOS Monterey + Python 3.11环境运行正常,升级至macOS Ventura后,执行engine.getProperty('voices')时出现KeyError: 'VoiceAge'错误,精简代码可复现问题:
import pyttsx3 engine = pyttsx3.init('nsss') voices = engine.getProperty('voices')
报错信息
File "./voice assistant/tts.py", line 18, in <module> voices = engine.getProperty('voices') File "./voice assistant/venv/lib/python3.10/site-packages/pyttsx3/engine.py", line 146, in getProperty return self.proxy.getProperty(name) File "./voice assistant/venv/lib/python3.10/site-packages/pyttsx3/driver.py", line 173, in getProperty return self._driver.getProperty(name) File "./voice assistant/venv/lib/python3.10/site-packages/pyttsx3/drivers/nsss.py", line 69, in getProperty return [self._toVoice(NSSpeechSynthesizer.attributesForVoice_(v)) File "./voice assistant/venv/lib/python3.10/site-packages/pyttsx3/drivers/nsss.py", line 69, in <listcomp> return [self._toVoice(NSSpeechSynthesizer.attributesForVoice_(v)) File "./voice assistant/venv/lib/python3.10/site-packages/pyttsx3/drivers/nsss.py", line 64, in _toVoice attr['VoiceAge']) File "./voice assistant/venv/lib/python3.10/site-packages/objc/_convenience_mapping.py", line 18, in __getitem__objectForKey_ return container_unwrap(res, KeyError, key) File "./voice assistant/venv/lib/python3.10/site-packages/objc/_convenience.py", line 122, in container_unwrap raise exc_type(*exc_args) KeyError: 'VoiceAge'
已尝试无效操作
- 重装pyttsx3
- 使用sudo运行代码
- 改用
pyttsx3.init('dummy')初始化(无报错但无法发声)
解决方案
方案1:修改pyttsx3的nsss驱动文件
错误原因是macOS Ventura中部分系统语音的属性不再包含VoiceAge字段,而pyttsx3的nsss驱动直接通过键取值导致报错。修改驱动文件处理缺失字段:
- 找到虚拟环境中nsss.py的路径:
./voice assistant/venv/lib/python3.10/site-packages/pyttsx3/drivers/nsss.py - 打开文件,找到
_toVoice函数(约60行处) - 将原代码中直接取值的部分改为用
get方法设置默认值:
原代码:
return Voice( id=attr['VoiceIdentifier'], name=attr['VoiceName'], languages=attr['VoiceLanguages'], gender=attr['VoiceGender'], age=attr['VoiceAge'])
修改为:
return Voice( id=attr['VoiceIdentifier'], name=attr['VoiceName'], languages=attr['VoiceLanguages'], gender=attr.get('VoiceGender', 'VoiceGenderNeutral'), age=attr.get('VoiceAge', 0))
- 保存文件后重新运行代码即可正常获取语音列表。
方案2:改用原生NSSpeechSynthesizer接口(推荐)
绕过pyttsx3的兼容性问题,直接通过pyobjc调用macOS原生语音合成接口:
- 安装依赖:
pip install pyobjc
- 替代代码示例(支持选择指定语音):
from Foundation import NSSpeechSynthesizer def va_speak(phrase, voice_id=None): if voice_id: synth = NSSpeechSynthesizer.alloc().initWithVoice_(voice_id) else: synth = NSSpeechSynthesizer.alloc().init() # 设置语速(范围100-300,默认175) synth.setRate_(150) # 设置音量(范围0-1,默认1) synth.setVolume_(1.0) synth.startSpeakingString_(phrase) while synth.isSpeaking(): pass # 获取所有可用语音并筛选en_US男性语音 voices = NSSpeechSynthesizer.availableVoices() target_voice = None for voice in voices: attrs = NSSpeechSynthesizer.attributesForVoice_(voice) if attrs.get('VoiceLanguages') == ['en_US'] and attrs.get('VoiceGender') == 'VoiceGenderMale': target_voice = voice break # 使用指定语音发声 va_speak("Hello there", target_voice)
内容的提问来源于stack exchange,提问作者Simple_Mac User
相关产品推荐
相关产品推荐

