// ==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();
}
})();