AI助手選擇器

一個 Tampermonkey 腳本,提供浮動介面整合多款 AI 助手,支援右鍵呼叫、清空歷史訊息、可調整尺寸,並記錄 AI 選擇狀態與位置,從Tampermonkey 選單呼叫。

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

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