Tkinter window will update after the code has finished - python

When I run the code the window will appear after the code finished and if I add the main loop at the start the code won't run until I close the window. I want the window to update every time I add a label variable in my code. I searched on multiple docs but they all seem to give the same answer and it did not work.
import pyttsx3
import datetime
import wikipedia
import webbrowser
import os
import tkinter
import speech_recognition as sr
from notifypy import Notify
window = tkinter.Tk()
window.title("GUI")
window.geometry('500x500')
engine = pyttsx3.init('sapi5')
voices = engine.getProperty('voices')
engine.setProperty('voice', voices[0].id)
# print(voices)
def speak(audio):
engine.say(audio)
engine.runAndWait()
def wishme():
hour = int(datetime.datetime.now().hour)
if hour>=0 and hour<=12:
speak("good morning sir")
lab1 = tkinter.Label(window,text="Good morning sir").pack()
elif hour>=12 and hour<=18:
speak("good afternoon sir")
lab2 = tkinter.Label(window,text="Good afternoon sir").pack()
elif hour>=18 and hour<=22:
speak("good evening sir")
lab3 = tkinter.Label(window,text="Good evening sir").pack()
else:
speak("good night sir")
lab4 = tkinter.Label(window,text="Good night sir").pack()
lab5 = tkinter.Label(window,text="I am D bot,how may I help you").pack()
speak("I am D bot,how may I help you")
def takecommand():
r = sr.Recognizer()
with sr.Microphone() as sourse:
lab6 = tkinter.Label(window,text="listning...").pack()
r.pause_threshold = 1
audio = r.listen(sourse)
try:
lab7 = tkinter.Label(window,text="recognizing...").pack()
query = r.recognize_google(audio,language='en-in')
# print(query)
lab8 = tkinter.Label(window,text=query).pack()
except Exception as e:
lab9 = tkinter.Label(window,text="Good morning").pack()
lab10 = tkinter.Label(window,text="say that again please").pack()
speak("say that again please")
takecommand().lower
return "none"
return query
def wiki():
# if 'wikipedia' in query:
lab11 = tkinter.Label(window,text="searching wikipedia").pack()
speak('searching wikipedia...')
results = wikipedia.summary(query, sentences=2)
lab12 = tkinter.Label(window,text="according to wikipedia").pack()
speak("according to wikipedia")
# print(results)
lab13 = tkinter.Label(window,text=results).pack()
speak(results)
lab14 = tkinter.Label(window,text="check the notification for more details").pack()
speak('check the notification for more details')
notification = Notify()
notification.title = "check out this website for more details"
notification.message = 'https://en.wikipedia.org/wiki/Main_Page'
notification.icon='G:\code projects\python\D bot\drone_115355.ico'
notification.application_name="D bot"
notification.send()
if __name__=="__main__":
wishme()
while True:
# if 1:
query = takecommand().lower()
# query = "play music"
if 'open youtube' in query:
webbrowser.get(using=None).open_new_tab("https://youtube.com/")
# C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe
# elif "close" in query:
# break
elif 'open amazon' in query:
webbrowser.get(using=None).open_new_tab("https://www.amazon.com/")
elif 'open gmail' in query:
webbrowser.get(using=None).open_new_tab("https://mail.google.com/mail/u/0/#inbox")
elif 'open google' in query:
google = "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"
elif 'open chrome' in query:
google = "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"
os.startfile(google)
elif 'open stack overflow' in query:
webbrowser.get(using=None).open_new_tab("https://stackoverflow.com/")
elif "what's the time" in query:
strtime = datetime.datetime.now().strftime('%H:%M:%S')
# print('the time is '+strtime)
lab15 = tkinter.Label(window,text="Hello sir,nice to meet you,how may i help you"+strtime).pack()
speak('the time is '+strtime)
window.mainloop()
I am so sorry the mainloop was not shown in the code. I have now edited the code.

all you need to do is add these two functions every time you want the window to update
window.update_idletasks()
window.update()

Programs written for event-driven GUI toolkits like tkinter are significantly different from standard Python scripts.
Once you have created a window, filled it with widgets and have initialized global data, you need to start the mainloop.
Without a running mainloop, there is no interaction with the GUI.
In essence, your program consists of a bunch of functions that are called from the mainloop, in response to the user operating controls, or timers expiring.
(I'm leaving out complications like using threading out on purpose for the sake of simplicity.)
I don't think that pyttsx3 was written with event-driven GUIs in mind. So I suspect you will have to run it in a separate thread or process. Both threads and processes have their pros and cons.
If you are using a process to run pyttsx3, you have to explicitly send the data to the GUI process using interprocess communication. On the other hand, the sound collection process cannot interfere with the GUI.
You could probably relatively easily test it separately from the GUI.
If you use threads you might have issues with responsiveness because in CPython only one thread at a time can be executing Python bytecode.
On the other hand, transferring the data to the GUI is trivial since both live in the same address space.
In my experience calling tkinter functions or methods from a second thread is possible if two conditions are met;
You are using Python 3 and
the tcl and tk used were built with support for threads enabled.

Related

How to let pyttsx3 only listen when a command is given?

I would like pyttsx3 to only listen when a click some sort of button or speak some sort of hotword otherwise it should stay quiet and keep waiting for my command.
My code runs in a loop like shown below:
if __name__ == "__main__": # main program
wish()
while True:
# if 1:
query = takecommand().lower()
# logic building for tasks
if "open notepad" in query:
npath = "C:\\Windows\\system32\\notepad.exe"
os.startfile(npath)
elif 'hi' in query or 'hello' in query:
speak('Hello sir, how may I help you?')
time.sleep(3)
and so on...
How About this:
Wake = "Hey Robot" #here you can use whatever word you want
while True:
text = get_audio().lower()# this takes the audio. Change this for the name of your audio function
if text.count(Wake) > 0:
speak("I am On.")
text = get_audio().lower()#This make it say I am on when it is activated. And then start listening
#Erase the .lower() if your talk function has it implemented
hi_words = ["hello", "hi",]
for phrase in hi_words:
if phrase in text:
speak("Hello sir, how may I help you")
This will make the program activate when you say the wake word. Then it will wait for a command, Afterwards it will go to sleep and wait till you say the wake word again

How to run a loop from a program in background while the code proceeds to do other things

so, i was trying to make a personal assistant and i wanted to make a reminder type of commnd.
here is the code of the reminder(notification).
and the speak and takecommand fuctions are custom.
elif "remind" in query:
speak("what should i remind you")
messageT = takeCommand()
speak("ok, so when should i remind you.")
timeOfReminder = takeCommand()
while True:
current_time = tm.strftime("%H:%M:%S")
if current_time == timeOfReminder:
print(current_time)
break;
toaster = ToastNotifier()
toaster.show_toast(messageT,
duration=10)
so the problem is not with this code, but the code contains a while loop which prohibits me to proceed with my code(this whole code is also a part of a while loop which contains all the command).
i wanna know how to like run this loop in parellel of the other main while loop(this while loop checks the time while the main while loop checks what command the user is giving.)
is there any way to do this (if you want i can post my full code if it helps).
Use the threading library in Python 3.
import threading
Create a function:
def my_long_function():
while 1:
print("runs in background")
time.sleep(1)
long_thread = threading.Thread(target=my_long_function)
long_thread.start()
while 1:
print("Running in foreground")
time.sleep(3)
Hope this works for you!

Pywinauto unable to find/close pop-up window

Source code
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
if is_admin():
app = Application(backend='uia').start("C:\\Program Files (x86)\\Advantech\\AdamApax.NET Utility\\Program\\AdamNET.exe")
win = app['Advantech Adam/Apax .NET Utility (Win32) Version 2.05.11 (B19)']
win.wait('ready')
win.menu_select("Setup->Refresh Serial and Ethernet")
win.top_window().print_control_identifiers(filename="file.txt")
# win.top_window().OKButton.click_input() ---------This is what I hope to do
else
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
Problem Statement
I had to run this application with elevation rights. The above is my code. The problem is I can't identify the window (view in output image) that pops up after selection from menu. I need to close the window. Please excuse the line
win.top_window().print_control_identifiers(filename="file.txt")
It was meant write the identifiers into a text file because the structure of this code does not display the outputs for me to view. However, since nothing is appended, I guess pywinauto couldn't identify the dialog.
For a clearer understanding, please view the image (input) of when it selects the menu.
Input
Now, it pops up with this dialog (output)
Output
I've also used spy to identify the caption and it gives:
(Handle: 004E07D4,
Caption: Information,
Class: #32770(Dialog),
Style: 94C801C5)
Other things I've tried:
Besides using win.topwindow() to identify the dialog, I've used
win[Information].OKButton.click_input()
win[Information].OK.click_input()
win[Information].OK.close()
win[Information].OK.kill(soft=false)
win.Information.OKButton.click_input()
win.Information.OK.click_input()
win.Information.OK.close()
win.Information.OK.kill(soft=false)
app[Information] ...... curious if I could discover the new window from original application
I've also send keys like enter, space, esc & alt-f4 to close the dialog with libraries like keyboard, pynput & ctypes. It still doesn't work.
Link to download the same application: http://downloadt.advantech.com/download/downloadsr.aspx?File_Id=1-1NHAMZX
Any help would be greatly appreciated !
I finally found a thread that demonstrated the way multi thread works to solve this issue. I tried it myself and it works. It's a little different as a few parts of the code have depreciated. Here is the link to the solution:
How to stop a warning dialog from halting execution of a Python program that's controlling it?
Here are the edits I made to solve the problem:
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
if is_admin():
def __init__(self, window_name, quit_event):
threading.Thread.__init__(self)
self.quit_event = quit_event
self.window_name = window_name
def run(self):
while True:
try:
handles = windows.find_windows(title=self.window_name)
except windows.WindowNotFoundError:
pass
else:
for hwnd in handles:
app = Application()
app.connect(handle=hwnd)
popup = app[self.window_name]
popup.close()
if self.quit_event.is_set():
break
time.sleep(1)
quit_event = threading.Event()
mythread = ClearPopupThread('Information', quit_event)
mythread.start()
application = Application(backend="uia").start("C:\\Program Files (x86)\\Advantech\\AdamApax.NET Utility\\Program\\AdamNET.exe")
time.sleep(2)
win = application['Advantech Adam/Apax .NET Utility (Win32) Version 2.05.11 (B19)']
win.menu_select("Setup->Refresh Serial and Ethernet")
quit_event.set()
else:
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
The best thing is this solution works for every other dialog that halts the main script from working & I could use them to do different actions like clicking buttons, inserting values, by adding more multi threads.

GUI and AI Logical Flow

I whipped up a basic voice assistant using what I know on python with some research, as a self learning project.
Link to the code is here
I am basically converting the audio to text and then splitting it to look for keywords and then trigger a response or an action so to speak, which is not very intelligent but it's working for the time being.
How else can I look for keywords, is there a better approach, an efficient way, if you will, than a thousand lines of ifs and elifs?
Another problem I have is, I built a GUI interface for this program so I could interact with it at the click of a button but the problem is, the window isn't responding after clicking the button, turns out it's a known problem and I don't know how to get around it as I don't know the concept of threads and processes and queues. I am hoping that someone could help me with my problem.
I would like to point out that if I have to do any learning for this project, I would be interested to do that since the idea behind this whole project is learning how to code or build an AI, which may sound stupid
PS: I implemented, well, sort of did, always listen feature or keep running feature by keeping the function in a while loop. I would like to find a way for a voice speech trigger as well to wake up the assistant. Any help in that aspect would be much appreciated.
And also, help me set a name to this assistant, preferably female.
The code is here:
import os
import time
import random
import webbrowser
import tkinter as tk
from gtts import gTTS
from mutagen.mp3 import MP3
from PIL import ImageTk, Image
from playsound import playsound
import speech_recognition as sr
from weather import Weather, Unit
def startAssistant():
keepRunning = 1
while keepRunning is 1:
mainFunction()
if mainFunction() is 0: break
def doNothing(): print("I don't do anything apart from printing this line of course!")
def mainFunction():
f = open("assistant.txt", "a")
# Printing what a user is saying for better user experience
def say(text):
print(text)
f.write("\n" + text + "\n")
return text
# This function will take inputs to talk back
def talkBack(text, recordingName):
# Variable Declaration
extension = ".mp3"
# Synthesising the reponse as speech
tts = gTTS(text=say(text), lang="en-us")
# Saving the response files
fileName = recordingName + extension
audioPath = "audioFiles\\"
responseFile = audioPath + fileName
# Checking to see if the file is already created
if not os.path.exists(responseFile):
tts.save(responseFile)
# Playing the audio
playsound(responseFile)
# Initialising things here
recognizer = sr.Recognizer()
microphone = sr.Microphone()
# Asking for input and saving that
with microphone as source:
print ("Speak:")
audio = recognizer.listen(source)
# Converting audio into text
convertedAudio = recognizer.recognize_google(audio)
convertedAudioSplit = convertedAudio.split()
# Printing what was picked up when the user Spoke and also logging it
print("\n" + convertedAudio + "\n")
f.write("\n" + convertedAudio + "\n")
# Start of a conversation
if "hello" in convertedAudioSplit:
talkBack("Hi, how are you doing today?", "hello")
# Wishing people based on the time of the day
elif "morning" in convertedAudioSplit:
talkBack("Good morning! The sun's shining bright, let's head out for a run. We'll get back and make a healthy breakfast for ourselves", "morning")
elif "afternoon" in convertedAudioSplit:
talkBack("Good afternoon! You must be hungry right about now, why don't you break for lunch?", "afternoon")
elif "night" in convertedAudioSplit:
talkBack("Nighty night sleepy pot! Get a good night's sleep while I learn more to be more helpful to you tomorrow.", "night")
# Getting her information
elif "doing" in convertedAudioSplit:
talkBack("I am doing very good, Thank you for asking!", "doing")
# Making the assistant open web browser with a URL
elif "Google" in convertedAudioSplit:
talkBack("Okay, lets get you to Google.", "google")
# Opening the browser with the required URL
webbrowser.open("https://www.google.com/", new = 1)
# Brings the weather report
elif "weather" in convertedAudioSplit:
weatherVariable = Weather(unit=Unit.CELSIUS)
location = weatherVariable.lookup_by_location('bangalore')
condition = location.condition.text
talkBack("It is {0} right now in Bengaluru.".format(condition), "weather")
# Exiting the program on user's consent
elif "exit" in convertedAudioSplit:
talkBack("Sure, if that's what you want! I will miss you, have a good day.", "exit")
return 0
# If there is an UnknownValueError, this will kick in
elif sr.UnknownValueError:
talkBack("I am sorry, I couldn't quite get what you said. Could you please say that again?", "UnknownValueError")
# When things go out of the box
else:
# Out of scope reply
talkBack("I am a demo version. When you meet the completed me, you will be surprised.", "somethingElse")
return 0
root = tk.Tk()
root.title("Voice Assistant")
mainFrame = tk.Frame(root, width = 1024, height = 720, bg = "turquoise", borderwidth = 5)
menu = tk.Menu(root)
root.config(menu=menu)
subMenu = tk.Menu(menu)
startButton = tk.Button(mainFrame, text="Interact", command = startAssistant)
startButton.place(relx = 0.5, rely = 1.0, anchor = tk.S)
menu.add_cascade(label="File", menu=subMenu)
subMenu.add_command(label="Do Nothing", command=doNothing)
subMenu.add_separator()
subMenu.add_command(label="Exit", command=root.quit)
mainFrame.pack()
root.mainloop()
One potential solution is to use a simpler GUI package. Perhaps the GUI package PySimpleGUI would be a fit. It could solve your GUI problem and free you up to work on the other portions of your project.
Check out the Chat Demo that implements a Chat front-end. Therre's also a Chatterbot Demo that implements a front-end to the Chatterbot project.
You can start by copying that code and modifying it.

Python global var in If statement doesn't work

First, I am an absolute beginner and sorry if I ask stupid questions.
I try to code a little program for school.
Imagine a motor with three emergency switches. A "Overheating", a "Circuit breaker" and a "manual"-switch witch all stop the motor.
In the program, the switches are simulated by tkinter-buttons in a little GUI.
If you press the button, it should output whatever case is simulated.
If the motor "stopped" but a button (or a new button) is pressed again, a message "Machine already stopped" should appear.
But that last part of the program does not work.
I've learned that vars in Python are local by default and so I tried to define the var "triggered" as global. But I've probably made some mistakes.
If I run the program, the first message (for example "Overheating!") appears but the second message "Machine already stopped" is missing when the button is pressed again.
Can you tell me where my fault is? I tried to google it but I don't know what is wrong. Sometimes it is difficult to read threads or tutorials because I am not native english-speaking.
And please tell me if there's any pseudocode in there.
As I said I am an absolute beginner but I try hard to learn it.
from tkinter import *
import sys, os
root = Tk()
root.title("Control Panel")
root.geometry("400x200")
app = Frame(root)
app.grid()
# Vars can be used later
overheat = False
# Stops motor if temperature is too high
circuitbreaker = False
# Stops if current flow is too high
manual = False
# Stops when switch is triggered manually
global triggered
triggered = False
# Returns True if one emergency unit has triggered
def Button_Overheat():
global triggered
if triggered == False:
triggered = True
print("Overheating!")
blockPrint()
else:
enablePrint()
print("Machine already stopped")
blockPrint
return
button_overheat = Button(app, text = "Overheat", command = Button_Overheat)
button_overheat.grid()
def Button_CircuitBreaker():
global triggered
if triggered == False:
print("Overload! Breaking Circuit...")
blockPrint()
else:
print("Machine already stopped")
blockPrint()
return
button_cicuitbreaker = Button(app, text = "Circuitbreaker", command = Button_CircuitBreaker)
button_cicuitbreaker.grid()
def Button_Manual():
global triggered
if triggered == False:
print("Machine was manually stopped")
blockPrint()
triggered = True
else:
print("Machine already stopped")
blockPrint()
return
button_manual = Button(app, text = "Turn off manually", command = Button_Manual)
button_manual.grid()
def blockPrint():
sys.stdout = open(os.devnull, 'w')
def enablePrint():
sys.stdout = sys.__stdout__
mainloop()
Please notice that other than in Overheating you never re enabled printing to allow it to print "Machine already stopped".
Just add enablePrint() to the other two options else clauses as well:
def Button_CircuitBreaker():
global triggered
if triggered == False:
print("Overload! Breaking Circuit...")
blockPrint()
else:
enablePrint()
print("Machine already stopped")
blockPrint()
return
def Button_Manual():
global triggered
if triggered == False:
print("Machine was manually stopped")
blockPrint()
triggered = True
else:
enablePrint()
print("Machine already stopped")
blockPrint()
return

Categories

Resources