Улучши UI


<!doctype html>
<html lang="ru">
<head>
    <meta charset="utf-8">
    <title>Чат с ИИ</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- Подключаем Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- Подключаем свои стили -->
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background-color: #f0f2f5;
            display: flex;
            flex-direction: column;
            height: 100vh;
            margin: 0;
        }

        .chat-container {
            flex: 1;
            display: flex;
            flex-direction: column;
            max-width: 768px;
            margin: 0 auto;
            width: 100%;
            background-color: #fff;
            border: 1px solid #ddd;
            border-radius: 8px;
            overflow: hidden;
        }

        .chat-header {
            background-color: #4A76A8;
            color: #fff;
            padding: 15px;
            text-align: center;
        }

        #chat {
            flex: 1;
            padding: 20px;
            overflow-y: auto;
            background-color: #f9f9f9;
        }

        .message {
            display: flex;
            margin-bottom: 15px;
            align-items: flex-end;
        }

        .message.user {
            flex-direction: row-reverse;
        }

        .message .avatar {
            width: 40px;
            height: 40px;
            border-radius: 50%;
            background-color: #ddd;
            margin: 0 10px;
        }

        .message-content {
            max-width: 70%;
            padding: 15px;
            border-radius: 15px;
            position: relative;
            word-wrap: break-word;
            font-size: 16px;
            background-color: #e1ffc7;
        }

        .message.ai .message-content {
            background-color: #fff;
        }

        .message.user .message-content {
            background-color: #dcf8c6;
        }

        .chat-form {
            display: flex;
            padding: 10px;
            background-color: #fff;
            border-top: 1px solid #ddd;
        }

        .chat-form textarea {
            flex: 1;
            resize: none;
            border: 1px solid #ccc;
            border-radius: 20px;
            padding: 10px 15px;
            font-size: 16px;
            min-height: 50px;
            margin-right: 10px;
            outline: none;
        }

        .chat-form button {
            padding: 10px 20px;
            font-size: 16px;
            border: none;
            background-color: #4A76A8;
            color: #fff;
            cursor: pointer;
            border-radius: 20px;
            transition: background-color 0.3s;
        }

        .chat-form button:hover {
            background-color: #3b5a76;
        }

        .reset-button {
            text-align: center;
            padding: 10px;
            background-color: #fff;
            border-top: 1px solid #ddd;
        }

        .reset-button button {
            padding: 10px 20px;
            font-size: 16px;
            border: none;
            background-color: #f44336;
            color: #fff;
            cursor: pointer;
            border-radius: 20px;
            transition: background-color 0.3s;
        }

        .reset-button button:hover {
            background-color: #da190b;
        }

        /* Стили для спиннера */
        .spinner {
            display: none;
            margin: 20px auto;
            width: 50px;
            height: 50px;
            border: 5px solid rgba(0,0,0,0.1);
            border-top: 5px solid #4A76A8;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            to { transform: rotate(360deg); }
        }

        /* Блокировка кнопок */
        .disabled {
            opacity: 0.6;
            pointer-events: none;
        }

        /* Стили для кода */
        pre {
            background-color: #f5f5f5;
            padding: 15px;
            border-radius: 5px;
            overflow-x: auto;
            max-width: 100%;
        }

        code {
            font-family: Consolas, monospace;
            font-size: 16px;
            word-wrap: break-word;
        }

        /* Пользовательские скроллбары */
        ::-webkit-scrollbar {
            width: 8px;
        }

        ::-webkit-scrollbar-track {
            background: #f0f2f5;
        }

        ::-webkit-scrollbar-thumb {
            background-color: #c1c1c1;
            border-radius: 4px;
        }

        /* Адаптивность для мобильных устройств */
        @media (max-width: 600px) {
            .message-content {
                max-width: 100%;
            }

            .chat-form textarea {
                font-size: 14px;
            }

            .chat-form button {
                font-size: 14px;
                padding: 10px;
            }

            .reset-button button {
                font-size: 14px;
                padding: 10px;
            }
        }
    </style>
    <!-- Подключаем CSS для подсветки синтаксиса -->
    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.0/styles/github.min.css">
    <!-- Подключаем библиотеку Highlight.js -->
    <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.0/highlight.min.js"></script>
</head>
<body>
    <div class="chat-container">
        <div class="chat-header">
            <h1>Чат с ИИ</h1>
        </div>
        <div id="chat">
            <!-- Здесь будут отображаться сообщения -->
        </div>
        <!-- Спиннер загрузки -->
        <div id="spinner" class="spinner"></div>
        <form class="chat-form" id="chat-form">
            <textarea id="message-input" placeholder="Введите сообщение" autofocus required></textarea>
            <button type="submit" id="send-btn">➤</button>
        </form>
        <div class="reset-button">
            <button type="button" id="reset-btn">Очистить чат</button>
        </div>
    </div>

    <!-- Подключаем Bootstrap JS и зависимости -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        let chatCounter = 0;
        let chatbot = [];

        const chatContainer = document.getElementById('chat');
        const spinner = document.getElementById('spinner');
        const sendBtn = document.getElementById('send-btn');
        const resetBtn = document.getElementById('reset-btn');
        const messageInput = document.getElementById('message-input');

        // Загрузка истории чата из localStorage
        if (localStorage.getItem('chatHistory')) {
            chatContainer.innerHTML = localStorage.getItem('chatHistory');
            chatCounter = parseInt(localStorage.getItem('chatCounter')) || 0;
            chatbot = JSON.parse(localStorage.getItem('chatbot')) || [];
            // Инициализируем подсветку в загруженных сообщениях
            hljs.highlightAll();
            // Прокручиваем чат вниз при загрузке
            chatContainer.scrollTop = chatContainer.scrollHeight;
        }

        document.getElementById('chat-form').addEventListener('submit', function (event) {
            event.preventDefault();
            const userMessage = messageInput.value.trim();
            if (userMessage === '') return;

            // Отображаем сообщение пользователя
            addMessage('user', userMessage);
            messageInput.value = '';

            // Показываем спиннер и блокируем кнопки
            toggleLoadingState(true);

            // Отправляем сообщение на сервер
            fetch('/chat', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    message: userMessage,
                    chat_counter: chatCounter,
                    chatbot: chatbot
                }),
            })
                .then(response => response.json())
                .then(data => {
                    // Скрываем спиннер и разблокируем кнопки
                    toggleLoadingState(false);

                    // Отображаем ответ ИИ
                    addMessage('ai', data.response);

                    // Обновляем chatCounter и chatbot
                    chatCounter = data.chat_counter;
                    chatbot = data.chatbot;

                    // Сохраняем историю чата и состояние в localStorage
                    localStorage.setItem('chatHistory', chatContainer.innerHTML);
                    localStorage.setItem('chatCounter', chatCounter);
                    localStorage.setItem('chatbot', JSON.stringify(chatbot));

                    // Инициализируем подсветку в новых сообщениях
                    hljs.highlightAll();
                })
                .catch((error) => {
                    console.error('Ошибка:', error);
                    // Скрываем спиннер и разблокируем кнопки в случае ошибки
                    toggleLoadingState(false);
                });
        });

        resetBtn.addEventListener('click', function () {
            // Показываем спиннер и блокируем кнопки
            toggleLoadingState(true);

            // Отправляем запрос на сброс состояния на сервер
            fetch('/reset', {
                method: 'POST',
            })
                .then(response => response.json())
                .then(data => {
                    // Скрываем спиннер и разблокируем кнопки
                    toggleLoadingState(false);

                    // Очищаем историю чата и состояние
                    chatContainer.innerHTML = '';
                    chatCounter = 0;
                    chatbot = [];

                    // Удаляем данные из localStorage
                    localStorage.removeItem('chatHistory');
                    localStorage.removeItem('chatCounter');
                    localStorage.removeItem('chatbot');
                })
                .catch((error) => {
                    console.error('Ошибка:', error);
                    // Скрываем спиннер и разблокируем кнопки в случае ошибки
                    toggleLoadingState(false);
                });
        });

        function addMessage(sender, text) {
            const messageDiv = document.createElement('div');
            messageDiv.classList.add('message', sender);

            const avatarDiv = document.createElement('div');
            avatarDiv.classList.add('avatar');

            const messageContent = document.createElement('div');
            messageContent.classList.add('message-content');

            // Обработка текста как HTML
            messageContent.innerHTML = text;

            messageDiv.appendChild(avatarDiv);
            messageDiv.appendChild(messageContent);

            chatContainer.appendChild(messageDiv);

            // Инициализируем подсветку синтаксиса в новом сообщении
            hljs.highlightAll();

            // Прокручиваем чат вниз
            chatContainer.scrollTop = chatContainer.scrollHeight;

            // Сохраняем историю чата в localStorage
            localStorage.setItem('chatHistory', chatContainer.innerHTML);
        }

        function toggleLoadingState(isLoading) {
            if (isLoading) {
                spinner.style.display = 'block';
                sendBtn.classList.add('disabled');
                resetBtn.classList.add('disabled');
                sendBtn.disabled = true;
                resetBtn.disabled = true;
                messageInput.disabled = true;
            } else {
                spinner.style.display = 'none';
                sendBtn.classList.remove('disabled');
                resetBtn.classList.remove('disabled');
                sendBtn.disabled = false;
                resetBtn.disabled = false;
                messageInput.disabled = false;
                messageInput.focus();
            }
        }

        // Автофокус на поле ввода при загрузке страницы
        window.onload = function() {
            messageInput.focus();
        };
    </script>
</body>
</html>