1

I am creating a voice assistant that can speak and hear (using Python). While I was adding the speaking feature I programmed it to greet while the programme starts. I was multithreading the programme because the speak functions take to much time, it hangs the programme and it looks like it has stopped. While I was multithreading the speak function using pyttsx3 library of python, this error comes: "Runtime Error: the run loop has already started". My code:

from threading import Thread
from tkinter import *

from ctypes import windll, byref, create_unicode_buffer, create_string_buffer

import pyttsx3
import datetime

FR_PRIVATE = 0x10
FR_NOT_ENUM = 0x20


def load_font(font_path, private=True, enumerable=True):
    path_buf = None
    add_font_resource_ex = None

    if isinstance(font_path, bytes):
        path_buf = create_string_buffer(font_path)
        add_font_resource_ex = windll.gdi32.AddFontResourceExA

    elif isinstance(font_path, str):
        path_buf = create_unicode_buffer(font_path)
        add_font_resource_ex = windll.gdi32.AddFontResourceExW

    flags = (FR_PRIVATE if private else 0) | (FR_NOT_ENUM if not enumerable else 0)
    num_fonts_added = add_font_resource_ex(byref(path_buf), flags, 0)

    return bool(num_fonts_added)


class MainWindow(Tk):
    def __init__(self):
        super().__init__()

        self.title("Voice Assistant")
        self.geometry("550x505")
        self.resizable(False, False)

        self.engine = pyttsx3.init()

        self.output_area = Text(self, bd=2, relief=SOLID, font=("Poppins", 16), width=40, height=12, state=DISABLED)
        self.output_area.place(x=10, y=10)

        self.command_en = Entry(self, font=("Poppins", 11), width=48)
        self.command_en.place(x=10, y=465)

        self.hear_btn = Button(self, text="Hear", font=("Arial", 10), width=9, height=1)
        self.hear_btn.place(x=455, y=465)

        self.wish_me()

        self.mainloop()

    def speak(self, audio):
        self.engine.say(audio)
        self.engine.runAndWait()

    def say(self, audio):
        speak_thread = Thread(target=self.speak, args=[audio])
        speak_thread.start()

    def wish_me(self):
        hour = int(datetime.datetime.now().hour)

        if 0 <= hour < 12:
            self.say("Good morning")
        elif 12 <= hour <= 18:
            self.say("Good afternoon")
        else:
            self.say("Good evening")

        self.say("I am Jarvis, How can I help you?")


if __name__ == "__main__":
    loaded = load_font("Poppins-Regular.otf")
    root = MainWindow()

Error:

Exception in thread Thread-2:
Traceback (most recent call last):
  File "C:\Users\Manbir Singh Judge\Python 3.8.6\lib\threading.py", line 932, in _bootstrap_inner
    self.run()
  File "C:\Users\Manbir Singh Judge\Python 3.8.6\lib\threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "C:/Users/Manbir Singh Judge/PycharmProjects/Voice Assistant/main.py", line 56, in speak
    self.engine.runAndWait()
  File "C:\Users\Manbir Singh Judge\Python 3.8.6\lib\site-packages\pyttsx3\engine.py", line 177, in runAndWait
    raise RuntimeError('run loop already started')
RuntimeError: run loop already started

Manbir Judge
  • 113
  • 1
  • 13

1 Answers1

0

I just found this workaround, just use the subprocess library to call another python from main python and it will run in different thread from another file

  1. This is your main file: add this code

from subprocess import call
phrase = "Hi everyone"
call(["python3", "speak.py", phrase])

  1. This is your speak.py file where will be run after calling it
import sys
import pyttsx3

def init_engine():
    engine = pyttsx3.init()
    return engine

def say(s):
    engine.say(s)
    engine.runAndWait() # In here the program will wait as if is in main file

engine = init_engine()
say(str(sys.argv[1])) # Here it will get the text through sys from main file

That's it, just edit this code to fit your requirements.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Mussa Charles
  • 659
  • 7
  • 10
  • 1
    Thanks for answering but I had just scrapped that app idea so... if I will do any other project related to Pyttsx then this will most probably help me. Thanks!! – Manbir Judge Apr 25 '21 at 14:28