Исправь ошибки:
[{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "W0612:unused-variable",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/warning/unused-variable.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 4,
	"message": "Unused variable 'new_chat_counter'",
	"source": "Pylint",
	"startLineNumber": 78,
	"startColumn": 30,
	"endLineNumber": 78,
	"endColumn": 46
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "W0612:unused-variable",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/warning/unused-variable.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 4,
	"message": "Unused variable 'status_code'",
	"source": "Pylint",
	"startLineNumber": 78,
	"startColumn": 48,
	"endLineNumber": 78,
	"endColumn": 59
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "W0612:unused-variable",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/warning/unused-variable.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 4,
	"message": "Unused variable 'reset_text'",
	"source": "Pylint",
	"startLineNumber": 78,
	"startColumn": 61,
	"endLineNumber": 78,
	"endColumn": 71
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "W0718:broad-exception-caught",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/warning/broad-exception-caught.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 4,
	"message": "Catching too general exception Exception",
	"source": "Pylint",
	"startLineNumber": 94,
	"startColumn": 16,
	"endLineNumber": 94,
	"endColumn": 25
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "W0718:broad-exception-caught",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/warning/broad-exception-caught.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 4,
	"message": "Catching too general exception Exception",
	"source": "Pylint",
	"startLineNumber": 130,
	"startColumn": 20,
	"endLineNumber": 130,
	"endColumn": 29
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "W0201:attribute-defined-outside-init",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/warning/attribute-defined-outside-init.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 4,
	"message": "Attribute 'thread' defined outside __init__",
	"source": "Pylint",
	"startLineNumber": 407,
	"startColumn": 9,
	"endLineNumber": 407,
	"endColumn": 20
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "W0201:attribute-defined-outside-init",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/warning/attribute-defined-outside-init.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 4,
	"message": "Attribute 'worker' defined outside __init__",
	"source": "Pylint",
	"startLineNumber": 408,
	"startColumn": 9,
	"endLineNumber": 408,
	"endColumn": 20
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "W0612:unused-variable",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/warning/unused-variable.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 4,
	"message": "Unused variable 'translator'",
	"source": "Pylint",
	"startLineNumber": 690,
	"startColumn": 5,
	"endLineNumber": 690,
	"endColumn": 15
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "C0114:missing-module-docstring",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/convention/missing-module-docstring.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 2,
	"message": "Missing module docstring",
	"source": "Pylint",
	"startLineNumber": 1,
	"startColumn": 1,
	"endLineNumber": 1,
	"endColumn": 1
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "C0411:wrong-import-order",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/convention/wrong-import-order.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 2,
	"message": "standard import \"import errno\" should be placed before \"import requests\"",
	"source": "Pylint",
	"startLineNumber": 6,
	"startColumn": 1,
	"endLineNumber": 6,
	"endColumn": 13
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "C0116:missing-function-docstring",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/convention/missing-function-docstring.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 2,
	"message": "Missing function or method docstring",
	"source": "Pylint",
	"startLineNumber": 64,
	"startColumn": 5,
	"endLineNumber": 64,
	"endColumn": 12
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "C0301:line-too-long",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/convention/line-too-long.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 2,
	"message": "Line too long (137/100)",
	"source": "Pylint",
	"startLineNumber": 367,
	"startColumn": 1,
	"endLineNumber": 367,
	"endColumn": 1
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "C0415:import-outside-toplevel",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/convention/import-outside-toplevel.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 2,
	"message": "Import outside toplevel (html)",
	"source": "Pylint",
	"startLineNumber": 375,
	"startColumn": 9,
	"endLineNumber": 375,
	"endColumn": 20
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "C0301:line-too-long",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/convention/line-too-long.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 2,
	"message": "Line too long (122/100)",
	"source": "Pylint",
	"startLineNumber": 476,
	"startColumn": 1,
	"endLineNumber": 476,
	"endColumn": 1
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "C0301:line-too-long",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/convention/line-too-long.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 2,
	"message": "Line too long (106/100)",
	"source": "Pylint",
	"startLineNumber": 505,
	"startColumn": 1,
	"endLineNumber": 505,
	"endColumn": 1
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "C0301:line-too-long",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/convention/line-too-long.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 2,
	"message": "Line too long (120/100)",
	"source": "Pylint",
	"startLineNumber": 511,
	"startColumn": 1,
	"endLineNumber": 511,
	"endColumn": 1
},{
	"resource": "/C:/Users/Admin/Desktop/Casino AI/ddd.py",
	"owner": "_generated_diagnostic_collection_name_#2",
	"code": {
		"value": "C0304:missing-final-newline",
		"target": {
			"$mid": 1,
			"path": "/en/latest/user_guide/messages/convention/missing-final-newline.html",
			"scheme": "https",
			"authority": "pylint.readthedocs.io"
		}
	},
	"severity": 2,
	"message": "Final newline missing",
	"source": "Pylint",
	"startLineNumber": 701,
	"startColumn": 1,
	"endLineNumber": 701,
	"endColumn": 1
}]
```python
import sys
import os
import re
import json
import requests
import errno

from PyQt5.QtWidgets import (
    QApplication, QFontComboBox, QMainWindow, QWidget, QVBoxLayout,
    QHBoxLayout, QTextEdit, QPushButton, QLabel, QFileDialog,
    QMessageBox, QDialog, QScrollArea, QFrame, QAction, QInputDialog,
    QColorDialog, QFontDialog, QComboBox
)
from PyQt5.QtCore import Qt, QObject, pyqtSignal, QThread, QEvent, QTranslator
from PyQt5.QtGui import QFont, QIcon, QTextCursor
from PyQt5.QtPrintSupport import QPrinter

from gradio_client import Client
from pygments import highlight
from pygments.lexers import (
    PythonLexer, JavascriptLexer, JsonLexer, TextLexer
)
from pygments.formatters import HtmlFormatter

# Инициализация клиента для API
CLIENT = Client("yuntian-deng/o1mini")

# Карта поддерживаемых лексеров для подсветки синтаксиса
LEXER_MAP = {
    'python': PythonLexer(),
    'javascript': JavascriptLexer(),
    'json': JsonLexer(),
    # Добавьте другие языки здесь
}

# Компилированный паттерн для поиска блоков кода
CODE_PATTERN = re.compile(r'```(\w+)?\n(.*?)```', re.DOTALL)


def highlight_code(text, language='python'):
    """
    Подсвечивает синтаксис кода.
    Поддерживаемые языки можно расширять, добавляя их в LEXER_MAP.
    """
    lexer = LEXER_MAP.get(language.lower(), TextLexer())
    formatter = HtmlFormatter(style="friendly")
    highlighted = highlight(text, lexer, formatter)
    return highlighted


class Worker(QObject):
    """
    Рабочий объект для выполнения API-запросов в отдельном потоке.
    """
    finished = pyqtSignal(str)
    error = pyqtSignal(str)

    def __init__(self, message, chat_history, chat_counter):
        super().__init__()
        self.message = message
        self.chat_history = chat_history
        self.chat_counter = chat_counter

    def run(self):
        try:
            result = CLIENT.predict(
                inputs=self.message,
                top_p=1,
                temperature=1,
                chat_counter=self.chat_counter,
                chatbot=self.chat_history,
                api_name="/predict"
            )

            if len(result) < 4:
                raise ValueError("Некорректный формат ответа от API.")

            chatbot_history, new_chat_counter, status_code, reset_text = result

            if not isinstance(chatbot_history, (list, tuple)):
                raise TypeError("chatbot_history должно быть списком или кортежем.")

            if len(chatbot_history) == 0:
                chatbot_response = "Нет ответа от бота."
            else:
                latest_entry = chatbot_history[-1]
                if isinstance(latest_entry, (list, tuple)) and len(latest_entry) == 2:
                    chatbot_response = latest_entry[1]
                else:
                    chatbot_response = "Не удалось получить ответ бота."

            self.finished.emit(chatbot_response)

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


class ChatBot(QMainWindow):
    """
    Главный класс приложения чат-бота.
    """
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Чат-бот на основе API `yuntian-deng/o1mini`")
        self.setGeometry(100, 100, 900, 700)

        self.chat_history = []
        self.chat_counter = 0

        # Инициализация настроек
        self.settings = {}
        self.current_language = 'ru'

        # Загрузка настроек
        self.load_settings()

        # Инициализация пользовательского интерфейса
        self.init_ui()

    def load_settings(self):
        """
        Загружает настройки из файла конфигурации.
        """
        self.config_path = 'config.json'
        if os.path.exists(self.config_path):
            try:
                with open(self.config_path, 'r', encoding='utf-8') as f:
                    self.settings = json.load(f)
                    self.current_language = self.settings.get('language', 'ru')
            except Exception as e:
                QMessageBox.warning(self, self.tr("Ошибка"), self.tr(
                    f"Не удалось загрузить настройки:\n{e}"))
                self.settings = {}
        else:
            self.settings = {}

    def save_settings(self):
        """
        Сохраняет текущие настройки в файл конфигурации.
        """
        try:
            with open(self.config_path, 'w', encoding='utf-8') as f:
                json.dump(self.settings, f, ensure_ascii=False, indent=4)
        except OSError as e:
            QMessageBox.warning(self, self.tr("Ошибка"), self.tr(
                f"Не удалось сохранить настройки:\n{e.strerror}"))

    def init_ui(self):
        """
        Инициализирует пользовательский интерфейс.
        """
        # Создаём центральный виджет и устанавливаем его
        central_widget = QWidget()
        self.setCentralWidget(central_widget)

        main_layout = QVBoxLayout(central_widget)

        # Меню
        self.create_menu()

        # Заголовок
        title = QLabel(self.tr("Чат-бот на основе API `yuntian-deng/o1mini`"))
        title.setFont(QFont("Arial", 20))
        title.setAlignment(Qt.AlignCenter)
        main_layout.addWidget(title)

        # Область чата с прокруткой
        self.chat_area = QTextEdit()
        self.chat_area.setReadOnly(True)
        self.chat_area.setFont(QFont("Arial", 12))
        # Применение сохранённого цвета фона, если есть
        bg_color = self.settings.get('chat_bg_color', '#f9f9f9')
        self.chat_area.setStyleSheet(f"""
            QTextEdit {{
                background-color: {bg_color};
                border: 1px solid #ccc;
                border-radius: 5px;
                padding: 10px;
            }}
        """)

        scroll = QScrollArea()
        scroll.setWidgetResizable(True)
        scroll.setWidget(self.chat_area)
        scroll.setFrameStyle(QFrame.NoFrame)
        main_layout.addWidget(scroll)

        # Поле ввода сообщения и подсчёт символов и токенов
        input_container = QWidget()
        input_layout = QVBoxLayout()

        self.input_field = QTextEdit()
        self.input_field.setPlaceholderText(
            self.tr("Введите сообщение и нажмите Enter"))
        self.input_field.setFixedHeight(100)
        self.input_field.setFont(QFont("Arial", 12))
        self.input_field.setStyleSheet("""
            QTextEdit {
                padding: 8px;
                border: 1px solid #ccc;
                border-radius: 5px;
            }
        """)
        self.input_field.installEventFilter(self)
        input_layout.addWidget(self.input_field)

        counters_layout = QHBoxLayout()
        self.char_count_label = QLabel(self.tr("Символы: 0"))
        self.token_count_label = QLabel(self.tr("Токены: 0"))
        counters_layout.addWidget(self.char_count_label)
        counters_layout.addWidget(self.token_count_label)
        counters_layout.addStretch()
        input_layout.addLayout(counters_layout)

        input_container.setLayout(input_layout)
        main_layout.addWidget(input_container)

        # Кнопка отправки и индикатор статуса
        send_layout = QHBoxLayout()
        self.send_button = QPushButton(self.tr("Отправить"))
        self.send_button.setIcon(QIcon.fromTheme("send"))
        self.send_button.clicked.connect(self.send_message)
        send_layout.addWidget(self.send_button)

        self.status_label = QLabel("")
        self.status_label.setStyleSheet("color: green;")
        send_layout.addWidget(self.status_label)
        send_layout.addStretch()
        main_layout.addLayout(send_layout)

        # Кнопки дополнительных функций
        func_layout = QHBoxLayout()

        self.reset_btn = QPushButton(self.tr("Сбросить чат"))
        self.reset_btn.setIcon(QIcon.fromTheme("edit-clear"))
        self.reset_btn.clicked.connect(self.reset_chat)
        func_layout.addWidget(self.reset_btn)

        self.export_btn = QPushButton(self.tr("Экспортировать чат"))
        self.export_btn.setIcon(QIcon.fromTheme("document-save"))
        self.export_btn.clicked.connect(self.export_chat)
        func_layout.addWidget(self.export_btn)

        self.pdf_export_btn = QPushButton(self.tr("Экспортировать в PDF"))
        self.pdf_export_btn.setIcon(QIcon.fromTheme("document-print"))
        self.pdf_export_btn.clicked.connect(self.export_chat_to_pdf)
        func_layout.addWidget(self.pdf_export_btn)

        self.fact_btn = QPushButton(self.tr("Случайный факт"))
        self.fact_btn.setIcon(QIcon.fromTheme("information"))
        self.fact_btn.clicked.connect(self.get_random_fact)
        func_layout.addWidget(self.fact_btn)

        main_layout.addLayout(func_layout)

        # Информация о ошибках
        self.info_label = QLabel("")
        self.info_label.setStyleSheet("color: red;")
        main_layout.addWidget(self.info_label)

        # Применение стилей
        self.setStyleSheet("""
            QWidget {
                background-color: #e6e6e6;
            }
            QPushButton {
                padding: 8px 16px;
                border: none;
                background-color: #4CAF50;
                color: white;
                border-radius: 5px;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
            QLabel {
                font-size: 12px;
            }
        """)

    def create_menu(self):
        """
        Создаёт меню для настроек и локализации.
        """
        # Настройки
        settings_menu = self.menuBar().addMenu(self.tr('Настройки'))
        settings_action = QAction(self.tr("Настройки"), self)
        settings_action.triggered.connect(self.open_settings)
        settings_menu.addAction(settings_action)

        # Язык интерфейса
        language_menu = self.menuBar().addMenu(self.tr('Язык'))
        language_action = QAction(self.tr("Сменить язык"), self)
        language_action.triggered.connect(self.change_language)
        language_menu.addAction(language_action)

    def change_language(self):
        """
        Меняет язык интерфейса.
        """
        languages = {
            'Русский': 'ru',
            'English': 'en'
        }
        lang, ok = QInputDialog.getItem(self, self.tr("Выберите язык"), self.tr(
            "Язык:"), list(languages.keys()), 0, False)
        if ok and lang:
            self.current_language = languages[lang]
            self.settings['language'] = self.current_language
            self.save_settings()
            QMessageBox.information(self, self.tr("Перезагрузка"), self.tr(
                "Изменения вступят в силу после перезагрузки приложения."))
            # Для полной смены языка необходимо перезапустить приложение

    def append_message(self, sender, message):
        """
        Добавляет сообщение в чат. Обрабатывает текст и блоки кода.
        """
        parts = CODE_PATTERN.split(message)

        # Проход по частям сообщения
        for i in range(0, len(parts), 3):
            text = parts[i].strip()
            if text:
                formatted_text = self.format_text(sender, text)
                self.chat_area.append(formatted_text)

            # Проверяем наличие блока кода
            if i + 2 < len(parts):
                language = parts[i + 1] if parts[i + 1] else 'python'
                code = parts[i + 2].strip()
                highlighted_code = highlight_code(code, language)
                formatted_code = f"""
                <div style="background-color:#f4f4f4; padding:10px; border-radius:5px; position:relative;">
                    {highlighted_code}
                    <button onclick="copyToClipboard(this)" style="position:absolute; top:5px; right:5px; padding:2px 5px; font-size:10px;">{self.tr('Копировать')}</button>
                </div>
                <script>
                function copyToClipboard(button) {{
                    var code = button.parentElement.querySelector('pre').innerText;
                    navigator.clipboard.writeText(code).then(function() {{
                        button.textContent = '{self.tr('Скопировано!')}';
                        setTimeout(function() {{
                            button.textContent = '{self.tr('Копировать')}';
                        }}, 2000);
                    }}, function(err) {{
                        alert('{self.tr('Не удалось скопировать код')}');
                    }});
                }}
                </script>
                """
                self.chat_area.append(formatted_code)

        self.chat_area.moveCursor(QTextCursor.End)

    def format_text(self, sender, text):
        """
        Форматирует текстовое сообщение.
        """
        if sender == self.tr("Вы"):
            align = 'right'
            color = '#0084ff'  # Синий для пользователя
        else:
            align = 'left'
            color = '#333333'  # Тёмно-серый для бота

        formatted = f"<p style='text-align: {align};'><span style='color: {color};'><b>{sender}:</b> {self.escape_html(text)}</span></p>"
        return formatted

    @staticmethod
    def escape_html(text):
        """
        Экранирует специальные HTML символы для предотвращения XSS атак.
        """
        import html
        return html.escape(text)

    def update_counters(self):
        """
        Обновляет подсчёт символов и токенов.
        """
        text = self.input_field.toPlainText()
        char_count = len(text)
        token_count = char_count // 4  # Примерное соотношение символов к токенам
        self.char_count_label.setText(self.tr(f"Символы: {char_count}"))
        self.token_count_label.setText(self.tr(f"Токены: {token_count}"))

    def send_message(self):
        """
        Обрабатывает отправку сообщения.
        """
        user_message = self.input_field.toPlainText().strip()
        if not user_message:
            return

        self.append_message(self.tr("Вы"), user_message)
        self.chat_history.append((user_message, ""))
        self.input_field.clear()
        self.update_counters()

        # Показываем статус "Бот набирает..."
        self.status_label.setText(self.tr("Бот набирает ответ..."))
        self.send_button.setEnabled(False)
        QApplication.processEvents()

        # Запускаем рабочий поток для асинхронного запроса
        self.thread = QThread()
        self.worker = Worker(
            user_message, self.chat_history, self.chat_counter)
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.run)
        self.worker.finished.connect(self.handle_response)
        self.worker.error.connect(self.handle_error)
        self.worker.finished.connect(self.thread.quit)
        self.worker.finished.connect(self.worker.deleteLater)
        self.thread.finished.connect(self.thread.deleteLater)
        self.thread.start()

    def handle_response(self, response):
        """
        Обрабатывает ответ от бота.
        """
        self.status_label.setText("")
        self.send_button.setEnabled(True)
        self.chat_counter += 1
        self.chat_history[-1] = (self.chat_history[-1][0], response)
        self.append_message(self.tr("Бот"), response)

    def handle_error(self, error_message):
        """
        Обрабатывает ошибку при запросе.
        """
        self.status_label.setText("")
        self.send_button.setEnabled(True)
        QMessageBox.critical(self, self.tr("Ошибка"), self.tr(
            f"Не удалось отправить сообщение:\n{error_message}"))

    def reset_chat(self):
        """
        Сбрасывает историю чата.
        """
        confirmation = QMessageBox.question(
            self, self.tr("Сбросить чат"),
            self.tr("Вы уверены, что хотите сбросить историю чата?"),
            QMessageBox.Yes | QMessageBox.No
        )
        if confirmation == QMessageBox.Yes:
            self.chat_history = []
            self.chat_counter = 0
            self.chat_area.clear()
            QMessageBox.information(self, self.tr(
                "Чат сброшен"), self.tr("История чата была сброшена."))

    def export_chat(self):
        """
        Экспортирует историю чата в файл HTML или TXT.
        """
        if not self.chat_history:
            QMessageBox.warning(self, self.tr("Экспорт"), self.tr(
                "Нет истории чата для экспорта."))
            return

        options = QFileDialog.Options()
        file_path, _ = QFileDialog.getSaveFileName(
            self, self.tr("Сохранить чат"), "",
            self.tr("HTML файлы (*.html);;Текстовые файлы (*.txt)"), options=options
        )
        if file_path:
            try:
                if file_path.endswith('.html'):
                    with open(file_path, "w", encoding="utf-8") as file:
                        file.write(
                            "<html><head><meta charset='UTF-8'><title>Чат</title></head><body>")
                        for user_msg, bot_msg in self.chat_history:
                            file.write(
                                f"<p style='text-align: right;'><b>{self.tr('Вы')}:</b> {self.escape_html(user_msg)}</p>")
                            self.export_bot_message(file, bot_msg)
                        file.write("</body></html>")
                else:
                    with open(file_path, "w", encoding="utf-8") as file:
                        for user_msg, bot_msg in self.chat_history:
                            file.write(
                                f"{self.tr('Вы')}: {user_msg}\n{self.tr('Бот')}: {bot_msg}\n\n")
                QMessageBox.information(self, self.tr("Экспорт"), self.tr(
                    f"Чат успешно сохранен в {file_path}"))
            except OSError as e:
                if e.errno == errno.EACCES:
                    error_message = "Доступ запрещен."
                elif e.errno == errno.ENOENT:
                    error_message = "Файл или директория не найдены."
                else:
                    error_message = e.strerror
                QMessageBox.critical(self, self.tr("Ошибка"), self.tr(
                    f"Не удалось сохранить чат:\n{error_message}"))

    def export_bot_message(self, file, bot_msg):
        """
        Экспортирует сообщение бота в HTML файл, обрабатывая блоки кода.
        """
        parts = CODE_PATTERN.split(bot_msg)
        for i in range(0, len(parts), 3):
            text = parts[i].strip()
            if text:
                file.write(
                    f"<p style='text-align: left;'><b>{self.tr('Бот')}:</b> {self.escape_html(text)}</p>")
            if i + 2 < len(parts):
                language = parts[i + 1] if parts[i + 1] else 'python'
                code = parts[i + 2].strip()
                highlighted_code = highlight_code(code, language)
                file.write(
                    f"<pre style='background-color:#f4f4f4; padding:10px; border-radius:5px;'>{highlighted_code}</pre>")

    def export_chat_to_pdf(self):
        """
        Экспортирует историю чата в PDF с сохранением форматирования и подсветки кода.
        """
        if not self.chat_history:
            QMessageBox.warning(self, self.tr("Экспорт PDF"), self.tr(
                "Нет истории чата для экспорта."))
            return

        options = QFileDialog.Options()
        file_path, _ = QFileDialog.getSaveFileName(
            self, self.tr("Сохранить чат в PDF"), "",
            self.tr("PDF файлы (*.pdf)"), options=options
        )
        if file_path:
            try:
                printer = QPrinter(QPrinter.HighResolution)
                printer.setOutputFormat(QPrinter.PdfFormat)
                printer.setOutputFileName(file_path)
                self.chat_area.document().print_(printer)
                QMessageBox.information(self, self.tr("Экспорт PDF"), self.tr(
                    f"Чат успешно сохранен в {file_path}"))
            except OSError as e:
                error_message = e.strerror
                QMessageBox.critical(self, self.tr("Ошибка"), self.tr(
                    f"Не удалось сохранить PDF:\n{error_message}"))

    def get_random_fact(self):
        """
        Получает случайный факт и добавляет его в чат.
        """
        try:
            response = requests.get(
                "https://uselessfacts.jsph.pl/random.json?language=ru", timeout=5)
            if response.status_code == 200:
                fact = response.json().get("text", self.tr("Не удалось получить факт."))
            else:
                fact = self.tr("Ошибка при получении факта.")
        except requests.RequestException as e:
            fact = self.tr(f"Ошибка при получении факта: {e}")

        self.append_message(self.tr("Бот"), fact)

    def eventFilter(self, obj, event):  # pylint: disable=invalid-name
        """
        Обрабатывает события для поля ввода сообщения.
        Позволяет использовать Shift + Enter для вставки новой строки.
        """
        if obj == self.input_field:
            if event.type() == QEvent.KeyPress:
                if event.key() in (Qt.Key_Return, Qt.Key_Enter):
                    if event.modifiers() == Qt.ShiftModifier:
                        cursor = self.input_field.textCursor()
                        cursor.insertBlock()
                        return True
                    else:
                        self.send_message()
                        return True
        return super().eventFilter(obj, event)

    def open_settings(self):
        """
        Открывает диалог настроек.
        """
        settings_dialog = SettingsDialog(self)
        if settings_dialog.exec_():
            # Применение сохранённых настроек
            bg_color = self.settings.get('chat_bg_color', '#f9f9f9')
            self.chat_area.setStyleSheet(f"""
                QTextEdit {{
                    background-color: {bg_color};
                    border: 1px solid #ccc;
                    border-radius: 5px;
                    padding: 10px;
                }}
            """)
            font = self.settings.get('chat_font', "Arial")
            font_size = self.settings.get('chat_font_size', 12)
            self.chat_area.setFont(QFont(font, font_size))
            self.save_settings()


class SettingsDialog(QDialog):
    """
    Диалоговое окно настроек.
    """
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle(self.tr("Настройки"))
        self.setFixedSize(400, 300)
        self.parent = parent
        self.init_ui()

    def init_ui(self):
        """
        Инициализирует интерфейс диалога настроек.
        """
        layout = QVBoxLayout()

        # Выбор цвета чата
        color_btn = QPushButton(self.tr("Выбрать цвет фона чата"))
        color_btn.clicked.connect(self.choose_color)
        layout.addWidget(color_btn)

        # Выбор шрифта
        font_btn = QPushButton(self.tr("Выбрать шрифт чата"))
        font_btn.clicked.connect(self.choose_font)
        layout.addWidget(font_btn)

        # Дополнительные настройки
        font_label = QLabel(self.tr("Шрифт:"))
        layout.addWidget(font_label)

        self.font_combo = QFontComboBox()
        current_font = self.parent.settings.get('chat_font', "Arial")
        self.font_combo.setCurrentFont(QFont(current_font))
        layout.addWidget(self.font_combo)

        size_label = QLabel(self.tr("Размер шрифта:"))
        layout.addWidget(size_label)

        self.size_combo = QComboBox()
        self.size_combo.addItems([str(size) for size in range(8, 30, 2)])
        current_size = str(self.parent.settings.get('chat_font_size', 12))
        index = self.size_combo.findText(current_size)
        if index >= 0:
            self.size_combo.setCurrentIndex(index)
        layout.addWidget(self.size_combo)

        # Кнопки OK и Отмена
        btn_layout = QHBoxLayout()
        ok_btn = QPushButton(self.tr("OK"))
        ok_btn.clicked.connect(self.accept)
        cancel_btn = QPushButton(self.tr("Отмена"))
        cancel_btn.clicked.connect(self.reject)
        btn_layout.addWidget(ok_btn)
        btn_layout.addWidget(cancel_btn)
        layout.addLayout(btn_layout)

        self.setLayout(layout)

    def choose_color(self):
        """
        Открывает диалог выбора цвета для фона чата.
        """
        color = QColorDialog.getColor()
        if color.isValid():
            self.parent.settings['chat_bg_color'] = color.name()

    def choose_font(self):
        """
        Открывает диалог выбора шрифта для чата.
        """
        font, ok = QFontDialog.getFont()
        if ok:
            self.parent.settings['chat_font'] = font.family()
            self.parent.settings['chat_font_size'] = font.pointSize()

    def accept(self):
        """
        Сохранение выбранных настроек и закрытие диалога.
        """
        # Сохранение выбранных шрифта и размера
        selected_font = self.font_combo.currentFont().family()
        selected_size = int(self.size_combo.currentText())
        self.parent.settings['chat_font'] = selected_font
        self.parent.settings['chat_font_size'] = selected_size
        super().accept()


def main():
    """
    Главная функция приложения.
    """
    app = QApplication(sys.argv)

    # Установка переводов (для полноценной локализации необходимо создать и подключить .qm файлы)
    translator = QTranslator()
    # Предполагается наличие файлов перевода, например, translations_ru.qm
    # if translator.load(f"translations_{self.current_language}.qm"):
    #     app.installTranslator(translator)

    chatbot = ChatBot()
    chatbot.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
```