System: 
                Ты - русскоязычный ассистент. Отвечай только на русском языке, независимо от языка запроса.
                Ты можешь просматривать экран, выполнять действия на компьютере и работать с файлами.
                
User: привет
Assistant: Привет! Как я могу вам помочь сегодня?
User: что ты можешь делать?
Assistant: Я могу помочь с различными задачами, такими как предоставление информации, ответ на вопросы, помощь с учебой, генерация идей, написание текстов и многое другое. Если у тебя есть конкретный запрос или вопрос, просто дай знать, и я постараюсь помочь!
User: посмотри на мой код import sys
import os
import re
import subprocess
import sqlite3
import logging
import requests
from bs4 import BeautifulSoup
from PySide6.QtWidgets import (QApplication, QMainWindow, QTextEdit, QLineEdit, QVBoxLayout, QHBoxLayout, 
                               QWidget, QPushButton, QFileDialog, QColorDialog, QDialog, QFormLayout, 
                               QComboBox, QLabel, QStyleFactory, QMessageBox, QPlainTextEdit)
from PySide6.QtCore import Qt, QSettings, QThread, Signal
from PySide6.QtGui import QColor, QIcon, QPalette
import g4f
import speech_recognition as sr
import mss
import pyautogui

# Настройка логирования
logging.basicConfig(level=logging.INFO)

class SettingsDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("Настройки")
        layout = QFormLayout(self)

        self.theme_combo = QComboBox()
        self.theme_combo.addItems(["Светлая", "Темная", "Пользовательская"])
        layout.addRow("Тема:", self.theme_combo)

        self.custom_color_button = QPushButton("Выбрать цвет")
        self.custom_color_button.clicked.connect(self.choose_color)
        layout.addRow("Пользовательский цвет:", self.custom_color_button)

        self.db_path_edit = QLineEdit()
        self.db_path_button = QPushButton("Выбрать")
        self.db_path_button.clicked.connect(self.choose_db_path)
        db_layout = QHBoxLayout()
        db_layout.addWidget(self.db_path_edit)
        db_layout.addWidget(self.db_path_button)
        layout.addRow("Путь к базе данных:", db_layout)

        self.save_button = QPushButton("Сохранить")
        self.save_button.clicked.connect(self.accept)
        layout.addRow(self.save_button)

    def choose_color(self):
        color = QColorDialog.getColor()
        if color.isValid():
            self.custom_color = color.name()
            self.parent().settings.setValue("custom_color", self.custom_color)  # Сохраняем цвет в настройках

    def choose_db_path(self):
        path, _ = QFileDialog.getSaveFileName(self, "Выберите файл базы данных", "", "SQLite Database (*.db)")
        if path:
            self.db_path_edit.setText(path)

class AIResponseThread(QThread):
    response_ready = Signal(str)

    def __init__(self, message_history, parent=None):
        super().__init__(parent)
        self.message_history = message_history
        self.retry_count = 0

    def run(self):
        while self.retry_count < 3:
            try:
                system_message = """
                Ты - русскоязычный ассистент. Отвечай только на русском языке, независимо от языка запроса.
                Ты можешь просматривать экран, выполнять действия на компьютере и работать с файлами.
                """
                messages = [{"role": "system", "content": system_message}] + self.message_history
                
                logging.info(f"Отправляемые сообщения: {messages}")
                response = g4f.ChatCompletion.create(
                    model=g4f.models.gpt_4o,
                    messages=messages,
                    method="POST",
                    stream=False
                )
                logging.info(f"Полученный ответ: {response}")
                if isinstance(response, str):
                    if "general (unknown) error" in response.lower():
                        self.retry_count += 1
                        continue
                    self.response_ready.emit(response)
                    return
                else:
                    self.response_ready.emit("Получен неожиданный формат ответа")
                    return
            except Exception as e:
                logging.error(f"Ошибка при получении ответа: {str(e)}")
                self.response_ready.emit(f"Произошла ошибка при получении ответа: {str(e)}")
                return
        self.response_ready.emit("general (unknown) error")

class ChatWindow(QMainWindow):
    def __init__(self, app):
        super().__init__()
        self.app = app
        self.setWindowTitle("AI Assistant")
        self.setGeometry(100, 100, 800, 600)

        # Установка значка приложения
        self.setWindowIcon(QIcon('icon.png'))  # Замените 'icon.png' на путь к вашему значку

        self.settings = QSettings("MyCompany", "AIAssistant")
        self.load_settings()

        central_widget = QWidget()
        layout = QVBoxLayout(central_widget)

        self.chat_area = QTextEdit()
        self.chat_area.setReadOnly(True)
        layout.addWidget(self.chat_area)

        input_layout = QHBoxLayout()
        self.input_field = QLineEdit()
        self.input_field.setPlaceholderText("Введите ваше сообщение...")
        self.input_field.returnPressed.connect(self.send_message)
        input_layout.addWidget(self.input_field)

        self.voice_button = QPushButton("Голосовой ввод")
        self.voice_button.clicked.connect(self.voice_input)
        input_layout.addWidget(self.voice_button)

        self.file_button = QPushButton("Загрузить файл")
        self.file_button.clicked.connect(self.upload_file)
        input_layout.addWidget(self.file_button)

        layout.addLayout(input_layout)

        self.settings_button = QPushButton("Настройки")
        self.settings_button.clicked.connect(self.open_settings)
        layout.addWidget(self.settings_button)

        self.setCentralWidget(central_widget)

        self.threads = []  # Список для хранения потоков
        self.message_history = []  # Добавляем список для хранения истории сообщений

    def load_settings(self):
        self.theme = self.settings.value("theme", "Светлая")
        self.custom_color = self.settings.value("custom_color", "#FFFFFF")
        self.db_path = self.settings.value("db_path", "chat_history.db")
        self.apply_theme()

        # Инициализация соединения с базой данных после установки db_path
        self.db_conn = sqlite3.connect(self.db_path)
        self.create_table()

    def apply_theme(self):
        if self.theme == "Темная":
            self.app.setStyle(QStyleFactory.create("Fusion"))
            dark_palette = QPalette()
            dark_palette.setColor(QPalette.Window, QColor(53, 53, 53))
            dark_palette.setColor(QPalette.WindowText, Qt.white)
            dark_palette.setColor(QPalette.Base, QColor(25, 25, 25))
            dark_palette.setColor(QPalette.AlternateBase, QColor(53, 53, 53))
            dark_palette.setColor(QPalette.ToolTipBase, Qt.white)
            dark_palette.setColor(QPalette.ToolTipText, Qt.white)
            dark_palette.setColor(QPalette.Text, Qt.white)
            dark_palette.setColor(QPalette.Button, QColor(53, 53, 53))
            dark_palette.setColor(QPalette.ButtonText, Qt.white)
            dark_palette.setColor(QPalette.BrightText, Qt.red)
            dark_palette.setColor(QPalette.Link, QColor(42, 130, 218))
            dark_palette.setColor(QPalette.Highlight, QColor(42, 130, 218))
            dark_palette.setColor(QPalette.HighlightedText, Qt.black)
            self.app.setPalette(dark_palette)
            self.app.setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }")
        elif self.theme == "Пользовательская":
            self.app.setStyle(QStyleFactory.create("Fusion"))
            custom_palette = QPalette()
            custom_palette.setColor(QPalette.Window, QColor(self.custom_color))
            custom_palette.setColor(QPalette.WindowText, Qt.black)
            custom_palette.setColor(QPalette.Base, QColor(self.custom_color).lighter(120))
            custom_palette.setColor(QPalette.AlternateBase, QColor(self.custom_color))
            custom_palette.setColor(QPalette.ToolTipBase, Qt.white)
            custom_palette.setColor(QPalette.ToolTipText, Qt.black)
            custom_palette.setColor(QPalette.Text, Qt.black)
            custom_palette.setColor(QPalette.Button, QColor(self.custom_color))
            custom_palette.setColor(QPalette.ButtonText, Qt.black)
            custom_palette.setColor(QPalette.BrightText, Qt.red)
            custom_palette.setColor(QPalette.Link, QColor(42, 130, 218))
            custom_palette.setColor(QPalette.Highlight, QColor(42, 130, 218))
            custom_palette.setColor(QPalette.HighlightedText, Qt.black)
            self.app.setPalette(custom_palette)
        else:
            self.app.setStyle(QStyleFactory.create("Fusion"))
            self.app.setPalette(self.app.style().standardPalette())

    def open_settings(self):
        dialog = SettingsDialog(self)
        dialog.theme_combo.setCurrentText(self.theme)
        dialog.db_path_edit.setText(self.db_path)
        if dialog.exec():
            self.theme = dialog.theme_combo.currentText()
            self.custom_color = getattr(dialog, 'custom_color', self.custom_color)
            self.db_path = dialog.db_path_edit.text()
            self.settings.setValue("theme", self.theme)
            self.settings.setValue("custom_color", self.custom_color)
            self.settings.setValue("db_path", self.db_path)
            self.apply_theme()
            self.db_conn.close()
            self.db_conn = sqlite3.connect(self.db_path)
            self.create_table()

    def create_table(self):
        cursor = self.db_conn.cursor()
        cursor.execute('''CREATE TABLE IF NOT EXISTS chat_history
                          (id INTEGER PRIMARY KEY AUTOINCREMENT,
                           role TEXT,
                           message TEXT,
                           timestamp DATETIME DEFAULT CURRENT_TIMESTAMP)''')
        self.db_conn.commit()

    def save_message(self, role, message):
        cursor = self.db_conn.cursor()
        cursor.execute("INSERT INTO chat_history (role, message) VALUES (?, ?)", (role, message))
        self.db_conn.commit()

    def process_url(self, url):
        try:
            response = requests.get(url)
            soup = BeautifulSoup(response.text, 'html.parser')
            
            # Извлекаем текст из тегов p, h1, h2, h3, h4, h5, h6
            text = ' '.join([tag.get_text() for tag in soup.find_all(['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'])])
            
            # Ограничиваем длину текста до 2000 символов
            text = text[:2000] + '...' if len(text) > 2000 else text
            
            return f"Содержимое страницы {url}:\n\n{text}"
        except Exception as e:
            return f"Не удалось получить содержимое страницы {url}. Ошибка: {str(e)}"

    def send_message(self):
        user_message = self.input_field.text()
        self.display_message("Вы", user_message)
        self.input_field.clear()
        self.save_message("user", user_message)
        
        # Проверяем, содержит ли сообщение URL
        url_pattern = re.compile(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+')
        urls = url_pattern.findall(user_message)
        
        if urls:
            for url in urls:
                content = self.process_url(url)
                user_message += f"\n\n{content}"
        
        # Добавляем сообщение пользователя в историю
        self.message_history.append({"role": "user", "content": user_message})

        # Разбиваем сообщение на части, если оно слишком длинное
        parts = [user_message[i:i+4000] for i in range(0, len(user_message), 4000)]
        for part in parts:
            self.chat_area.append("<i>AI генерирует ответ...</i>")
            thread = AIResponseThread(self.message_history)  # Передаем всю историю сообщений
            thread.response_ready.connect(self.handle_ai_response)
            self.threads.append(thread)
            thread.start()

    def handle_ai_response(self, ai_response):
        # Удаляем индикатор генерации
        self.chat_area.append("")  # Удаляем последнюю строку, которая содержит индикатор
        if ai_response == "general (unknown) error":
            self.chat_area.append("<b style='color: red;'>AI:</b> general (unknown) error")
        else:
            formatted_response = self.format_response(ai_response)
            self.chat_area.append(f"<b style='color: blue;'>AI:</b> {formatted_response}")
        
        # Добавляем ответ AI в историю
        self.message_history.append({"role": "assistant", "content": ai_response})
        
        self.save_message("ai", ai_response)

    def format_response(self, response):
        # Форматируем ответ для лучшей читаемости
        return "<br>".join(response.split("\n"))

    def display_message(self, sender, message):
        if sender == "Вы":
            self.chat_area.append(f"<b style='color: green;'>{sender}:</b> {message}")
        else:
            # Проверяем, содержит ли сообщение код
            if "```" in message:
                code_blocks = re.findall(r'```(.*?)```', message, re.DOTALL)
                for code in code_blocks:
                    self.chat_area.append(f"<b style='color: orange;'>{sender}:</b> <br><pre>{code}</pre>")
                    self.add_copy_button(code)
            else:
                self.chat_area.append(f"<b style='color: blue;'>{sender}:</b> {message}")

    def add_copy_button(self, code):
        # Создаем виджет для отображения кода и кнопки копирования
        code_widget = QWidget()
        layout = QVBoxLayout(code_widget)
        code_edit = QPlainTextEdit()
        code_edit.setPlainText(code)
        code_edit.setReadOnly(True)
        layout.addWidget(code_edit)

        copy_button = QPushButton("Копировать")
        copy_button.clicked.connect(lambda: self.copy_to_clipboard(code))
        layout.addWidget(copy_button)

        self.chat_area.append(code_widget)

    def copy_to_clipboard(self, text):
        clipboard = QApplication.clipboard()
        clipboard.setText(text)
        self.chat_area.append("Код скопирован в буфер обмена.")

    def execute_action(self, response):
        """
        Функция для выполнения команд, полученных от LLM, связанных с управлением ПК.
        """
        try:
            if "создай файл" in response or "удали файл" in response:
                confirmation = self.confirm_action(response)
                if not confirmation:
                    return "Действие отменено пользователем."
            # Примерные шаблоны команд
            if "создай файл" in response:
                result = self.create_file(response)
            elif "удали файл" in response:
                result = self.delete_file(response)
            elif "запусти процесс" in response:
                result = self.start_process(response)
            elif "прочитай файл" in response:
                result = self.read_file(response)
            elif "покажи рабочий стол" in response:
                result = self.show_desktop()
            else:
                result = "Не удалось распознать команду."
            return result
        except Exception as e:
            return f"Ошибка при выполнении команды: {str(e)}"

    def confirm_action(self, action):
        reply = QMessageBox.question(self, 'Подтверждение действия',
                                     f"Вы уверены, что хотите выполнить действие: {action}?",
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        return reply == QMessageBox.Yes

    def create_file(self, response):
        filename = re.search(r'создай файл (.+)', response)
        if filename:
            filename = filename.group(1).strip()
            if os.path.exists(filename):
                return f"Файл {filename} уже существует."
            with open(filename, 'w') as file:
                file.write("")
            return f"Файл {filename} создан."
        else:
            return "Не удалось распознать имя файла."

    def delete_file(self, response):
        filename = re.search(r'удали файл (.+)', response)
        if filename:
            filename = filename.group(1).strip()
            if not os.path.exists(filename):
                return f"Файл {filename} не найден."
            os.remove(filename)
            return f"Файл {filename} удалён."
        else:
            return "Не удалось распознать имя файла."

    def start_process(self, response):
        process_name = re.search(r'запусти процесс (.+)', response)
        if process_name:
            process_name = process_name.group(1).strip()
            try:
                subprocess.Popen(process_name)
                return f"Процесс {process_name} запущен."
            except FileNotFoundError:
                return f"Процесс {process_name} не найден."
            except Exception as e:
                return f"Ошибка при запуске процесса: {str(e)}"
        else:
            return "Не удалось распознать название процесса."

    def read_file(self, response):
        filename = re.search(r'прочитай файл (.+)', response)
        if filename:
            filename = filename.group(1).strip()
            if os.path.exists(filename):
                with open(filename, 'r') as file:
                    content = file.read()
                return f"Содержимое файла {filename}: {content}"
            else:
                return f"Файл {filename} не найден."
        else:
            return "Не удалось распознать имя файла."

    def show_desktop(self):
        screenshot = pyautogui.screenshot()
        screenshot_path = "screenshot.png"
        screenshot.save(screenshot_path)
        return f"Скриншот рабочего стола сохранён как {screenshot_path}"

    def voice_input(self):
        recognizer = sr.Recognizer()
        # Получаем список доступных микрофонов
        mic_list = sr.Microphone.list_microphone_names()
        if not mic_list:
            self.chat_area.append("Микрофон не найден.")
            return

        # Используем первый доступный микрофон
        mic_index = 0
        self.chat_area.append(f"Используется микрофон: {mic_list[mic_index]}")

        try:
            with sr.Microphone(device_index=mic_index) as source:
                self.chat_area.append("Говорите...")
                audio = recognizer.listen(source)

            user_message = recognizer.recognize_google(audio, language="ru-RU")
            self.chat_area.append(f"Вы (голос): {user_message}")
            self.input_field.setText(user_message)
            self.send_message()
        except sr.UnknownValueError:
            self.chat_area.append("Не удалось распознать речь.")
        except sr.RequestError as e:
            self.chat_area.append(f"Ошибка при распознавании речи: {str(e)}")
        except Exception as e:
            self.chat_area.append(f"Ошибка: {str(e)}")

    def upload_file(self):
        file_dialog = QFileDialog(self)
        file_path, _ = file_dialog.getOpenFileName()
        if file_path:
            self.chat_area.append(f"Загружен файл: {file_path}")

    def closeEvent(self, event):
        for thread in self.threads:
            if thread.isRunning():
                thread.wait()  # Дожидаемся завершения всех потоков перед закрытием
        event.accept()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main_window = ChatWindow(app)
    main_window.show()
    sys.exit(app.exec())

Assistant: