user11620362
user11620362

Reputation:

How to use multithreading with tkinter in this program

This code accepts user input as audio and responds accordingly and I want to use tkinter to display the conversation. I tried using using multithreading but it won't work.Please help me regarding how to use multithreading here. Expected result :

  1. The code should print the conversation on a window
  2. And also listen to the user simultaneously

Here is my code

import pyttsx3
import speech_recognition as sr
import datetime
import wikipedia
import webbrowser
import os
import smtplib
from tkinter import *
import threading
import time

root = Tk()

engine = pyttsx3.init('sapi5')
voices = engine.getProperty('voices')
# print(voices[0].id)
engine.setProperty('voice', voices[0].id)


def speak(audio):
    engine.say(audio)
    engine.runAndWait()
    t = Text(root)
    t.grid(row=0, column=0,
       columnspan=2, rowspan=2, padx=5, pady=5)
    t.insert(END, 'Genos says: ' + audio + '\n')


def wishme():
    hour = int(datetime.datetime.now().hour)
    if hour >= 0 and hour < 12:
        speak("Good Morning sir")

    elif hour >= 12 and hour < 18:
        speak("Good Afternoon sir")

    else:
        speak("Good Evening sir")
    speak("I am Genos. How can I Serve you?")
    return
    t = Text(root)
    t.grid(row=0, column=0,
       columnspan=2, rowspan=2, padx=5, pady=5)
    t.insert(END, 'Genos says: ' + wishme() + '\n')


def takecommand():
    # it takes mic input from the user and return string output
    r = sr.Recognizer()
    with sr.Microphone() as source:
        print("Listening...")
        r.pause_threshold = 1
        audio = r.listen(source)

    try:
        print("Recognizing..")
        query = r.recognize_google(audio, language='en-in')
        print(f"user Said :{query}\n")

    except Exception as e:
        print(e)

        speak("Say that again please")
        return "None"
    t1 = Text(root)
    t1.grid(row=0, column=2,
        columnspan=2, rowspan=2, padx=5, pady=5)
    t1.insert(END, 'user says: ' + query + '\n')
    return query


def sendEmail(to, content):
    server = smtplib.SMTP("smtp.gmail.com", 587)
    server.ehlo()
    server.starttls()
    server.login('[email protected]', '###')
    server.sendmail('[email protected]', to, content)
    server.close()
    return


if __name__ == "__main__":

    wishme()

    # while True:
    for _ in range(10):
        query = takecommand().lower()

        # Logic for executing task based query
        if 'wikipedia' in query:
            speak('searching Wikipedia....')
            query = query.replace("wikipedia", "")
            results = wikipedia.summary(query, sentences=5)
            speak("According to wikipedia")
            print(results)
            speak(results)

        elif 'open youtube' in query:
            webbrowser.open("youtube.com")

        elif 'open google' in query:
            webbrowser.open("google.com")

        elif 'open stackoverflow' in query:
            webbrowser.open("stackoverflow.com")

        elif 'play music' in query:
            music_dir = 'D:\\SAHIL\\$ONGS_MJ'
            songs = os.listdir(music_dir)
            print(songs)
            os.startfile(os.path.join(music_dir, songs[0]))

        elif 'the time' in query:
            strTime = datetime.datetime.now().strftime("%H:%M:%S")
            speak(f"Sir the time is {strTime}")

        elif 'open code' in query:
            codepath = "C:\\Users\\Sahil\\AppData\\Local\\Programs\\Microsoft VS Code 
Insiders\\Code - Insiders.exe"
            os.startfile(codepath)

        elif 'email to sahil' in query:
            try:
                speak("What should i say ?")
                content = takecommand()
                to = "[email protected]@gmail.com"
                sendEmail(to, content)
                speak("Email has been sent")
            except Exception as e:
                print(e)
                speak("Could nott send the email ")

        elif 'open mailbox' in query:
            webbrowser.open("gmail.com");

        elif 'how are you' in query:
            speak("I am fine sir. How are you?")
            continue

        elif 'i am fine' in query:
            speak("that's good to know, how can I help you")
            continue

        elif 'goodbye' in query:
            speak("bye Sir")
            exit()


root.mainloop()

Upvotes: 0

Views: 578

Answers (1)

furas
furas

Reputation: 143098

I couldn't test speech recognition but at least it displays text which it speeks.

I put all your loop in function and run in Thread. I also send queue to this thread soit can send text (or commands like \quit) to main thread which use after to periodically (200ms) get text from queue and display in Text

import os
import pyttsx3
import speech_recognition as sr
import datetime
import wikipedia
import webbrowser
import smtplib
import time

import threading
import queue
import tkinter as tk

# --- functions ---

def speak(text):
    engine.say(text)
    engine.runAndWait()

def wishme(queue):
    hour = datetime.datetime.now().hour

    if 0 <= hour < 12:
        text = "Good Morning sir"
    elif 12 <= hour < 18:
        text = "Good Afternoon sir"
    else:
        text = "Good Evening sir"

    queue.put(f'{text}.')
    speak(text)

    queue.put("I am Genos. How can I Serve you?\n")
    speak("I am Genos. How can I Serve you?")


def takecommand():
    # it takes mic input from the user and return string output
    r = sr.Recognizer()
    with sr.Microphone() as source:
        print("Listening...")
        r.pause_threshold = 1
        audio = r.listen(source)

    try:
        print("Recognizing..")
        query = r.recognize_google(audio, language='en-in')
        print(f"user Said :{query}\n")

    except Exception as e:
        print(e)

        speak("Say that again please")
        return "None"

    return query


def sendEmail(to, content):
    server = smtplib.SMTP("smtp.gmail.com", 587)
    server.ehlo()
    server.starttls()
    server.login('[email protected]', '###')
    server.sendmail('[email protected]', to, content)
    server.close()
    return


def my_loop(queue):
    wishme(queue)

    while True:
        query = takecommand().lower()

        # Logic for executing task based query
        if 'wikipedia' in query:
            queue.put('searching Wikipedia....')
            speak('searching Wikipedia....')

            query = query.replace("wikipedia", "")
            results = wikipedia.summary(query, sentences=5)

            queue.put("According to wikipedia" + str(results))

            speak("According to wikipedia")
            print(results)
            speak(results)

        elif 'open youtube' in query:
            queue.put("opening youtube.com")
            webbrowser.open("youtube.com")

        elif 'open google' in query:
            queue.put("opening google.com")
            webbrowser.open("google.com")

        elif 'open stackoverflow' in query:
            queue.put("opening stackoverflow.com")
            webbrowser.open("stackoverflow.com")

        elif 'open mailbox' in query:
            webbrowser.open("gmail.com");


        elif 'play music' in query:
            music_dir = 'D:\\SAHIL\\$ONGS_MJ'
            songs = os.listdir(music_dir)

            queue.put(f"playing music {songs[0]}")

            print(songs)
            os.startfile(os.path.join(music_dir, songs[0]))

        elif 'the time' in query:
            strTime = datetime.datetime.now().strftime("%H:%M:%S")

            speak(f"Sir the time is {strTime}", queue)

        elif 'open code' in query:
            codepath = "C:\\Users\\Sahil\\AppData\\Local\\Programs\\Microsoft VS Code Insiders\\Code - Insiders.exe"

            queue.put(f"opening code {codepath}")

            os.startfile(codepath)

        elif 'email to sahil' in query:
            try:
                queue.put("What should i say ?")
                speak("What should i say ?")

                content = takecommand()
                to = "[email protected]@gmail.com"
                sendEmail(to, content)

                queue.put(f"Email has been sent: {content}")
                speak("Email has been sent")
            except Exception as e:
                print(e)
                queue.put(f"Could nott send the email: {e}")
                speak("Could nott send the email ")

        elif 'how are you' in query:
            queue.put("I am fine sir. How are you?")
            speak("I am fine sir. How are you?")

        elif 'i am fine' in query:
            queue.put("that's good to know, how can I help you")
            speak("that's good to know, how can I help you")

        elif 'goodbye' in query:
            queue.put("bye Sir")
            speak("bye Sir")
            queue.put("\quit")
            break # exit loop and thread will end                      
            #exit()

def update_text():
    if not queue.empty():
        text = queue.get()
        if text == '\quit':
            root.destroy() # close window and stop `root.mainloop()`
            return # don't run `after` again           
        else:
            t.insert('end', text)

    root.after(200, update_text)

# --- main ---

if __name__ == "__main__":

    engine = pyttsx3.init('sapi5') # Windows
    #engine = pyttsx3.init('espeak') # Linux
    voices = engine.getProperty('voices')
    # print(voices[0].id)
    engine.setProperty('voice', voices[0].id)

    # --- 

    root = tk.Tk()

    t = tk.Text()
    t.pack()

    queue = queue.Queue()

    update_text()

    task = threading.Thread(target=my_loop, args=(queue,)) # it has to be `,` in `(queue,)` to create tuple with one value
    task.start() # start thread

    root.mainloop()

    task.join() # wait for end of thread

Upvotes: 1

Related Questions