im folgenden skript ist eine umsetzung einer ai anwendung für automatisierte ai softwareentwicklung mit zugehörigem ai agent chat. es wird darin die robocoder api verwendet die ich in dieser nachricht auch hinzufüge. Prüfe den code der anwendung und nenne mir alle bereiche in denen du verbesserungsmöglichkeiten erkennst oder fehler/probleme korrigieren könntest. Prüfe dabei alle bereiche, dazu gehört auch die art und weise der umsetzung des gui und so weiter. Prüfe zudem ob es weitere funktionen oder optionen gibt die in dieser anwendung noch nicht verwendet und enthalten sind, oder ob vorhandene inhalte vervollständigt oder verbessert werden können. Erstelle in deiner nachricht noch kein neues skript für die anwendung, stattdessen erstelle nur eine liste aller änderungen/verbesserungen/korrekturen etc die du vornehmen würdest. 

Robocoder API:

# Robocoders.ai API Documentation

## Overview

Robocoders.ai provides an API for interacting with coding agents through a session-based system. This document outlines how to authenticate, create sessions, interact with agents, and handle errors.

## Authentication

### 1. Get Access Token

- Obtain your access token from [https://api.robocoders.ai/auth](https://api.robocoders.ai/auth)
- Keep the access token secure and use it to access the API

### 2. Authenticated Endpoints

All authenticated requests require the ACCESS token in the `Authorization` header:

```
Authorization: Bearer <ACCESS_TOKEN>
```

## Endpoints

### 1. Create Session

**Endpoint**: `GET /create-session`

Initializes a session for interacting with agents.

**Response:**
```json
{
  "sid": "<created-session-id>"
}
```

### 2. Chat

**Endpoint**: `POST /chat`

Sends a Task/prompt to the selected agent within the active session.

**Request Body:**
```json
{
  "sid": "session_id",
  "prompt": "user_prompt",
  "agent": "AgentType"
}
```

**Response**: Streaming JSON response with model output.

### 3. Get Access to Code Repository

**Endpoint**: `POST /get-session-code`

Adds a GitHub username as a collaborator to the session's repository.

**Request Body:**
```json
{
  "sid": "session_id",
  "github_username": "collaborator_username"
}
```

**Response:**
```json
{
  "repo_url": "https://github.com/owner/repo_name",
  "message": "Collaborator added successfully"
}
```

**Notes**:
- Adds collaborator with "read" permission
- Collaborator will receive an email invite

## Error Handling

The API returns standard HTTP status codes to indicate errors:

- **400 Bad Request**: Invalid Google token or malformed request
- **401 Unauthorized**: Missing or invalid JWT token
- **403 Forbidden**: Access to the endpoint is forbidden
- **500 Internal Server Error**: An error occurred on the server

## Authentication Flow

1. Get the API Access token by visiting [https://api.robocoders.ai/auth](https://api.robocoders.ai/auth)
2. Use this Access token in the `Authorization` header for all authenticated requests

## Example Usage

### Step 1: Start a Session

```bash
curl -X GET https://api.robocoders.ai/create-session -H 'Authorization: Bearer <ACCESS_TOKEN>'
```

### Step 2: Interact with Agents

#### Start a Generation

```bash
curl -X POST "https://api.robocoders.ai/chat" -H "Content-Type: application/json" -H 'Authorization: Bearer <ACCESS_TOKEN>' -d '{
  "sid": "<session-id>",
  "prompt": "write a Python file to add two numbers",
  "agent": "GeneralCodingAgent"
}'
```

#### Continue a Session

Use the same `sid` to send additional prompts or reply to agent responses:

```bash
curl -X POST "https://api.robocoders.ai/chat" -H "Content-Type: application/json" -H 'Authorization: Bearer <ACCESS_TOKEN>' -d '{
  "sid": "<session-id>",
  "prompt": "Follow-up response",
  "agent": "GeneralCodingAgent"
}'
```

### Step 3: Get Access to the Session Code

Use the same `sid` used in `/chat` endpoint.

```bash
curl -X POST "https://api.robocoders.ai/get-session-code" -H "Content-Type: application/json" -H 'Authorization: Bearer <ACCESS_TOKEN>' -d '{
  "sid": "<session-id>",
  "github_username": "your_github_username"
}'
```

## Agent Options

Select the best agent for your specific coding task:

- **GeneralCodingAgent**: Best for initiating general coding projects
- **RepoAgent**: Ideal for interacting with existing repositories or files
- **FrontEndAgent**: Tailored for UI development, specializing in React, Next.js, and Tailwind CSS

## Additional Resources

- Swagger API Documentation: [https://api.robocoders.ai/api-docs](https://api.robocoders.ai/api-docs)




Skript der Anwendung:

import sys
import os
import requests
import json
import datetime
import re
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QPushButton, QTextEdit, QLineEdit, QLabel, QComboBox, QFileDialog,
    QMessageBox, QProgressBar, QSplitter, QInputDialog, QToolTip,
    QListWidget, QTabWidget, QDialog, QSizePolicy, QListWidgetItem,
    QAction, QMenu, QTreeView
)
from PyQt5.QtCore import (
    Qt, QThread, pyqtSignal, QSettings, QTimer,
    QRegularExpression, QRegularExpressionMatch, QFileSystemModel
)
from PyQt5.QtGui import (
    QFont, QColor, QTextCursor, QTextCharFormat,
    QPalette, QIcon, QSyntaxHighlighter
)

class SettingsDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("Settings")
        self.setModal(True)
        self.settings = QSettings("RobocoderApp", "Settings")
        
        layout = QVBoxLayout()
        
        # Robocoder API Key
        api_key_layout = QHBoxLayout()
        api_key_layout.addWidget(QLabel("Robocoder API Key:"))
        self.api_key_input = QLineEdit()
        self.api_key_input.setText(self.settings.value("api_key", ""))
        api_key_layout.addWidget(self.api_key_input)
        layout.addLayout(api_key_layout)
        
        # GitHub Access Token
        github_token_layout = QHBoxLayout()
        github_token_layout.addWidget(QLabel("GitHub Access Token:"))
        self.github_token_input = QLineEdit()
        self.github_token_input.setText(self.settings.value("github_token", ""))
        github_token_layout.addWidget(self.github_token_input)
        layout.addLayout(github_token_layout)
        
        # GitHub Username
        github_username_layout = QHBoxLayout()
        github_username_layout.addWidget(QLabel("GitHub Username:"))
        self.github_username_input = QLineEdit()
        self.github_username_input.setText(self.settings.value("github_username", ""))
        github_username_layout.addWidget(self.github_username_input)
        layout.addLayout(github_username_layout)
        
        # Save Button
        save_button = QPushButton("Save")
        save_button.clicked.connect(self.save_settings)
        layout.addWidget(save_button)
        
        self.setLayout(layout)
    
    def save_settings(self):
        self.settings.setValue("api_key", self.api_key_input.text())
        self.settings.setValue("github_token", self.github_token_input.text())
        self.settings.setValue("github_username", self.github_username_input.text())
        self.accept()

class CodeHighlighter(QSyntaxHighlighter):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.highlighting_rules = []

        keyword_format = QTextCharFormat()
        keyword_format.setForeground(Qt.darkBlue)
        keyword_format.setFontWeight(QFont.Bold)
        keywords = [
            "def", "class", "import", "from", "for", "while", "if", "else",
            "elif", "try", "except", "finally", "return", "break", "continue",
            "with", "as", "pass", "lambda", "yield", "raise", "assert", "del"
        ]
        keyword_pattern = r'\b(' + '|'.join(keywords) + r')\b'
        self.highlighting_rules.append((QRegularExpression(keyword_pattern), keyword_format))

        # Strings
        string_format = QTextCharFormat()
        string_format.setForeground(Qt.darkGreen)
        self.highlighting_rules.append((QRegularExpression(r'".*?"'), string_format))
        self.highlighting_rules.append((QRegularExpression(r"'.*?'"), string_format))

        # Comments
        comment_format = QTextCharFormat()
        comment_format.setForeground(Qt.gray)
        self.highlighting_rules.append((QRegularExpression(r'#.*'), comment_format))

        # Function names
        function_format = QTextCharFormat()
        function_format.setForeground(Qt.blue)
        function_format.setFontItalic(True)
        self.highlighting_rules.append((QRegularExpression(r'\b[A-Za-z0-9_]+(?=\()'), function_format))

    def highlightBlock(self, text):
        for pattern, fmt in self.highlighting_rules:
            match_iter = pattern.globalMatch(text)
            while match_iter.hasNext():
                match: QRegularExpressionMatch = match_iter.next()
                start = match.capturedStart()
                length = match.capturedLength()
                self.setFormat(start, length, fmt)
        self.setCurrentBlockState(0)

class RobocoderAPI:
    def __init__(self, api_key):
        self.API_BASE_URL = "https://api.robocoders.ai"
        self.API_KEY = api_key
        self.session_id = None

    def create_session(self):
        url = f"{self.API_BASE_URL}/create-session"
        headers = {"Authorization": f"Bearer {self.API_KEY}"}
        response = requests.get(url, headers=headers, timeout=10)
        if response.status_code == 200:
            self.session_id = response.json().get("sid")
            if not self.session_id:
                raise Exception("Session ID not found in response.")
            return self.session_id
        else:
            raise Exception(f"Failed to create session: {response.text}")

    def chat_with_agent(self, prompt, agent, context=None):
        if not self.session_id:
            raise Exception("No active session. Please create a session first.")

        url = f"{self.API_BASE_URL}/chat"
        headers = {
            "Authorization": f"Bearer {self.API_KEY}",
            "Content-Type": "application/json"
        }
        data = {
            "sid": self.session_id,
            "prompt": prompt,
            "agent": agent
        }
        if context:
            data["context"] = context
            
        try:
            print("Request Data:", json.dumps(data, indent=4))  # Protokollierung der Anfrage
            with requests.post(url, headers=headers, json=data, stream=True) as response:
                response.raise_for_status()
                for line in response.iter_lines():
                    if line:
                        decoded_line = line.decode('utf-8')
                        try:
                            json_response = json.loads(decoded_line)
                            if "message" in json_response:
                                yield json_response["message"]
                            else:
                                print("Unexpected response format:", json_response)
                                yield f"Unexpected response format: {json_response}"
                        except json.JSONDecodeError:
                            print("Failed to decode JSON:", decoded_line)
                            yield f"Failed to decode response: {decoded_line}"
        except requests.exceptions.Timeout:
            error_message = "The request timed out. Please try again."
            print(error_message)
            yield error_message
        except requests.exceptions.RequestException as e:
            error_message = f"An error occurred while making the request: {str(e)}"
            print(f"Request failed: {e}")  # Protokollierung von Fehlern
            yield error_message
        

    def get_session_code(self, github_username):
        if not self.session_id:
            raise Exception("No active session. Please create a session first.")

        url = f"{self.API_BASE_URL}/get-session-code"
        headers = {
            "Authorization": f"Bearer {self.API_KEY}",
            "Content-Type": "application/json"
        }
        data = {
            "sid": self.session_id,
            "github_username": github_username
        }
        try:
            response = requests.post(url, headers=headers, json=data, timeout=10)
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            raise Exception(f"Failed to get session code: {str(e)}")

class ChatWorker(QThread):
    finished = pyqtSignal(str)
    error = pyqtSignal(str)
    progress = pyqtSignal(int)
    partial_response = pyqtSignal(str)

    def __init__(self, api, prompt, agent, context=None):
        super().__init__()
        self.api = api
        self.prompt = prompt
        self.agent = agent
        self.context = context

    def run(self):
        try:
            self.progress.emit(10)
            full_response = ""
            for chunk in self.api.chat_with_agent(self.prompt, self.agent, self.context):
                if chunk.startswith("An error occurred") or chunk.startswith("The request timed out"):
                    self.error.emit(chunk)
                    self.progress.emit(100)
                    return
                full_response += chunk
                self.partial_response.emit(chunk)
                self.progress.emit(50)  # You might want to adjust this based on the actual progress
            self.progress.emit(90)
            self.finished.emit(full_response)
            self.progress.emit(100)
        except Exception as e:
            self.error.emit(str(e))
            self.progress.emit(100)

class APIKeyDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("API Key")
        self.setWindowIcon(QIcon())  # Optionally set an icon
        layout = QVBoxLayout()

        self.api_key_input = QLineEdit()
        self.api_key_input.setEchoMode(QLineEdit.Password)
        layout.addWidget(QLabel("Enter your Robocoder API Key:"))
        layout.addWidget(self.api_key_input)

        buttons = QHBoxLayout()
        ok_button = QPushButton("OK")
        ok_button.clicked.connect(self.accept)
        cancel_button = QPushButton("Cancel")
        cancel_button.clicked.connect(self.reject)
        buttons.addStretch()
        buttons.addWidget(ok_button)
        buttons.addWidget(cancel_button)
        layout.addLayout(buttons)

        self.setLayout(layout)
        self.setFixedSize(400, 150)

    def get_api_key(self):
        return self.api_key_input.text().strip()

class RobocoderApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.settings = QSettings("RobocoderApp", "Settings")
        self.api_key = self.settings.value("api_key", "")
        self.github_token = self.settings.value("github_token", "")
        self.github_username = self.settings.value("github_username", "")
        if not self.api_key:
            self.open_settings()
        self.api = RobocoderAPI(self.api_key)
        self.chat_archives = {}
        self.current_chat_id = None
        self.init_ui()

    def open_settings(self):
        dialog = SettingsDialog(self)
        if dialog.exec_() == QDialog.Accepted:
            self.api_key = self.settings.value("api_key", "")
            self.github_token = self.settings.value("github_token", "")
            self.github_username = self.settings.value("github_username", "")
            if self.api_key:
                self.api = RobocoderAPI(self.api_key)
            else:
                QMessageBox.warning(self, "Invalid Input", "API Key cannot be empty.")
                self.open_settings()

    def init_ui(self):
        self.setWindowTitle('Robocoder Application')
        self.setGeometry(100, 100, 1400, 900)
        self.setWindowIcon(QIcon())  # Optionally set an application icon

        # Set application-wide style
        self.setStyleSheet("""
            QMainWindow, QWidget {
                background-color: #2b2b2b;
                color: #e0e0e0;
            }
            QLabel {
                font-size: 14px;
                font-weight: bold;
            }
            QListWidget, QTextEdit, QLineEdit, QTreeView {
                background-color: #363636;
                border: 1px solid #4a4a4a;
                border-radius: 5px;
                padding: 5px;
                color: #e0e0e0;
                font-size: 13px;
            }
            QPushButton {
                background-color: #4a4a4a;
                color: #e0e0e0;
                border: none;
                padding: 8px 15px;
                border-radius: 5px;
                font-size: 13px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #5a5a5a;
            }
            QComboBox {
                background-color: #363636;
                border: 1px solid #4a4a4a;
                border-radius: 5px;
                padding: 5px;
                color: #e0e0e0;
                font-size: 13px;
            }
            QTabWidget::pane {
                border: 1px solid #4a4a4a;
                border-radius: 5px;
            }
            QTabBar::tab {
                background-color: #363636;
                color: #e0e0e0;
                padding: 8px 15px;
                border-top-left-radius: 5px;
                border-top-right-radius: 5px;
            }
            QTabBar::tab:selected {
                background-color: #4a4a4a;
            }
        """)

        # Create menu bar
        menubar = self.menuBar()
        file_menu = menubar.addMenu('File')
        
        # Add Settings action
        settings_action = QAction('Settings', self)
        settings_action.triggered.connect(self.open_settings)
        file_menu.addAction(settings_action)

        # Add New Chat action
        new_chat_action = QAction('New Chat', self)
        new_chat_action.triggered.connect(self.new_chat)
        file_menu.addAction(new_chat_action)

        # Main layout
        main_layout = QHBoxLayout()

        # Left panel for chat archives and file tree
        left_panel = QWidget()
        left_layout = QVBoxLayout()
        left_layout.setContentsMargins(10, 10, 10, 10)
        left_layout.setSpacing(10)

        # Chat archives
        self.chat_list = QListWidget()
        self.chat_list.setToolTip("Select a chat archive to load")
        self.chat_list.itemClicked.connect(self.load_chat)
        left_layout.addWidget(QLabel('Chat Archives:'))
        left_layout.addWidget(self.chat_list)

        # File tree
        self.file_tree = QTreeView()
        self.file_tree.setToolTip("View and select files in the current chat session")
        self.file_tree.clicked.connect(self.open_file_from_tree)
        left_layout.addWidget(QLabel('Files:'))
        left_layout.addWidget(self.file_tree)

        left_panel.setLayout(left_layout)
        left_panel.setFixedWidth(250)

        # Middle panel for chat
        middle_panel = QWidget()
        middle_layout = QVBoxLayout()
        middle_layout.setContentsMargins(10, 10, 10, 10)
        middle_layout.setSpacing(10)

        self.chat_history = QTextEdit()
        self.chat_history.setReadOnly(True)
        chat_font = QFont("Segoe UI", 11)
        self.chat_history.setFont(chat_font)
        middle_layout.addWidget(self.chat_history)

        agent_layout = QHBoxLayout()
        agent_label = QLabel('Select Agent:')
        self.agent_combo = QComboBox()
        self.agent_combo.addItems(["GeneralCodingAgent", "RepoAgent", "FrontEndAgent"])
        self.agent_combo.setToolTip("Select the AI agent you want to interact with")
        agent_layout.addWidget(agent_label)
        agent_layout.addWidget(self.agent_combo)
        agent_layout.addStretch()
        middle_layout.addLayout(agent_layout)

        prompt_layout = QHBoxLayout()
        self.prompt_input = QLineEdit()
        self.prompt_input.setPlaceholderText("Type your message here...")
        self.prompt_input.setToolTip("Enter your message or question for the AI")
        self.prompt_input.returnPressed.connect(self.send_message)
        self.send_button = QPushButton('Send')
        self.send_button.setToolTip("Send your message to the AI")
        self.send_button.clicked.connect(self.send_message)
        prompt_layout.addWidget(self.prompt_input)
        prompt_layout.addWidget(self.send_button)
        middle_layout.addLayout(prompt_layout)

        self.progress_bar = QProgressBar()
        self.progress_bar.setVisible(False)
        middle_layout.addWidget(self.progress_bar)

        # GitHub Repository Shortcuts
        github_layout = QHBoxLayout()
        github_layout.addWidget(QLabel('GitHub Repositories:'))
        self.repo_combo = QComboBox()
        self.repo_combo.setToolTip("Select a GitHub repository")
        github_layout.addWidget(self.repo_combo)
        self.refresh_repos_button = QPushButton('Refresh')
        self.refresh_repos_button.setToolTip("Refresh the list of GitHub repositories")
        self.refresh_repos_button.clicked.connect(self.refresh_github_repos)
        github_layout.addWidget(self.refresh_repos_button)
        middle_layout.addLayout(github_layout)

        middle_panel.setLayout(middle_layout)

        # Right panel for file content
        right_panel = QWidget()
        right_layout = QVBoxLayout()
        right_layout.setContentsMargins(10, 10, 10, 10)
        right_layout.setSpacing(10)

        self.file_content = QTextEdit()
        self.file_content.setReadOnly(False)
        self.highlighter = CodeHighlighter(self.file_content.document())
        right_layout.addWidget(self.file_content)

        # Save file button
        self.save_file_button = QPushButton('Save File')
        self.save_file_button.setToolTip("Save changes to the current file")
        self.save_file_button.clicked.connect(self.save_file)
        right_layout.addWidget(self.save_file_button)

        right_panel.setLayout(right_layout)

        # Add panels to main layout
        main_layout.addWidget(left_panel)
        main_layout.addWidget(middle_panel, 2)
        main_layout.addWidget(right_panel, 1)

        # Central widget
        central_widget = QWidget()
        central_widget.setLayout(main_layout)
        self.setCentralWidget(central_widget)

        # Status bar
        self.statusBar().showMessage("Ready")

        # Initialize session
        self.new_chat()

        # Set up auto-save timer
        self.auto_save_timer = QTimer(self)
        self.auto_save_timer.timeout.connect(self.auto_save)
        self.auto_save_timer.start(60000)  # Auto-save every minute

        # Refresh GitHub repositories
        self.refresh_github_repos()

    def create_chat_directory(self):
        chat_dir = self.get_chat_directory()
        os.makedirs(chat_dir, exist_ok=True)

    def update_file_tree(self):
        chat_dir = self.get_chat_directory()
        model = QFileSystemModel()
        model.setRootPath(chat_dir)
        self.file_tree.setModel(model)
        self.file_tree.setRootIndex(model.index(chat_dir))
        self.file_tree.setColumnWidth(0, 200)

    def open_file_from_tree(self, index):
        file_path = self.file_tree.model().filePath(index)
        if os.path.isfile(file_path):
            self.open_file(file_path)

    def refresh_github_repos(self):
        if self.github_token and self.github_username:
            try:
                headers = {'Authorization': f'token {self.github_token}'}
                response = requests.get(f'https://api.github.com/users/{self.github_username}/repos', headers=headers)
                repos = response.json()
                self.repo_combo.clear()
                for repo in repos:
                    self.repo_combo.addItem(repo['name'], repo['clone_url'])
            except Exception as e:
                QMessageBox.warning(self, "Error", f"Failed to fetch GitHub repositories: {str(e)}")
        else:
            QMessageBox.warning(self, "Missing Information", "Please set your GitHub token and username in the settings.")

    def new_chat(self):
        try:
            self.api.create_session()
            chat_id = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
            self.current_chat_id = chat_id
            self.chat_archives[chat_id] = []
            self.chat_list.addItem(chat_id)
            self.chat_list.setCurrentRow(self.chat_list.count() - 1)
            self.chat_history.clear()
            self.add_system_message("New session created successfully.")
            self.update_file_list()
        except Exception as e:
            self.add_system_message(f"Error creating session: {str(e)}", error=True)

    def load_chat(self, item: QListWidgetItem):
        chat_id = item.text()
        self.current_chat_id = chat_id
        self.chat_history.clear()
        self.load_chat_archive()
        self.update_file_list()
        self.add_system_message(f"Loaded chat session: {chat_id}")

    def load_chat_archive(self):
        chat_dir = self.get_chat_directory()
        archive_file = os.path.join(chat_dir, "chat_archive.json")
        if os.path.exists(archive_file):
            with open(archive_file, 'r', encoding='utf-8') as f:
                try:
                    self.chat_archives[self.current_chat_id] = json.load(f)
                except json.JSONDecodeError:
                    self.chat_archives[self.current_chat_id] = []
        else:
            self.chat_archives[self.current_chat_id] = []

        for message in self.chat_archives[self.current_chat_id]:
            if message['type'] == 'user':
                self.add_user_message(message['content'], save=False)
            elif message['type'] == 'ai':
                self.add_ai_message(message['content'], save=False)
            elif message['type'] == 'system':
                self.add_system_message(message['content'], message.get('error', False), save=False)

    def send_message(self):
        prompt = self.prompt_input.text().strip()
        agent = self.agent_combo.currentText()
        
        if not prompt:
            QMessageBox.warning(self, "Input Error", "Please enter a message to send.")
            return

        self.add_user_message(prompt)
        self.prompt_input.clear()

        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)

        context = self.get_file_context()

        self.worker = ChatWorker(self.api, prompt, agent, context)
        self.worker.finished.connect(self.handle_response)
        self.worker.error.connect(self.handle_error)
        self.worker.progress.connect(self.update_progress)
        self.worker.partial_response.connect(self.handle_partial_response)
        self.worker.start()

    def handle_partial_response(self, chunk):
        self.add_ai_message(chunk, save=False)

    def get_file_context(self):
        context = {}
        chat_dir = self.get_chat_directory()
        for i in range(self.file_list.count()):
            file_name = self.file_list.item(i).text()
            file_path = os.path.join(chat_dir, file_name)
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    # Lesen Sie nur die ersten 1000 Zeilen, um den Speicherverbrauch zu begrenzen
                    context[file_name] = ''.join(f.readlines()[:1000])
                if len(context[file_name]) == 1000:
                    context[file_name] += "\n... (file truncated)"
            except Exception as e:
                context[file_name] = f"Error reading file {file_name}: {str(e)}"
        return context

    def handle_api_error(self, error_message):
        QMessageBox.critical(self, "API Error", f"An error occurred while communicating with the API: {error_message}")
        self.add_system_message(f"API Error: {error_message}", error=True)

    def handle_network_error(self, error_message):
        QMessageBox.warning(self, "Network Error", f"A network error occurred: {error_message}")
        self.add_system_message(f"Network Error: {error_message}", error=True)

    def update_progress(self, value):
        self.progress_bar.setValue(value)

    def handle_response(self, response):
        self.progress_bar.setVisible(False)
        # Die vollständige Antwort wurde bereits in Teilen angezeigt,
        # hier speichern wir sie nur noch in den Chat-Archiven
        self.chat_archives[self.current_chat_id].append({'type': 'ai', 'content': response})
        self.save_chat_archive()

    def handle_error(self, error_message):
        self.progress_bar.setVisible(False)
        if error_message.startswith("An error occurred while making the request"):
            self.handle_network_error(error_message)
        elif error_message.startswith("The request timed out"):
            self.handle_api_error(error_message)
        else:
            self.add_system_message(f"Error: {error_message}", error=True)

    def add_user_message(self, message, save=True):
        formatted_message = self.format_message(message)
        self.chat_history.append(f'''
            <div style="text-align: right; margin: 10px 0;">
                <div style="display: inline-block; max-width: 70%; background-color: #3a6351; color: #e0e0e0; padding: 10px; border-radius: 15px 0 15px 15px; position: relative; font-size: 14px;">
                    <div style="font-weight: bold; margin-bottom: 5px; font-size: 12px; color: #a0a0a0;">You</div>
                    {formatted_message}
                    <div style="position: absolute; right: -10px; top: 0; width: 0; height: 0; border-left: 10px solid #3a6351; border-top: 10px solid transparent;"></div>
                </div>
            </div>
        ''')
        if save:
            self.chat_archives[self.current_chat_id].append({'type': 'user', 'content': message})

    def add_ai_message(self, message, save=True):
        formatted_message = self.format_message(message)
        self.chat_history.append(f'''
            <div style="text-align: left; margin: 10px 0;">
                <div style="display: inline-block; max-width: 70%; background-color: #4a4a4a; color: #e0e0e0; padding: 10px; border-radius: 0 15px 15px 15px; position: relative; font-size: 14px;">
                    <div style="font-weight: bold; margin-bottom: 5px; font-size: 12px; color: #a0a0a0;">AI</div>
                    {formatted_message}
                    <div style="position: absolute; left: -10px; top: 0; width: 0; height: 0; border-right: 10px solid #4a4a4a; border-top: 10px solid transparent;"></div>
                </div>
            </div>
        ''')
        if save:
            self.chat_archives[self.current_chat_id].append({'type': 'ai', 'content': message})

    def format_message(self, message):
        # Format code blocks
        message = re.sub(r'```([\s\S]*?)```', r'<pre style="background-color: #2b2b2b; padding: 10px; border-radius: 5px; font-family: monospace; font-size: 12px;"><code>\1</code></pre>', message)
        
        # Format inline code
        message = re.sub(r'`([^`\n]+)`', r'<code style="background-color: #2b2b2b; padding: 2px 4px; border-radius: 3px; font-family: monospace; font-size: 12px;">\1</code>', message)
        
        # Format links
        url_pattern = r'(https?://\S+)'
        message = re.sub(url_pattern, r'<a href="\1" style="color: #4a9eff; text-decoration: none;">\1</a>', message)
        
        # Convert newlines to <br> tags
        message = message.replace('\n', '<br>')
        
        return message

    def add_system_message(self, message, error=False, save=True):
        color = "#ff6b6b" if error else "#4ecdc4"
        self.chat_history.append(f'''
            <div style="text-align: center; margin: 10px 0;">
                <span style="background-color: {color}; color: #2b2b2b; padding: 5px 10px; border-radius: 15px; font-size: 12px; font-weight: bold;">
                    System: {message}
                </span>
            </div>
        ''')
        if save:
            self.chat_archives[self.current_chat_id].append({'type': 'system', 'content': message, 'error': error})

    def open_file(self, item: QListWidgetItem):
        file_name = item.text()
        file_path = os.path.join(self.get_chat_directory(), file_name)
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            self.file_content.setText(content)
            self.tabs.setCurrentIndex(1)  # Switch to file tab
            self.add_system_message(f"File opened: {file_name}")
        except Exception as e:
            self.add_system_message(f"Error opening file {file_name}: {str(e)}", error=True)

    def save_file(self):
        file_name = None
        # Check if currently editing an existing file
        current_items = self.file_list.selectedItems()
        if current_items:
            file_name = current_items[0].text()
            file_path = os.path.join(self.get_chat_directory(), file_name)
        else:
            # Prompt to save as new file
            file_name, _ = QFileDialog.getSaveFileName(self, "Save File", self.get_chat_directory(), "All Files (*)")
            if not file_name:
                return
            file_path = file_name
            # Extract just the file name
            file_name = os.path.basename(file_path)

        try:
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(self.file_content.toPlainText())
            self.update_file_list()
            self.add_system_message(f"File saved: {file_name}")
        except Exception as e:
            self.add_system_message(f"Error saving file {file_name}: {str(e)}", error=True)

    def update_file_list(self):
        self.file_list.clear()
        chat_dir = self.get_chat_directory()
        if os.path.exists(chat_dir):
            try:
                files = os.listdir(chat_dir)
                for file in files:
                    if os.path.isfile(os.path.join(chat_dir, file)) and not file.endswith(".json"):
                        self.file_list.addItem(file)
            except Exception as e:
                self.add_system_message(f"Error listing files: {str(e)}", error=True)

    def get_chat_directory(self):
        base_dir = os.path.join(os.path.expanduser("~"), "RobocoderChats")
        chat_dir = os.path.join(base_dir, self.current_chat_id)
        os.makedirs(chat_dir, exist_ok=True)
        return chat_dir

    def auto_save(self):
        self.save_chat_archive()
        self.status_bar .setText(f"Auto-saved at {datetime.datetime.now().strftime('%H:%M:%S')}")
        QTimer.singleShot(3000, lambda: self.status_bar.clear())

    def save_chat_archive(self):
        chat_dir = self.get_chat_directory()
        archive_file = os.path.join(chat_dir, "chat_archive.json")
        try:
            with open(archive_file, 'w', encoding='utf-8') as f:
                json.dump(self.chat_archives[self.current_chat_id], f, ensure_ascii=False, indent=4)
        except Exception as e:
            self.add_system_message(f"Error auto-saving chat: {str(e)}", error=True)

    def closeEvent(self, event):
        self.save_chat_archive()
        event.accept()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    
    # Optional: Set application style for better visuals
    app.setStyle("Fusion")
    
    # Optional: Improve the palette
    palette = QPalette()
    palette.setColor(QPalette.Window, QColor(240, 240, 240))
    palette.setColor(QPalette.WindowText, Qt.black)
    palette.setColor(QPalette.Base, QColor(255, 255, 255))
    palette.setColor(QPalette.AlternateBase, QColor(240, 240, 240))
    palette.setColor(QPalette.ToolTipBase, Qt.black)
    palette.setColor(QPalette.ToolTipText, Qt.white)
    palette.setColor(QPalette.Text, Qt.black)
    palette.setColor(QPalette.Button, QColor(200, 200, 200))
    palette.setColor(QPalette.ButtonText, Qt.black)
    palette.setColor(QPalette.BrightText, Qt.red)

    app.setPalette(palette)
    
    ex = RobocoderApp()
    ex.show()
    sys.exit(app.exec_())