<!DOCTYPE html><html lang="ru"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Нейрочат</title> <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet" /> <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.css" rel="stylesheet" /> <link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&display=swap" rel="stylesheet"><style>/* Стили CSS - с изменениями для улучшения темной темы */html { line-height: 1.15; -webkit-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;}:root { --primary-color: #d97757; --primary-hover: #c36242; --text-color: #29261B; --text-secondary: #6b6661; --bg-color: #faf9f7; --border-color: #e5e2dd; --code-bg: #181d28; --chat-max-width: 1200px;/* Универсальные стили для полосы прокрутки */ --scrollbar-track-color: #e5e2dd; /* Цвет фона полосы прокрутки */ --scrollbar-thumb-color: #d97757; /* Цвет ползунка полосы прокрутки */ --scrollbar-thumb-hover-color: #c36242; /* Цвет ползунка при наведении */ --scrollbar-width: 8px; /* Ширина полосы прокрутки */ --scrollbar-border-radius: 4px; /* Радиус скругления углов полосы прокрутки */}/* Стили для WebKit (Chrome, Safari) */::-webkit-scrollbar { width: var(--scrollbar-width);}::-webkit-scrollbar-track { background: var(--scrollbar-track-color); border-radius: var(--scrollbar-border-radius);}::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb-color); border-radius: var(--scrollbar-border-radius);}::-webkit-scrollbar-thumb:hover { background: var(--scrollbar-thumb-hover-color);}/* Стили для Firefox */* { scrollbar-color: var(--scrollbar-thumb-color) var(--scrollbar-track-color); scrollbar-width: thin;}* { margin: 0; padding: 0; box-sizing: border-box;}body { margin: 0;}main { display: block;}h1 { font-size: 2em; margin: 0.67em 0;}hr { box-sizing: content-box; height: 0; overflow: visible;}pre { font-family: monospace, monospace; font-size: 1em;}a { background-color: transparent;}abbr[title] { border-bottom: none; text-decoration: underline; text-decoration: underline dotted;}b,strong { font-weight: bolder;}code,kbd,samp { font-family: 'Fira Code', monospace; font-size: 1em;}small { font-size: 80%;}sub,sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline;}sub { bottom: -0.25em;}sup { top: -0.5em;}img { border-style: none;}button,input,optgroup,select,textarea { font-family: inherit; font-size: 100%; line-height: 1.15; margin: 0;}button,input { overflow: visible;}button,select { text-transform: none;}button,[type="button"],[type="reset"],[type="submit"] { -webkit-appearance: button;}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner { border-style: none; padding: 0;}button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring { outline: 1px dotted ButtonText;}fieldset { padding: 0.35em 0.75em 0.625em;}legend { box-sizing: border-box; color: inherit; display: table; max-width: 100%; padding: 0; white-space: normal;}progress { vertical-align: baseline;}textarea { overflow: auto;}[type="checkbox"],[type="radio"] { box-sizing: border-box; padding: 0;}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button { height: auto;}[type="search"] { -webkit-appearance: textfield; outline-offset: -2px;}[type="search"]::-webkit-search-decoration { -webkit-appearance: none;}::-webkit-file-upload-button { -webkit-appearance: button; font: inherit;}details { display: block;}summary { display: list-item;}template { display: none;}[hidden] { display: none;}body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 1.1rem; letter-spacing: -0.035em; color: var(--text-color); background-color: var(--bg-color); min-height: 100vh; display: flex; flex-direction: column;}p { line-height: 1.65rem;}ul { list-style-type: none; padding: 0; margin: 0;}li { margin: 1px 0; line-height: 1.7;}ol { list-style-type: decimal; padding-left: 14px;}ol li { margin-left: 0;}.chat-container { flex: 1; display: flex; flex-direction: column; max-width: var(--chat-max-width); width: 100%; margin: 0 auto; padding: 0; height: 100vh; display: flex; flex-direction: column;}.chat-header { display: flex; justify-content: space-between; align-items: center; padding: 15px 55px 15px 0; background-color: var(--bg-color); position: sticky; top: 0; z-index: 100;}.chat-header h2 { margin: 0; padding: 0 20px; color: #5F5B49; font-size: 1.25rem; font-weight: 600;}.clear-link { font-size: 0.9rem; color: var(--text-secondary); text-decoration: none; cursor: pointer; transition: color 0.2s, transform 0.2s;}.clear-link:hover { color: #565250;}.clear-link:active { transform: scale(0.98);}#messages { flex: 1; overflow-y: auto; padding: 20px; background-color: var(--bg-color); margin: 5px 0; border-radius: 4px;}#messages::-webkit-scrollbar { width: 8px;}#messages::-webkit-scrollbar-track { background: #f1efed; border-radius: 4px;}#messages::-webkit-scrollbar-thumb { background: #d1cdc7; border-radius: 4px;}.message { position: relative; margin: 16px 0; padding: 16px 35px 16px 16px; border-radius: 16px; max-width: 97%; word-wrap: break-word; border: 1px solid var(--border-color); opacity: 0; transform: translateY(-20px); transition: opacity 0.3s ease-out, transform 0.3s ease-out;}.message.message-fade-in { opacity: 1; transform: translateY(0);}.message.assistant { scroll-margin: 40px;}.user {white-space: pre-wrap;margin-left: auto;background-color: #f1f0e8; max-height: 500px; overflow-y: auto;}}.assistant {margin-right: auto;background-color: #FCFCFB;width: 100%;}.input-container {display: flex;flex-direction: column;gap: 10px;padding: 20px;background-color: var(--bg-color); position: sticky; bottom: 0; z-index: 100;}#user-input { width: 100%; min-height: 100px; max-height: 200px; padding: 12px; border: 1px solid var(--border-color); border-radius: 16px; outline: none; font-size: 1rem; resize: vertical; background-color: #ffffff; font-family: inherit; position: relative;}#user-input:focus { border-color: var(--border-color); box-shadow: 0 0 0 1px rgba(184, 178, 167, 0.2);}button { align-self: center; padding: 8px 16px; background-color: var(--primary-color); color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 0.9rem; transition: background-color 0.2s, transform 0.2s;}button:hover { background-color: var(--primary-hover);}button:active { transform: scale(0.97);}.code-block-wrapper { margin: 10px 0; border-radius: 8px; overflow: hidden; background: #3d3a47;}.code-block-header { position: relative; background: var(--code-bg); padding: 8px 15px; border-bottom: 1px solid #3d3d3d; border-radius: 8px 8px 0 0; display: flex; justify-content: flex-end; align-items: center;}.copy-button { background: transparent; border: 1px solid var(--text-secondary); color: #cbcbcb; padding: 4px 8px; font-size: 12px; border-radius: 4px; cursor: pointer; transition: all 0.2s ease;}.copy-button:hover { background: var(--code-bg); color: white;}.copy-button.copied { background: #539353; border-color: #4a524a; color: white;}.download-button { background: transparent; border: 1px solid var(--text-secondary); color: #cbcbcb; padding: 4px 8px; font-size: 12px; border-radius: 4px; cursor: pointer; transition: all 0.2s ease; margin-left: 5px;}.download-button:hover { background: var(--code-bg); color: white;}.markdown-content pre { margin: 0; border-radius: 0 0 8px 8px;}pre { background: #212121; border-radius: 6px; border-bottom: 1px solid #3d3d3d; padding: 12px 16px; overflow: auto; font-family: 'Fira Code', 'Fira Mono', Menlo, Consolas, 'DejaVu Sans Mono', monospace; font-size: 15px; line-height: 1.4; margin: 16px 0;}code:not(pre code) { font-size: 0.9rem; color: #7c1b13; word-wrap: normal; padding: 3px; background: #F3F3F1; border: 1px solid var(--border-color); border-radius: 5px; white-space: pre;}:not(pre) > code[class*=language-],pre[class*=language-] { background: #181d28;}code[class*=language-],pre[class*=language-] { color: #dfe2e8; font-size: 15px; line-height: 1.2; font-family: 'Fira Code', monospace;}.token.prolog,.token.doctype,.token.cdata { color: #6a9955;}.token.comment { color: #5c6370; }.token.punctuation { color: #d4d4d4; }.token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: #98c379; }.token.property { color: #e06c75; }.token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: #ce9178; }.token.selector { color: #98c379; }.token.operator, .token.entity, .token.url, .language-css .token.string, .style .token.string { color: #d4d4d4; }.token.atrule, .token.attr-value, .token.keyword { color: #c678dd; }.token.function, .token.class-name { color: #61afef; }.token.regex, .token.important, .token.variable { color: #9cdcfe; }.token.attr-value, .token.char, .token.regex, .token.string, .token.variable { color: #98c379; }.delete-btn { position: absolute; top: 5px; right: 5px; cursor: pointer; color: #9b9991; font-size: 18px; line-height: 1; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; border-radius: 50%; transition: all 0.2s ease;}.delete-btn:hover { background-color: rgba(0,0,0,0.04); color: #565250;}.thinking { font-style: italic; color: #777; text-align: center; animation: pulse 1s infinite;}@keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.5; } 100% { opacity: 1; }}@media (max-width: 768px) { .chat-container { padding: 10px; } .message { max-width: 95%; }}/* Стили для иконки */#hiddenIcon { width: 50px; height: 50px; background-color: #f0f0f0; display: none; cursor: pointer; text-align: center; line-height: 45px; font-size: 24px; position: absolute; top: 10px; right: 10px; border-radius: 50%; user-select: none; border: 1px solid #ccc;}#hiddenIcon .close-icon { position: absolute; top: -7px; right: -5px; font-size: 16px; color: #888; cursor: pointer; display: none; border-radius: 50%; background-color: white; border: 1px solid #ccc; width: 20px; height: 20px; line-height: 16px; } #hiddenIcon:hover .close-icon { display: block;}#hiddenContainer { display: none;}#container { position: relative; width: 100%;}/* Стили для модального окна */.modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); justify-content: center; align-items: center;}.modal-content { background-color: white; padding: 20px; border-radius: 10px; width: 80%; max-width: 800px; text-align: center; position: relative;}.close { position: absolute; top: 10px; right: 15px; font-size: 24px; cursor: pointer; font-weight: bold;}/* Контейнер для текста с сохранением форматирования */.modal-text { max-height: 500px; overflow-y: auto; text-align: left; padding: 10px; background: #f9f9f9; border: 1px solid #ddd; font-family: monospace; white-space: pre-wrap; word-wrap: break-word;}/* Стили для переключателя темы */.theme-switch-container { display: flex; align-items: center; cursor: pointer; position: relative;}.theme-switch-container:hover { transform: scale(1.1); transition: transform 0.2s ease;}.theme-switch-icon { font-size: 20px; margin-left: 8px; transition: transform 0.3s ease-in-out; font-family: 'Segoe UI Symbol', sans-serif; /* Добавлен явный шрифт */}.theme-switch-icon.light { color: #ffc107; /* Цвет для светлой темы - желтый (Солнце) */}.theme-switch-icon.dark { color: #faf9f7; /* Цвет для темной темы - белый */ transform: rotate(180deg)}/* Стили для темной темы */.dark-theme { --primary-color: #cf9c03; --primary-hover: #ffb300; --text-color: #faf9f7; /* Белый текст для темной темы */ --text-secondary: #e5e2dd; --bg-color: #1a1b1c; /* Темно-серый фон */ --border-color: #4d4a45; --code-bg: #2c2c2c; /* Темный фон для кода */ --scrollbar-track-color: #2c2c2c; /* Цвет фона полосы прокрутки */ --scrollbar-thumb-color: #ffc107; /* Цвет ползунка полосы прокрутки */ --scrollbar-thumb-hover-color: #ffb300; /* Цвет ползунка при наведении */}.dark-theme .chat-header h2{ color: #faf9f7;}.dark-theme .clear-link { color: #e5e2dd;}.dark-theme .clear-link:hover { color: #faf9f7;}.dark-theme .user{ background-color: #454341;}.dark-theme .assistant {background-color: #3b3939;}.dark-theme #user-input{ background-color: #454341; color: #faf9f7;}.dark-theme code:not(pre code){ color: #ffc107; background: #2c2c2c;}.dark-theme pre { background: #2c2c2c; border-bottom: 1px solid #3d3d3d;}.dark-theme :not(pre) > code[class*=language-],.dark-theme pre[class*=language-] { background: #2c2c2c;}.dark-theme #messages::-webkit-scrollbar-track { background: #2c2c2c;}.dark-theme .delete-btn{ color: #9b9991;}.dark-theme .delete-btn:hover { background-color: rgba(255,255,255,0.04); color: #faf9f7;}.dark-theme .modal-text { background: #2c2c2c; border: 1px solid #4d4a45; color: #faf9f7;}.dark-theme .modal-content { background-color: #3b3939;}</style></head><body> <div class="chat-container"> <div class="chat-header"> <div style="display: flex; align-items: center;"> <h2>Нейрочат</h2> <div class="theme-switch-container" id="theme-switch"> <span class="theme-switch-icon light" id="theme-icon">☀</span> <!-- Солнце --> </div> </div> <a href="#" id="clear-history-link" class="clear-link">Очистить историю</a> </div> <div id="messages"></div> <div id="container"> <div class="input-container" id="input-area"> <textarea id="user-input" autofocus placeholder="Введите сообщение..." rows="3" onkeypress="if(event.key === 'Enter' && !event.shiftKey) { event.preventDefault(); sendMessage(); }"></textarea> <div id="hiddenIcon">📄 <span class="close-icon" onclick="Chat.instance.clearHiddenText(event)">×</span></div> <button onclick="sendMessage()">Отправить</button> </div> </div> <div id="hiddenContainer"></div> </div> <!-- Модальное окно --> <div id="myModal" class="modal"> <div class="modal-content"> <span class="close">×</span> <pre id="modalText" class="modal-text"></pre> </div> </div> <!-- Load Prism.js for code highlighting --> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-markup.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-css.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-clike.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-javascript.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/10.0.0/marked.min.js"></script><script>document.addEventListener('DOMContentLoaded', function() { setTimeout(() => { window.scrollTo({ top: document.documentElement.scrollHeight, behavior: 'smooth' }); }, 200); // Задержка в 100 миллисекунд});class Chat { constructor(messagesContainerId, userInputId, inputAreaId, apiUrl, hiddenIconId, hiddenContainerId, modalId, modalTextId, closeBtnClass, themeSwitchId, themeIconId) { this.messagesContainer = document.getElementById(messagesContainerId); this.userInput = document.getElementById(userInputId); this.inputArea = document.getElementById(inputAreaId); this.API_URL = apiUrl; this.GEMINI_API_KEY = null; this.MAX_HISTORY = 10; this.messages = JSON.parse(localStorage.getItem('chatHistory')) || []; this.hiddenIcon = document.getElementById(hiddenIconId); this.hiddenContainer = document.getElementById(hiddenContainerId); this.modal = document.getElementById(modalId); this.modalText = document.getElementById(modalTextId); this.closeBtn = document.querySelector(closeBtnClass); this.themeSwitch = document.getElementById(themeSwitchId); this.themeIcon = document.getElementById(themeIconId); this.isDarkTheme = localStorage.getItem('theme') === 'dark'; this.init(); // Свойство для хранения экземпляра чата Chat.instance = this; } async init() { this.setupEventListeners(); this.setupTextareaHandling(); await this.initializeApiKey(); this.loadChatHistory(); this.scrollInputIntoView(); this.setInitialTheme(); } setInitialTheme() { if(this.isDarkTheme) { this.setDarkTheme(); } else { this.setLightTheme(); } } scrollInputIntoView() { if (this.inputArea) { this.inputArea.scrollIntoView({ behavior: 'smooth', block: 'end' }); } } setupEventListeners() { this.userInput.addEventListener('input', this.handleInput.bind(this)); this.userInput.addEventListener('keydown', this.handleEnter.bind(this)); this.themeSwitch.addEventListener('click', this.toggleTheme.bind(this)); } handleEnter(event) { if (event.key === 'Enter' && !event.shiftKey) { event.preventDefault(); this.sendMessage(); } } toggleTheme() { if (this.isDarkTheme) { this.setLightTheme(); localStorage.setItem('theme', 'light'); } else { this.setDarkTheme(); localStorage.setItem('theme', 'dark'); } this.isDarkTheme = !this.isDarkTheme; } setLightTheme() { document.body.classList.remove('dark-theme'); this.themeIcon.classList.remove('dark'); this.themeIcon.classList.add('light'); this.themeIcon.innerHTML = '☀'; // Иконка солнца } setDarkTheme() { document.body.classList.add('dark-theme'); this.themeIcon.classList.remove('light'); this.themeIcon.classList.add('dark'); this.themeIcon.innerHTML = '☽'; // Иконка луны } async initializeApiKey() { try { const response = await fetch(this.API_URL); const data = await response.json(); this.GEMINI_API_KEY = data.api_key || null; if (!this.GEMINI_API_KEY) throw new Error('API key not found'); } catch (error) { console.error('Ошибка получения ключа:', error); this.addMessage('Ошибка инициализации. Перезагрузите страницу.', 'assistant'); } }handleInput() {document.querySelector('button').disabled = !this.userInput.value.trim();} setupTextareaHandling() { this.userInput.addEventListener('input', () => { const text = this.userInput.value; if (text.length > 400) { // Перемещаем весь текст в скрытый контейнер this.hiddenContainer.textContent += text + '\n'; // Очищаем поле ввода this.userInput.value = ''; // Показываем иконку this.hiddenIcon.style.display = 'block'; } }); // Открыть модальное окно с текстом this.hiddenIcon.addEventListener('click', () => { this.modalText.textContent = this.hiddenContainer.textContent; // Заполняем текст this.modal.style.display = 'flex'; }); // Закрыть модальное окно this.closeBtn.addEventListener('click', () => { this.modal.style.display = 'none'; }); // Закрытие окна при клике вне его window.addEventListener('click', (event) => { if (event.target === this.modal) { this.modal.style.display = 'none'; } }); } async sendMessage() { if (!this.GEMINI_API_KEY) { this.addMessage('Система не готова. Обновите страницу.', 'assistant'); return; } let userMessage = this.userInput.value.trim(); if (this.hiddenContainer.textContent.trim() !== '') { userMessage = userMessage + '\n\n' + this.hiddenContainer.textContent.trim() ; this.hiddenContainer.textContent = ''; this.hiddenIcon.style.display = 'none'; } if (!userMessage) return; this.addMessage(userMessage, "user"); this.userInput.value = ""; this.userInput.style.height = 'auto'; this.messages.push({ role: "user", content: userMessage }); this.saveChatHistory(); this.addMessage("Думаю над ответом...", "assistant", true); try { const response = await fetch( `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=${this.GEMINI_API_KEY}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ contents: this.messages.slice(-this.MAX_HISTORY).map(msg => ({ role: msg.role, parts: [{ text: msg.content }] })) }) } ); const data = await response.json(); if (!response.ok) throw new Error(data.error?.message || 'API Error'); const botMessage = data.candidates?.[0]?.content?.parts?.[0]?.text || 'Не удалось получить ответ'; this.removeThinkingMessage(); this.addMessage(botMessage, "assistant", false, true); this.messages.push({ role: "assistant", content: botMessage }); this.saveChatHistory(); } catch (error) { console.error("Error:", error); this.removeThinkingMessage(); this.addMessage(`Ошибка: ${error.message}`, "assistant"); } } clearHiddenText(event) { event.stopPropagation(); this.hiddenContainer.textContent = ''; this.hiddenIcon.style.display = 'none'; } addMessage(text, role, isTemporary = false, animate = true) { const messageElement = document.createElement("div"); messageElement.className = `message ${role}`; // Начальные стили для анимации messageElement.style.transition = 'opacity 0.3s ease-out, transform 0.3s ease-out'; if (animate) { messageElement.style.opacity = '0'; messageElement.style.transform = 'translateY(-20px)'; } else { messageElement.style.opacity = '1'; messageElement.style.transform = 'translateY(0)'; } if (!isTemporary) { messageElement.dataset.content = text; // Кнопка удаления const deleteBtn = document.createElement('div'); deleteBtn.className = 'delete-btn'; deleteBtn.innerHTML = '×'; deleteBtn.onclick = () => { messageElement.remove(); this.updateMessagesFromDOM(); this.saveChatHistory(); }; messageElement.appendChild(deleteBtn); } if (isTemporary) { messageElement.classList.add("thinking"); messageElement.textContent = text; } else { if (role === "assistant") { const htmlContent = marked.parse(text); const contentDiv = document.createElement("div"); contentDiv.className = "markdown-content"; contentDiv.innerHTML = htmlContent; // Обработка блоков кода contentDiv.querySelectorAll('pre').forEach(pre => { const wrapper = document.createElement('div'); wrapper.className = 'code-block-wrapper'; const header = document.createElement('div'); header.className = 'code-block-header'; const copyButton = document.createElement('button'); copyButton.className = 'copy-button'; copyButton.textContent = 'Копировать'; copyButton.onclick = () => this.handleCopyClick(pre, copyButton); const downloadButton = document.createElement('button'); downloadButton.className = 'download-button'; downloadButton.textContent = 'Скачать'; downloadButton.onclick = () => this.handleDownloadClick(pre); header.appendChild(copyButton); header.appendChild(downloadButton); wrapper.append(header, pre.cloneNode(true)); pre.parentNode.replaceChild(wrapper, pre); }); messageElement.appendChild(contentDiv); setTimeout(() => Prism.highlightAllUnder(messageElement), 0); } else { const textNode = document.createElement('div'); textNode.textContent = text.replace(/\n/g, '\n'); // Явное сохранение переносов messageElement.appendChild(textNode); } } this.messagesContainer.appendChild(messageElement); // Активация анимации if (animate) { setTimeout(() => { messageElement.style.opacity = '1'; messageElement.style.transform = 'translateY(0)'; }, 10); } if(role === 'assistant') { messageElement.scrollIntoView({ behavior: 'smooth', block: 'start' }); } else { // Плавная прокрутка вниз this.messagesContainer.scrollTo({ top: this.messagesContainer.scrollHeight, behavior: "smooth" }); } } handleCopyClick(pre, button) { const code = pre.textContent; if (this.copyToClipboard(code)) { button.textContent = 'Скопировано!'; button.classList.add('copied'); setTimeout(() => { button.textContent = 'Копировать'; button.classList.remove('copied'); }, 2000); } else { button.textContent = 'Ошибка!'; setTimeout(() => button.textContent = 'Копировать', 2000); } } handleDownloadClick(pre) { const code = pre.textContent; const blob = new Blob([code], { type: 'text/html' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'code.html'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } copyToClipboard(text) { const textarea = document.createElement('textarea'); textarea.value = text; textarea.style.position = 'fixed'; document.body.appendChild(textarea); textarea.select(); try { return document.execCommand('copy'); } finally { document.body.removeChild(textarea); } } removeThinkingMessage() { const thinking = this.messagesContainer.querySelector('.thinking'); if (thinking) thinking.remove(); } saveChatHistory() { localStorage.setItem('chatHistory', JSON.stringify(this.messages.slice(-this.MAX_HISTORY))); } updateMessagesFromDOM() { this.messages = Array.from(this.messagesContainer.querySelectorAll('.message:not(.thinking)')) .map(el => ({ role: el.classList.contains('user') ? 'user' : 'assistant', content: el.dataset.content || el.textContent })); } loadChatHistory() { this.messages.forEach(msg => this.addMessage(msg.content, msg.role, false, false)); } clearChatHistory() { this.messages = []; localStorage.removeItem('chatHistory'); this.messagesContainer.innerHTML = ""; }}document.addEventListener('DOMContentLoaded', () => { const chat = new Chat('messages', 'user-input', 'input-area', 'http://mcmstest.atwebpages.com/apikey', 'hiddenIcon', 'hiddenContainer', 'myModal', 'modalText', '.close', 'theme-switch', 'theme-icon'); document.querySelector('button').addEventListener('click', () => chat.sendMessage()); // Устанавливаем обработчик клика на ссылку очистки истории document.getElementById('clear-history-link').addEventListener('click', function(event) { event.preventDefault(); if (Chat.instance) { Chat.instance.clearChatHistory(); } else { console.error('Экземпляр чата не инициализирован'); } });});// Настройки Markdownmarked.setOptions({ headerIds: false, mangle: false, highlight: (code, lang) => { return Prism.languages[lang] ? Prism.highlight(code, Prism.languages[lang], lang) : code; }});</script></body></html>