pythontext-to-speechpyttsx

Python pyttsx, how to use external loop


In my program I need class(which can be some thread) to check some list like "say_list" and when other classes add some text to it, pyttsx say that text. I search in pyttsx docs and I find some external loops feature but I can not find example which work correctly. I want something like this:

import pyttsx
import threading

class VoiceAssistant(threading.Thread):
    def __init__(self):
        super(VoiceAssistant, self).__init__()
        self.engine = pyttsx.init()
        self.say_list = []

    def add_say(self, msg):
        self.say_list.append(msg)

    def run(self):
        while True:
            if len(self.say_list) > 0:
                self.engine.say(self.say_list[0])
                self.say_list.remove(self.say_list[0])


if __name__ == '__main__':
    va = VoiceAssistant()
    va.start()

Thanks.


Solution

  • I can get the proper results by using python's built in Queue class:

    import pyttsx
    from Queue import Queue
    from threading import Thread
    
    q = Queue()
    
    def say_loop():
        engine = pyttsx.init()
        while True:
            engine.say(q.get())
            engine.runAndWait()
            q.task_done()
    
    def another_method():
        t = Thread(target=say_loop)
        t.daemon = True
        t.start()
        for i in range(0, 3):
            q.put('Sally sells seashells by the seashore.')
        print "end of another method..."
    
    def third_method():
        q.put('Something Something Something')
    
    if __name__=="__main__":
        another_method()
        third_method()
        q.join() # ends the loop when queue is empty
    

    Above is a simple example I whipped up. It uses the 'queue/consumer' model to allow separate functions/classes to access the same queue, then a worker that will execute anytime the queue has items. Should be pretty easy to adapt to your needs.

    Further reading about Queues: https://docs.python.org/2/library/queue.html There appears to be an interface for this in the docs you linked to, but it seemed like you were already on the separate thread track so this seemed closer to what you wanted.

    And here's the modified version of your code:

    import pyttsx
    from Queue import Queue
    import threading
    
    class VoiceAssistant(threading.Thread):
        def __init__(self):
            super(VoiceAssistant, self).__init__()
            self.engine = pyttsx.init()
            self.q = Queue()
            self.daemon = True
    
        def add_say(self, msg):
            self.q.put(msg)
    
        def run(self):
            while True:
                self.engine.say(self.q.get())
                self.engine.runAndWait()
                self.q.task_done()
    
    
    if __name__ == '__main__':
        va = VoiceAssistant()
        va.start()
        for i in range(0, 3):
            va.add_say('Sally sells seashells by the seashore.')
        print "now we want to exit..."
        va.q.join() # ends the loop when queue is empty