您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Добавляет продвинутые функции в DeepSeek!
// ==UserScript== // @name DeepSeek Chat Продвинутый! // @namespace http://tampermonkey.net/ // @version 1.0 // @description Добавляет продвинутые функции в DeepSeek! // @match https://chat.deepseek.com/* // @author YouTubeDrawaria, des.g_company // @grant none // @license MIT // @icon https://www.google.com/s2/favicons?sz=64&domain=chat.deepseek.com // ==/UserScript== (function() { 'use strict'; // Селекторы для DeepSeek const SELECTORS = { CHAT_INPUT_TEXTAREA: 'textarea#chat-input', CHAT_INPUT_CONTAINER: '.dd442025._42b6996', RESPONSE_CONTAINER: '.ds-markdown.ds-markdown--block', MESSAGE_CONTENT: '.ds-markdown-paragraph', SEND_BUTTON: '.ds-button.ds-button--primary', FILE_INPUT: 'input[type="file"]', CHAR_COUNTER: '#deepseek-char-counter' }; // Категоризированные промпты const ALL_CATEGORIZED_PROMPTS = { "Скрипты/Разработка": [ { name: "Создать скрипт Drawaria", text: `Создай полный скрипт Tampermonkey для drawaria.online со следующим начальным шаблоном:\n // ==UserScript==\n// @name New Userscript\n// @namespace http://tampermonkey.net/\n// @version 1.0\n// @description try to take over the world!\n// @author YouTubeDrawaria\n// @match https://drawaria.online/*\n// @grant none\n// @license MIT\n// @icon https://www.google.com/s2/favicons?sz=64&domain=drawaria.online\n// ==/UserScript==\n\n(function() {\n 'use strict';\n\n // Ваш код здесь...\n})();\n` }, { name: "Продвинутый скрипт Drawaria", text: "Создай полный скрипт Tampermonkey для drawaria.online с расширенными функциями: визуальные эффекты, частицы, анимации, улучшенный интерфейс и особые возможности. Не используй заглушки и внешние файлы." }, { name: "Улучшить скрипт Drawaria", text: `Улучшай, обновляй, максимизируй, удивляй, создавай реализм и высокий уровень детализации в скрипте для drawaria.online. Хочу элементы X на экране, музыку, эффекты, частицы, блики и хорошо анимированный, детализированный интерфейс со всем. Не используй заглушки, .mp3 и data:image/png;base64. Графику нужно создавать самому, без заменяемых файлов.` }, { name: "Атрибуты игры", text: `Дай мне атрибуты игры. Включи: иконку игры (<link rel="icon" href="https://drawaria.online/avatar/cache/ab53c430-1b2c-11f0-af95-072f6d4ed084.1749767757401.jpg" type="image/x-icon">) и фоновую музыку с автоматическим воспроизведением при клике: (<audio id="bg-music" src="https://www.myinstants.com/media/sounds/super-mini-juegos-2.mp3" loop></audio><script>const music = document.getElementById('bg-music'); document.body.addEventListener('click', () => { if (music.paused) { music.play(); } });</script>).` }, { name: "API для Cubic Engine", text: `Предоставь информацию о популярных API, которые не размещены на Vercel, не имеют проблем с CORS при использовании в браузерах/консоли, быстро интегрируются в Cubic Engine / Drawaria, бесплатны и доступны для немедленного использования.` }, { name: "Интегрировать функцию в Cubic Engine", text: `Для интеграции нового дополнения в модуль Cubic Engine мне нужен полный код обновлённой функции. Это включает кнопку со всеми её свойствами, активаторы с их ID, слушатели этого события и файлы, которые её запускают. Приведи только обновлённый код функции, не весь исходный код Cubic Engine с нуля.` }, { name: "Скрипт Tampermonkey", text: `Создай полноценный скрипт tampermonkey с продвинутыми функциями. Не используй заглушки или внешние файлы.` }, { name: "Интеграция API", text: `Предоставь информацию о бесплатных API, которые можно быстро интегрировать без проблем с CORS.` } ] }; let featuresInitialized = false; let draggableMenu = null; // Глобальная ссылка для перетаскиваемого меню /** * Создает кнопку в стиле DeepSeek */ function createButton(text, onClick, styles = {}) { const button = document.createElement('button'); button.textContent = text; button.className = 'ds-button ds-button--primary ds-button--filled ds-button--rect ds-button--m'; button.style.cssText = ` background: linear-gradient(135deg, #1B73FF 0%, #0C5ADB 100%); color: white; padding: 8px 16px; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 500; margin: 0; transition: all 0.3s ease; white-space: nowrap; box-shadow: 0 2px 8px rgba(27, 115, 255, 0.2); ${Object.entries(styles).map(([key, value]) => `${key}:${value};`).join('')} `; button.onmouseover = () => { button.style.transform = 'translateY(-1px)'; button.style.boxShadow = '0 4px 12px rgba(27, 115, 255, 0.3)'; button.style.background = 'linear-gradient(135deg, #2B7EFF 0%, #1C64E5 100%)'; }; button.onmouseout = () => { button.style.transform = 'translateY(0)'; button.style.boxShadow = '0 2px 8px rgba(27, 115, 255, 0.2)'; button.style.background = 'linear-gradient(135deg, #1B73FF 0%, #0C5ADB 100%)'; }; button.onclick = onClick; return button; } /** * Создает категоризированный выпадающий список */ function createCategorizedDropdown(categorizedOptions, onSelect, placeholder = "Выбрать Промпт") { const select = document.createElement('select'); select.style.cssText = ` background: linear-gradient(135deg, #1B73FF 0%, #0C5ADB 100%); color: white; padding: 8px 12px; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 500; margin: 0; min-width: 100%; transition: all 0.3s ease; box-shadow: 0 2px 8px rgba(27, 115, 255, 0.2); -webkit-appearance: none; -moz-appearance: none; appearance: none; background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20256%20256%22%3E%3Cpolygon%20points%3D%22208%2C80%20128%2C160%2048%2C80%22%20fill%3D%22%23ffffff%22%2F%3E%3C%2Fsvg%3E'); background-repeat: no-repeat; background-position: right 8px center; background-size: 16px; `; const defaultOption = document.createElement('option'); defaultOption.value = ""; defaultOption.textContent = placeholder; defaultOption.disabled = true; defaultOption.selected = true; select.appendChild(defaultOption); for (const category in categorizedOptions) { const optgroup = document.createElement('optgroup'); optgroup.label = category; optgroup.style.cssText = 'background: #1a1a1a; color: white;'; categorizedOptions[category].forEach(opt => { const option = document.createElement('option'); option.value = opt.text; option.textContent = opt.name; option.style.cssText = 'background: #1a1a1a; color: white; padding: 4px;'; optgroup.appendChild(option); }); select.appendChild(optgroup); } select.onchange = (event) => { if (event.target.value) { onSelect(event.target.value); event.target.value = ""; defaultOption.selected = true; } }; select.onmouseover = () => { select.style.transform = 'translateY(-1px)'; select.style.boxShadow = '0 4px 12px rgba(27, 115, 255, 0.3)'; }; select.onmouseout = () => { select.style.transform = 'translateY(0)'; select.style.boxShadow = '0 2px 8px rgba(27, 115, 255, 0.2)'; }; return select; } /** * Создает и показывает модальное окно */ function showModal(title, contentHtml) { const existingModal = document.getElementById('deepseek-custom-modal-overlay'); if (existingModal) { existingModal.remove(); } const modalOverlay = document.createElement('div'); modalOverlay.id = 'deepseek-custom-modal-overlay'; modalOverlay.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.8); display: flex; justify-content: center; align-items: center; z-index: 10000; backdrop-filter: blur(5px); `; const modalContent = document.createElement('div'); modalContent.style.cssText = ` background: linear-gradient(135deg, #0F0F0F 0%, #1a1a1a 100%); color: white; padding: 30px; border-radius: 16px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); max-width: 80%; max-height: 80%; overflow-y: auto; position: relative; border: 1px solid #333; `; const modalTitle = document.createElement('h3'); modalTitle.textContent = title; modalTitle.style.cssText = ` margin-top: 0; margin-bottom: 20px; color: #1B73FF; font-size: 1.4em; text-align: center; font-weight: 600; `; const closeButton = document.createElement('button'); closeButton.textContent = '×'; closeButton.style.cssText = ` position: absolute; top: 15px; right: 20px; background: none; border: none; color: #ccc; font-size: 1.5em; cursor: pointer; width: 30px; height: 30px; border-radius: 50%; display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; `; closeButton.onmouseover = () => { closeButton.style.backgroundColor = '#333'; closeButton.style.color = 'white'; }; closeButton.onmouseout = () => { closeButton.style.backgroundColor = 'transparent'; closeButton.style.color = '#ccc'; }; closeButton.onclick = () => modalOverlay.remove(); modalContent.appendChild(closeButton); modalContent.appendChild(modalTitle); const contentDiv = document.createElement('div'); contentDiv.innerHTML = contentHtml; modalContent.appendChild(contentDiv); modalOverlay.appendChild(modalContent); document.body.appendChild(modalOverlay); } /** * Устанавливает значение textarea так, чтобы React его распознал */ function setNativeValue(element, value) { const lastValue = element.value; element.value = value; const event = new Event('input', { bubbles: true }); event.simulated = true; const tracker = element._valueTracker; if (tracker) { tracker.setValue(lastValue); } element.dispatchEvent(event); // Также отправляем события изменений для DeepSeek element.dispatchEvent(new Event('change', { bubbles: true })); element.dispatchEvent(new Event('keyup', { bubbles: true })); } /** * Получает текущее содержимое чата */ function getCurrentChatContent() { const responses = document.querySelectorAll(SELECTORS.MESSAGE_CONTENT); let chatContent = []; responses.forEach((response, index) => { const messageText = response.textContent.trim(); if (messageText) { chatContent.push({ type: 'DeepSeek', text: messageText, timestamp: new Date().toISOString(), index: index }); } }); return chatContent; } /** * Сохраняет текущий диалог */ function saveCurrentChat() { const chatContent = getCurrentChatContent(); if (chatContent.length === 0) { alert('Нет диалога для сохранения.'); return; } const chatName = prompt("Введите название для этого диалога:", `DeepSeek Чат ${new Date().toLocaleString()}`); if (chatName) { try { const savedChats = JSON.parse(localStorage.getItem('deepseek_chat_conversations') || '[]'); savedChats.push({ name: chatName, timestamp: new Date().toISOString(), messages: chatContent, url: window.location.href }); localStorage.setItem('deepseek_chat_conversations', JSON.stringify(savedChats)); alert(`Диалог "${chatName}" успешно сохранен.`); } catch (e) { console.error("Ошибка при сохранении диалога:", e); alert("Ошибка при сохранении диалога."); } } } /** * Загружает сохраненные диалоги */ function loadSavedChats() { const savedChats = JSON.parse(localStorage.getItem('deepseek_chat_conversations') || '[]'); if (savedChats.length === 0) { alert('Нет сохраненных диалогов.'); return; } let chatListHtml = '<div style="max-height: 400px; overflow-y: auto;">'; savedChats.forEach((chat, index) => { chatListHtml += ` <div style="margin-bottom: 15px; background: linear-gradient(135deg, #1a1a1a 0%, #2a2a2a 100%); padding: 15px; border-radius: 12px; border: 1px solid #333;"> <div style="display: flex; justify-content: space-between; align-items: center;"> <div> <div style="font-size: 1.1em; font-weight: 600; color: #1B73FF; margin-bottom: 4px;">${chat.name}</div> <div style="font-size: 0.9em; color: #aaa;">${new Date(chat.timestamp).toLocaleString()}</div> <div style="font-size: 0.8em; color: #888;">${chat.messages.length} ответов</div> </div> <div> <button class="view-chat-btn" data-index="${index}" style="background: #1B73FF; color: white; border: none; padding: 8px 12px; border-radius: 8px; cursor: pointer; margin-right: 8px; font-size: 12px;">Просмотр</button> <button class="delete-chat-btn" data-index="${index}" style="background: #dc3545; color: white; border: none; padding: 8px 12px; border-radius: 8px; cursor: pointer; font-size: 12px;">Удалить</button> </div> </div> </div> `; }); chatListHtml += '</div>'; showModal('Сохраненные Диалоги', chatListHtml); // Обработчики событий для кнопок document.querySelectorAll('.view-chat-btn').forEach(button => { button.onclick = (e) => { const index = e.target.dataset.index; const chatToView = savedChats[index]; let chatViewHtml = '<div style="background: #0F0F0F; padding: 15px; border-radius: 12px; max-height: 400px; overflow-y: auto; border: 1px solid #333;">'; chatToView.messages.forEach((msg, msgIndex) => { chatViewHtml += ` <div style="margin-bottom: 15px; padding: 12px; background: #1a1a1a; border-radius: 12px; border-left: 4px solid #1B73FF;"> <div style="color: #1B73FF; font-weight: 600; margin-bottom: 8px;">Ответ ${msgIndex + 1}:</div> <div style="color: #e0e0e0; line-height: 1.5;">${msg.text}</div> </div> `; }); chatViewHtml += '</div>'; showModal(`Просмотр Диалога: ${chatToView.name}`, chatViewHtml); }; }); document.querySelectorAll('.delete-chat-btn').forEach(button => { button.onclick = (e) => { const indexToDelete = parseInt(e.target.dataset.index); if (confirm(`Вы уверены, что хотите удалить диалог "${savedChats[indexToDelete].name}"?`)) { savedChats.splice(indexToDelete, 1); localStorage.setItem('deepseek_chat_conversations', JSON.stringify(savedChats)); alert('Диалог удален.'); document.getElementById('deepseek-custom-modal-overlay')?.remove(); loadSavedChats(); } }; }); } /** * Экспортирует диалог в текстовый файл */ function exportChatToText() { const chatContent = getCurrentChatContent(); if (chatContent.length === 0) { alert('Нет диалога для экспорта.'); return; } let exportText = `--- Диалог DeepSeek Chat (${new Date().toLocaleString()}) ---\n\n`; chatContent.forEach((msg, index) => { exportText += `Ответ ${index + 1}:\n${msg.text}\n\n`; }); exportText += `--- Конец Диалога ---\n`; const blob = new Blob([exportText], { type: 'text/plain; charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `deepseek_chat_${new Date().toISOString().replace(/[:.]/g, '-')}.txt`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); alert('Диалог экспортирован в текстовый файл.'); } /** * Вставляет промпт в textarea */ function handlePromptSelection(promptText) { const inputTextArea = document.querySelector(SELECTORS.CHAT_INPUT_TEXTAREA); if (inputTextArea) { setNativeValue(inputTextArea, promptText); inputTextArea.focus(); } } /** * Динамически загружает библиотеки для OCR и обработки файлов */ function loadTesseractJs() { return new Promise((resolve, reject) => { if (window.Tesseract) { resolve(); return; } const script = document.createElement('script'); script.src = "https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js"; script.onload = () => resolve(); script.onerror = reject; document.head.appendChild(script); }); } function loadPdfJs() { return new Promise((resolve, reject) => { if (window.pdfjsLib) { resolve(); return; } const script = document.createElement('script'); script.src = "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.2.67/pdf.min.js"; script.onload = () => { window.pdfjsLib.GlobalWorkerOptions.workerSrc = "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.2.67/pdf.worker.min.js"; resolve(); }; script.onerror = reject; document.head.appendChild(script); }); } function loadMammothJs() { return new Promise((resolve, reject) => { if (window.mammoth) { resolve(); return; } const script = document.createElement('script'); script.src = "https://unpkg.com/mammoth/mammoth.browser.min.js"; script.onload = () => resolve(); script.onerror = reject; document.head.appendChild(script); }); } /** * Обрабатывает импортированные файлы */ async function processDroppedFiles(files) { const inputTextArea = document.querySelector(SELECTORS.CHAT_INPUT_TEXTAREA); if (!inputTextArea) return; let allContent = ''; for (const file of files) { const extension = file.name.split('.').pop().toLowerCase(); try { if (['txt', 'md', 'html', 'css', 'js', 'json'].includes(extension)) { const content = await readFileAsText(file); allContent += `\n\n--- Содержимое ${file.name} ---\n${content}`; } else if (['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp'].includes(extension)) { await loadTesseractJs(); const originalText = document.getElementById('deepseek-main-draggable-menu').querySelector('#deepseek-menu-header').textContent; document.getElementById('deepseek-main-draggable-menu').querySelector('#deepseek-menu-header').textContent = 'DeepSeek Продвинутое Меню (Обработка OCR...)'; const { data: { text } } = await Tesseract.recognize(file, 'rus+eng'); allContent += `\n\n--- OCR из ${file.name} ---\n${text.trim()}`; document.getElementById('deepseek-main-draggable-menu').querySelector('#deepseek-menu-header').textContent = originalText; } else if (extension === 'pdf') { await loadPdfJs(); const text = await extractTextFromPdf(file); allContent += `\n\n--- Содержимое PDF ${file.name} ---\n${text}`; } else if (extension === 'docx') { await loadMammothJs(); const text = await extractTextFromDocx(file); allContent += `\n\n--- Содержимое Word ${file.name} ---\n${text}`; } else { alert(`Неподдерживаемый тип файла: ${file.name}`); continue; } } catch (error) { console.error(`Ошибка при обработке ${file.name}:`, error); alert(`Ошибка при обработке ${file.name}: ${error.message}`); } } if (allContent) { const currentValue = inputTextArea.value; setNativeValue(inputTextArea, currentValue + allContent); } } function readFileAsText(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => resolve(e.target.result); reader.onerror = reject; reader.readAsText(file); }); } async function extractTextFromPdf(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = async (e) => { try { const typedarray = new Uint8Array(e.target.result); const loadingTask = window.pdfjsLib.getDocument({ data: typedarray }); const pdf = await loadingTask.promise; let text = ''; for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) { const page = await pdf.getPage(pageNum); const content = await page.getTextContent(); text += content.items.map(item => item.str).join(' ') + '\n'; } resolve(text); } catch (err) { reject(err); } }; reader.onerror = reject; reader.readAsArrayBuffer(file); }); } async function extractTextFromDocx(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = async (e) => { try { const result = await mammoth.extractRawText({ arrayBuffer: e.target.result }); resolve(result.value.trim()); } catch (err) { reject(err); } }; reader.onerror = reject; reader.readAsArrayBuffer(file); }); } /** * Добавляет счетчик символов */ function addCharCounter() { const inputTextArea = document.querySelector(SELECTORS.CHAT_INPUT_TEXTAREA); const inputContainer = document.querySelector(SELECTORS.CHAT_INPUT_CONTAINER); if (!inputTextArea || !inputContainer) return; // Проверяем, если уже существует if (document.querySelector(SELECTORS.CHAR_COUNTER)) return; const counter = document.createElement('div'); counter.id = 'deepseek-char-counter'; counter.style.cssText = ` position: absolute; bottom: 8px; right: 12px; font-size: 11px; color: #1B73FF; background: rgba(27, 115, 255, 0.1); padding: 4px 8px; border-radius: 8px; z-index: 10; pointer-events: none; box-shadow: 0 2px 4px rgba(0,0,0,0.1); border: 1px solid rgba(27, 115, 255, 0.2); font-weight: 500; `; const updateCounter = () => { const count = inputTextArea.value.length; counter.textContent = `${count} симв.`; }; inputTextArea.addEventListener('input', updateCounter); updateCounter(); inputContainer.style.position = 'relative'; inputContainer.appendChild(counter); } /** * Настраивает функцию редактирования и повторной отправки сообщений */ function setupEditAndResend() { const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.type === 'childList') { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1) { const responses = node.querySelectorAll ? node.querySelectorAll(SELECTORS.MESSAGE_CONTENT) : []; responses.forEach(addEditFunctionality); if (node.matches && node.matches(SELECTORS.MESSAGE_CONTENT)) { addEditFunctionality(node); } } }); } }); }); observer.observe(document.body, { childList: true, subtree: true }); // Добавить к существующим элементам document.querySelectorAll(SELECTORS.MESSAGE_CONTENT).forEach(addEditFunctionality); } function addEditFunctionality(element) { if (element.dataset.editEnabled) return; element.dataset.editEnabled = 'true'; element.style.cursor = 'pointer'; element.style.transition = 'all 0.3s ease'; element.title = 'Нажмите, чтобы использовать этот ответ как промпт'; element.addEventListener('click', () => { const text = element.textContent.trim(); if (text) { const textarea = document.querySelector(SELECTORS.CHAT_INPUT_TEXTAREA); if (textarea) { setNativeValue(textarea, text); textarea.focus(); element.style.background = 'rgba(27, 115, 255, 0.1)'; element.style.borderRadius = '12px'; element.style.padding = '8px'; setTimeout(() => { element.style.background = ''; element.style.borderRadius = ''; element.style.padding = ''; }, 1000); } } }); element.addEventListener('mouseenter', () => { element.style.background = 'rgba(27, 115, 255, 0.05)'; element.style.borderRadius = '12px'; element.style.padding = '8px'; }); element.addEventListener('mouseleave', () => { if (!element.style.background.includes('0.1')) { element.style.background = ''; element.style.borderRadius = ''; element.style.padding = ''; } }); } /** * Создает главное перетаскиваемое меню */ function createDraggableMainMenu() { if (draggableMenu) return draggableMenu; draggableMenu = document.createElement('div'); draggableMenu.id = 'deepseek-main-draggable-menu'; draggableMenu.style.cssText = ` position: fixed; top: 100px; right: 20px; background: linear-gradient(135deg, #0F0F0F 0%, #1a1a1a 100%); border: 1px solid #333; border-radius: 16px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4); z-index: 10001; width: auto; max-width: 320px; min-width: 220px; overflow: hidden; display: flex; flex-direction: column; resize: both; min-height: 120px; backdrop-filter: blur(12px); `; const menuHeader = document.createElement('div'); menuHeader.id = 'deepseek-menu-header'; menuHeader.style.cssText = ` background: linear-gradient(135deg, #1B73FF 0%, #0C5ADB 100%); color: white; padding: 12px 16px; cursor: grab; border-top-left-radius: 14px; border-top-right-radius: 14px; font-weight: 600; display: flex; justify-content: space-between; align-items: center; user-select: none; `; menuHeader.textContent = 'DeepSeek Продвинутое Меню'; const closeButton = document.createElement('button'); closeButton.textContent = '×'; closeButton.style.cssText = ` background: none; border: none; color: white; font-size: 1.5em; cursor: pointer; line-height: 1; padding: 0 5px; transition: color 0.2s; `; closeButton.onmouseover = () => closeButton.style.color = '#eee'; closeButton.onmouseout = () => closeButton.style.color = 'white'; closeButton.onclick = () => draggableMenu.style.display = 'none'; menuHeader.appendChild(closeButton); draggableMenu.appendChild(menuHeader); const menuContent = document.createElement('div'); menuContent.id = 'deepseek-menu-content'; menuContent.style.cssText = ` padding: 16px; display: flex; flex-direction: column; gap: 12px; align-items: stretch; `; draggableMenu.appendChild(menuContent); document.body.appendChild(draggableMenu); // Функция перетаскивания let isDragging = false; let offsetX, offsetY; menuHeader.addEventListener('mousedown', (e) => { isDragging = true; offsetX = e.clientX - draggableMenu.getBoundingClientRect().left; offsetY = e.clientY - draggableMenu.getBoundingClientRect().top; menuHeader.style.cursor = 'grabbing'; document.body.style.userSelect = 'none'; }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; draggableMenu.style.left = (e.clientX - offsetX) + 'px'; draggableMenu.style.top = (e.clientY - offsetY) + 'px'; draggableMenu.style.right = 'auto'; }); document.addEventListener('mouseup', () => { isDragging = false; menuHeader.style.cursor = 'grab'; document.body.style.userSelect = ''; }); return draggableMenu; } /** * Создает плавающую кнопку для переключения главного меню */ function createToggleMenuButton() { const existingToggleButton = document.getElementById('deepseek-toggle-menu-button'); if (existingToggleButton) return; const toggleButton = document.createElement('button'); toggleButton.id = 'deepseek-toggle-menu-button'; toggleButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M12 2v6h4"/> <path d="M12 8V4H8"/> <path d="M22 13a8 8 0 0 1-8 8H6a2 2 0 0 0-2 2v-4a2 2 0 0 0-2-2 8 8 0 0 1 8-8h2a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H6C2.686 0 0 2.686 0 6v6c0 3.314 2.686 6 6 6h8c4.418 0 8-3.582 8-8z"/> </svg>`; toggleButton.title = "Переключить DeepSeek Продвинутое Меню"; toggleButton.style.cssText = ` position: fixed; bottom: 20px; right: 20px; background: linear-gradient(135deg, #1B73FF 0%, #0C5ADB 100%); color: white; border: none; border-radius: 50%; width: 56px; height: 56px; display: flex; justify-content: center; align-items: center; cursor: pointer; box-shadow: 0 4px 15px rgba(27, 115, 255, 0.3); z-index: 10002; transition: all 0.3s ease; `; toggleButton.onmouseover = () => { toggleButton.style.transform = 'scale(1.05)'; toggleButton.style.boxShadow = '0 6px 20px rgba(27, 115, 255, 0.4)'; }; toggleButton.onmouseout = () => { toggleButton.style.transform = 'scale(1)'; toggleButton.style.boxShadow = '0 4px 15px rgba(27, 115, 255, 0.3)'; }; toggleButton.onclick = () => { if (draggableMenu) { draggableMenu.style.display = draggableMenu.style.display === 'none' ? 'flex' : 'none'; } }; document.body.appendChild(toggleButton); } /** * Инициализирует все функции */ function initializeFeatures() { if (featuresInitialized) return; const chatInputTextArea = document.querySelector(SELECTORS.CHAT_INPUT_TEXTAREA); if (!chatInputTextArea) { return; } featuresInitialized = true; const menu = createDraggableMainMenu(); const menuContent = document.getElementById('deepseek-menu-content'); // Создать элементы меню const promptsDropdown = createCategorizedDropdown(ALL_CATEGORIZED_PROMPTS, handlePromptSelection, "🚀 Выбрать Промпт"); const saveButton = createButton('💾 Сохранить Диалог', saveCurrentChat, {width: '100%'}); const loadButton = createButton('📂 Загрузить Диалоги', loadSavedChats, {width: '100%'}); const exportButton = createButton('📤 Экспорт (TXT)', exportChatToText, {width: '100%'}); // Скрытый input для файлов const fileInputForMenu = document.createElement('input'); fileInputForMenu.type = 'file'; fileInputForMenu.multiple = true; fileInputForMenu.accept = '.txt,.md,.html,.css,.js,.json,.png,.jpg,.jpeg,.gif,.bmp,.webp,.pdf,.docx'; fileInputForMenu.style.display = 'none'; const importButtonInMenu = createButton('📁 Импорт Файлов (OCR)', () => fileInputForMenu.click(), { background: 'linear-gradient(135deg, #10B981 0%, #059669 100%)', fontSize: '14px', width: '100%', marginBottom: '10px' }); // События drag and drop для импорта importButtonInMenu.addEventListener('dragover', (e) => { e.preventDefault(); importButtonInMenu.style.background = 'linear-gradient(135deg, #34D399 0%, #10B981 100%)'; importButtonInMenu.style.boxShadow = '0 6px 12px rgba(16, 185, 129, 0.3)'; }); importButtonInMenu.addEventListener('dragleave', () => { importButtonInMenu.style.background = 'linear-gradient(135deg, #10B981 0%, #059669 100%)'; importButtonInMenu.style.boxShadow = '0 2px 8px rgba(16, 185, 129, 0.2)'; }); importButtonInMenu.addEventListener('drop', (e) => { e.preventDefault(); importButtonInMenu.style.background = 'linear-gradient(135deg, #10B981 0%, #059669 100%)'; importButtonInMenu.style.boxShadow = '0 2px 8px rgba(16, 185, 129, 0.2)'; if (e.dataTransfer.files.length > 0) { processDroppedFiles(e.dataTransfer.files); } }); fileInputForMenu.addEventListener('change', (e) => { if (e.target.files.length > 0) { processDroppedFiles(e.target.files); e.target.value = ''; } }); document.body.appendChild(fileInputForMenu); // Добавить элементы в меню menuContent.appendChild(promptsDropdown); menuContent.appendChild(importButtonInMenu); menuContent.appendChild(saveButton); menuContent.appendChild(loadButton); menuContent.appendChild(exportButton); // Создать кнопку переключения createToggleMenuButton(); // Инициализировать другие функции addCharCounter(); setupEditAndResend(); console.log('DeepSeek Chat Продвинутый: Все функции инициализированы.'); } // Наблюдатель для ожидания загрузки интерфейса const observer = new MutationObserver((mutations, obs) => { if (!featuresInitialized && document.querySelector(SELECTORS.CHAT_INPUT_TEXTAREA)) { initializeFeatures(); } }); observer.observe(document.body, { childList: true, subtree: true }); // Попытаться инициализировать немедленно, если уже загружено if (document.readyState === 'complete' || document.readyState === 'interactive') { setTimeout(initializeFeatures, 1000); } })();