1

I am trying to make a simple gui for an AI assistant using PyQt5. In the gui I created a QPlainTextEdit to show the output of my Main program and created an QInputDialog to take user input. The output is working fine.

For the input I tried two things:

  1. First I tried to call the QInputDialog from the Main function (which is in another file), wherever input was needed I replace input() with userInput() (this function contains the QInputDialog). But importing the userInput function causes the MainWindow of GUI to run again, resulting in error.
  2. I created a button called "Input" to connect to the QInputDialog. This works fine, I click the "Input" button whenever written user input is required and the QInputDialog pops up. But I am unable to provide the returned value as input to the Main program.

Please let me know how can I return the QInputDialog value as input()

Here is the code

techna.py

from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtGui import QMovie, QTextBlock
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from gui.technaui2 import Ui_technaui2
import sys
import techna2


class MainThread(QThread):
    def __init__(self):
        super(MainThread, self).__init__()

    def run(self):
        self.TaskGui()

    def TaskGui(self):
        while True:
            techna2.Main()


startFunction = MainThread()


class GuiStart(QMainWindow):
    def __init__(self):
        super().__init__()

        self.technaui2 = Ui_technaui2()
        self.technaui2.setupUi(self)
        self.technaui2.pushButton.clicked.connect(self.startFunc)
        self.technaui2.pushButton_2.clicked.connect(self.close)
        self.technaui2.btn1.clicked.connect(self.userInput2)
        sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)

    def __del__(self):
        # Restore sys.stdout
        sys.stdout = sys.__stdout__

    def normalOutputWritten(self, text):
        """Append text to the QTextEdit."""
        cursor = self.technaui2.textEdit.textCursor()
        cursor.movePosition(QtGui.QTextCursor.End)
        cursor.insertText(text)
        self.technaui2.textEdit.setTextCursor(cursor)
        self.technaui2.textEdit.ensureCursorVisible()

    def startFunc(self):
        self.technaui2.movies = QtGui.QMovie(
            "C:\\Users\\Hp\\Desktop\\SP\\techna2\\gui\\images\\gif\\ai2.gif"
        )
        self.technaui2.gif.setMovie(self.technaui2.movies)
        self.technaui2.movies.start()

        startFunction.start()

    def userInput2(self):
        text, ok = QtWidgets.QInputDialog.getText(self, "Introduce value", "Value:")
        if ok:
            return str(text)
        else:
            print("Invalid")
            # return ""


class EmittingStream(QtCore.QObject):
    textWritten = QtCore.pyqtSignal(str)

    def write(self, text):
        self.textWritten.emit(str(text))


guiApp = QApplication(sys.argv)

guiTechna = GuiStart()

guiTechna.show()

exit(guiApp.exec_())

technaui2.py

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
import sys


class Ui_technaui2(object):
    def setupUi(self, technaui2):
        technaui2.setObjectName("technaui2")
        technaui2.resize(1000, 800)
        self.centralwidget = QtWidgets.QWidget(technaui2)
        self.centralwidget.setObjectName("centralwidget")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(-6, -1, 651, 411))
        self.label.setText("")
        self.label.setPixmap(
            QtGui.QPixmap(
                "C:\\Users\\Hp\\Desktop\\SP\\techna2\\gui\\images\\use\\bg.webp"
            )
        )
        self.label.setScaledContents(True)
        self.label.setObjectName("label")
        self.gif = QtWidgets.QLabel(self.centralwidget)
        self.gif.setGeometry(QtCore.QRect(147, 0, 321, 261))
        self.gif.setStyleSheet("border : 1px solid purple;")
        self.gif.setText("")
        self.gif.setPixmap(
            QtGui.QPixmap(
                "C:\\Users\\Hp\\Desktop\\SP\\techna2\\gui\\images\\gif\\ai2.gif"
            )
        )
        self.gif.setScaledContents(True)
        self.gif.setObjectName("gif")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(675, 330, 111, 51))
        self.pushButton.setStyleSheet(
            'font: 16pt "Modern No. 20";\n'
            "background-color: rgb(0, 0, 0);\n"
            "color: rgb(255, 255, 255);\n"
            "color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 61, 162, 255), stop:1 rgba(255, 255, 255, 255));\n"
            "border : 1px solid;\n"
            "border-color: rgb(170, 85, 255);"
        )
        self.pushButton.setObjectName("pushButton")
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(675, 400, 111, 51))
        self.pushButton_2.setStyleSheet(
            'font: 16pt "Modern No. 20";\n'
            "\n"
            "background-color: rgb(0, 0, 0);\n"
            "color: rgb(255, 255, 255);\n"
            "color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 61, 162, 255), stop:1 rgba(255, 255, 255, 255));\n"
            "border : 1px solid;\n"
            "border-color: rgb(170, 0, 255);"
        )
        self.pushButton_2.setObjectName("pushButton_2")

        self.textEdit = QtWidgets.QPlainTextEdit(self.centralwidget)
        self.textEdit.setGeometry(QtCore.QRect(0, 500, 651, 211))
        self.textEdit.setObjectName("textEdit")
        technaui2.setCentralWidget(self.centralwidget)
        self.textEdit.setStyleSheet(
            'font: 12pt "Modern No. 10";\n'
            "background-color: rgb(0, 0, 0);\n"
            "color: rgb(255, 255, 255);\n"
            "padding-left: 30px;\n"
        )

        self.btn1 = QtWidgets.QPushButton(self.centralwidget)
        self.btn1.setGeometry(QtCore.QRect(675, 900, 111, 51))
        self.btn1.setStyleSheet(
            'font: 16pt "Modern No. 20";\n'
            "background-color: rgb(0, 0, 0);\n"
            "color: rgb(255, 255, 255);\n"
            "color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 61, 162, 255), stop:1 rgba(255, 255, 255, 255));\n"
            "border : 1px solid;\n"
            "border-color: rgb(170, 85, 255);"
        )
        self.btn1.setObjectName("Input")
        self.btn1.resize(140, 70)

        self.label.resize(1006, 800)
        self.gif.resize(700, 500)
        self.pushButton.resize(140, 70)
        self.pushButton_2.resize(140, 70)
        self.textEdit.resize(1000, 300)

        self.retranslateUi(technaui2)
        QtCore.QMetaObject.connectSlotsByName(technaui2)

    def retranslateUi(self, technaui2):
        _translate = QtCore.QCoreApplication.translate
        technaui2.setWindowTitle(_translate("technaui2", "TECHnA"))
        technaui2.setWindowIcon(
            QtGui.QIcon(
                "C:\\Users\\Hp\\Desktop\\SP\\techna2\\gui\\images\\Difference-between-AI-and-Neural-Network-768x614.jpg"
            )
        )
        self.pushButton.setText(_translate("technaui2", "START"))
        self.pushButton_2.setText(_translate("technaui2", "STOP"))
        self.btn1.setText(_translate("technaui2", "INPUT"))


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    technaui2 = QtWidgets.QMainWindow()
    ui = Ui_technaui2()
    ui.setupUi(technaui2)
    technaui2.show()
    sys.exit(app.exec_())

The program I am running in QPlainTextEdit and need input for:

techna2.py

    import random
    import json
    import torch
    from brain import NeuralNet  # myfile
    from neuralnetwork import bag_of_words, tokenize  # myfile
    import datetime
    import os
    
    
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    with open("C:\\Users\\Hp\\Desktop\\SP\\techna2\\intents.json", "r") as json_data:
        intents = json.load(json_data)
    
    FILE = "C:\\Users\\Hp\\Desktop\\SP\\techna2\\TrainData.pth"
    data = torch.load(FILE)
    
    input_size = data["input_size"]
    hidden_size = data["hidden_size"]
    output_size = data["output_size"]
    all_words = data["all_words"]
    tags = data["tags"]
    model_state = data["model_state"]
    
    model = NeuralNet(input_size, hidden_size, output_size).to(device)
    model.load_state_dict(model_state)
    model.eval()
    
    
    Name = "Techna"
    from wish import wishMe
    
    from listen import *  # my files
    from speak import Say
    from task import (
        NonInputExecution,
        InputExecution,
        Game,
        Calculations,
        Bye,
        Email,
        Open,
        Close,
        Video,
        Youtube,
        Sound,
        Whatsapp,
        screenShot,
        Joke,
        shutDown,
        Weather,
        Location,
        How,
        News,
        Covid,
        Reader,
        Notepad,
        Alarm,
    )
    
    
    def Main():
        sentence = Listen()
        result = str(sentence)
    
    
        sentence = tokenize(sentence)
        X = bag_of_words(sentence, all_words)
        X = X.reshape(1, X.shape[0])
        X = torch.from_numpy(X).to(device)
    
        output = model(X)
    
        _, predicted = torch.max(output, dim=1)
    
        tag = tags[predicted.item()]
    
        probs = torch.softmax(output, dim=1)
        prob = probs[0][predicted.item()]
    
        if prob.item() > 0.75:
            for intent in intents["intents"]:
                if tag == intent["tag"]:
                    reply = random.choice(intent["responses"])
    
                    if "time" in reply:
                        NonInputExecution(reply)
    
                    elif "alarm" in reply:
                        Say("For what time?")
                        time = input()  #Example, Whenever input is needed I want to provide it through the QInputDialog (or another way of providing the input is also welcomed)
                        Alarm(time)
    
                    else:
                        Say(reply)
  • 1
    Your question is a bit confusing, are you trying to send the string that the user inputs in the dialog to the other thread? If that's the case, we need to know more about that, because your code is insufficient, as there are a lot of missing parts we know nothing about (for example `techna2`), so please provide a valid [mre]. – musicamante May 09 '23 at 00:12
  • In order to do what you want you'll need to implement a custom signal in the QThread to notify the GUI that an input is required, and add a Queue to allow communication from the UI to the thread, so that it will be waiting until a response is given. Unfortunately, this also means that you should completely change the structure of the QThread, as it would need to integrate everything you have in `Main()` in order to allow proper inter thread communication. – musicamante May 09 '23 at 14:15

1 Answers1

1

From what i understand, you want to take the input from user, then pass that input into function 'normalOutputWritten'. Here is my solution:

class GuiStart(QMainWindow):
    textWritten = QtCore.pyqtSignal(str) # Text written should be put here.

    def __init__(self):
        super().__init__()

        self.technaui2 = Ui_technaui2()
        self.technaui2.setupUi(self)
        self.technaui2.pushButton.clicked.connect(self.startFunc)
        self.technaui2.pushButton_2.clicked.connect(self.close)
        self.technaui2.btn1.clicked.connect(self.userInput2)
        self.textWritten.connect(self.normalOutputWritten)  # Add this to use the input value
        sys.stdout = EmittingStream(
            textWritten=self.normalOutputWritten)  # You might not need this line and also this class EmittingStream

    ...

    def userInput2(self):
        text, ok = QtWidgets.QInputDialog.getText(self, "Introduce value", "Value:")
        if ok:
            self.textWritten.emit(str(text)) #Send the input.
        else:
            print("Invalid")
            self.textWritten.emit("") #Send the input.
Ananta
  • 553
  • 4
  • 9
  • 1
    I tried your solution but the output is now showing up in the terminal instead of the QPlainTextEdit, if I keep the EmittingStream class then the output is fine but the input of QInputDialog only gets displayed in the QPlainTextEdit. In the file "techna.py" you can see I am importing a function "techna2.Main()", this is the program running in the QPlainTextEdit. I want to provide the value of QInputDialog to this function whenever it asks for input using python's input() function – Lily Johnson May 08 '23 at 19:49