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.
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
pyttsx3 loop pronunciation
import pyttsx3
voice_text = 'test'
def loopSound():
def onEnd(name, completed):
print('finishing', name, completed)
engine.say(voice_text, 'voice_a')
engine = pyttsx3.init()
engine.connect('finished-utterance', onEnd)
engine.say(voice_text, 'voice_e')
engine.startLoop()
loopSound()
Related
I have one class produceMessages() that keeps feeding messages to its attribute message_logs.
I want to process these messages in the other class processMessages(). However, the code in processMessages() won't execute until produceMessages() is done - which is never as I want these messages to come forever.
Looking at documentation, I've found that the library asyncio might help me but I'm struggling to get the below example work:
This is first_file.py
import asyncio
import random
class produceMessages():
def __init__(self, timeout = 10):
self.timeout = timeout
self.message_logs = []
async def run(self):
while(True):
self.message_logs.append(random.uniform(0, 1))
await asyncio.sleep(self.timeout)
This is second_file.py
import first_file
import asyncio
import time
class processMessages():
def __init__(self):
self.producer = first_file.produceMessages()
asyncio.run(self.producer.run())
def print_logs(self):
print(self.producer.message_logs)
time.sleep(1)
x = processMessages()
x.print_logs()
How can I make this work? Thanks
I would recommend you try the library threading. This is how I would approach it with that:
import first_file
import asyncio
import time
class processMessages():
def __init__(self):
self.test = first_file.produceMessages()
t = threading.Thread(target=self.test.run)
t.run()
t2 = threading.Thread(target=self.print_logs)
def print_logs(self):
print(self.test.message_logs)
time.sleep(1)
x = processMessages()
x.t2.run()
I have a class to start a thread for a while loop. I tried to scheduling the thread class to start within a certain time but it doesn't work:
def test():
if __name__ == "__main__":
main()
schedule.every().day.at("17:25:50").do(test)
The function does not do anything even the time reached "17:25:50"
My full code:
import discord
import random
import time
import asyncio
import schedule
from facebook_scraper import get_posts, _scraper, exceptions
from discord.ext import commands, tasks
import threading
import time
import re
class LEDManager(threading.Thread):
def __init__(self, id_manager):
threading.Thread.__init__(self)
self.id_manager = int(id_manager)
def run(self):
while True:
try:
wanted = "Pecahan setiap negeri (Kumulatif):" # wanted post
for post in get_posts("myhealthkkm", pages=5):
if post.get("post_text") is not None and wanted in post.get("post_text"):
# print("Found", t)
listposts.append(post.get("post_text"))
# append until 3 page finish then go here
time.sleep(1)
print(listposts)
global listView
if listposts != 0:
listView = listposts.copy()
print(listView)
listposts.clear()
except exceptions.TemporarilyBanned:
print("Temporarily banned, sleeping for 10m")
time.sleep(600)
def main():
thread_id = ("0")
led_index = 0
thread_list = list()
for objs in thread_id:
thread = LEDManager(led_index)
thread_list.append(thread)
led_index += 1
for thread in thread_list:
thread.start()
time.sleep(1)
def test():
if __name__ == "__main__":
main()
schedule.every().day.at("17:25:50").do(test)
You forgot to add these lines:
while True:
schedule.run_pending()
time.sleep(1)
You should add them at the end of the file, so the system will keep checking forever, if "the job" needs to be done (if the hour is "17:25:50").
And here is the full documentation to see how to use the schedule module:
https://schedule.readthedocs.io/en/stable/
I'm a newbie to Python and learning about threads. I have created a sample Producer-Consumer code wherein I add a movie to a list in Producer thread and pop the front element from the same list in Consumer thread. The problem is while printing the items of the movie List along with thread name I'm getting incorrect thread name in Producer thread. This is my code
Producer.py
from threading import Thread
from threading import RLock
import time
class Producer(Thread):
def __init__(self):
Thread.__init__(self)
Thread.name = 'Producer'
self.movieList = list()
self.movieListLock = RLock()
def printMovieList(self):
self.movieListLock.acquire()
if len(self.movieList) > 0:
for movie in self.movieList:
print(Thread.name, movie)
print('\n')
self.movieListLock.release()
def pushMovieToList(self, movie):
self.movieListLock.acquire()
self.movieList.append(movie)
self.printMovieList()
self.movieListLock.release()
def run(self):
for i in range(6):
self.pushMovieToList('Avengers' + str(i + 1))
time.sleep(1)
Consumer.py
from threading import Thread
import time
class Consumer(Thread):
def __init__(self):
Thread.__init__(self)
Thread.name = 'Consumer'
self.objProducer = None
def popMovieFromList(self):
self.objProducer.movieListLock.acquire()
if len(self.objProducer.movieList) > 0:
movie = self.objProducer.movieList.pop(0)
print(Thread.name, ':', movie)
print('\n')
self.objProducer.movieListLock.release()
def run(self):
while True:
time.sleep(1)
self.popMovieFromList()
Main.py
from Producer import *
from Consumer import *
def main():
objProducer = Producer()
objConsumer = Consumer()
objConsumer.objProducer = objProducer
objProducer.start()
objConsumer.start()
objProducer.join()
objConsumer.join()
main()
I am not sure whether you solve this problem.
Hope my answer will be helpful.
You can check the document of threading.
Here it says that Thread.name may set same name for multiple thread.
name
A string used for identification purposes only. It has no semantics. Multiple threads may be given the same name. The initial name is set by the constructor.
I think Thread.name is a static variable so it shares in different thread.
If you want to set name of thread, you can set it in thread object like this:
class Producer(Thread):
def __init__(self):
Thread.__init__(self)
self.name= 'Producer'
and get it by threading.current_thread().name.
if len(self.movieList) > 0:
for movie in self.movieList:
print(threading.current_thread().name, movie)
Hope you enjoy it!
I have the following situation process=Process(target=sample_object.run) I then would like to edit a property of the sample_object: sample_object.edit_property(some_other_object).
class sample_object:
def __init__(self):
self.storage=[]
def edit_property(self,some_other_object):
self.storage.append(some_other_object)
def run:
while True:
if len(self.storage) is not 0:
print "1"
#I know it's an infinite loop. It's just an example.
_______________________________________________________
from multiprocessing import Process
from sample import sample_object
from sample2 import some_other_object
class driver:
if __name__ == "__main__":
samp = sample_object()
proc = Process(target=samp.run)
proc.start()
while True:
some = some_other_object()
samp.edit_property(some)
#I know it's an infinite loop
The previous code never prints "1". How would I connect the Process to the sample_object so that an edit made to the object whose method Process is calling is recognized by the process? In other words, is there a way to get .run to recognize the change in sample_object ?
Thank you.
You can use multiprocessing.Manager to share Python data structures between processes.
from multiprocessing import Process, Manager
class A(object):
def __init__(self, storage):
self.storage = storage
def add(self, item):
self.storage.append(item)
def run(self):
while True:
if self.storage:
print 1
if __name__ == '__main__':
manager = Manager()
storage = manager.list()
a = A(storage)
p = Process(target=a.run)
p.start()
for i in range(10):
a.add({'id': i})
p.join()
I'm using a library which heaviliy uses I/O. For that reason calls to that library can last very long (more than 5 seconds) possible.
Using that directly inside an UI is not a good idea because it will freeze.
For that reason I outsourced the library calls to a thread queue like shown in this example: Python threads: communication and stopping
Nevertheless I'm not very happy with that solution since this has a major drawback:
I cannot really communicate with the UI.
Every lib command returns a return message, which can either be an error message or some computational result.
How would I get this?
Consider a library call do_test(foo):
def do_test(foo):
time.sleep(10)
return random.random() * foo
def ui_btn_click():
threaded_queue.put((do_test, 42))
# Now how to display the result without freezing the UI?
Can someone give me advice how to realize such a pattern?
Edit:
This here is a minimal example:
import os, time, random
import threading, queue
CMD_FOO = 1
CMD_BAR = 2
class ThreadedQueue(threading.Thread):
def __init__(self):
super().__init__()
self.in_queue = queue.Queue()
self.out_queue = queue.Queue()
self.__stoprequest = threading.Event()
def run(self):
while not self.__stoprequest.isSet():
(cmd, arg) = self.in_queue.get(True)
if cmd == CMD_FOO:
ret = self.handle_foo(arg)
elif cmd == CMD_BAR:
ret = self.handle_bar(arg)
else:
print("Unsupported cmd {0}".format(cmd))
self.out_queue.put(ret)
self.in_queue.task_done()
def handle_foo(self, arg):
print("start handle foo")
time.sleep(10)
return random.random() * arg
def handle_bar(self, arg):
print("start handle bar")
time.sleep(2)
return (random.random() * arg, 2 * arg)
if __name__ == "__main__":
print("START")
t = ThreadedQueue()
t.start()
t.in_queue.put((CMD_FOO, 10))
t.in_queue.put((CMD_BAR, 10))
print("Waiting")
while True:
x = t.out_queue.get(True)
t.out_queue.task_done()
print(x)
I personally use PySide but I don't want to depend this library on PySide or any other ui-related library.
I thought a bit about my implementations. THe conclusion is that I start another thread for picking the results of the queue:
class ReceiveThread(threading.Thread):
"""
Processes the output queue and calls a callback for each message
"""
def __init__(self, queue, callback):
super().__init__()
self.__queue = queue
self.__callback = callback
self.__stoprequest = threading.Event()
self.start()
def run(self):
while not self.__stoprequest.isSet():
ret = self.__queue.get(True)
self.__callback(ret)
self.__queue.task_done()
The given callback from an UI or elsewhere is called with every result from the queue.