Please improve this script's logic in order to have it autonomously execute and debug code (looping up to 5 retries) and saving the final result. Ensure it doesnt get stuck repeating the same errors implementing the same fix.import sys
import os
import subprocess
import re
import uuid
import shutil
import json
from PyQt6.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QHBoxLayout, QTextEdit,
    QPushButton, QLabel, QLineEdit, QFileDialog, QMessageBox, QProgressBar
)
from PyQt6.QtCore import Qt, QThread, pyqtSignal
from gradio_client import Client
from PyQt6.QtGui import QMovie, QPixmap

# Worker thread for generating scripts
class GenerateScriptThread(QThread):
    finished = pyqtSignal(str)
    error = pyqtSignal(str)

    def __init__(self, prompt, api_client):
        super().__init__()
        self.prompt = prompt
        self.api_client = api_client

    def run(self):
        try:
            response = self.api_client.predict(
                inputs=self.prompt,
                top_p=1,
                temperature=0.5,
                api_name="/predict"  # Correct endpoint
            )
            
            if isinstance(response, (list, tuple)):
                response_text = "\n".join(str(item) for item in response)
            else:
                response_text = str(response)
            
            # Extract Python code from the response
            extracted_code = self.extract_code(response_text)
            if not extracted_code:
                self.error.emit("Could not extract Python code from the API response.")
                return

            # Unescape any escaped characters (e.g., \n) to ensure proper formatting
            unescaped_code = self.unescape_code(extracted_code)
            self.finished.emit(unescaped_code)
        except Exception as e:
            self.error.emit(str(e))
    
    def extract_code(self, text):
        """
        Extracts Python code enclosed within ```python and ``` from the given text.
        Returns the extracted code or None if not found.
        """
        pattern = r"```python(.*?)```"
        matches = re.findall(pattern, text, re.DOTALL)
        if matches:
            # Clean up the code by stripping leading/trailing whitespace
            return matches[0].strip()
        else:
            # Attempt to extract code without markdown if present
            return text.strip() if text.startswith("import") else None

    def unescape_code(self, code):
        """
        Unescapes any escaped characters within the code string.
        Converts sequences like '\\n' to actual newlines.
        """
        return bytes(code, "utf-8").decode("unicode_escape")

# Worker thread for executing scripts
class ExecuteScriptThread(QThread):
    finished = pyqtSignal(str)
    error = pyqtSignal(str)

    def __init__(self, script):
        super().__init__()
        self.script = script

    def run(self):
        try:
            # Generate a unique identifier for the temp script
            unique_id = uuid.uuid4().hex
            temp_dir = os.path.join(os.getcwd(), "temp_scripts")
            os.makedirs(temp_dir, exist_ok=True)
            script_filename = f"temp_script_{unique_id}.py"
            script_path = os.path.join(temp_dir, script_filename)

            # Save the script to a temporary file
            with open(script_path, 'w') as file:
                file.write(self.script)

            # Execute the script
            result = subprocess.run(
                [sys.executable, script_path],
                capture_output=True,
                text=True,
                check=True
            )
            self.finished.emit(result.stdout)
        except subprocess.CalledProcessError as e:
            error_message = e.stderr
            self.error.emit(error_message)
        except Exception as e:
            self.error.emit(str(e))

# Worker thread for fetching suggestions
class FetchSuggestionThread(QThread):
    finished = pyqtSignal(str)
    error = pyqtSignal(str)

    def __init__(self, error_message, script, api_client):
        super().__init__()
        self.error_message = error_message
        self.script = script
        self.api_client = api_client

    def run(self):
        try:
            prompt = f"""An error occurred while executing the following Python script:

Error: {self.error_message}

Script:
{self.script}

Please suggest a fix for the error."""
    
            response = self.api_client.predict(
                inputs=prompt,
                top_p=1,
                temperature=0.5,
                api_name="/predict_1"  # Correct endpoint for suggestions
            )
            
            if isinstance(response, (list, tuple)):
                suggestion_text = "\n".join(str(item) for item in response)
            else:
                suggestion_text = str(response)
            
            # Extract suggestion from response
            extracted_suggestion = self.extract_code(suggestion_text)
            if not extracted_suggestion:
                # Assume entire response is a suggestion
                extracted_suggestion = suggestion_text.strip()
            
            # Unescape any escaped characters
            unescaped_suggestion = self.unescape_code(extracted_suggestion)
            self.finished.emit(unescaped_suggestion)
        except Exception as e:
            self.error.emit(str(e))
    
    def extract_code(self, text):
        """
        Extracts suggestion text, possibly within markdown code blocks.
        """
        pattern = r"```python(.*?)```"
        matches = re.findall(pattern, text, re.DOTALL)
        if matches:
            return matches[0].strip()
        else:
            return text.strip()

    def unescape_code(self, text):
        """
        Unescapes any escaped characters within the text.
        """
        return bytes(text, "utf-8").decode("unicode_escape")

class ScriptRequesterGUI(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()
        self.retry_limit = 5
        self.current_retries = 0
        self.errors_fixed = set()  # Track fixed errors to prevent repeats
        self.api_client = Client("yuntian-deng/ChatGPT")  # Initialize the API client

    def init_ui(self):
        self.setWindowTitle('Script Generator and Executor')
        self.setGeometry(100, 100, 1000, 800)

        layout = QVBoxLayout()

        # Section: Describe the Script
        layout.addWidget(QLabel("Describe the Script You Need:"))
        self.script_request_input = QTextEdit()
        self.script_request_input.setPlaceholderText("e.g., Create a Python script that fetches weather data for a given city.")
        layout.addWidget(self.script_request_input)

        # Buttons: Generate and Execute
        button_layout = QHBoxLayout()
        self.generate_button = QPushButton('Generate Script')
        self.generate_button.clicked.connect(self.start_generate_script)
        self.execute_button = QPushButton('Execute Script')
        self.execute_button.clicked.connect(self.start_execute_script)
        self.execute_button.setEnabled(False)  # Disabled until a script is generated
        button_layout.addWidget(self.generate_button)
        button_layout.addWidget(self.execute_button)
        layout.addLayout(button_layout)

        # Progress Bar and Animation
        progress_layout = QHBoxLayout()
        self.progress_bar = QProgressBar()
        self.progress_bar.setMinimum(0)
        self.progress_bar.setMaximum(0)  # Indeterminate state
        self.progress_bar.setVisible(False)
        progress_layout.addWidget(self.progress_bar)

        # Loading Animation
        self.loading_label = QLabel()
        self.loading_movie = QMovie("loading.gif")  # Ensure you have a 'loading.gif' in the same directory
        self.loading_label.setMovie(self.loading_movie)
        self.loading_label.setVisible(False)
        progress_layout.addWidget(self.loading_label)

        layout.addLayout(progress_layout)

        # Section: Generated Code
        layout.addWidget(QLabel("Generated Script:"))
        self.generated_code_display = QTextEdit()
        self.generated_code_display.setReadOnly(True)
        layout.addWidget(self.generated_code_display)

        # Section: Execution Output
        layout.addWidget(QLabel("Execution Output:"))
        self.output_display = QTextEdit()
        self.output_display.setReadOnly(True)
        layout.addWidget(self.output_display)

        # Section: Project Management
        project_layout = QHBoxLayout()
        self.project_name_input = QLineEdit()
        self.project_name_input.setPlaceholderText("Enter Project Name")
        self.save_button = QPushButton('Save Project')
        self.save_button.clicked.connect(self.save_project)
        self.save_button.setEnabled(False)  # Disabled until a script is generated
        project_layout.addWidget(self.project_name_input)
        project_layout.addWidget(self.save_button)
        layout.addLayout(project_layout)

        self.setLayout(layout)

        # Initialize loading animation
        self.loading_movie.setSpeed(100)
        self.loading_label.setScaledContents(True)
        self.loading_label.setFixedSize(50, 50)  # Adjust size as needed

    def start_generate_script(self):
        request_text = self.script_request_input.toPlainText().strip()
        if not request_text:
            QMessageBox.warning(self, "Input Required", "Please describe the script you need.")
            return

        self.generate_button.setEnabled(False)
        self.execute_button.setEnabled(False)
        self.save_button.setEnabled(False)
        self.output_display.clear()
        self.generated_code_display.clear()
        self.current_retries = 0
        self.errors_fixed.clear()

        # Show progress indicators
        self.progress_bar.setVisible(True)
        self.loading_label.setVisible(True)
        self.loading_movie.start()

        # Start the script generation thread
        self.generate_thread = GenerateScriptThread(request_text, self.api_client)
        self.generate_thread.finished.connect(self.on_generate_success)
        self.generate_thread.error.connect(self.on_generate_error)
        self.generate_thread.start()

    def on_generate_success(self, script):
        self.generated_code_display.setPlainText(script)
        self.execute_button.setEnabled(True)
        self.save_button.setEnabled(True)
        QMessageBox.information(self, "Script Generated", "The script has been generated successfully.")
        # Hide progress indicators
        self.progress_bar.setVisible(False)
        self.loading_label.setVisible(False)
        self.loading_movie.stop()
        self.generate_button.setEnabled(True)

    def on_generate_error(self, error_message):
        QMessageBox.critical(self, "API Error", f"An error occurred while generating the script:\n{error_message}")
        # Hide progress indicators
        self.progress_bar.setVisible(False)
        self.loading_label.setVisible(False)
        self.loading_movie.stop()
        self.generate_button.setEnabled(True)

    def start_execute_script(self):
        script = self.generated_code_display.toPlainText().strip()
        if not script:
            QMessageBox.warning(self, "No Script", "There is no script to execute.")
            return

        self.execute_button.setEnabled(False)
        self.save_button.setEnabled(False)
        self.output_display.clear()
        self.current_retries = 0

        # Show progress indicators
        self.progress_bar.setVisible(True)
        self.loading_label.setVisible(True)
        self.loading_movie.start()

        # Start the script execution thread
        self.execute_thread = ExecuteScriptThread(script)
        self.execute_thread.finished.connect(self.on_execute_success)
        self.execute_thread.error.connect(self.on_execute_error)
        self.execute_thread.start()

    def on_execute_success(self, output):
        self.output_display.setPlainText(output)
        QMessageBox.information(self, "Execution Successful", "The script executed successfully.")
        # Hide progress indicators
        self.progress_bar.setVisible(False)
        self.loading_label.setVisible(False)
        self.loading_movie.stop()
        self.execute_button.setEnabled(True)
        self.save_button.setEnabled(True)

    def on_execute_error(self, error_message):
        self.output_display.setPlainText(error_message)
        self.handle_error(error_message)
        # Hide progress indicators in the current operation
        self.progress_bar.setVisible(False)
        self.loading_label.setVisible(False)
        self.loading_movie.stop()

    def handle_error(self, error_message):
        if self.current_retries >= self.retry_limit:
            QMessageBox.critical(self, "Execution Failed",
                                 f"Exceeded maximum retry attempts ({self.retry_limit}). Please review the script manually.")
            self.execute_button.setEnabled(True)
            self.save_button.setEnabled(True)
            return

        # Check if the error was already fixed
        if error_message in self.errors_fixed:
            QMessageBox.warning(self, "Repeated Error",
                                "Encountered a repeated error. Please review the script manually.")
            self.execute_button.setEnabled(True)
            self.save_button.setEnabled(True)
            return

        self.errors_fixed.add(error_message)

        # Prompt the user to fetch a suggestion
        reply = QMessageBox.question(
            self,
            "Error Occurred",
            f"Attempt {self.current_retries + 1}: {error_message}\n\nWould you like to fetch a suggestion to fix this error?",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
        )

        if reply == QMessageBox.StandardButton.Yes:
            # Show progress indicators
            self.progress_bar.setVisible(True)
            self.loading_label.setVisible(True)
            self.loading_movie.start()

            # Start the suggestion fetching thread
            self.suggestion_thread = FetchSuggestionThread(error_message, self.generated_code_display.toPlainText(), self.api_client)
            self.suggestion_thread.finished.connect(self.on_fetch_suggestion_success)
            self.suggestion_thread.error.connect(self.on_fetch_suggestion_error)
            self.suggestion_thread.start()
        else:
            QMessageBox.information(self, "Execution Halted", "Script execution has been halted. Please review the script manually.")
            self.execute_button.setEnabled(True)
            self.save_button.setEnabled(True)

    def on_fetch_suggestion_success(self, suggestion):
        # Hide progress indicators
        self.progress_bar.setVisible(False)
        self.loading_label.setVisible(False)
        self.loading_movie.stop()

        QMessageBox.information(self, "Suggestion Received", f"Suggested Fix:\n{suggestion}")

        # Apply the suggestion
        fixed_script = self.apply_fix(self.generated_code_display.toPlainText(), suggestion)
        self.generated_code_display.setPlainText(fixed_script)

        # Restart the execution with the fixed script
        self.start_execute_script()

    def on_fetch_suggestion_error(self, error_message):
        QMessageBox.critical(self, "Suggestion Error", f"An error occurred while fetching suggestion:\n{error_message}")
        # Hide progress indicators
        self.progress_bar.setVisible(False)
        self.loading_label.setVisible(False)
        self.loading_movie.stop()
        self.execute_button.setEnabled(True)
        self.save_button.setEnabled(True)

    def apply_fix(self, script, suggestion):
        """
        Applies the suggestion to the script.
        This implementation attempts to intelligently apply fixes based on common suggestions.
        Modify this method to handle more complex or specific suggestion formats as needed.
        """
        # Example: If the suggestion is to import a module, prepend it
        import_match = re.match(r'(import\s+\w+)', suggestion)
        if import_match:
            import_statement = import_match.group(1)
            if import_statement not in script:
                fixed_script = import_statement + "\n" + script
                return fixed_script

        # Example: If the suggestion is to define a missing function
        def_match = re.match(r'(def\s+\w+\(.*\):)', suggestion)
        if def_match:
            def_statement = def_match.group(1)
            fixed_script = def_statement + "\n    pass\n" + script
            return fixed_script

        # For other suggestions, append as a comment for manual review
        fixed_script = script + f"\n# Suggested Fix: {suggestion}"
        return fixed_script

    def save_project(self):
        project_name = self.project_name_input.text().strip()
        if not project_name:
            QMessageBox.warning(self, "Input Required", "Please enter a project name.")
            return

        # Choose directory to save the project
        directory = QFileDialog.getExistingDirectory(self, "Select Directory")
        if not directory:
            return

        # Create a unique project folder to prevent overwriting
        unique_id = uuid.uuid4().hex[:8]
        project_folder = f"{project_name}_{unique_id}"
        project_path = os.path.join(directory, project_folder)
        os.makedirs(project_path, exist_ok=True)

        try:
            # Save the request to a text file
            request_path = os.path.join(project_path, "request.txt")
            with open(request_path, 'w') as file:
                file.write(self.script_request_input.toPlainText())

            # Save the generated script to a .py file
            script = self.generated_code_display.toPlainText().strip()
            if script:
                script_path = os.path.join(project_path, "script.py")
                with open(script_path, 'w') as file:
                    file.write(script)

            # Save the execution output to a text file
            output = self.output_display.toPlainText().strip()
            if output:
                output_path = os.path.join(project_path, "execution_output.txt")
                with open(output_path, 'w') as file:
                    file.write(output)

            QMessageBox.information(self, "Project Saved", f"Project '{project_folder}' has been saved successfully at:\n{project_path}")
        except Exception as e:
            QMessageBox.critical(self, "Save Error", f"An error occurred while saving the project:\n{e}")

    def closeEvent(self, event):
        """
        Clean up temporary files upon closing the application.
        """
        temp_dir = os.path.join(os.getcwd(), "temp_scripts")
        if os.path.exists(temp_dir):
            try:
                shutil.rmtree(temp_dir)
            except Exception as e:
                print(f"Error cleaning up temp files: {e}")
        event.accept()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    
    # Ensure the loading.gif exists
    if not os.path.exists("loading.gif"):
        QMessageBox.critical(None, "Missing Resource", "The 'loading.gif' file is missing in the application directory.")
        sys.exit()

    gui = ScriptRequesterGUI()
    gui.show()
    sys.exit(app.exec())