您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
一個 Tampermonkey 腳本,提供浮動介面整合多款 AI 助手,支援右鍵呼叫、清空歷史訊息、可調整尺寸,並記錄 AI 選擇狀態與位置,修復 ChatGPT 回應監聽與 UI 更
当前为
// ==UserScript== // @name AI助手選擇器 / AI Assistant Selector // @name:en AI Assistant Selector // @namespace http://tampermonkey.net/ // @version 3.0 // @description 一個 Tampermonkey 腳本,提供浮動介面整合多款 AI 助手,支援右鍵呼叫、清空歷史訊息、可調整尺寸,並記錄 AI 選擇狀態與位置,修復 ChatGPT 回應監聽與 UI 更 // @description:en A Tampermonkey script that provides a floating interface to integrate multiple AI assistants, supporting right-click invocation, clearing history messages, resizable UI, and recording AI selection state and position, with fixes for ChatGPT response monitoring and UI updates // @author Your name // @match *://*/* // @match *://grok.com/* // @match *://chatgpt.com/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @grant GM_openInTab // @license MIT // ==/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-bubble { position: fixed; width: 40px; height: 40px; background: #666; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: white; font-size: 16px; font-weight: bold; cursor: move; z-index: 10000; box-shadow: 0 2px 4px rgba(0,0,0,0.2); } .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 { 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 { 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 { font-size: 16px; font-weight: bold; } .grok-response-close, .chatgpt-response-close { cursor: pointer; padding: 5px; } .grok-response, .chatgpt-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 { 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' } ]; // 添加樣式 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`); console.log(`Saved ${saveKeyPrefix}Top: ${element.style.top}, ${saveKeyPrefix}Left: ${element.style.left}`); } } } // 創建UI function createUI() { const bubble = document.createElement('div'); bubble.className = 'ai-selector-bubble'; bubble.textContent = 'AI'; const savedBubbleTop = GM_getValue('positionTop', '20px'); const savedBubbleLeft = GM_getValue('positionLeft', 'calc(100% - 60px)'); bubble.style.top = savedBubbleTop; bubble.style.left = savedBubbleLeft; const container = document.createElement('div'); container.className = 'ai-selector-container'; container.style.display = 'none'; // 從 GM_getValue 獲取保存的尺寸和位置 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; console.log(`Loaded container - width: ${container.style.width}, height: ${container.style.height}, top: ${container.style.top}, left: ${container.style.left}`); 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); document.body.appendChild(bubble); document.body.appendChild(container); document.body.appendChild(grokResponseContainer); document.body.appendChild(chatgptResponseContainer); return { bubble, container, grokResponseContainer, grokResponseDiv, chatgptResponseContainer, chatgptResponseDiv, header, grokHeader, chatgptHeader, grokClearButton, chatgptClearButton }; } // 初始化事件監聽 function initializeEvents(bubble, container, grokResponseContainer, grokResponseDiv, chatgptResponseContainer, chatgptResponseDiv, header, grokHeader, chatgptHeader, grokClearButton, chatgptClearButton) { 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'); 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'; bubble.style.display = 'flex'; }); 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); if (ai.id === 'grok') { grokResponseContainer.style.display = 'block'; while (grokResponseDiv.firstChild) { grokResponseDiv.removeChild(grokResponseDiv.firstChild); } const p = document.createElement('p'); p.textContent = '等待 Grok 回應... / Waiting for Grok response...'; grokResponseDiv.appendChild(p); } if (ai.id === 'chatgpt') { chatgptResponseContainer.style.display = 'block'; while (chatgptResponseDiv.firstChild) { chatgptResponseDiv.removeChild(chatgptResponseDiv.firstChild); } const p = document.createElement('p'); p.textContent = '等待 ChatGPT 回應... / Waiting for ChatGPT response...'; chatgptResponseDiv.appendChild(p); } } }); 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); }); grokCloseButton.addEventListener('click', () => { grokResponseContainer.style.display = 'none'; }); chatgptCloseButton.addEventListener('click', () => { chatgptResponseContainer.style.display = 'none'; }); bubble.addEventListener('click', showContainer); makeDraggable(container, header, 'container'); makeDraggable(bubble, null, 'position'); makeDraggable(grokResponseContainer, grokHeader, 'grokResponse'); makeDraggable(chatgptResponseContainer, chatgptHeader, 'chatgptResponse'); document.addEventListener('contextmenu', (e) => { if (container.style.display === 'none') { e.preventDefault(); showContainer(); } }); 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`; } }); 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); console.log(`Saved containerWidth: ${target.offsetWidth}, containerHeight: ${target.offsetHeight}, display: ${target.style.display}`); } else if (target === grokResponseContainer) { GM_setValue('grokResponseWidth', target.offsetWidth); GM_setValue('grokResponseHeight', target.offsetHeight); console.log(`Saved grokResponseWidth: ${target.offsetWidth}, grokResponseHeight: ${target.offsetHeight}, display: ${target.style.display}`); } else if (target === chatgptResponseContainer) { GM_setValue('chatgptResponseWidth', target.offsetWidth); GM_setValue('chatgptResponseHeight', target.offsetHeight); console.log(`Saved chatgptResponseWidth: ${target.offsetWidth}, chatgptResponseHeight: ${target.offsetHeight}, display: ${target.style.display}`); } } else { console.log(`Skipped saving for ${target.className} - display: ${target.style.display}, width: ${target.offsetWidth}, height: ${target.offsetHeight}`); } } }); resizeObserver.observe(container); resizeObserver.observe(grokResponseContainer); resizeObserver.observe(chatgptResponseContainer); function showContainer() { bubble.style.display = 'none'; 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`; console.log(`Show container - width: ${container.style.width}, height: ${container.style.height}, top: ${container.style.top}, left: ${container.style.left}`); } } // 在新標籤頁中打開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(); console.log('儲存 Grok 回應:', lastContent); GM_setValue('grokResponse', lastContent); } }, 500); } } // 處理 ChatGPT 頁面 function handleChatGPTPage() { if (window.location.hostname === 'chatgpt.com') { let lastContent = ''; setInterval(() => { const assistantMessages = document.querySelectorAll('div[data-message-author-role="assistant"]:not(.processed)'); let currentContent = ''; assistantMessages.forEach(div => { const innerDiv = div.querySelector('div.markdown.prose.w-full.break-words'); const content = div.innerHTML.trim(); if (content && innerDiv && !innerDiv.classList.contains('result-streaming') && !innerDiv.classList.contains('result-thinking')) { currentContent += content + '\n'; div.classList.add('processed'); } }); if (currentContent && currentContent !== lastContent) { lastContent = currentContent.trim(); console.log('儲存 ChatGPT 回應:', lastContent); GM_setValue('chatgptResponse', lastContent); } }, 500); } } // 檢查並顯示 Grok 回應 function checkGrokResponse(grokResponseContainer, grokResponseDiv) { if (!grokResponseDiv) return; setInterval(() => { const response = GM_getValue('grokResponse', ''); if (response && grokResponseContainer.style.display === 'block') { console.log('更新 Grok UI:', response); 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') { console.log('更新 ChatGPT UI:', response); const newResponse = document.createElement('p'); newResponse.innerHTML = response; while (chatgptResponseDiv.firstChild) { chatgptResponseDiv.removeChild(chatgptResponseDiv.firstChild); } chatgptResponseDiv.appendChild(newResponse); GM_setValue('chatgptResponse', ''); } }, 1000); } // 啟動腳本 function initialize() { const { bubble, container, grokResponseContainer, grokResponseDiv, chatgptResponseContainer, chatgptResponseDiv, header, grokHeader, chatgptHeader, grokClearButton, chatgptClearButton } = createUI(); initializeEvents(bubble, container, grokResponseContainer, grokResponseDiv, chatgptResponseContainer, chatgptResponseDiv, header, grokHeader, chatgptHeader, grokClearButton, chatgptClearButton); handleGeminiPage(); handleGrokPage(); handleChatGPTPage(); checkGrokResponse(grokResponseContainer, grokResponseDiv); checkChatGPTResponse(chatgptResponseContainer, chatgptResponseDiv); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initialize); } else { initialize(); } })();