您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
一個 Tampermonkey 腳本,提供浮動介面整合多款 AI 助手,支援右鍵呼叫、清空歷史訊息、可調整尺寸,並記錄 AI 選擇狀態與位置,從Tampermonkey 選單呼叫。
// ==UserScript== // @name AI助手選擇器 // @name:en AI Assistant Selector // @namespace http://tampermonkey.net/ // @version 3.2 // @description 一個 Tampermonkey 腳本,提供浮動介面整合多款 AI 助手,支援右鍵呼叫、清空歷史訊息、可調整尺寸,並記錄 AI 選擇狀態與位置,從Tampermonkey 選單呼叫。 // @description:en A Tampermonkey script that provides a floating interface integrating multiple AI assistants, supporting right-click invocation, clearing history messages, adjustable size, recording AI selection status and position, and callable from the Tampermonkey menu. // @author 請替換成您的名字或暱稱 / Replace with your name or nickname // @match *://*/* // @match *://grok.com/* // @match *://chatgpt.com/* // @match *://chat.deepseek.com/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @license MIT // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @grant GM_openInTab // @grant GM_registerMenuCommand // ==/UserScript== (function() { 'use strict'; // 樣式定義(移除氣泡相關樣式) const styles = ` .ai-selector-container { position: fixed; background: #2c2c2c; padding: 15px; border-radius: 10px; z-index: 9999; min-width: 200px; min-height: 200px; top: ${GM_getValue('containerTop', '50px')}; left: ${GM_getValue('containerLeft', '50px')}; box-shadow: 0 4px 6px rgba(0,0,0,0.1); color: white; font-family: Arial, sans-serif; resize: both; overflow: auto; } .ai-selector-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; cursor: move; background: #3a3a3a; padding: 5px 10px; border-radius: 5px; } .ai-selector-title { font-size: 16px; font-weight: bold; } .ai-selector-minimize { cursor: pointer; padding: 5px; } .ai-selector-content { display: none; flex-direction: column; gap: 10px; } .ai-option { display: flex; align-items: center; padding: 8px; border-radius: 5px; cursor: pointer; transition: background 0.3s; } .ai-option:hover { background: rgba(255,255,255,0.1); } .ai-option.selected { background: #4285f4; } .ai-name { margin-left: 10px; } .question-input { width: 100%; padding: 8px; border-radius: 5px; border: 1px solid #444; background: #1c1c1c; color: white; margin-top: 10px; box-sizing: border-box; } .send-button { width: 100%; padding: 8px; border-radius: 5px; border: none; background: #4285f4; color: white; cursor: pointer; margin-top: 10px; } .send-button:hover { background: #5294ff; } .send-button:disabled { background: #666; cursor: not-allowed; } .clear-button { width: 100%; padding: 8px; border-radius: 5px; border: none; background: #e74c3c; color: white; cursor: pointer; margin-bottom: 10px; } .clear-button:hover { background: #ff6655; } .grok-response-container, .chatgpt-response-container, .deepseek-response-container { position: fixed; background: #2c2c2c; padding: 15px; border-radius: 10px; z-index: 9998; min-width: 200px; min-height: 200px; top: ${GM_getValue('grokResponseTop', '100px')}; left: ${GM_getValue('grokResponseLeft', '100px')}; box-shadow: 0 4px 6px rgba(0,0,0,0.1); color: white; font-family: Arial, sans-serif; resize: both; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; } .grok-response-header, .chatgpt-response-header, .deepseek-response-header { display: flex; justify-content: space-between; align-items: center; background: #3a3a3a; padding: 5px 10px; border-radius: 5px; cursor: move; flex-shrink: 0; margin-bottom: 0; } .grok-response-title, .chatgpt-response-title, .deepseek-response-title { font-size: 16px; font-weight: bold; } .grok-response-close, .chatgpt-response-close, .deepseek-response-close { cursor: pointer; padding: 5px; } .grok-response, .chatgpt-response, .deepseek-response { padding: 10px; background: #1c1c1c; border-radius: 5px; border: 1px solid #444; color: white; white-space: pre-wrap; flex-grow: 1; } .grok-response p, .chatgpt-response p, .deepseek-response p { margin: 5px 0; padding: 5px; background: #333; border-radius: 3px; } `; // AI助手配置 const AIs = [ { id: 'gemini', name: 'Gemini', url: 'https://gemini.google.com/app', inputSelector: 'rich-textarea.text-input-field_textarea', color: '#8e44ad' }, { id: 'grok', name: 'Grok', url: 'https://grok.com/', color: '#e74c3c' }, { id: 'chatgpt', name: 'ChatGPT', url: 'https://chatgpt.com/', color: '#27ae60' }, { id: 'perplexity', name: 'Perplexity', url: 'https://www.perplexity.ai/', color: '#3498db' }, { id: 'deepseek', name: 'DeepSeek', url: 'https://chat.deepseek.com/', color: '#f1c40f' } ]; // 添加樣式 GM_addStyle(styles); // 拖動功能 function makeDraggable(element, handle, saveKeyPrefix) { let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; let isDragging = false; let moved = false; const dragHandle = handle || element; dragHandle.addEventListener('mousedown', dragStart); function dragStart(e) { const rect = element.getBoundingClientRect(); const isBottomRight = e.clientX > rect.right - 20 && e.clientY > rect.bottom - 20; if (isBottomRight && element.style.resize === 'both') { return; } e.preventDefault(); pos3 = e.clientX; pos4 = e.clientY; isDragging = true; moved = false; document.addEventListener('mousemove', dragMove); document.addEventListener('mouseup', dragEnd); } function dragMove(e) { if (!isDragging) return; e.preventDefault(); pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; let newTop = element.offsetTop - pos2; let newLeft = element.offsetLeft - pos1; newTop = Math.max(0, Math.min(newTop, window.innerHeight - element.offsetHeight)); newLeft = Math.max(0, Math.min(newLeft, window.innerWidth - element.offsetWidth)); element.style.top = `${newTop}px`; element.style.left = `${newLeft}px`; moved = true; } function dragEnd(e) { if (!isDragging) return; document.removeEventListener('mousemove', dragMove); document.removeEventListener('mouseup', dragEnd); isDragging = false; if (saveKeyPrefix && moved) { GM_setValue(`${saveKeyPrefix}Top`, element.style.top || `${element.offsetTop}px`); GM_setValue(`${saveKeyPrefix}Left`, element.style.left || `${element.offsetLeft}px`); } } } // 創建UI(移除氣泡) function createUI() { const container = document.createElement('div'); container.className = 'ai-selector-container'; container.style.display = 'none'; const savedWidth = GM_getValue('containerWidth', 300); const savedHeight = GM_getValue('containerHeight', 300); const savedTop = GM_getValue('containerTop', '50px'); const savedLeft = GM_getValue('containerLeft', '50px'); container.style.width = `${Math.max(savedWidth, 200)}px`; container.style.height = `${Math.max(savedHeight, 200)}px`; container.style.top = savedTop; container.style.left = savedLeft; const header = document.createElement('div'); header.className = 'ai-selector-header'; const title = document.createElement('div'); title.className = 'ai-selector-title'; title.textContent = 'AI助手選擇器 / AI Assistant Selector'; const minimize = document.createElement('div'); minimize.className = 'ai-selector-minimize'; minimize.textContent = '×'; header.appendChild(title); header.appendChild(minimize); const content = document.createElement('div'); content.className = 'ai-selector-content'; const selectedAIs = GM_getValue('selectedAIs', AIs.map(ai => ai.id)); AIs.forEach(ai => { const option = document.createElement('div'); option.className = 'ai-option'; option.dataset.aiId = ai.id; option.style.border = `2px solid ${ai.color}`; if (selectedAIs.includes(ai.id)) { option.classList.add('selected'); } const name = document.createElement('span'); name.className = 'ai-name'; name.textContent = ai.name; option.appendChild(name); content.appendChild(option); }); const questionInput = document.createElement('textarea'); questionInput.className = 'question-input'; questionInput.placeholder = '輸入您的問題 / Enter your question'; const sendButton = document.createElement('button'); sendButton.className = 'send-button'; sendButton.textContent = '發送到選中的AI / Send to Selected AI'; content.appendChild(questionInput); content.appendChild(sendButton); container.appendChild(header); container.appendChild(content); // Grok 回應 UI const grokResponseContainer = document.createElement('div'); grokResponseContainer.className = 'grok-response-container'; grokResponseContainer.style.display = 'none'; let grokWidth = GM_getValue('grokResponseWidth', 300); let grokHeight = GM_getValue('grokResponseHeight', 200); const grokTop = GM_getValue('grokResponseTop', '100px'); const grokLeft = GM_getValue('grokResponseLeft', '100px'); grokWidth = Math.max(grokWidth, 200); grokHeight = Math.max(grokHeight, 200); grokResponseContainer.style.top = grokTop; grokResponseContainer.style.left = grokLeft; grokResponseContainer.style.width = `${grokWidth}px`; grokResponseContainer.style.height = `${grokHeight}px`; const grokHeader = document.createElement('div'); grokHeader.className = 'grok-response-header'; const grokTitle = document.createElement('div'); grokTitle.className = 'grok-response-title'; grokTitle.textContent = 'Grok 回應 / Grok Response'; const grokClose = document.createElement('div'); grokClose.className = 'grok-response-close'; grokClose.textContent = '×'; grokHeader.appendChild(grokTitle); grokHeader.appendChild(grokClose); const grokResponseDiv = document.createElement('div'); grokResponseDiv.className = 'grok-response'; const grokInitialP = document.createElement('p'); grokInitialP.textContent = '等待 Grok 回應... / Waiting for Grok response...'; grokResponseDiv.appendChild(grokInitialP); const grokClearButton = document.createElement('button'); grokClearButton.className = 'clear-button'; grokClearButton.textContent = '清空歷史訊息 / Clear History'; grokResponseContainer.appendChild(grokHeader); grokResponseContainer.appendChild(grokClearButton); grokResponseContainer.appendChild(grokResponseDiv); // ChatGPT 回應 UI const chatgptResponseContainer = document.createElement('div'); chatgptResponseContainer.className = 'chatgpt-response-container'; chatgptResponseContainer.style.display = 'none'; let chatgptWidth = GM_getValue('chatgptResponseWidth', 300); let chatgptHeight = GM_getValue('chatgptResponseHeight', 200); const chatgptTop = GM_getValue('chatgptResponseTop', '150px'); const chatgptLeft = GM_getValue('chatgptResponseLeft', '150px'); chatgptWidth = Math.max(chatgptWidth, 200); chatgptHeight = Math.max(chatgptHeight, 200); chatgptResponseContainer.style.top = chatgptTop; chatgptResponseContainer.style.left = chatgptLeft; chatgptResponseContainer.style.width = `${chatgptWidth}px`; chatgptResponseContainer.style.height = `${chatgptHeight}px`; const chatgptHeader = document.createElement('div'); chatgptHeader.className = 'chatgpt-response-header'; const chatgptTitle = document.createElement('div'); chatgptTitle.className = 'chatgpt-response-title'; chatgptTitle.textContent = 'ChatGPT 回應 / ChatGPT Response'; const chatgptClose = document.createElement('div'); chatgptClose.className = 'chatgpt-response-close'; chatgptClose.textContent = '×'; chatgptHeader.appendChild(chatgptTitle); chatgptHeader.appendChild(chatgptClose); const chatgptResponseDiv = document.createElement('div'); chatgptResponseDiv.className = 'chatgpt-response'; const chatgptInitialP = document.createElement('p'); chatgptInitialP.textContent = '等待 ChatGPT 回應... / Waiting for ChatGPT response...'; chatgptResponseDiv.appendChild(chatgptInitialP); const chatgptClearButton = document.createElement('button'); chatgptClearButton.className = 'clear-button'; chatgptClearButton.textContent = '清空歷史訊息 / Clear History'; chatgptResponseContainer.appendChild(chatgptHeader); chatgptResponseContainer.appendChild(chatgptClearButton); chatgptResponseContainer.appendChild(chatgptResponseDiv); // DeepSeek 回應 UI const deepseekResponseContainer = document.createElement('div'); deepseekResponseContainer.className = 'deepseek-response-container'; deepseekResponseContainer.style.display = 'none'; let deepseekWidth = GM_getValue('deepseekResponseWidth', 300); let deepseekHeight = GM_getValue('deepseekResponseHeight', 200); const deepseekTop = GM_getValue('deepseekResponseTop', '200px'); const deepseekLeft = GM_getValue('deepseekResponseLeft', '200px'); deepseekWidth = Math.max(deepseekWidth, 200); deepseekHeight = Math.max(deepseekHeight, 200); deepseekResponseContainer.style.top = deepseekTop; deepseekResponseContainer.style.left = deepseekLeft; deepseekResponseContainer.style.width = `${deepseekWidth}px`; deepseekResponseContainer.style.height = `${deepseekHeight}px`; const deepseekHeader = document.createElement('div'); deepseekHeader.className = 'deepseek-response-header'; const deepseekTitle = document.createElement('div'); deepseekTitle.className = 'deepseek-response-title'; deepseekTitle.textContent = 'DeepSeek 回應 / DeepSeek Response'; const deepseekClose = document.createElement('div'); deepseekClose.className = 'deepseek-response-close'; deepseekClose.textContent = '×'; deepseekHeader.appendChild(deepseekTitle); deepseekHeader.appendChild(deepseekClose); const deepseekResponseDiv = document.createElement('div'); deepseekResponseDiv.className = 'deepseek-response'; const deepseekInitialP = document.createElement('p'); deepseekInitialP.textContent = '等待 DeepSeek 回應... / Waiting for DeepSeek response...'; deepseekResponseDiv.appendChild(deepseekInitialP); const deepseekClearButton = document.createElement('button'); deepseekClearButton.className = 'clear-button'; deepseekClearButton.textContent = '清空歷史訊息 / Clear History'; deepseekResponseContainer.appendChild(deepseekHeader); deepseekResponseContainer.appendChild(deepseekClearButton); deepseekResponseContainer.appendChild(deepseekResponseDiv); document.body.appendChild(container); document.body.appendChild(grokResponseContainer); document.body.appendChild(chatgptResponseContainer); document.body.appendChild(deepseekResponseContainer); return { container, grokResponseContainer, grokResponseDiv, chatgptResponseContainer, chatgptResponseDiv, deepseekResponseContainer, deepseekResponseDiv, header, grokHeader, chatgptHeader, deepseekHeader, grokClearButton, chatgptClearButton, deepseekClearButton }; } // 初始化事件監聽(移除氣泡相關事件,新增選單按鈕) function initializeEvents(container, grokResponseContainer, grokResponseDiv, chatgptResponseContainer, chatgptResponseDiv, deepseekResponseContainer, deepseekResponseDiv, header, grokHeader, chatgptHeader, deepseekHeader, grokClearButton, chatgptClearButton, deepseekClearButton) { const aiOptions = container.querySelectorAll('.ai-option'); const questionInput = container.querySelector('.question-input'); const sendButton = container.querySelector('.send-button'); const minimizeButton = container.querySelector('.ai-selector-minimize'); const content = container.querySelector('.ai-selector-content'); const grokCloseButton = grokResponseContainer.querySelector('.grok-response-close'); const chatgptCloseButton = chatgptResponseContainer.querySelector('.chatgpt-response-close'); const deepseekCloseButton = deepseekResponseContainer.querySelector('.deepseek-response-close'); aiOptions.forEach(option => { option.addEventListener('click', () => { option.classList.toggle('selected'); const selectedAIs = Array.from(aiOptions) .filter(opt => opt.classList.contains('selected')) .map(opt => opt.dataset.aiId); GM_setValue('selectedAIs', selectedAIs); }); }); minimizeButton.addEventListener('click', () => { container.style.display = 'none'; }); sendButton.addEventListener('click', () => { const selectedAIs = Array.from(aiOptions).filter(option => option.classList.contains('selected')); const question = questionInput.value.trim(); if (selectedAIs.length > 0 && question) { selectedAIs.forEach(aiOption => { const aiId = aiOption.dataset.aiId; const ai = AIs.find(a => a.id === aiId); if (ai) { openAIInNewTab(ai, question); } }); questionInput.value = ''; } }); grokClearButton.addEventListener('click', () => { while (grokResponseDiv.firstChild) { grokResponseDiv.removeChild(grokResponseDiv.firstChild); } const p = document.createElement('p'); p.textContent = '等待 Grok 回應... / Waiting for Grok response...'; grokResponseDiv.appendChild(p); }); chatgptClearButton.addEventListener('click', () => { while (chatgptResponseDiv.firstChild) { chatgptResponseDiv.removeChild(chatgptResponseDiv.firstChild); } const p = document.createElement('p'); p.textContent = '等待 ChatGPT 回應... / Waiting for ChatGPT response...'; chatgptResponseDiv.appendChild(p); }); deepseekClearButton.addEventListener('click', () => { while (deepseekResponseDiv.firstChild) { deepseekResponseDiv.removeChild(deepseekResponseDiv.firstChild); } const p = document.createElement('p'); p.textContent = '等待 DeepSeek 回應... / Waiting for DeepSeek response...'; deepseekResponseDiv.appendChild(p); }); grokCloseButton.addEventListener('click', () => { grokResponseContainer.style.display = 'none'; }); chatgptCloseButton.addEventListener('click', () => { chatgptResponseContainer.style.display = 'none'; }); deepseekCloseButton.addEventListener('click', () => { deepseekResponseContainer.style.display = 'none'; }); makeDraggable(container, header, 'container'); makeDraggable(grokResponseContainer, grokHeader, 'grokResponse'); makeDraggable(chatgptResponseContainer, chatgptHeader, 'chatgptResponse'); makeDraggable(deepseekResponseContainer, deepseekHeader, 'deepseekResponse'); window.addEventListener('resize', () => { if (container.style.display !== 'none') { const containerWidth = container.offsetWidth; const containerHeight = container.offsetHeight; let containerTop = parseInt(container.style.top || GM_getValue('containerTop', '50px')); let containerLeft = parseInt(container.style.left || GM_getValue('containerLeft', '50px')); containerTop = Math.max(0, Math.min(containerTop, window.innerHeight - containerHeight)); containerLeft = Math.max(0, Math.min(containerLeft, window.innerWidth - containerWidth)); container.style.top = `${containerTop}px`; container.style.left = `${containerLeft}px`; GM_setValue('containerTop', `${containerTop}px`); GM_setValue('containerLeft', `${containerLeft}px`); } if (grokResponseContainer.style.display !== 'none') { const grokWidth = grokResponseContainer.offsetWidth; const grokHeight = grokResponseContainer.offsetHeight; let grokTop = parseInt(grokResponseContainer.style.top); let grokLeft = parseInt(grokResponseContainer.style.left); grokTop = Math.max(0, Math.min(grokTop, window.innerHeight - grokHeight)); grokLeft = Math.max(0, Math.min(grokLeft, window.innerWidth - grokWidth)); grokResponseContainer.style.top = `${grokTop}px`; grokResponseContainer.style.left = `${grokLeft}px`; } if (chatgptResponseContainer.style.display !== 'none') { const chatgptWidth = chatgptResponseContainer.offsetWidth; const chatgptHeight = chatgptResponseContainer.offsetHeight; let chatgptTop = parseInt(chatgptResponseContainer.style.top); let chatgptLeft = parseInt(chatgptResponseContainer.style.left); chatgptTop = Math.max(0, Math.min(chatgptTop, window.innerHeight - chatgptHeight)); chatgptLeft = Math.max(0, Math.min(chatgptLeft, window.innerWidth - chatgptWidth)); chatgptResponseContainer.style.top = `${chatgptTop}px`; chatgptResponseContainer.style.left = `${chatgptLeft}px`; } if (deepseekResponseContainer.style.display !== 'none') { const deepseekWidth = deepseekResponseContainer.offsetWidth; const deepseekHeight = deepseekResponseContainer.offsetHeight; let deepseekTop = parseInt(deepseekResponseContainer.style.top); let deepseekLeft = parseInt(deepseekResponseContainer.style.left); deepseekTop = Math.max(0, Math.min(deepseekTop, window.innerHeight - deepseekHeight)); deepseekLeft = Math.max(0, Math.min(deepseekLeft, window.innerWidth - deepseekWidth)); deepseekResponseContainer.style.top = `${deepseekTop}px`; deepseekResponseContainer.style.left = `${deepseekLeft}px`; } }); const resizeObserver = new ResizeObserver(entries => { for (let entry of entries) { const target = entry.target; if (target.style.display !== 'none') { if (target === container) { GM_setValue('containerWidth', target.offsetWidth); GM_setValue('containerHeight', target.offsetHeight); } else if (target === grokResponseContainer) { GM_setValue('grokResponseWidth', target.offsetWidth); GM_setValue('grokResponseHeight', target.offsetHeight); } else if (target === chatgptResponseContainer) { GM_setValue('chatgptResponseWidth', target.offsetWidth); GM_setValue('chatgptResponseHeight', target.offsetHeight); } else if (target === deepseekResponseContainer) { GM_setValue('deepseekResponseWidth', target.offsetWidth); GM_setValue('deepseekResponseHeight', target.offsetHeight); } } } }); resizeObserver.observe(container); resizeObserver.observe(grokResponseContainer); resizeObserver.observe(chatgptResponseContainer); resizeObserver.observe(deepseekResponseContainer); // 顯示容器函數 function showContainer() { container.style.display = 'block'; content.style.display = 'flex'; const savedWidth = GM_getValue('containerWidth', 300); const savedHeight = GM_getValue('containerHeight', 300); const savedTop = GM_getValue('containerTop', '50px'); const savedLeft = GM_getValue('containerLeft', '50px'); container.style.width = `${Math.max(savedWidth, 200)}px`; container.style.height = `${Math.max(savedHeight, 200)}px`; container.style.top = savedTop; container.style.left = savedLeft; const containerWidth = container.offsetWidth; const containerHeight = container.offsetHeight; let containerTop = parseInt(savedTop); let containerLeft = parseInt(savedLeft); containerTop = Math.max(0, Math.min(containerTop, window.innerHeight - containerHeight)); containerLeft = Math.max(0, Math.min(containerLeft, window.innerWidth - containerWidth)); container.style.top = `${containerTop}px`; container.style.left = `${containerLeft}px`; } // 註冊 Tampermonkey 選單按鈕 GM_registerMenuCommand('開啟 AI 助手選擇器 / Open AI Assistant Selector', showContainer); } // 在新標籤頁中打開AI function openAIInNewTab(ai, question) { const url = `${ai.url}${ai.id === 'gemini' ? '?q=' : '?q='}${encodeURIComponent(question)}`; GM_openInTab(url, { active: false, insert: true, setParent: true }); } // 處理 Gemini 頁面 function handleGeminiPage() { if (window.location.hostname === 'gemini.google.com' && window.location.search.includes('q=')) { const query = new URLSearchParams(window.location.search).get('q'); if (query) { function setTextAndSendAfterDelay(string) { const richTextarea = document.querySelector('rich-textarea.text-input-field_textarea'); if (!richTextarea) return false; const firstDiv = richTextarea.querySelector('div'); if (!firstDiv) return false; firstDiv.innerText = string; const event = new Event('input', { bubbles: true }); firstDiv.dispatchEvent(event); setTimeout(() => { const sendButton = document.querySelector('.send-button'); if (sendButton) sendButton.click(); }, 1000); return true; } const waitForElement = (selector, maxAttempts = 30) => { return new Promise((resolve) => { let attempts = 0; const interval = setInterval(() => { const element = document.querySelector(selector); attempts++; if (element || attempts >= maxAttempts) { clearInterval(interval); resolve(element); } }, 500); }); }; const trySetQuestion = async () => { await waitForElement('rich-textarea.text-input-field_textarea'); setTextAndSendAfterDelay(decodeURIComponent(query)); }; trySetQuestion(); window.history.replaceState({}, document.title, '/app'); } } } // 處理 Grok 頁面 function handleGrokPage() { if (window.location.hostname === 'grok.com') { let lastContent = ''; setInterval(() => { const messageBubbles = document.querySelectorAll('div.message-bubble:not(.processed)'); let currentContent = ''; messageBubbles.forEach(div => { const content = div.innerHTML.trim(); if (content) { const nextSibling = div.nextElementSibling; let buttonCount = 0; if (nextSibling) { buttonCount = nextSibling.querySelectorAll('button').length; } if (buttonCount > 2) { currentContent += content + '\n'; div.classList.add('processed'); } } }); if (currentContent && currentContent !== lastContent) { lastContent = currentContent.trim(); setTimeout(() => { const finalCheck = document.querySelectorAll('div.message-bubble.processed'); let finalContent = ''; finalCheck.forEach(div => { finalContent += div.innerHTML.trim() + '\n'; }); finalContent = finalContent.trim(); if (finalContent === lastContent) { GM_setValue('grokResponse', lastContent); } }, 1000); } }, 500); } } // 處理 ChatGPT 頁面 function handleChatGPTPage() { if (window.location.hostname === 'chatgpt.com') { let lastContent = ''; setInterval(() => { const stopButton = document.querySelector('[data-testid="stop-button"]'); if (stopButton) { return; } const messageBubbles = document.querySelectorAll('div[data-message-author-role="assistant"]:not(.processed)'); let currentContent = ''; messageBubbles.forEach(div => { const content = div.innerHTML.trim(); if (content) { const grandParent = div.parentElement.parentElement; if (grandParent.children.length === 3) { currentContent += content + '\n'; div.classList.add('processed'); } } }); if (currentContent && currentContent !== lastContent) { lastContent = currentContent.trim(); setTimeout(() => { GM_setValue('chatgptResponse', lastContent); }, 1000); } }, 500); } } // 處理 DeepSeek 頁面 function handleDeepSeekPage() { if (window.location.hostname === 'chat.deepseek.com' && window.location.search.includes('q=')) { const query = new URLSearchParams(window.location.search).get('q'); if (query) { const waitForElement = (selector, maxAttempts = 30) => { return new Promise((resolve) => { let attempts = 0; const interval = setInterval(() => { const element = document.querySelector(selector); attempts++; if (element || attempts >= maxAttempts) { clearInterval(interval); resolve(element); } }, 500); }); }; const trySetQuestion = async () => { const chatInput = await waitForElement('#chat-input'); if (chatInput) { chatInput.value = decodeURIComponent(query); const inputEvent = new Event('input', { bubbles: true }); chatInput.dispatchEvent(inputEvent); setTimeout(() => { const enterEvent = new KeyboardEvent('keydown', { bubbles: true, cancelable: true, keyCode: 13 }); chatInput.dispatchEvent(enterEvent); }, 1000); } }; trySetQuestion(); window.history.replaceState({}, document.title, '/'); } } let lastContent = ''; setInterval(() => { const responseElements = document.querySelectorAll('.chat-message[data-from="assistant"]:not(.processed)'); let currentContent = ''; responseElements.forEach(element => { const content = element.innerHTML.trim(); if (content) { currentContent += content + '\n'; element.classList.add('processed'); } }); if (currentContent && currentContent !== lastContent) { lastContent = currentContent.trim(); setTimeout(() => { GM_setValue('deepseekResponse', lastContent); }, 1000); } }, 500); } // 檢查並顯示 Grok 回應 function checkGrokResponse(grokResponseContainer, grokResponseDiv) { if (!grokResponseDiv) return; setInterval(() => { const response = GM_getValue('grokResponse', ''); if (response && grokResponseContainer.style.display === 'block') { const newResponse = document.createElement('p'); newResponse.innerHTML = response; while (grokResponseDiv.firstChild) { grokResponseDiv.removeChild(grokResponseDiv.firstChild); } grokResponseDiv.appendChild(newResponse); GM_setValue('grokResponse', ''); } }, 1000); } // 檢查並顯示 ChatGPT 回應 function checkChatGPTResponse(chatgptResponseContainer, chatgptResponseDiv) { if (!chatgptResponseDiv) return; setInterval(() => { const response = GM_getValue('chatgptResponse', ''); if (response && chatgptResponseContainer.style.display === 'block') { const newResponse = document.createElement('p'); newResponse.innerHTML = response; while (chatgptResponseDiv.firstChild) { chatgptResponseDiv.removeChild(chatgptResponseDiv.firstChild); } chatgptResponseDiv.appendChild(newResponse); GM_setValue('chatgptResponse', ''); } }, 1000); } // 檢查並顯示 DeepSeek 回應 function checkDeepSeekResponse(deepseekResponseContainer, deepseekResponseDiv) { if (!deepseekResponseDiv) return; setInterval(() => { const response = GM_getValue('deepseekResponse', ''); if (response && deepseekResponseContainer.style.display === 'block') { const newResponse = document.createElement('p'); newResponse.innerHTML = response; while (deepseekResponseDiv.firstChild) { deepseekResponseDiv.removeChild(deepseekResponseDiv.firstChild); } deepseekResponseDiv.appendChild(newResponse); GM_setValue('deepseekResponse', ''); } }, 1000); } // 啟動腳本 function initialize() { const { container, grokResponseContainer, grokResponseDiv, chatgptResponseContainer, chatgptResponseDiv, deepseekResponseContainer, deepseekResponseDiv, header, grokHeader, chatgptHeader, deepseekHeader, grokClearButton, chatgptClearButton, deepseekClearButton } = createUI(); initializeEvents(container, grokResponseContainer, grokResponseDiv, chatgptResponseContainer, chatgptResponseDiv, deepseekResponseContainer, deepseekResponseDiv, header, grokHeader, chatgptHeader, deepseekHeader, grokClearButton, chatgptClearButton, deepseekClearButton); handleGeminiPage(); handleGrokPage(); handleChatGPTPage(); handleDeepSeekPage(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initialize); } else { initialize(); } })();