KoljaB / RealtimeTTS

Converts text to speech in realtime
2.07k stars 209 forks source link

KeyError: 'VoiceAge' in mac M1 #9

Open lout33 opened 1 year ago

lout33 commented 1 year ago
(venv) ➜  RealtimeTTS git:(main) ✗ python3 simple_test.py
Traceback (most recent call last):
  File "/Users/lout/Documents/projects/explore_ai/RealtimeTTS/simple_test.py", line 12, in <module>
    engine = SystemEngine() # replace with your TTS engine
             ^^^^^^^^^^^^^^
  File "/Users/lout/Documents/projects/explore_ai/venv/lib/python3.11/site-packages/RealtimeTTS/engines/base_engine.py", line 10, in __call__
    instance = super().__call__(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lout/Documents/projects/explore_ai/venv/lib/python3.11/site-packages/RealtimeTTS/engines/system_engine.py", line 36, in __init__
    self.set_voice(voice)
  File "/Users/lout/Documents/projects/explore_ai/venv/lib/python3.11/site-packages/RealtimeTTS/engines/system_engine.py", line 105, in set_voice
    installed_voices = self.engine.getProperty('voices')
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lout/Documents/projects/explore_ai/venv/lib/python3.11/site-packages/pyttsx3/engine.py", line 146, in getProperty
    return self.proxy.getProperty(name)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lout/Documents/projects/explore_ai/venv/lib/python3.11/site-packages/pyttsx3/driver.py", line 173, in getProperty
    return self._driver.getProperty(name)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lout/Documents/projects/explore_ai/venv/lib/python3.11/site-packages/pyttsx3/drivers/nsss.py", line 69, in getProperty
    return [self._toVoice(NSSpeechSynthesizer.attributesForVoice_(v))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lout/Documents/projects/explore_ai/venv/lib/python3.11/site-packages/pyttsx3/drivers/nsss.py", line 69, in <listcomp>
    return [self._toVoice(NSSpeechSynthesizer.attributesForVoice_(v))
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lout/Documents/projects/explore_ai/venv/lib/python3.11/site-packages/pyttsx3/drivers/nsss.py", line 64, in _toVoice
    attr['VoiceAge'])
    ~~~~^^^^^^^^^^^^
  File "/Users/lout/Documents/projects/explore_ai/venv/lib/python3.11/site-packages/objc/_convenience_mapping.py", line 18, in __getitem__objectForKey_
    return container_unwrap(res, KeyError, key)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lout/Documents/projects/explore_ai/venv/lib/python3.11/site-packages/objc/_convenience.py", line 134, in container_unwrap
    raise exc_type(*exc_args)
KeyError: 'VoiceAge'

Code:

from RealtimeTTS import TextToAudioStream, SystemEngine

def dummy_generator():
    yield "This is a sentence. And here's another! Yet, "
    yield "there's more. This ends now."

TextToAudioStream(SystemEngine()).feed(dummy_generator()).play()

Also i had to install the pip3 install pyobjc==9.0.1 for this sample to work

import pyttsx3
engine = pyttsx3.init()
engine.say("I will speak this text")
engine.runAndWait()
KoljaB commented 1 year ago

Hey there, thanks a lot for reporting that issue.

It is quite much all pyttsx3 related and a fix for this is out of scope for RealtimeTTS. I think I can integrate the pyobjc installation for mac.

The - quite rough - suggested solution I found online was to just edit the nsss.py file of pyttsx3 and remove the attr['VoiceAge'] part. So it can be solved by editing your /opt/anaconda3/lib/python3.9/site-packages/pyttsx3/drivers/nsss.py at the 64 line and remove the attr['VoiceAge'] at this location

holytony commented 9 months ago

Hey there, thanks a lot for reporting that issue.

It is quite much all pyttsx3 related and a fix for this is out of scope for RealtimeTTS. I think I can integrate the pyobjc installation for mac.

The - quite rough - suggested solution I found online was to just edit the nsss.py file of pyttsx3 and remove the attr['VoiceAge'] part. So it can be solved by editing your /opt/anaconda3/lib/python3.9/site-packages/pyttsx3/drivers/nsss.py at the 64 line and remove the attr['VoiceAge'] at this location

deleting the attr['VoiceAge'] do solve the error, however when I try the following demo code, the program runs but generate no sound.

`from RealtimeTTS import TextToAudioStream, SystemEngine

engine = SystemEngine(voice= 'Zoe (Premium)') # replace with your TTS engine stream = TextToAudioStream(engine) stream.feed("Hello world! How are you today?") stream.play_async()`

KoljaB commented 9 months ago

Oh, sorry - this demo code might be misleading.

You either need to write:

stream.play_async()
while stream.is_playing():
    time.sleep(0.1)

Or this:

stream.play()
holytony commented 9 months ago
stream.play_async()
while stream.is_playing():
    time.sleep(0.1)

when I tried that or the stream.play() one, this is the new error I got

engine system failed to synthesize sentence "How are you today?" with error: run loop already started Traceback: Traceback (most recent call last): File "/venv/lib/python3.10/site-packages/RealtimeTTS/text_to_stream.py", line 279, in synthesize_worker success = self.engine.synthesize(sentence) File "/venv/lib/python3.10/site-packages/RealtimeTTS/engines/system_engine.py", line 69, in synthesize self.engine.runAndWait() File "*****/venv/lib/python3.10/site-packages/pyttsx3/engine.py", line 183, in runAndWait raise RuntimeError('run loop already started') RuntimeError: run loop already started

Error: run loop already started engine system is the only engine available, can't switch to another engine

KoljaB commented 9 months ago

Hm, never saw this one so far. Googled it but no idea currently. What happens if you run this basic pyttsx3 test without RealtimeTTS?

import pyttsx3
engine = pyttsx3.init()
engine.say("I will speak this text")
engine.runAndWait()

Does this play out?

holytony commented 9 months ago

Hm, never saw this one so far. Googled it but no idea currently. What happens if you run this basic pyttsx3 test without RealtimeTTS?

import pyttsx3
engine = pyttsx3.init()
engine.say("I will speak this text")
engine.runAndWait()

Does this play out?

it plays out no problem

KoljaB commented 9 months ago

I'm lost with this one, I have to admit.

RealtimeTTS would split the input text into sentences and then loop

        self.engine.save_to_file(text, self.file_path)
        self.engine.runAndWait()

for every sentence. Unsure what goes wrong here with the runAndWait(), googled the error but got no insights. Sadly I got no Mac here to debug, very sorry I can't offer further help currently.

holytony commented 9 months ago

I'm lost with this one, I have to admit.

RealtimeTTS would split the input text into sentences and then loop

        self.engine.save_to_file(text, self.file_path)
        self.engine.runAndWait()

for every sentence. Unsure what goes wrong here with the runAndWait(), googled the error but got no insights. Sadly I got no Mac here to debug, very sorry I can't offer further help currently.

the pyttsx3 lib was known for its blocking behaviour which have caused a lot of weird problems on Mac, well, I'm not gonna give up on this one, because it's currently the best performing one on GitHub, if I figure out what's going on, I will let you know

Jiminator commented 5 months ago

@holytony have u figured out the solution to this problem? I'm also a MacBook user struggling with this problem

holytony commented 4 months ago

@holytony have u figured out the solution to this problem? I'm also a MacBook user struggling with this problem

Nah, unfortunately the clusterfuck with nsss and pyttsx3 on macOS it's beyond me

holytony commented 4 months ago

I'm lost with this one, I have to admit.

RealtimeTTS would split the input text into sentences and then loop

        self.engine.save_to_file(text, self.file_path)
        self.engine.runAndWait()

for every sentence. Unsure what goes wrong here with the runAndWait(), googled the error but got no insights. Sadly I got no Mac here to debug, very sorry I can't offer further help currently.

Still haven't figured out a way to make it work, but here is what I have found:

  1. pyttsx3+nsss on macOS can't generate wav file, it will generate a 4kb empty file instead. The only way to make save_to_file in pyttsx3/system_engine works on macOS is using a file path with aiff extension.See: [https://github.com/nateshmbhat/pyttsx3/issues/142]
  2. The VoiceAge error thing in macOS can be "solved" by a dirty fix, just go and delete Voice Age part in nsss.py in pyttsx3, See: [https://github.com/nateshmbhat/pyttsx3/issues/248]
  3. it takes time for the nsss on macOS to generate file, on the synthesis part of System_engine, if you try to read the file straight a way, after the engine.run_and_wait(), it will read a empty file, but set a time.sleep() for 1 seconds-ish+, it will be able to read the audio file

also @Jiminator if you are still working on this, hope the infos above helps