document.addEventListener('DOMContentLoaded', function() { // Элементы DOM const userInput = document.getElementById('user-input'); const sendBtn = document.getElementById('send-btn'); const messagesContainer = document.getElementById('messages'); const chatContainer = document.getElementById('chat-container'); const welcomeScreen = document.getElementById('welcome-screen'); const newChatBtn = document.getElementById('new-chat'); const chatHistory = document.getElementById('chat-history'); const toggleModeBtn = document.getElementById('toggle-mode'); const examples = document.querySelectorAll('.example'); // Состояние приложения let currentChatId = generateId(); let chats = {}; let isWaitingForResponse = false; // Инициализация initTheme(); loadChats(); // Обработчики событий sendBtn.addEventListener('click', sendMessage); userInput.addEventListener('keydown', handleKeyDown); newChatBtn.addEventListener('click', createNewChat); toggleModeBtn.addEventListener('click', toggleDarkMode); // Обработка примеров запросов examples.forEach(example => { example.addEventListener('click', () => { const prompt = example.getAttribute('data-prompt'); if (prompt) { hideWelcomeScreen(); userInput.value = prompt; sendMessage(); } }); }); // Автоматическое изменение высоты текстового поля userInput.addEventListener('input', function() { this.style.height = 'auto'; this.style.height = (this.scrollHeight) + 'px'; // Активация/деактивация кнопки отправки sendBtn.disabled = this.value.trim() === '' || isWaitingForResponse; }); // Функции function sendMessage() { const message = userInput.value.trim(); if (message === '' || isWaitingForResponse) return; // Добавляем сообщение пользователя addMessage('user', message); // Очищаем ввод userInput.value = ''; userInput.style.height = 'auto'; sendBtn.disabled = true; // Показываем индикатор набора текста showTypingIndicator(); // Устанавливаем флаг ожидания ответа isWaitingForResponse = true; // Сохраняем чат saveChat(message); // Отправляем запрос на сервер fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: message }) }) .then(response => response.json()) .then(data => { // Удаляем индикатор набора текста removeTypingIndicator(); // Добавляем ответ от AI if (data.error) { addMessage('ai', `Ошибка: ${data.error}`); } else { addMessage('ai', data.response); } // Сохраняем ответ в чат saveChat(null, data.response || `Ошибка: ${data.error}`); // Сбрасываем флаг ожидания ответа isWaitingForResponse = false; // Активируем кнопку отправки, если есть текст sendBtn.disabled = userInput.value.trim() === ''; }) .catch(error => { console.error('Ошибка:', error); removeTypingIndicator(); addMessage('ai', 'Произошла ошибка при обработке запроса. Пожалуйста, попробуйте еще раз.'); isWaitingForResponse = false; sendBtn.disabled = userInput.value.trim() === ''; }); } function handleKeyDown(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } } function addMessage(sender, text) { // Скрываем экран приветствия, если он отображается hideWelcomeScreen(); const messageDiv = document.createElement('div'); messageDiv.className = `message ${sender}`; const avatarDiv = document.createElement('div'); avatarDiv.className = `message-avatar ${sender}`; avatarDiv.innerHTML = sender === 'user' ? '' : ''; const contentDiv = document.createElement('div'); contentDiv.className = 'message-content'; const senderDiv = document.createElement('div'); senderDiv.className = 'message-sender'; senderDiv.textContent = sender === 'user' ? 'Вы' : 'AI'; const textDiv = document.createElement('div'); textDiv.className = 'message-text'; // Обрабатываем текст с поддержкой Markdown if (sender === 'ai') { textDiv.innerHTML = marked.parse(text); // Подсветка синтаксиса кода textDiv.querySelectorAll('pre code').forEach((block) => { hljs.highlightElement(block); }); // Добавляем кнопки действий const actionsDiv = document.createElement('div'); actionsDiv.className = 'message-actions'; const copyBtn = document.createElement('button'); copyBtn.className = 'action-btn'; copyBtn.innerHTML = ' Копировать'; copyBtn.addEventListener('click', () => copyToClipboard(text)); actionsDiv.appendChild(copyBtn); contentDiv.appendChild(actionsDiv); } else { textDiv.textContent = text; } contentDiv.appendChild(senderDiv); contentDiv.appendChild(textDiv); messageDiv.appendChild(avatarDiv); messageDiv.appendChild(contentDiv); messagesContainer.appendChild(messageDiv); // Прокручиваем к последнему сообщению messageDiv.scrollIntoView({ behavior: 'smooth' }); } function showTypingIndicator() { const indicatorDiv = document.createElement('div'); indicatorDiv.className = 'message ai typing'; indicatorDiv.innerHTML = `
`; messagesContainer.appendChild(indicatorDiv); indicatorDiv.scrollIntoView({ behavior: 'smooth' }); } function removeTypingIndicator() { const typingIndicator = document.querySelector('.message.typing'); if (typingIndicator) { typingIndicator.remove(); } } function hideWelcomeScreen() { if (welcomeScreen.style.display !== 'none') { welcomeScreen.style.display = 'none'; } } function createNewChat() { // Сохраняем текущий чат перед созданием нового saveChats(); // Создаем новый чат currentChatId = generateId(); chats[currentChatId] = { id: currentChatId, title: 'Новый чат', messages: [], timestamp: Date.now() }; // Очищаем сообщения messagesContainer.innerHTML = ''; // Показываем экран приветствия welcomeScreen.style.display = 'flex'; // Обновляем историю чатов updateChatHistory(); } function saveChat(userMessage, aiResponse) { if (!chats[currentChatId]) { chats[currentChatId] = { id: currentChatId, title: userMessage ? userMessage.substring(0, 30) : 'Новый чат', messages: [], timestamp: Date.now() }; } if (userMessage) { chats[currentChatId].messages.push({ sender: 'user', text: userMessage, timestamp: Date.now() }); // Обновляем заголовок чата, если это первое сообщение if (chats[currentChatId].messages.length === 1) { chats[currentChatId].title = userMessage.substring(0, 30) + (userMessage.length > 30 ? '...' : ''); } } if (aiResponse) { chats[currentChatId].messages.push({ sender: 'ai', text: aiResponse, timestamp: Date.now() }); } // Сохраняем чаты в localStorage saveChats(); // Обновляем историю чатов updateChatHistory(); } function saveChats() { localStorage.setItem('mistral_chats', JSON.stringify(chats)); } function loadChats() { const savedChats = localStorage.getItem('mistral_chats'); if (savedChats) { chats = JSON.parse(savedChats); updateChatHistory(); // Если есть чаты, загружаем последний активный const chatIds = Object.keys(chats); if (chatIds.length > 0) { // Сортируем по времени и берем самый последний const sortedIds = chatIds.sort((a, b) => chats[b].timestamp - chats[a].timestamp); loadChat(sortedIds[0]); } } } function updateChatHistory() { chatHistory.innerHTML = ''; // Сортируем чаты по времени (сначала новые) const sortedChats = Object.values(chats).sort((a, b) => b.timestamp - a.timestamp); sortedChats.forEach(chat => { const chatItem = document.createElement('div'); chatItem.className = `chat-item ${chat.id === currentChatId ? 'active' : ''}`; chatItem.setAttribute('data-id', chat.id); chatItem.innerHTML = ` ${chat.title} `; chatItem.addEventListener('click', () => loadChat(chat.id)); chatHistory.appendChild(chatItem); }); } function loadChat(chatId) { if (!chats[chatId]) return; currentChatId = chatId; messagesContainer.innerHTML = ''; welcomeScreen.style.display = 'none'; // Загружаем сообщения chats[chatId].messages.forEach(msg => { addMessage(msg.sender, msg.text); }); // Обновляем активный чат в истории updateChatHistory(); } function toggleDarkMode() { const isDarkMode = document.body.classList.toggle('dark-mode'); localStorage.setItem('dark_mode', isDarkMode ? 'true' : 'false'); // Обновляем иконку toggleModeBtn.innerHTML = isDarkMode ? '' : ''; } function initTheme() { const savedTheme = localStorage.getItem('dark_mode'); if (savedTheme === 'true') { document.body.classList.add('dark-mode'); toggleModeBtn.innerHTML = ''; } } function copyToClipboard(text) { navigator.clipboard.writeText(text).then(() => { // Показываем уведомление об успешном копировании const notification = document.createElement('div'); notification.className = 'copy-notification'; notification.textContent = 'Скопировано в буфер обмена'; document.body.appendChild(notification); setTimeout(() => { notification.remove(); }, 2000); }).catch(err => { console.error('Ошибка при копировании: ', err); }); } function generateId() { return Date.now().toString(36) + Math.random().toString(36).substring(2); } });