nateshmbhat / pyttsx3

Offline Text To Speech synthesis for python
Mozilla Public License 2.0
1.99k stars 321 forks source link

Not working pyttsx3 with python 3.11.4 #286

Closed Fledermaus-20 closed 5 months ago

Fledermaus-20 commented 11 months ago

I own a macbook air m2 16 gb ram and 512gb storage mac os 13.5 python v. 3.11.4

/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/pyttsx3/drivers/nsss.py:12: ObjCSuperWarning: Objective-C subclass uses super(), but super is not objc.super class NSSpeechDriver(NSObject): Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/pyttsx3/init.py", line 20, in init eng = _activeEngines[driverName]


  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/weakref.py", line 136, in __getitem__
    o = self.data[key]()
        ~~~~~~~~~^^^^^
KeyError: None

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/username/Library/Mobile Documents/com~apple~CloudDocs/Coding/Sprach Assistent/test.py", line 3, in <module>
    engine = pyttsx3.init()
             ^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/pyttsx3/__init__.py", line 22, in init
    eng = Engine(driverName, debug)
          ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/pyttsx3/engine.py", line 30, in __init__
    self.proxy = driver.DriverProxy(weakref.proxy(self), driverName, debug)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/pyttsx3/driver.py", line 52, in __init__
    self._driver = self._module.buildDriver(weakref.proxy(self))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/pyttsx3/drivers/nsss.py", line 9, in buildDriver
    return NSSpeechDriver.alloc().initWithProxy(proxy)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/pyttsx3/drivers/nsss.py", line 15, in initWithProxy
    self = super(NSSpeechDriver, self).init()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'super' object has no attribute 'init'
sys:1: UninitializedDeallocWarning: leaking an uninitialized object of type NSSpeechDriver
essenciary commented 11 months ago

Found the solution on SO - you need to replace the faulty line (nsss.py:15) by this:

self = objc.super(NSSpeechDriver, self).init()

Also make sure that pyobjc is installed as a dependency.

This fixed it for me, though I'm facing a different issue now: after speaking, the script/app exits.

Fledermaus-20 commented 11 months ago

Is that the same issue what you hvae found? Python[11740:160581] -[OC_BuiltinPythonArray hasPrefix:]: unrecognized selector sent to instance 0x11c10d270

m1guelperez commented 11 months ago

This fixed it for me, though I'm facing a different issue now: after speaking, the script/app exits.

Wow. Just saw this. Do you mean it exits without any error or status code whatever? Because as soon as it talked in my case it just terminates without any info. I also edited the nsss.py file.

I tried to trace it down and it seems that in the file /Users/username/miniconda3/envs/test/lib/python3.10/sitepackages/PyObjCTools/AppHelper.py

def runConsoleEventLoop(
    argv=None, installInterrupt=False, mode=NSDefaultRunLoopMode, maxTimeout=3.0
):
    if argv is None:
        argv = sys.argv
    if installInterrupt:
        installMachInterrupt()
    runLoop = NSRunLoop.currentRunLoop()
    stopper = PyObjCAppHelperRunLoopStopper.alloc().init()
    PyObjCAppHelperRunLoopStopper.addRunLoopStopper_toRunLoop_(stopper, runLoop)
    try:
        while stopper.shouldRun():
            print("shouldRun " + str(stopper.shouldRun()))
            nextfire = runLoop.limitDateForMode_(mode)
            if not stopper.shouldRun():
                print("stopper.shouldRun() is false")
                break
            soon = NSDate.dateWithTimeIntervalSinceNow_(maxTimeout)
            if nextfire is not None:
                nextfire = soon.earlierDate_(nextfire)
                print("nextfire")
            if not runLoop.runMode_beforeDate_(mode, nextfire):
                print("runloop stopped")
                print(runLoop.runMode_beforeDate_(mode, nextfire))
                stopper.stop()
        print("done")
    finally:
        print("finally")
        PyObjCAppHelperRunLoopStopper.removeRunLoopStopperFromRunLoop_(runLoop)

This code never prints finally, runloop stopped, stopper.shouldRun() is false nor done. The output is just:

shouldRun True
nextfire
shouldRun True
nextfire
shouldRun True
nextfire

And then it seems to abruptly terminate. However, if we would exit the while loop correctly we would print the done.

EDIT: As stated in #279 downgrading to pyobjc 9.0.1 works like a charm. Maybe it also solves your issue @essenciary

essenciary commented 11 months ago

@m1guelperez Yes, indeed, it just exited without any info/output, practically crashing the app.

I did manage to make it work by downgrading, but then I ran into another issue when attempting to save as audio files: the audio file was generated but was always the same size (I think 16KB) and empty.

I was running the script on an M2 aarm mac.

Fledermaus-20 commented 5 months ago

This solved it finally for me #297