please combine the following two scripts. The idea is to have a GUI that makes the llm follow the prof synapse chain of reason logic visualizing the process. Have the script use the mistral model as the llm: 
import sys
import threading
import time
from PyQt6.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QHBoxLayout, QTextEdit,
    QPushButton, QLabel, QProgressBar, QListWidget, QListWidgetItem
)
from PyQt6.QtCore import Qt, pyqtSignal, QObject
from gradio_client import Client

# Initialize the Gradio client with the appropriate model
client = Client("yuntian-deng/ChatGPT4Turbo")

class WorkerSignals(QObject):
    """Defines the signals available from a running worker thread."""
    reasoning_step = pyqtSignal(str)
    finished = pyqtSignal(str)
    error = pyqtSignal(str)

class ReasoningWorker(threading.Thread):
    """Worker thread to handle the reasoning process."""
    def __init__(self, user_input, chat_history, signals):
        super().__init__()
        self.user_input = user_input
        self.chat_history = chat_history
        self.signals = signals

    def run(self):
        try:
            # Emit initial reasoning step
            self.signals.reasoning_step.emit("Processing user input...")

            # Step: Use Gradio client to get the model's prediction
            result, updated_history = self.chat_function(self.user_input, self.chat_history)

            # Emit reasoning steps
            for role, message in updated_history:
                self.signals.reasoning_step.emit(f"{role}: {message}")

            # Get the final bot response from updated history
            if updated_history:
                final_answer = updated_history[-1][1]
            else:
                final_answer = "No response generated."

            self.signals.finished.emit(final_answer)

        except Exception as e:
            self.signals.error.emit(str(e))

    def chat_function(self, user_input, chat_history):
        # Use the client to get the model's prediction
        result = client.predict(
            inputs=user_input,
            top_p=1,
            temperature=1,
            chat_counter=len(chat_history),
            chatbot=chat_history,
            api_name="/predict",
            max_tokens=8192,
        )
        # Append user input and model response to the chat history
        chat_history.append(("User", user_input))
        chat_history.append(("Bot", result))
        return chat_history, chat_history

class ChatbotGUI(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Chatbot with ChatGPT4Turbo")
        self.setGeometry(100, 100, 800, 600)
        self.setup_ui()
        self.chat_history = []  # Initialize chat history

    def setup_ui(self):
        layout = QVBoxLayout()

        # Chat Display Area
        self.chat_display = QListWidget()
        layout.addWidget(QLabel("Conversation:"))
        layout.addWidget(self.chat_display)

        # Reasoning Steps Area
        self.reasoning_display = QListWidget()
        layout.addWidget(QLabel("Reasoning Steps:"))
        layout.addWidget(self.reasoning_display)

        # Progress Bar
        self.progress_bar = QProgressBar()
        self.progress_bar.setValue(0)
        layout.addWidget(self.progress_bar)

        # Input Area
        input_layout = QHBoxLayout()
        self.user_input = QTextEdit()
        self.user_input.setFixedHeight(50)
        input_layout.addWidget(self.user_input)

        self.send_button = QPushButton("Send")
        self.send_button.clicked.connect(self.send_message)
        input_layout.addWidget(self.send_button)

        layout.addLayout(input_layout)

        self.setLayout(layout)

    def send_message(self):
        user_text = self.user_input.toPlainText().strip()
        if not user_text:
            return

        # Clear previous reasoning steps and reset progress bar
        self.reasoning_display.clear()
        self.progress_bar.setValue(0)

        # Append user message to chat display
        user_item = QListWidgetItem(f"User: {user_text}")
        self.chat_display.addItem(user_item)

        # Disable send button to prevent multiple inputs
        self.send_button.setEnabled(False)

        # Setup worker signals
        self.signals = WorkerSignals()
        self.signals.reasoning_step.connect(self.update_reasoning_steps)
        self.signals.finished.connect(self.process_finished)
        self.signals.error.connect(self.process_error)

        # Start worker thread
        self.worker = ReasoningWorker(user_text, self.chat_history, self.signals)
        self.worker.start()

    def update_reasoning_steps(self, step):
        step_item = QListWidgetItem(step)
        self.reasoning_display.addItem(step_item)
        # Update progress bar (assuming max 10 steps for simplicity)
        current = self.progress_bar.value() + 10
        if current > 100:
            current = 100
        self.progress_bar.setValue(current)

    def process_finished(self, answer):
        # Append bot's final answer to chat display
        bot_item = QListWidgetItem(f"Bot: {answer}")
        self.chat_display.addItem(bot_item)
        self.progress_bar.setValue(100)
        self.send_button.setEnabled(True)

    def process_error(self, error_message):
        error_item = QListWidgetItem(f"Bot: Error occurred - {error_message}")
        self.chat_display.addItem(error_item)
        self.progress_bar.setValue(0)
        self.send_button.setEnabled(True)

def main():
    app = QApplication(sys.argv)
    gui = ChatbotGUI()
    gui.show()
    sys.exit(app.exec())

if __name__ == "__main__":
    main()


import customtkinter as ctk
import huggingface_hub
import subprocess
import re
import threading
import io
import sys
import time

# Global flag to stop threads
stop_flag = threading.Event()

client = huggingface_hub.InferenceClient(
    "mistralai/Mistral-7B-Instruct-v0.3",
    token="<TRUFFLEHOG_REDACTED_HUGGINGFACE>"
)

def interact_with_llm(prompt):
    output_text = ""
    try:
        for message in client.chat_completion(
            messages=[{"role": "user", "content": prompt}],
            max_tokens=2048,
            stream=True,
        ):
            if stop_flag.is_set():
                return ""  # Exit early if stop flag is set

            content = message['choices'][0]['delta']['content']
            output_text += content
    except Exception as e:
        print(f"Error interacting with LLM: {e}")
    return output_text

def extract_code_snippets(text):
    snippets = []
    code_blocks = re.findall(r"```(.*?)```", text, re.DOTALL)
    for block in code_blocks:
        lines = block.strip().split('\n')
        if lines:
            # Remove the first word in the first line
            lines[0] = ' '.join(lines[0].split()[1:])
        snippets.append('\n'.join(lines))
    return "\n\n".join(snippets)

def save_and_run_code(code, output_textbox):
    filename = "temp_code.py"
    try:
        # Save code to file with UTF-8 encoding
        with open(filename, "w", encoding="utf-8") as file:
            file.write(code)
    except Exception as e:
        output_textbox.configure(state=ctk.NORMAL)
        output_textbox.insert(ctk.END, f"\nError saving file: {e}")
        output_textbox.configure(state=ctk.DISABLED)
        return ""

    try:
        # Capture output and errors using subprocess.PIPE
        process = subprocess.Popen(
            ["python", filename],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        stdout, stderr = process.communicate()
        
        # Combine stdout and stderr
        output = stdout + stderr
        
        # Display the output in the GUI
        output_textbox.configure(state=ctk.NORMAL)
        output_textbox.delete("1.0", ctk.END)
        output_textbox.insert(ctk.END, output)
        output_textbox.configure(state=ctk.DISABLED)
        
        return output
    except Exception as e:
        output_textbox.configure(state=ctk.NORMAL)
        output_textbox.insert(ctk.END, f"\nError running file: {e}")
        output_textbox.configure(state=ctk.DISABLED)
        return ""

def flash_window(window, color, times=1):
    for _ in range(times):
        window.configure(fg_color=color)
        window.update()
        time.sleep(0.5)
        window.configure(fg_color="white")
        window.update()
        time.sleep(0.5)

def handle_traceback_and_loop(code, output):
    retry_count = 0
    max_retries = 20
    
    while retry_count < max_retries:
        if stop_flag.is_set():
            return  # Exit early if stop flag is set

        if 'No module named' in output:
            # Extract the list of dependencies to install
            prompt = (f"Here is the error message indicating missing modules:\n{output}\n\n"
                      "Please provide a list of commands to install these dependencies, enclosed in triple backticks.")
            llm_response = interact_with_llm(prompt)
            
            # Extract installation commands from the LLM response
            install_commands = re.search(r"```(.*?)```", llm_response, re.DOTALL)
            if install_commands:
                install_commands = install_commands.group(1).strip()
                
                # Update the GUI with installation commands
                install_commands_textbox.configure(state=ctk.NORMAL)
                install_commands_textbox.delete("1.0", ctk.END)
                install_commands_textbox.insert(ctk.END, install_commands)
                install_commands_textbox.configure(state=ctk.DISABLED)
                
                # Flash blue to indicate that installation commands are ready
                flash_window(install_commands_textbox, "lightblue", times=3)
                
                # Stop the loop
                break
            else:
                output_textbox.configure(state=ctk.NORMAL)
                output_textbox.insert(ctk.END, "\nUnable to extract installation commands.")
                output_textbox.configure(state=ctk.DISABLED)
                break
        
        # Flash the output window red to indicate an error loop
        flash_window(output_textbox, "red", times=3)
        
        # Check for SyntaxError
        if 'SyntaxError' in output:
            prompt = f"Here is the code with a SyntaxError:\n{code}\n\nConsole output:\n{output}\n\nPlease fix the syntax error and provide a complete script."
        else:
            # Send the code and output back to LLM
            prompt = f"Here is the full code with an error:\n{code}\n\nConsole output:\n{output}\n\nPlease provide a complete script to fix the error. Ensure the response is a full script and not a partial or placeholder."
        
        llm_response = interact_with_llm(prompt)
        
        # Check if the response contains errors and needs to be appended
        if 'Traceback' in llm_response:
            prompt = f"Here is the current code:\n{code}\n\nThe error response was:\n{llm_response}\n\nPlease combine and fix the code and provide the complete script."
            llm_response = interact_with_llm(prompt)
        
        # Check for incomplete code indicators
        if '# ... rest of the code' in llm_response:
            initial_prompt = user_input.get("1.0", "end-1c")
            prompt = (f"Here is the initial user prompt:\n{initial_prompt}\n\n"
                      f"Latest snippet from code:\n{code}\n\n"
                      f"The error response was:\n{llm_response}\n\n"
                      f"Please combine and fix the code to provide a fully complete script.")
            llm_response = interact_with_llm(prompt)
        
        # Update the LLM response display
        response_display.configure(state=ctk.NORMAL)
        response_display.delete("1.0", ctk.END)
        response_display.insert(ctk.END, llm_response)
        response_display.configure(state=ctk.DISABLED)
        
        # Extract new code
        new_code = extract_code_snippets(llm_response)
        
        # Update the extracted code display
        code_display.configure(state=ctk.NORMAL)
        code_display.delete("1.0", ctk.END)
        code_display.insert(ctk.END, new_code)
        code_display.configure(state=ctk.DISABLED)
        
        # Save and run the new code
        output = save_and_run_code(new_code, output_textbox)
        
        retry_count += 1
        
        if retry_count >= max_retries:
            output_textbox.configure(state=ctk.NORMAL)
            output_textbox.insert(ctk.END, "\nMaximum retry attempts reached. Process failed.")
            output_textbox.configure(state=ctk.DISABLED)
            break
        
    # Flash green if resolved
    if retry_count < max_retries:
        flash_window(output_textbox, "lightgreen", times=1)
        output_textbox.configure(state=ctk.NORMAL)
        output_textbox.insert(ctk.END, "\nNo errors detected. Process succeeded.")
        output_textbox.configure(state=ctk.DISABLED)

def on_save_and_run():
    code = code_display.get("1.0", "end-1c")
    if code.strip():
        # Initial run
        output = save_and_run_code(code, output_textbox)
        
        # Start a thread to handle traceback and looping
        threading.Thread(target=handle_traceback_and_loop, args=(code, output)).start()

def on_submit():
    prompt = user_input.get("1.0", "end-1c")
    response = interact_with_llm(prompt)
    
    # Ensure LLM response is a complete script
    if re.search(r"(Rest of your code goes here|continue the code|complete the script|TODO)", response, re.IGNORECASE):
        response = "The LLM responded with incomplete code. Please provide a complete script."
    
    # Update the LLM response display
    response_display.configure(state=ctk.NORMAL)
    response_display.delete("1.0", ctk.END)
    response_display.insert(ctk.END, response)
    response_display.configure(state=ctk.DISABLED)

    # Extract code snippets
    code_snippets = extract_code_snippets(response)
    
    # Update the extracted code display
    code_display.configure(state=ctk.NORMAL)
    code_display.delete("1.0", ctk.END)
    code_display.insert(ctk.END, code_snippets)
    code_display.configure(state=ctk.DISABLED)

def on_stop_and_clear():
    # Set the stop flag to halt any ongoing process
    stop_flag.set()
    
    # Optionally, clear all text boxes
    user_input.delete("1.0", ctk.END)
    response_display.configure(state=ctk.NORMAL)
    response_display.delete("1.0", ctk.END)
    response_display.configure(state=ctk.DISABLED)
    code_display.configure(state=ctk.NORMAL)
    code_display.delete("1.0", ctk.END)
    code_display.configure(state=ctk.DISABLED)
    output_textbox.configure(state=ctk.NORMAL)
    output_textbox.delete("1.0", ctk.END)
    output_textbox.configure(state=ctk.DISABLED)
    install_commands_textbox.configure(state=ctk.NORMAL)
    install_commands_textbox.delete("1.0", ctk.END)
    install_commands_textbox.configure(state=ctk.DISABLED)

# GUI setup
app = ctk.CTk()
app.title("LLM Interaction Tool")

user_input = ctk.CTkTextbox(app, width=500, height=100)
user_input.pack(pady=10)

submit_button = ctk.CTkButton(app, text="Submit", command=on_submit)
submit_button.pack(pady=5)

stop_button = ctk.CTkButton(app, text="Stop and Clear", command=on_stop_and_clear)
stop_button.pack(pady=5)

save_and_run_button = ctk.CTkButton(app, text="Save and Run", command=on_save_and_run)
save_and_run_button.pack(pady=5)

response_display = ctk.CTkTextbox(app, width=500, height=200)
response_display.pack(pady=10)
response_display.configure(state=ctk.DISABLED)

code_display = ctk.CTkTextbox(app, width=500, height=200)
code_display.pack(pady=10)
code_display.configure(state=ctk.DISABLED)

output_textbox = ctk.CTkTextbox(app, width=500, height=100)
output_textbox.pack(pady=10)
output_textbox.configure(state=ctk.DISABLED)

install_commands_textbox = ctk.CTkTextbox(app, width=500, height=100)
install_commands_textbox.pack(pady=10)
install_commands_textbox.configure(state=ctk.DISABLED)

app.mainloop()