Greasy Fork is available in English.

AI网页内容总结(增强版)

使用AI总结网页内容的油猴脚本,采用Shadow DOM隔离样式

// ==UserScript==
// @name         AI网页内容总结(增强版)
// @namespace    http://tampermonkey.net/
// @version      1.7
// @description  使用AI总结网页内容的油猴脚本,采用Shadow DOM隔离样式
// @author       Jinfeng
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAABMBJREFUeF7tnU2LHGUQx/81wTXBBGRmtqfHCF7Vi+hBjYecA7mbHBTUi3fxBQ+iURERxLugJwPJFzAfIERQQchFIUchTk9Pd1bQkGB2t2TAwdlhd55+3rq6e2qvXS/9/H9PdXdNzfYQ9E9UARLNrsmhAIQ3gQJQAMIKCKfXClAAwgoIp9cKUADCCgin1wpQAMIKCKfXCmg7gGlZnuFdvMaEp8B4mggD4TVZpWfGpfFo8JGVU0Bj5wpg5q28KD9hprcB9AKeU+2hJCE4A8im5Y8gPF+7WpESSkFwAjCZlh8T4YNIWoiFlYBgDWA2+/O5Pd77ue2XnaMo1w3BGkCWl98AeENsm9aQuE4I9gCm5Q0QXlrVgUBg8Fp52mRTFwR7AHnxF0Ana9iI4inqgOAAoFy7zdNkYB2zTqWzfP35r55LbAjWYpkW0DUAcyAxISiAiuUXC4ICqAggViUoAAsAMSAoAEsAoSEoAAcAISEEA7Bostr0FOTbGIa4MQcDsNhIVQAURXH6wT59DcYLcz8C3+jR8TeT5GTmuCEru5keoysH+s/QF0LtAGazu+Pd/Xs3iWj7wGKZ8x4dfyY2hNAAfC9HtQPI8vIqgJcP3WnMl9PR8BXbXWhjHwOADwQJADsAHj1CtNtpMnjcRlBb21gAXCEIACgmAKWHC8d/pMnwtK2oNvYxAczPo8o9cPl8BQCUVwBcOOIS9F06Gr5qI6it7cYDyPO/033c/wWg8Yp4t/nE1rPjU6dmtqLa2G88gLlYWcaPMN15F8QXwbTb6+Eq7/W/TFO6ayOmi21nAbSlEXOBtuxzGMDlhq7x9wBfAaT9TRWkACITUgCRBTaFVwAmhSIfVwCRBTaFVwAmhSIfVwCRBTaF7wQAyXmASWDT8cYCqNqISc8DTAKbjre+EZOeB5gENh1vbAUsTtzUCWZ5KToPMAlsOt5+ANMiA9Ho8IXyJE2Gj5lEkDzefgC57DzAF17rAUjPAzYegPQ8QAH4KiDs3/pLkLB+3ukbC6BqI+atgHCA1jdiwvp5p29sBVRtxLwVEA6gABRAu/9L0pefVoCvgp7+nQCg84D/d0Ht3w3t4jxguahMnwavFmDtAHQecBBBMABVG7EuzgNa9dXETOcBB0ogWAVUbcQynQfIAtB5QKR7QNUK0HlAAwB49kKi7p1oxEQV9EyuADwF9HVXAL4Kevo3FkDVRsxz/eLuOhETRtDYCrB5DBXW0Cu9AvCSz9+5AQDWvevBf4HtjsBZmgxX3wCwdknWnwVN8vIaAefaLVScs2fg+3EyOG8T3RpAlhefAfS+TZINsv00TQZWr/W3BrCzs/PE/X/2bxFha4OENS6Vme89/FDvyX6//7vReMnAGsDcd5LfeY/An9sk6rwt4a10e/CV7TqdAMyTZNPyBxDOLBL6voGw5XGuj5L+WVvx5/bOAOY/4jOdlZcAegfAMZfkHfDZA/iL0fbgQyJ64LIeZwCLZFlZvohdvN7Wn7GyFY0ZBQi/EuM3PsbfjofDn2xjLNt7A/BJrr4elyAVL4wCWgFhdHSOogCcpQvjqADC6OgcRQE4SxfGUQGE0dE5igJwli6MowIIo6NzFAXgLF0YRwUQRkfnKArAWbowjv8CcMJrjudowOkAAAAASUVORK5CYII=
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// @grant        GM.xmlHttpRequest
// @connect      *
// @connect      pieces-os-azure.vercel.app
// @connect      api.ephone.ai
// @connect      snowy-forest-7d66.ttjmggm.workers.dev
// @connect      generativelanguage.googleapis.com
// @connect      free-api.jinfeng-li.us.kg
// @require      https://cdnjs.cloudflare.com/ajax/libs/markdown-it/13.0.1/markdown-it.min.js
// @license      Apache-2.0
// ==/UserScript==

// Copyright 2024 Jinfeng

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

(function() {
    'use strict';

    // 默认配置
    const DEFAULT_CONFIG = {
        API_URL: 'https://api.openai.com/v1/chat/completions',
        API_KEY: 'sk-randomKey1234567890',
        MAX_TOKENS: 4000,
        SHORTCUT: 'Alt+S',
        PROMPT: '请用markdown格式全面总结以下网页内容,包含主要观点、关键信息和重要细节。总结需要完整、准确、有条理。',
        MODEL: 'gpt-4o-mini',
        CURRENT_CONFIG_NAME: '' // 用于存储当前使用的配置名称
    };

    // 获取配置
    let CONFIG = {};
    function loadConfig() {
        CONFIG = {
            API_URL: GM_getValue('API_URL', DEFAULT_CONFIG.API_URL),
            API_KEY: GM_getValue('API_KEY', DEFAULT_CONFIG.API_KEY),
            MAX_TOKENS: GM_getValue('MAX_TOKENS', DEFAULT_CONFIG.MAX_TOKENS),
            SHORTCUT: GM_getValue('SHORTCUT', DEFAULT_CONFIG.SHORTCUT),
            PROMPT: GM_getValue('PROMPT', DEFAULT_CONFIG.PROMPT),
            MODEL: GM_getValue('MODEL', DEFAULT_CONFIG.MODEL),
            CURRENT_CONFIG_NAME: GM_getValue('CURRENT_CONFIG_NAME', DEFAULT_CONFIG.CURRENT_CONFIG_NAME)
        };
        // 如果存在已保存的当前配置名称,则加载该配置
        if (CONFIG.CURRENT_CONFIG_NAME) {
            const savedConfig = loadSavedConfig(CONFIG.CURRENT_CONFIG_NAME);
            if (savedConfig) {
                CONFIG = { ...savedConfig, CURRENT_CONFIG_NAME: CONFIG.CURRENT_CONFIG_NAME };
            }
        }
        return CONFIG;
    }

    // 预定义的提示词模版
    const PROMPT_TEMPLATES = [
        {
            title: "通用网页总结",
            content: "请用markdown格式全面总结以下网页内容,包含主要观点、关键信息和重要细节。总结需要完整、准确、有条理。"
        },
        {
            title: "学术论文总结",
            content: "请用markdown格式总结这篇学术论文,包含以下要点:\n1. 研究目的和背景\n2. 研究方法\n3. 主要发现\n4. 结论和意义\n请确保总结准确、专业,并突出论文的创新点。"
        },
        {
            title: "新闻事件总结",
            content: "请用markdown格式总结这则新闻,包含以下要点:\n1. 事件梗概(时间、地点、人物)\n2. 事件经过\n3. 影响和意义\n4. 各方反应\n请确保总结客观、准确,并突出新闻的重要性。"
        },
        {
            title: "一句话概括",
            content: "请用一句简洁但信息量充足的话概括这段内容的核心要点。要求:不超过50个字,通俗易懂,突出重点。"
        },
        {
            title: "知乎专业解答",
            content: "请以知乎回答的风格总结这段内容。要求:\n1. 开头要吸引眼球\n2. 分点论述,层次分明\n3. 使用专业术语\n4. 适当举例佐证\n5. 语气要专业且自信\n6. 结尾点题升华\n注意:要用markdown格式,保持知乎体特有的严谨专业但不失亲和力的风格。"
        },
        {
            title: "表格化总结",
            content: "请将内容重点提取并整理成markdown表格格式。表格应当包含以下列:\n| 主题/概念 | 核心要点 | 补充说明 |\n要求条理清晰,重点突出,易于阅读。"
        },
        {
            title: "深度分析",
            content: "请对内容进行深度分析,包含:\n1. 表层信息提炼\n2. 深层原因分析\n3. 可能的影响和发展\n4. 个人见解和建议\n注意:分析要有洞察力,观点要有独特性,论述要有逻辑性。使用markdown格式。"
        },
        {
            title: "轻松幽默风",
            content: "请用轻松幽默的语气总结这段内容。要求:\n1. 口语化表达\n2. 适当使用梗和比喻\n3. 保持内容准确性\n4. 增加趣味性类比\n注意:幽默要得体,不失专业性。使用markdown格式。"
        },
        {
            title: "要点清单",
            content: "请将内容整理成简洁的要点清单,要求:\n1. 用markdown的项目符号格式\n2. 每点都简洁明了(不超过20字)\n3. 按重要性排序\n4. 分类呈现(如适用)\n5. 突出关键词或数字"
        },
        {
            title: "ELI5通俗解释",
            content: "请用简单易懂的语言解释这段内容,就像向一个五年级学生解释一样。要求:\n1. 使用简单的词汇\n2. 多用比喻和类比\n3. 避免专业术语\n4. 循序渐进地解释\n注意:解释要生动有趣,便于理解,但不能有失准确性。"
        },
        {
            title: "观点对比",
            content: "请以对比的形式总结文中的不同观点或方面:\n\n### 正面观点/优势\n- 观点1\n- 观点2\n\n### 负面观点/劣势\n- 观点1\n- 观点2\n\n### 中立分析\n综合以上观点的分析和建议\n\n注意:要客观公正,论据充分。"
        },
        {
            title: "Q&A模式",
            content: "请将内容重点转化为问答形式,要求:\n1. 问题要简洁清晰\n2. 答案要详细准确\n3. 由浅入深\n4. 覆盖核心知识点\n格式:\nQ1: [问题]\nA1: [答案]\n\n注意:问答要有逻辑性,便于理解和记忆。"
        },
        {
            title: "商务简报",
            content: "请以商务简报的形式总结内容:\n\n### 执行摘要\n[一段概述]\n\n### 关键发现\n- 发现1\n- 发现2\n\n### 数据支撑\n[列出关键数据]\n\n### 行动建议\n1. 建议1\n2. 建议2\n\n注意:简报风格要专业、简洁、重点突出。"
        },
        {
            title: "时间轴梳理",
            content: "请将内容按时间顺序整理成清晰的时间轴:\n\n### 时间轴\n- [时间点1]:事件/进展描述\n- [时间点2]:事件/进展描述\n\n### 关键节点分析\n[分析重要时间节点的意义]\n\n注意:要突出重要时间节点,并分析其意义。"
        },
        {
            title: "观点提炼",
            content: "请提炼这段内容中的核心观点,按逻辑顺序列出。每个观点需要简洁明了,突出其关键性。要求:\n- 使用简洁的语言\n- 突出观点的主旨\n- 按照论点的层次组织"
        },
        {
            title: "趋势预测",
            content: "请基于这段内容分析其背后的趋势,预测未来可能的发展方向。要求:\n- 提出一个清晰的趋势分析框架\n- 分析现有数据和信息如何推动这一趋势\n- 预测可能的行业影响和未来趋势\n- 提供具体的建议或行动步骤"
        },
        {
            title: "关键问题分析",
            content: "请对文中提出的关键问题进行详细分析,包含以下要点:\n1. 问题的背景与成因\n2. 当前解决方案及其效果\n3. 可能的解决方案和优缺点\n4. 解决这一问题的长期影响和潜在风险\n要求:分析要有深度,确保逻辑严密,提出建设性意见。"
        },
        {
            title: "对话式总结",
            content: "请将内容总结为对话式的形式,类似于对话问答。要求:\n- 通过模拟两个人的对话来呈现信息\n- 每个问题要简洁明了\n- 答案要准确、易懂,避免过于专业的术语\n- 对话可以适当加入互动与思考"
        },
        {
            title: "SWOT分析",
            content: "请对这段内容进行SWOT分析(优势、劣势、机会、威胁)。要求:\n- 优势:列出文中描述的优势\n- 劣势:列出可能的劣势或挑战\n- 机会:分析潜在的机会\n- 威胁:分析可能面临的威胁"
        },
        {
            title: "情景假设",
            content: "请基于这段内容,设定一个假设情景并进行分析。要求:\n- 提供假设情景的背景和设定\n- 根据现有内容推演可能的结果\n- 讨论可能面临的挑战与解决方案\n- 结合现实情况,给出合理的建议"
        },
        {
            title: "步骤指南",
            content: "请将这段内容总结成一个清晰的操作步骤指南。要求:\n- 每一步操作清晰简洁\n- 每一步的目标或目的要明确\n- 适当提供示例或注意事项\n- 步骤顺序按逻辑组织"
        }
    ];

    // 保存配置
    function saveConfig(newConfig, configName = '') {
        // 保存基本配置到 GM storage
        Object.keys(newConfig).forEach(key => {
            GM_setValue(key, newConfig[key]);
        });

        // 更新当前配置名称
        if (configName) {
            GM_setValue('CURRENT_CONFIG_NAME', configName);
            // 如果选择了已保存的配置,也将其保存到 saved_configs
            const savedConfigs = getAllConfigs();
            savedConfigs[configName] = { ...newConfig };
            GM_setValue('saved_configs', savedConfigs);
        }

        // 更新内存中的配置
        CONFIG = {
            ...CONFIG,
            ...newConfig,
            CURRENT_CONFIG_NAME: configName || CONFIG.CURRENT_CONFIG_NAME
        };
    }

    // 更新配置选择器
    function updateConfigSelectors(settingsPanel, modal) {
        const configs = getAllConfigs();
        const configNames = Object.keys(configs);
        const currentConfigName = CONFIG.CURRENT_CONFIG_NAME;
    
        // 更新所有配置选择器的函数
        const updateSelect = (select, includeCurrentConfig = false) => {
            if (!select) return;
            
            let options = [];
            
            // 添加默认选项
            if (includeCurrentConfig) {
                options.push(`<option value="" ${!currentConfigName ? 'selected' : ''}>当前配置${!currentConfigName ? '(未保存)' : ''}</option>`);
            } else {
                options.push(`<option value="">--选择配置--</option>`);
            }
            
            // 添加已保存的配置
            options = options.concat(configNames.map(name =>
                `<option value="${name}" ${name === currentConfigName ? 'selected' : ''}>${name}</option>`
            ));
            
            select.innerHTML = options.join('');
        };
    
        // 更新设置面板的选择器
        if (settingsPanel) {
            const settingsPanelSelect = settingsPanel.querySelector('#config-select');
            updateSelect(settingsPanelSelect, false);
            
            // 更新操作按钮的显示状态
            const configSelected = settingsPanelSelect.value !== "";
            
            // 显示/隐藏删除配置按钮
            const deleteConfigBtn = settingsPanel.querySelector('.delete-config-btn');
            if (deleteConfigBtn) {
                deleteConfigBtn.style.display = configSelected ? 'inline-block' : 'none';
            }
            
            // 显示/隐藏重命名配置按钮
            const renameConfigBtn = settingsPanel.querySelector('.rename-config-btn');
            if (renameConfigBtn) {
                renameConfigBtn.style.display = configSelected ? 'inline-block' : 'none';
            }
        }
    
        // 更新总结模态框的选择器
        if (modal) {
            const modalSelect = modal.querySelector('.ai-config-select');
            updateSelect(modalSelect, true);
        }
    }

    // 重命名配置的函数
    function renameConfig(oldName, newName) {
        if (oldName === newName) return false;
        
        const configs = getAllConfigs();
        if (!configs[oldName]) {
            alert('找不到要重命名的配置');
            return false;
        }
        
        // 保存配置到新名称
        configs[newName] = configs[oldName];
        // 删除旧配置
        delete configs[oldName];
        
        // 保存更新后的配置
        GM_setValue('saved_configs', configs);
        
        // 如果重命名的是当前使用的配置,更新当前配置名称
        if (CONFIG.CURRENT_CONFIG_NAME === oldName) {
            CONFIG.CURRENT_CONFIG_NAME = newName;
            GM_setValue('CURRENT_CONFIG_NAME', newName);
        }
        
        return true;
    }

    // 初始化重命名相关的事件监听
    function initializeRenameEvents(settingsPanel, modal) {
        const renameBtn = settingsPanel.querySelector('.rename-config-btn');
        if (!renameBtn) return;

        renameBtn.addEventListener('click', () => {
            const currentConfigName = settingsPanel.querySelector('#config-select').value;
            if (!currentConfigName) {
                alert('请先选择要重命名的配置');
                return;
            }

            // 显示重命名输入组
            let renameGroup = settingsPanel.querySelector('.rename-input-group');
            if (!renameGroup) {
                renameGroup = document.createElement('div');
                renameGroup.className = 'rename-input-group';
                renameGroup.innerHTML = `
                    <input type="text" id="config-rename" placeholder="输入新配置名称">
                    <button class="confirm-rename-btn">确认重命名</button>
                    <button class="cancel-rename-btn">取消</button>
                `;
                // 插入到按钮组之前
                settingsPanel.querySelector('.buttons').insertAdjacentElement('beforebegin', renameGroup);
            }
            renameGroup.style.display = 'flex';
            
            // 设置输入框的默认值为当前配置名
            const renameInput = renameGroup.querySelector('#config-rename');
            renameInput.value = currentConfigName;
            renameInput.focus();
            renameInput.select();
        });

        // 代理事件处理
        settingsPanel.addEventListener('click', (e) => {
            if (e.target.classList.contains('confirm-rename-btn')) {
                const oldName = settingsPanel.querySelector('#config-select').value;
                const newName = settingsPanel.querySelector('#config-rename').value.trim();
                
                if (!newName) {
                    alert('请输入新配置名称');
                    return;
                }
                
                if (renameConfig(oldName, newName)) {
                    // 更新选择器
                    updateConfigSelectors(settingsPanel, modal);
                    // 隐藏重命名输入组
                    settingsPanel.querySelector('.rename-input-group').style.display = 'none';
                    alert('重命名成功');
                }
            } else if (e.target.classList.contains('cancel-rename-btn')) {
                // 隐藏重命名输入组
                settingsPanel.querySelector('.rename-input-group').style.display = 'none';
            }
        });
    }

    // 修改设置面板的事件处理
    function initializeSettingsEvents(panel, modal, settingsOverlay) {
        const saveBtn = panel.querySelector('.save-btn');
        const configSelect = panel.querySelector('#config-select');
        const shortcutInput = panel.querySelector('#shortcut');

        // 更新快捷键输入框的占位符提示
        const isMac = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
        shortcutInput.placeholder = isMac ?
            '例如: Option+S, ⌘+Shift+Y' :
            '例如: Alt+S, Ctrl+Shift+Y';

        // 更新"应用设置"按钮文本
        saveBtn.textContent = '保存并应用';

        // 配置选择变更事件
        configSelect.addEventListener('change', (e) => {
            const selectedConfig = loadSavedConfig(e.target.value);
            if (selectedConfig) {
                // 更新设置面板中的输入值
                panel.querySelector('#api-url').value = selectedConfig.API_URL;
                panel.querySelector('#api-key').value = selectedConfig.API_KEY;
                panel.querySelector('#max-tokens').value = selectedConfig.MAX_TOKENS;
                // 根据系统显示适当的快捷键格式
                shortcutInput.value = getSystemShortcutDisplay(selectedConfig.SHORTCUT);
                panel.querySelector('#prompt').value = selectedConfig.PROMPT;
                panel.querySelector('#model').value = selectedConfig.MODEL;
            }
        });

        // 保存按钮点击事件
        saveBtn.addEventListener('click', () => {
            let newShortcut = panel.querySelector('#shortcut').value.trim();

            // 统一将 Option 转换为 Alt 存储
            newShortcut = newShortcut.replace(/Option\+/g, 'Alt+');

            if (!validateShortcut(newShortcut)) {
                alert(isMac ?
                    '快捷键格式不正确,请使用例如 Option+S, ⌘+Shift+Y 的格式。' :
                    '快捷键格式不正确,请使用例如 Alt+S, Ctrl+Shift+Y 的格式。'
                );
                return;
            }

            const selectedConfigName = configSelect.value;
            const newConfig = {
                API_URL: panel.querySelector('#api-url').value.trim(),
                API_KEY: panel.querySelector('#api-key').value.trim(),
                MAX_TOKENS: parseInt(panel.querySelector('#max-tokens').value) || DEFAULT_CONFIG.MAX_TOKENS,
                SHORTCUT: newShortcut || DEFAULT_CONFIG.SHORTCUT,
                PROMPT: panel.querySelector('#prompt').value.trim() || DEFAULT_CONFIG.PROMPT,
                MODEL: panel.querySelector('#model').value.trim() || DEFAULT_CONFIG.MODEL
            };

            // 保存配置并更新当前配置名称
            saveConfig(newConfig, selectedConfigName);

            // 更新两个面板中的配置选择器
            updateConfigSelectors(panel, modal);

            // 关闭设置面板
            panel.style.display = 'none';
            settingsOverlay.style.display = 'none';

            alert(`配置已保存并应用${selectedConfigName ? `(当前配置:${selectedConfigName})` : ''}`);
        });
    }

    function getAllConfigs() {
        return GM_getValue('saved_configs', {});
    }

    function saveConfigAs(name, config) {
        const configs = getAllConfigs();
        configs[name] = config;
        GM_setValue('saved_configs', configs);
    }

    // 删除配置函数
    function deleteConfig(name, panel, modal) {
        const configs = getAllConfigs();
        delete configs[name];
        GM_setValue('saved_configs', configs);
    
        // 如果删除的是当前正在使用的配置,重置为默认配置
        if (name === CONFIG.CURRENT_CONFIG_NAME) {
            const defaultConfig = { ...DEFAULT_CONFIG, CURRENT_CONFIG_NAME: '' };
            Object.keys(defaultConfig).forEach(key => {
                GM_setValue(key, defaultConfig[key]);
            });
            CONFIG = defaultConfig;
    
            // 更新设置面板中的输入值为默认值
            if (panel) {
                panel.querySelector('#api-url').value = DEFAULT_CONFIG.API_URL;
                panel.querySelector('#api-key').value = DEFAULT_CONFIG.API_KEY;
                panel.querySelector('#max-tokens').value = DEFAULT_CONFIG.MAX_TOKENS;
                panel.querySelector('#shortcut').value = DEFAULT_CONFIG.SHORTCUT;
                panel.querySelector('#prompt').value = DEFAULT_CONFIG.PROMPT;
                panel.querySelector('#model').value = DEFAULT_CONFIG.MODEL;
            }
        }
    
        // 保存更新后的配置
        GM_setValue('saved_configs', configs);
    
        // 更新两个面板的配置选择器
        updateConfigSelectors(panel, modal);
    
        return Object.keys(configs).length;
    }

    // 删除配置按钮事件处理
    function initializeDeleteConfigButton(settingsPanel, modal) {
        const deleteBtn = settingsPanel.querySelector('.delete-config-btn');
        const configSelect = settingsPanel.querySelector('#config-select');
    
        // 删除配置按钮点击事件
        deleteBtn.addEventListener('click', () => {
            const configName = configSelect.value;
            if (!configName) {
                alert('请先选择要删除的配置');
                return;
            }
    
            if (confirm(`确定要删除配置"${configName}"吗?`)) {
                deleteConfig(configName, settingsPanel, modal);
    
                // 如果删除的是当前正在使用的配置,更新模态框中的配置显示
                if (configName === CONFIG.CURRENT_CONFIG_NAME) {
                    const modalSelect = modal.querySelector('.ai-config-select');
                    if (modalSelect) {
                        modalSelect.value = '';
                    }
    
                    // 如果有重试按钮,触发重新生成总结
                    const retryBtn = modal.querySelector('.ai-retry-btn');
                    if (retryBtn) {
                        retryBtn.click();
                    }
                }
    
                alert(`配置"${configName}"已删除${configName === CONFIG.CURRENT_CONFIG_NAME ? ',已恢复默认配置' : ''}`);
            }
        });
    }

    function loadSavedConfig(name) {
        const configs = getAllConfigs();
        return configs[name];
    }

    // 创建设置面板
    function createSettingsPanel(shadow) {
        const panel = document.createElement('div');
        panel.className = 'ai-settings-panel';
        panel.innerHTML = `
            <h3>设置</h3>
            <div class="form-group">
                <label for="api-url">API URL</label>
                <input type="text" id="api-url" value="${CONFIG.API_URL}">
            </div>
            <div class="form-group">
                <label for="api-key">API Key</label>
                <input type="text" id="api-key" value="${CONFIG.API_KEY}">
            </div>
            <div class="form-group">
                <label for="model">模型</label>
                <input type="text" id="model" value="${CONFIG.MODEL}">
            </div>
            <div class="form-group">
                <label for="max-tokens">最大Token数</label>
                <input type="number" id="max-tokens" value="${CONFIG.MAX_TOKENS}">
            </div>
            <div class="form-group">
                <label for="shortcut">快捷键 (例如: Alt+S, Ctrl+Shift+Y)</label>
                <input type="text" id="shortcut" value="${CONFIG.SHORTCUT}">
            </div>
            <div class="form-group">
                <label for="prompt">总结提示词</label>
                <textarea id="prompt">${CONFIG.PROMPT}</textarea>
            </div>
            <div class="form-group config-select-group">
                <label for="config-select">当前配置</label>
                <select class="ai-config-select" id="config-select">
                    <option value="">--选择配置--</option>
                    ${Object.keys(getAllConfigs()).map(name =>
                        `<option value="${name}">${name}</option>`
                    ).join('')}
                </select>
                <select class="ai-prompt-template-select" id="prompt-template-select">
                    <option value="">--提示词模版--</option>
                    ${PROMPT_TEMPLATES.map(template =>
                        `<option value="${template.title}">${template.title}</option>`
                    ).join('')}
                </select>
            </div>
            <div class="form-group save-as-group buttons" style="display: none;">
                <label for="config-name">配置名称</label>
                <div class="save-as-input-group">
                    <input type="text" id="config-name" placeholder="输入配置名称">
                    <button class="confirm-save-as-btn">保存配置</button>
                    <button class="cancel-save-as-btn">取消</button>
                </div>
            </div>
            <div class="form-group rename-group buttons" style="display: none;">
                <label for="rename-config">重命名配置</label>
                <div class="rename-input-group">
                    <input type="text" id="rename-config" placeholder="输入新配置名称">
                    <button class="confirm-rename-btn">确认重命名</button>
                    <button class="cancel-rename-btn">取消</button>
                </div>
            </div>
            <div class="buttons">
                <button class="clear-cache-btn">恢复默认设置</button>
                <button class="delete-config-btn">删除此配置</button>
                <button class="save-as-btn">另存为新配置</button>
                <button class="rename-config-btn">重命名配置</button>
                <button class="cancel-btn">关闭</button>
                <button class="save-btn">应用设置</button>
            </div>
        `;

        // 样式定义在Shadow DOM内部
        const style = document.createElement('style');
        style.textContent = `
            .ai-settings-panel {
                display: none;
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background: #fff;
                padding: 20px;
                border-radius: 8px;
                box-shadow: 0 4px 20px rgba(0,0,0,0.15);
                width: 90%;
                max-width: 600px;
                max-height: 80vh;
                overflow-y: auto;
                box-sizing: border-box;
                font-family: Microsoft Yahei,PingFang SC,HanHei SC,Arial;
                font-size: 15px;
                z-index: 100001;
            }
            .ai-settings-panel h3 {
                margin: 0 0 20px 0;
                padding-bottom: 10px;
                border-bottom: 1px solid #dee2e6;
                color: #495057;
                font-size: 18px;
                font-weight: 900;
            }
            .form-group {
                margin-bottom: 15px;
            }
            .form-group label {
                display: block;
                margin-bottom: 5px;
                color: #495057;
                font-weight: 600;
            }
            .form-group input,
            .form-group textarea {
                width: 100%;
                padding: 8px 12px;
                border: 1px solid #ced4da;
                border-radius: 4px;
                font-size: 14px;
                box-sizing: border-box;
                background: #fff;
                color: #495057;
            }
            .form-group input:focus,
            .form-group textarea:focus {
                outline: none;
                border-color: #60a5fa;
                box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.2);
            }
            .form-group textarea {
                height: 100px;
                resize: vertical;
                font-family: Microsoft Yahei,PingFang SC,HanHei SC,Arial;
            }
            .form-group.config-select-group {
                display: flex;
                align-items: center;
                gap: 10px;
            }

            .form-group.config-select-group label {
                flex: 0 0 auto;
                margin-bottom: 0;
            }

            .form-group:not(.config-select-group) {
                display: block; /* 恢复其他form-group的默认布局 */
            }
            .buttons {
                display: flex;
                justify-content: space-around;
                gap: 10px;
                margin-top: 20px;
            }
            .buttons button {
                padding: 8px 8px;
                border: none;
                border-radius: 4px;
                cursor: pointer;
                font-size: 14px;
                font-weight: bold;
                transition: background 0.3s;
                color: #fff;
            }
            .cancel-btn {
                background: #6c757d;
            }
            .cancel-btn:hover {
                background: #5a6268;
            }
            .clear-cache-btn {
                background: #b47474cc !important;
            }
            .clear-cache-btn:hover {
                background: #c82333 !important;
            }
            .ai-config-select {
                padding: 6px 12px;
                border: 1px solid #ced4da;
                border-radius: 4px;
                font-size: 14px;
                background: #fff;
                color: #495057;
                margin-right: 10px;
            }
            .save-as-group {
                margin-top: 10px;
                padding-top: 10px;
                border-top: 1px solid #dee2e6;
            }
            .delete-config-btn {
                background: #b47474cc !important;
            }
            .delete-config-btn:hover {
                background: #c82333 !important;
            }
            .save-as-input-group {
                display: flex;
                gap: 10px;
                align-items: center;
            }
            .save-as-input-group input {
                flex: 1;
            }
            .save-as-input-group button {
                padding: 8px 16px;
                border: none;
                border-radius: 4px;
                cursor: pointer;
                font-size: 14px;
                font-weight: bold;
                color: #fff;
            }
            .save-btn, .confirm-save-as-btn {
                background: #617043cc !important;
            }
            .save-btn:hover, .confirm-save-as-btn:hover {
                background: #218838 !important;
            }
            .cancel-save-as-btn {
                background: #6c757d;
            }
            .cancel-save-as-btn:hover {
                background: #5a6268;
            }
            .save-as-btn, .rename-config-btn {
                background: #647f96cc !important;
            }
            .save-as-btn:hover, .rename-config-btn:hover {
                background: #2980b9 !important;
            }
            .ai-prompt-template-select {
                padding: 6px 12px;
                border: 1px solid #ced4da;
                border-radius: 4px;
                font-size: 14px;
                background: #fff;
                color: #495057;
                margin-left: 10px;
                flex-grow: 1;
            }
            .form-group.config-select-group {
                display: flex;
                align-items: center;
                gap: 10px;
                flex-wrap: nowrap;
            }
            .ai-config-select {
                flex-grow: 1;
            }
            .rename-input-group {
                display: none;
                gap: 10px;
                margin: 10px 0;
                padding: 10px 0;
                border-top: 1px solid #dee2e6;
            }

            .rename-input-group input {
                flex: 1;
                padding: 8px 12px;
                border: 1px solid #ced4da;
                border-radius: 4px;
                font-size: 14px;
            }

            .rename-input-group button {
                padding: 8px 16px;
                border: none;
                border-radius: 4px;
                cursor: pointer;
                font-size: 14px;
                font-weight: bold;
                color: #fff;
            }

            .rename-input-group .confirm-rename-btn {
                background: #617043cc;
            }

            .rename-input-group .confirm-rename-btn:hover {
                background: #218838;
            }

            .rename-input-group .cancel-rename-btn {
                background: #6c757d;
            }

            .rename-input-group .cancel-rename-btn:hover {
                background: #5a6268;
            }
        `;

        // 创建新的覆盖层
        const settingsOverlay = document.createElement('div');
        settingsOverlay.className = 'ai-settings-overlay';
        settingsOverlay.style.display = 'none'; // 默认隐藏

        // 添加点击覆盖层关闭设置面板的事件
        settingsOverlay.addEventListener('click', () => {
            panel.style.display = 'none';
            settingsOverlay.style.display = 'none';
        });

        // 定义样式
        const overlayStyle = document.createElement('style');
        overlayStyle.textContent = `
            .ai-settings-overlay {
                display: none;
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0, 0, 0, 0.5);
                z-index: 100000; /* 确保覆盖层在设置面板下方 */
            }
        `;
        shadow.appendChild(overlayStyle);
        shadow.appendChild(settingsOverlay);
        shadow.appendChild(panel);

        // 事件监听
        panel.querySelector('.save-btn').addEventListener('click', () => {
            const newShortcut = panel.querySelector('#shortcut').value.trim();
            if (!validateShortcut(newShortcut)) {
                alert('快捷键格式不正确,请使用例如 Alt+S, Ctrl+Shift+Y 的格式。');
                return;
            }

            const newConfig = {
                API_URL: panel.querySelector('#api-url').value.trim(),
                API_KEY: panel.querySelector('#api-key').value.trim(),
                MAX_TOKENS: parseInt(panel.querySelector('#max-tokens').value) || DEFAULT_CONFIG.MAX_TOKENS,
                SHORTCUT: newShortcut || DEFAULT_CONFIG.SHORTCUT,
                PROMPT: panel.querySelector('#prompt').value.trim() || DEFAULT_CONFIG.PROMPT,
                MODEL: panel.querySelector('#model').value.trim() || DEFAULT_CONFIG.MODEL
            };
            saveConfig(newConfig);
            panel.style.display = 'none';
            settingsOverlay.style.display = 'none';
        });

        panel.querySelector('.cancel-btn').addEventListener('click', () => {
            panel.style.display = 'none';
            settingsOverlay.style.display = 'none';
        });

        // 清除缓存按钮事件
        panel.querySelector('.clear-cache-btn').addEventListener('click', () => {
            const keys = ['API_URL', 'API_KEY', 'MAX_TOKENS', 'SHORTCUT', 'PROMPT', 'MODEL'];
            keys.forEach(key => GM_setValue(key, undefined)); // 设置为undefined模拟删除

            // 重置为默认配置
            CONFIG = { ...DEFAULT_CONFIG };

            // 更新输入框的值
            panel.querySelector('#api-url').value = CONFIG.API_URL;
            panel.querySelector('#api-key').value = CONFIG.API_KEY;
            panel.querySelector('#max-tokens').value = CONFIG.MAX_TOKENS;
            panel.querySelector('#shortcut').value = CONFIG.SHORTCUT;
            panel.querySelector('#prompt').value = CONFIG.PROMPT;
            panel.querySelector('#model').value = CONFIG.MODEL;

            alert('缓存已清除,已恢复默认设置');
        });

        // 添加提示词模版选择的事件处理
        const promptTemplateSelect = panel.querySelector('#prompt-template-select');
        const promptTextarea = panel.querySelector('#prompt');

        promptTemplateSelect.addEventListener('change', (e) => {
            const selectedTemplate = PROMPT_TEMPLATES.find(t => t.title === e.target.value);
            if (selectedTemplate) {
                promptTextarea.value = selectedTemplate.content;
            }
        });

        shadow.appendChild(style);

        return { panel, overlay: settingsOverlay };
    }

    // 快捷键验证
    function validateShortcut(shortcut) {
        // 更新正则表达式以支持 Option 键
        const regex = /^((Ctrl|Alt|Shift|Meta|Option)\+)*[A-Za-z]$/;
        return regex.test(shortcut);
    }

    // 创建DOM元素并使用 Shadow DOM
    function createElements() {
        // 创建根容器
        const rootContainer = document.createElement('div');
        rootContainer.id = 'ai-summary-root';

        // 附加 Shadow DOM
        const shadow = rootContainer.attachShadow({ mode: 'open' });

        // 创建样式和结构
        const style = document.createElement('style');
        style.textContent = `
            .ai-summary-container {
                position: fixed;
                bottom: 20px;
                right: 20px;
                display: flex;
                align-items: center;
                z-index: 99990;
                user-select: none;
                align-items: stretch;
                box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
                height: 30px;
                background-color: rgba(75, 85, 99, 0.8);
                border-radius: 5px;
            }
            .ai-drag-handle {
                width: 15px;
                height: 100%;
                background-color: rgba(75, 85, 99, 0.5);
                border-radius: 5px;
                cursor: move;
                margin-right: 1px;
                display: flex;
                align-items: center;
                justify-content: center;
            }
            .ai-drag-handle::before {
                content: "⋮";
                color: #f3f4f6;
                font-size: 16px;
                transform: rotate(90deg);
            }
            .ai-summary-btn {
                padding: 5px 15px;
                background-color: rgba(75, 85, 99, 0.8);
                color: #f3f4f6;
                border: 1px solid rgba(75, 85, 99, 0.6);
                border-radius: 0 4px 4px 0;
                cursor: pointer;
                font-size: 12px;
                transition: all 0.3s;
                height: 100%;
                line-height: 1;
                font-family: Microsoft Yahei,PingFang SC,HanHei SC,Arial;
            }
            .ai-summary-btn:hover {
                background-color: rgba(75, 85, 99, 0.9);
            }
            .ai-summary-btn:active {
                transform: scale(0.95);
                transition: transform 0.1s;
            }
            .ai-summary-modal {
                user-select: none;
                display: none;
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                width: 80%;
                max-width: 800px;
                max-height: 80vh;
                background: #f8f9fa;
                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
                border-radius: 8px;
                z-index: 99995;
                overflow: hidden;
                font-family: Microsoft Yahei,PingFang SC,HanHei SC,Arial;
            }
            .ai-summary-overlay {
                display: none;
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0, 0, 0, 0.5);
                z-index: 99994;
            }
            .ai-summary-header {
                padding: 15px 20px;
                background: #e7ebee;
                border-bottom: 1px solid #dee2e6;
                display: flex;
                justify-content: space-between;
                align-items: center;
                position: sticky;
                top: 0;
                z-index: 1;
            }
            .ai-summary-header h3 {
                color: #495057;
                margin: 0;
                padding: 0;
                font-size: 18px;
                font-weight: 900;
                line-height: 1.4;
                font-family: inherit;
            }
            .ai-summary-close {
                background: none;
                border: none;
                font-size: 20px;
                cursor: pointer;
                color: #6c757d;
                padding: 0 5px;
                line-height: 1;
                font-family: inherit;
            }
            .ai-summary-close:hover {
                color: #495057;
            }
            .ai-summary-content {
                user-select: text;
                padding: 20px;
                overflow-y: auto;
                max-height: calc(80vh - 130px);
                line-height: 1.6;
                color: #374151;
                font-size: 15px;
                font-family: inherit;
                -webkit-overflow-scrolling: touch; /* 改善移动端滚动体验 */
            }
            .ai-summary-content h1 {
                font-size: 1.8em;
                margin: 1.5em 0 0.8em;
                padding-bottom: 0.3em;
                border-bottom: 2px solid #e5e7eb;
                font-weight: 600;
                line-height: 1.3;
                color: #1f2937;
            }
            .ai-summary-content h2 {
                font-size: 1.5em;
                margin: 1.3em 0 0.7em;
                padding-bottom: 0.2em;
                border-bottom: 1px solid #e5e7eb;
                font-weight: 600;
                line-height: 1.3;
                color: #1f2937;
            }
            .ai-summary-content h3 {
                font-size: 1.3em;
                margin: 1.2em 0 0.6em;
                font-weight: 600;
                line-height: 1.3;
                color: #1f2937;
            }
            .ai-summary-content p {
                margin: 1em 0;
                line-height: 1.8;
                color: inherit;
            }
            .ai-summary-content ul,
            .ai-summary-content ol {
                margin: 1em 0;
                padding-left: 2em;
                line-height: 1.6;
            }
            .ai-summary-content li {
                margin: 0.5em 0;
                line-height: inherit;
                color: inherit;
            }
            .ai-summary-content blockquote {
                margin: 1em 0;
                padding: 0.5em 1em;
                border-left: 4px solid #60a5fa;
                background: #f3f4f6;
                color: #4b5563;
                font-style: normal;
            }
            .ai-summary-content code {
                background: #f3f4f6;
                padding: 0.2em 0.4em;
                border-radius: 3px;
                font-family: Consolas, Monaco, "Courier New", monospace;
                font-size: 0.9em;
                color: #d946ef;
                white-space: pre-wrap;
            }
            .ai-summary-content pre {
                background: #1f2937;
                color: #e5e7eb;
                padding: 1em;
                border-radius: 6px;
                overflow-x: auto;
                margin: 1em 0;
                white-space: pre;
                word-wrap: normal;
            }
            .ai-summary-content pre code {
                background: none;
                color: inherit;
                padding: 0;
                border-radius: 0;
                font-size: inherit;
                white-space: pre;
            }
            .ai-summary-content table {
                border-collapse: collapse;
                width: 100%;
                margin: 1em 0;
                font-size: inherit;
            }
            .ai-summary-content th,
            .ai-summary-content td {
                border: 1px solid #d1d5db;
                padding: 0.5em;
                text-align: left;
                color: inherit;
                background: none;
            }
            .ai-summary-content th {
                background: #f9fafb;
                font-weight: 600;
            }
            .ai-summary-footer {
                padding: 15px 20px;
                border-top: 1px solid #dee2e6;
                display: flex;
                justify-content: flex-end;
                gap: 10px;
                align-items: center;
                position: sticky;
                bottom: 0;
                background: #f0f2f4;
                z-index: 1;
            }
            .ai-summary-footer button {
                padding: 8px 16px;
                background: #6c757d;
                color: #fff;
                border: none;
                border-radius: 4px;
                cursor: pointer;
                display: inline-flex;
                align-items: center;
                gap: 8px;
                transition: background 0.3s;
                font-size: 14px;
                line-height: 1;
                font-family: inherit;
            }
            .ai-summary-footer button:hover {
                background: #5a6268;
            }
            .ai-download-btn svg,
            .ai-retry-btn svg,
            .ai-copy-btn svg,
            .ai-settings-btn svg {
                width: 20px;
                height: 20px;
            }
            .ai-loading {
                text-align: center;
                padding: 20px;
                color: #6c757d;
                font-family: inherit;
            }
            .ai-loading-dots:after {
                content: '.';
                animation: dots 1.5s steps(5, end) infinite;
            }
            @keyframes dots {
                0%, 20% { content: '.'; }
                40% { content: '..'; }
                60% { content: '...'; }
                80%, 100% { content: ''; }
            }
            .ai-download-btn,
            .ai-summary-btn,
            .ai-retry-btn,
            .ai-copy-btn,
            .ai-settings-btn {
                z-index: 99991;
                position: relative;
            }
            /* 优化移动端响应式布局 */
            @media (max-width: 768px) {
                .ai-settings-panel,
                .ai-summary-modal {
                    width: 95%;
                    max-height: 90vh;
                }
                .ai-summary-footer {
                    flex-wrap: wrap;
                    gap: 8px;
                }
                .ai-summary-container {
                    bottom: 10px;
                    right: 10px;
                }
            }
            .ai-summary-modal,
            .ai-summary-overlay,
            .ai-settings-panel {
                transition: opacity 0.2s ease-in-out;
            }
            .buttons button:active {
                transform: translateY(1px);
            }

            * {
                margin: 0;
                padding: 0;
                box-sizing: border-box;
            }
            .ai-summary-header,
            .ai-summary-footer,
            .ai-summary-close,
            ai-download-btn,
            .ai-settings-btn,
            .ai-retry-btn,
            .ai-copy-btn {
                user-select: none;
            }
        `;

        // 创建按钮和拖动把手
        const container = document.createElement('div');
        container.className = 'ai-summary-container';
        container.innerHTML = `
            <div class="ai-drag-handle"></div>
            <button class="ai-summary-btn">总结网页</button>
        `;

        // 创建模态框
        const modal = document.createElement('div');
        modal.className = 'ai-summary-modal';
        modal.innerHTML = `
            <div class="ai-summary-header">
                <h3>网页内容总结</h3>
                <button class="ai-summary-close">×</button>
            </div>
            <div class="ai-summary-content"></div>
            <div class="ai-summary-footer">
                <select class="ai-config-select">
                    <option value="">当前配置</option>
                    ${Object.keys(getAllConfigs()).map(name =>
                        `<option value="${name}">${name}</option>`
                    ).join('')}
                </select>
                <button class="ai-settings-btn" title="打开设置">
                    <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2">
                        <circle cx="12" cy="12" r="3"></circle>
                        <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
                    </svg>
                </button>
                <button class="ai-retry-btn" title="重新总结">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                        <path d="M21 12a9 9 0 11-2.3-6M21 3v6h-6"></path>
                    </svg>
                </button>
                <button class="ai-download-btn" title="下载总结">
                    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                        <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
                        <polyline points="7 10 12 15 17 10"></polyline>
                        <line x1="12" y1="15" x2="12" y2="3"></line>
                    </svg>
                    <span>下载总结</span>
                </button>
                <button class="ai-copy-btn">
                    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                        <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
                        <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
                    </svg>
                    <span>复制总结</span>
                </button>
            </div>
        `;

        // 创建遮罩层
        const overlay = document.createElement('div');
        overlay.className = 'ai-summary-overlay';

        // 创建设置面板
        const { panel: settingsPanel, overlay: settingsOverlay } = createSettingsPanel(shadow);

        // 将所有元素添加到Shadow DOM
        shadow.appendChild(style);
        shadow.appendChild(container);
        shadow.appendChild(modal);
        shadow.appendChild(overlay);
        shadow.appendChild(settingsPanel);

        // 将根容器添加到body
        document.body.appendChild(rootContainer);

        return {
            container,
            button: container.querySelector('.ai-summary-btn'),
            modal,
            overlay,
            dragHandle: container.querySelector('.ai-drag-handle'),
            settingsPanel,
            settingsOverlay, // 返回新的覆盖层引用
            shadow,
            downloadBtn: modal.querySelector('.ai-download-btn')
        };
    }

    // 获取网页内容
    function getPageContent() {
        const title = document.title;
        const content = document.body.innerText;
        return { title, content };
    }

    // 显示错误信息
    function showError(container, error, details = '') {
        container.innerHTML = `
            <div class="ai-summary-error" style="color: red;">
                <strong>错误:</strong> ${error}
            </div>
            ${details ? `<div class="ai-summary-debug">${details}</div>` : ''}
        `;
    }

    // 创建全局的markdown渲染器实例
    const markdownRenderer = window.markdownit({
        html: true,
        linkify: true,
        typographer: true,
        breaks: true
    });

    // 全局变量,用于存储原始的 Markdown 文本
    let originalMarkdownText = '';

    // 打字机效果函数
    function typeWriter(element, text, renderMarkdown, speed = 30, step = 5) {
        let index = 0;
        element.innerHTML = ''; // 清空内容

        function type() {
            if (index < text.length) {
                const currentIndex = Math.min(index + step, text.length);
                const currentText = text.substring(0, currentIndex);
                // 使用 markdownRenderer 渲染当前文本
                element.innerHTML = renderMarkdown(currentText);
                index = currentIndex;
                // 使用 requestAnimationFrame 代替 setTimeout
                requestAnimationFrame(type);
            } else {
                // 确保完全渲染
                element.innerHTML = renderMarkdown(text);
            }
        }

        type();
    }

    // 调用API进行总结
    async function summarizeContent(content, shadow) {
        const contentContainer = shadow.querySelector('.ai-summary-content');
        contentContainer.innerHTML = '<div class="ai-loading">正在生成总结<span class="ai-loading-dots"></span></div>';

        let summary = '';

        // 添加超时检查
        const timeoutId = setTimeout(() => {
            contentContainer.innerHTML = `
                <p>错误: 请求超时,请检查API URL、API Key和网络连接</p>
            `;
            // 由于无法直接 reject,这里只更新 DOM
        }, 20000);

        try {
            const requestPromise = new Promise((resolve, reject) => {
                console.log("Sending request to:", CONFIG.API_URL); // Log the URL
                console.log("Request headers:", {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${CONFIG.API_KEY}` // Log the authorization header (carefully, don't expose your key publicly!)
                });
                console.log("Request body:", {
                    model: CONFIG.MODEL,
                    messages: [
                        { role: 'system', content: CONFIG.PROMPT },
                        { role: 'user', content: content }
                    ],
                    max_tokens: CONFIG.MAX_TOKENS,
                    temperature: 0.7,
                    stream: false
                });

                GM.xmlHttpRequest({
                    method: 'POST',
                    url: CONFIG.API_URL,
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${CONFIG.API_KEY}`
                    },
                    data: JSON.stringify({
                        model: CONFIG.MODEL,
                        messages: [
                            { role: 'system', content: CONFIG.PROMPT },
                            { role: 'user', content: content }
                        ],
                        max_tokens: CONFIG.MAX_TOKENS,
                        temperature: 0.7,
                        stream: false // 使用非流式请求
                    }),
                    onload: function(response) {
                        console.log("Response status:", response.status); // Log the response status
                        console.log("Response headers:", response.responseHeaders); // Log response headers
                        console.log("Response text:", response.responseText); // Log the response body

                        if (response.status >= 200 && response.status < 300) {
                            try {
                                const result = JSON.parse(response.responseText);
                                summary = result.choices[0].message.content;

                                // 存储完整的总结文本到全局变量
                                originalMarkdownText = summary;

                                // 使用打字机效果逐步显示总结
                                typeWriter(contentContainer, summary, markdownRenderer.render.bind(markdownRenderer), 30, 5);

                                clearTimeout(timeoutId); // 清除超时
                                resolve(summary);
                            } catch (e) {
                                clearTimeout(timeoutId); // 清除超时
                                reject(new Error(`解析响应失败: ${e.message}`));
                            }
                        } else {
                            clearTimeout(timeoutId); // 清除超时
                            reject(new Error(`API请求失败 (${response.status}): 请检查API URL和Key是否正确`));
                        }
                    },
                    onerror: function(error) {
                        console.error('请求错误:', error);
                        clearTimeout(timeoutId); // 清除超时
                        reject(new Error('网络请求错误'));
                    },
                    ontimeout: function() {
                        clearTimeout(timeoutId); // 清除超时
                        reject(new Error('请求超时'));
                    }
                });
            });

            // 等待请求完成或超时
            summary = await requestPromise;

            return summary;
        } catch (error) {
            clearTimeout(timeoutId); // 清除超时
            console.error('总结生成错误:', error);
            contentContainer.innerHTML = `
                <p>错误: ${error.message}</p>
            `;
            throw error;
        }
    }

    // 初始化事件监听
    function initializeEvents(elements) {
        const { container, button, modal, overlay, dragHandle, settingsPanel, settingsOverlay, shadow } = elements;

        // 初始化删除配置按钮
        initializeDeleteConfigButton(settingsPanel, modal);

        // 初始化拖动功能
        initializeDrag(container, dragHandle, shadow);

        // 点击按钮显示模态框
        button.addEventListener('click', async () => {
            if (!CONFIG.API_KEY) {
                alert('请先配置API Key。');
                settingsPanel.style.display = 'block';
                settingsOverlay.style.display = 'block';
                shadow.querySelector('.ai-summary-overlay').style.display = 'block';
                return;
            }

            showModal(modal, overlay);
            const contentContainer = modal.querySelector('.ai-summary-content');

            try {
                if (!CONFIG.API_URL) {
                    throw new Error('请先配置API URL');
                }

                const { content } = getPageContent();
                if (!content.trim()) {
                    throw new Error('网页内容为空,无法生成总结。');
                }

                const summary = await summarizeContent(content, shadow);
                if (summary) {
                    // contentContainer.innerHTML = markdownRenderer.render(summary);
                }
            } catch (error) {
                console.error('Summary Error:', error);
                showError(contentContainer, error.message);
            }
        });

        // 关闭模态框
        modal.querySelector('.ai-summary-close').addEventListener('click', () => {
            hideModal(modal, overlay);
        });

        // 点击总结页面外的覆盖层关闭模态框
        overlay.addEventListener('click', () => {
            hideModal(modal, overlay);
        });

        // 下载按钮功能
        elements.downloadBtn.addEventListener('click', () => {
            // 检查 originalMarkdownText 是否有内容
            if (!originalMarkdownText) {
                alert('总结内容尚未生成或已失效。');
                return;
            }

            // 提取第一行并去除markdown语法
            let firstLine = originalMarkdownText.split('\n')[0].trim();
            firstLine = firstLine.replace(/^#+\s*/, ''); // 移除开头的'#'和空格

            if (!firstLine) {
                alert('总结内容格式错误,无法生成文件名。');
                return;
            }

            // 生成安全的文件名
            let safeFirstLine = firstLine.length > 30 ? firstLine.substring(0, 30) : firstLine;
            // 移除文件名中的非法字符
            safeFirstLine = safeFirstLine.replace(/[<>:"/\\|?*]/g, '');
            // 替换空格为下划线
            const encodedFirstLine = encodeURIComponent(safeFirstLine).replace(/%20/g, '_');
            const fileName = `网页总结-${encodedFirstLine}.md`;

            // 创建 Blob 并触发下载
            const blob = new Blob([originalMarkdownText], { type: 'text/markdown;charset=utf-8' });
            const url = URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.setAttribute('href', url);
            link.setAttribute('download', fileName);
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);

        });

        // 复制按钮功能
        modal.querySelector('.ai-copy-btn').addEventListener('click', () => {
            // 检查 originalMarkdownText 是否有内容
            if (!originalMarkdownText) {
                alert('总结内容尚未生成或已失效。');
                return;
            }

            // 使用保存的原始markdown文本
            navigator.clipboard.writeText(originalMarkdownText).then(() => {
                const copyBtn = modal.querySelector('.ai-copy-btn');
                const textSpan = copyBtn.querySelector('span');
                const originalText = textSpan.textContent;
                textSpan.textContent = '已复制!';
                textSpan.style.opacity = '0.7';
                setTimeout(() => {
                    textSpan.textContent = originalText;
                    textSpan.style.opacity = '1';
                }, 2000);
            }).catch(() => {
                alert('复制失败,请手动复制内容。');
            });
        });

        // 添加快捷键支持
        document.addEventListener('keydown', (e) => {
            if (isShortcutPressed(e, CONFIG.SHORTCUT)) {
                e.preventDefault();
                button.click();
            }
            if (e.key === 'Escape') {
                // 优先关闭设置面板
                if (settingsPanel.style.display === 'block') {
                    settingsPanel.style.display = 'none';
                    settingsOverlay.style.display = 'none';
                }
                // 然后关闭总结模态框
                if (modal.style.display === 'block') {
                    hideModal(modal, overlay);
                }
            }
        });

        // 添加重试按钮事件处理
        modal.querySelector('.ai-retry-btn').addEventListener('click', async () => {
            const contentContainer = modal.querySelector('.ai-summary-content');
            contentContainer.innerHTML = '<div class="ai-loading">正在重新生成总结<span class="ai-loading-dots"></span></div>';
            try {
                const { content } = getPageContent();
                if (!content.trim()) {
                    throw new Error('网页内容为空,无法生成总结。');
                }
                const summary = await summarizeContent(content, shadow);
                if (summary) {
                    contentContainer.innerHTML = markdownRenderer.render(summary);
                }
            } catch (error) {
                console.error('Retry Error:', error);
                showError(contentContainer, error.message);
            }
        });

        // 设置按钮功能(现在在模态框底部)
        modal.querySelector('.ai-settings-btn').addEventListener('click', () => {
            // 更新设置面板中的值
            settingsPanel.querySelector('#api-url').value = CONFIG.API_URL;
            settingsPanel.querySelector('#api-key').value = CONFIG.API_KEY;
            settingsPanel.querySelector('#max-tokens').value = CONFIG.MAX_TOKENS;
            settingsPanel.querySelector('#shortcut').value = CONFIG.SHORTCUT;
            settingsPanel.querySelector('#prompt').value = CONFIG.PROMPT;
            settingsPanel.querySelector('#model').value = CONFIG.MODEL;

            settingsPanel.style.display = 'block';
            settingsOverlay.style.display = 'block';
        });

        // 关闭设置面板时,隐藏其覆盖层
        settingsPanel.querySelector('.cancel-btn').addEventListener('click', () => {
            settingsPanel.style.display = 'none';
            settingsOverlay.style.display = 'none';
        });
        settingsPanel.querySelector('#config-select').addEventListener('change', (e) => {
            const selectedConfig = loadSavedConfig(e.target.value);
            const configSelected = e.target.value !== "";
            
            // 更新表单值
            if (selectedConfig) {
                settingsPanel.querySelector('#api-url').value = selectedConfig.API_URL;
                settingsPanel.querySelector('#api-key').value = selectedConfig.API_KEY;
                settingsPanel.querySelector('#max-tokens').value = selectedConfig.MAX_TOKENS;
                settingsPanel.querySelector('#shortcut').value = selectedConfig.SHORTCUT;
                settingsPanel.querySelector('#prompt').value = selectedConfig.PROMPT;
                settingsPanel.querySelector('#model').value = selectedConfig.MODEL;
            }
        
            // 更新按钮显示状态
            settingsPanel.querySelector('.delete-config-btn').style.display = configSelected ? 'inline-block' : 'none';
            settingsPanel.querySelector('.rename-config-btn').style.display = configSelected ? 'inline-block' : 'none';
        });

        // 另存为配置按钮事件
        settingsPanel.querySelector('.save-as-btn').addEventListener('click', () => {
            const saveAsGroup = settingsPanel.querySelector('.save-as-group');
            saveAsGroup.style.display = 'block';
        });

        // 保存新配置事件
        settingsPanel.querySelector('#config-name').addEventListener('keyup', (e) => {
            if (e.key === 'Enter') {
                const configName = e.target.value.trim();
                if (configName) {
                    const newConfig = {
                        API_URL: settingsPanel.querySelector('#api-url').value.trim(),
                        API_KEY: settingsPanel.querySelector('#api-key').value.trim(),
                        MAX_TOKENS: parseInt(settingsPanel.querySelector('#max-tokens').value),
                        SHORTCUT: settingsPanel.querySelector('#shortcut').value.trim(),
                        PROMPT: settingsPanel.querySelector('#prompt').value.trim(),
                        MODEL: settingsPanel.querySelector('#model').value.trim()
                    };
                    saveConfigAs(configName, newConfig);
                    updateConfigSelectors();
                    settingsPanel.querySelector('.save-as-group').style.display = 'none';
                    e.target.value = '';
                    alert('配置已保存');
                }
            }
        });

        // 删除配置按钮事件
        settingsPanel.querySelector('.delete-config-btn').addEventListener('click', () => {
            const configSelect = settingsPanel.querySelector('#config-select');
            const configName = configSelect.value;
            if (configName && confirm(`确定要删除配置"${configName}"吗?`)) {
                deleteConfig(configName);
                // 如果删除的是当前正在使用的配置,则清除当前配置名称
                if (configName === CONFIG.CURRENT_CONFIG_NAME) {
                    CONFIG.CURRENT_CONFIG_NAME = '';
                    GM_setValue('CURRENT_CONFIG_NAME', '');
                }
                updateConfigSelectors();
                settingsPanel.querySelector('.delete-config-btn').style.display = 'none';
            }
        });

        // 总结面板中的配置选择事件
        modal.querySelector('.ai-config-select').addEventListener('change', async (e) => {
            const configName = e.target.value;
            if (configName) {
                // 选择了已保存的配置
                const selectedConfig = loadSavedConfig(configName);
                if (selectedConfig) {
                    CONFIG = { ...selectedConfig, CURRENT_CONFIG_NAME: configName };
                    saveConfig(CONFIG);
                    GM_setValue('CURRENT_CONFIG_NAME', configName);

                    // 使用新配置重新生成总结
                    modal.querySelector('.ai-retry-btn').click();
                }
            } else {
                // 如果选择了"当前配置",则恢复到未保存的当前配置状态
                CONFIG.CURRENT_CONFIG_NAME = '';
                GM_setValue('CURRENT_CONFIG_NAME', '');
                // 注意:这里不需要重置其他配置项,保持当前的设置不变
            }
        });

        // 总结模态框中的配置选择事件
        modal.querySelector('.ai-config-select').addEventListener('change', async (e) => {
            const configName = e.target.value;
            if (configName) {
                const selectedConfig = loadSavedConfig(configName);
                if (selectedConfig) {
                    saveConfig(selectedConfig, configName);
                    // 重新生成总结
                    modal.querySelector('.ai-retry-btn').click();
                }
            } else {
                // 选择了"当前配置"选项
                saveConfig(CONFIG, '');
            }

            // 同步更新设置面板的选择器
            updateConfigSelectors(settingsPanel, modal);
        });

        // 初始化设置面板的事件
        initializeSettingsEvents(settingsPanel, modal, settingsOverlay);

        // 初始化时更新一次选择器
        updateConfigSelectors(settingsPanel, modal);

        // 另存为配置按钮事件
        settingsPanel.querySelector('.save-as-btn').addEventListener('click', () => {
            const saveAsGroup = settingsPanel.querySelector('.save-as-group');
            saveAsGroup.style.display = 'block';
            settingsPanel.querySelector('#config-name').focus(); // 自动聚焦到输入框
        });

        // 取消保存配置
        settingsPanel.querySelector('.cancel-save-as-btn').addEventListener('click', () => {
            const saveAsGroup = settingsPanel.querySelector('.save-as-group');
            saveAsGroup.style.display = 'none';
            settingsPanel.querySelector('#config-name').value = '';
        });

        // 保存配置的函数
        function saveCurrentConfig(configName) {
            if (configName) {
                // 从设置面板获取当前的所有设置值
                const newConfig = {
                    API_URL: settingsPanel.querySelector('#api-url').value.trim(),
                    API_KEY: settingsPanel.querySelector('#api-key').value.trim(),
                    MAX_TOKENS: parseInt(settingsPanel.querySelector('#max-tokens').value) || DEFAULT_CONFIG.MAX_TOKENS,
                    SHORTCUT: settingsPanel.querySelector('#shortcut').value.trim() || DEFAULT_CONFIG.SHORTCUT,
                    PROMPT: settingsPanel.querySelector('#prompt').value.trim() || DEFAULT_CONFIG.PROMPT,
                    MODEL: settingsPanel.querySelector('#model').value.trim() || DEFAULT_CONFIG.MODEL
                };

                // 检查配置名是否已存在
                if (getAllConfigs()[configName] &&
                    !confirm(`配置"${configName}"已存在,是否覆盖?`)) {
                    return false;
                }

                // 保存配置到存储中
                saveConfigAs(configName, newConfig);

                // 更新当前配置
                CONFIG = { ...newConfig, CURRENT_CONFIG_NAME: configName };
                GM_setValue('CURRENT_CONFIG_NAME', configName);

                // 更新两个面板中的配置选择器
                updateConfigSelectors(settingsPanel, modal);

                // 重置并隐藏保存表单
                settingsPanel.querySelector('.save-as-group').style.display = 'none';
                settingsPanel.querySelector('#config-name').value = '';

                alert('配置已保存并设为当前配置');
                return true;
            }
            return false;
        }

        // 确认保存配置按钮事件
        settingsPanel.querySelector('.confirm-save-as-btn').addEventListener('click', () => {
            const configName = settingsPanel.querySelector('#config-name').value.trim();
            saveCurrentConfig(configName);
        });

        // 保存新配置事件(回车键)
        settingsPanel.querySelector('#config-name').addEventListener('keyup', (e) => {
            if (e.key === 'Enter') {
                const configName = e.target.value.trim();
                saveCurrentConfig(configName);
            }
        });

        // 重命名按钮事件
        settingsPanel.querySelector('.rename-config-btn').addEventListener('click', () => {
            const configSelect = settingsPanel.querySelector('#config-select');
            const currentConfigName = configSelect.value;
            
            if (!currentConfigName) {
                alert('请先选择要重命名的配置');
                return;
            }

            const renameGroup = settingsPanel.querySelector('.rename-group');
            const renameInput = settingsPanel.querySelector('#rename-config');
            
            // 设置输入框的默认值为当前配置名
            renameInput.value = currentConfigName;
            
            // 显示重命名输入组
            renameGroup.style.display = 'block';
            
            // 聚焦输入框并选中文本
            renameInput.focus();
            renameInput.select();
        });
        // 确认重命名按钮事件
        settingsPanel.querySelector('.confirm-rename-btn').addEventListener('click', () => {
            const configSelect = settingsPanel.querySelector('#config-select');
            const oldName = configSelect.value;
            const newName = settingsPanel.querySelector('#rename-config').value.trim();

            if (!oldName) {
                alert('请先选择要重命名的配置');
                return;
            }

            if (!newName) {
                alert('请输入新的配置名称');
                return;
            }

            if (oldName === newName) {
                alert('新名称与原名称相同');
                return;
            }

            // 检查新名称是否已存在
            const configs = getAllConfigs();
            if (configs[newName] && !confirm(`配置名"${newName}"已存在,是否覆盖?`)) {
                return;
            }

            // 执行重命名操作
            if (renameConfig(oldName, newName)) {
                // 更新选择器
                updateConfigSelectors(settingsPanel, modal);
                // 隐藏重命名输入组
                settingsPanel.querySelector('.rename-group').style.display = 'none';
                // 清空输入框
                settingsPanel.querySelector('#rename-config').value = '';
                alert('重命名成功');
            }
        });
        // 取消重命名按钮事件
        settingsPanel.querySelector('.cancel-rename-btn').addEventListener('click', () => {
            const renameGroup = settingsPanel.querySelector('.rename-group');
            renameGroup.style.display = 'none';
            settingsPanel.querySelector('#rename-config').value = '';
        });

        // 初始化重命名相关的事件
        initializeRenameEvents(elements.settingsPanel, elements.modal);
    }

    // 判断快捷键是否被按下
    function isShortcutPressed(event, shortcut) {
        const keys = shortcut.split('+');
        let ctrl = false, alt = false, shift = false, meta = false, key = null;

        keys.forEach(k => {
            const lower = k.toLowerCase();
            if (lower === 'ctrl') ctrl = true;
            // 将 Option 键映射到 Alt 键,因为在 Mac 中 Option 键触发的是 altKey
            if (lower === 'alt' || lower === 'option') alt = true;
            if (lower === 'shift') shift = true;
            if (lower === 'meta') meta = true;
            if (lower.length === 1 && /^[a-z]$/.test(lower)) key = lower;
        });

        if (key && event.key.toLowerCase() === key) {
            return event.ctrlKey === ctrl &&
                   event.altKey === alt &&
                   event.shiftKey === shift &&
                   event.metaKey === meta;
        }

        return false;
    }

    // 多系统适配的快捷键显示
    function getSystemShortcutDisplay(shortcut) {
        const isMac = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
        if (!isMac) return shortcut;

        // 为 Mac 系统转换快捷键显示
        return shortcut.replace(/Alt\+/g, 'Option+')
                    .replace(/Ctrl\+/g, '⌘+')
                    .replace(/Meta\+/g, '⌘+');
    }

    // 显示模态框
    function showModal(modal, overlay) {
        modal.style.display = 'block';
        overlay.style.display = 'block';
    }

    // 隐藏模态框
    function hideModal(modal, overlay) {
        modal.style.display = 'none';
        overlay.style.display = 'none';
    }

    const DOCK_POSITIONS = {
        LEFT: 'left',
        RIGHT: 'right',
        NONE: 'none'
    };

    const DEBOUNCE_TIME = 10; // 防抖时间
    const FOLD_DELAY = 1000; // 折叠延迟时间

    const DOCK_THRESHOLD = 100; // 贴靠触发阈值

    function savePosition(container) {
        const position = {
            left: container.style.left,
            top: container.style.top,
            right: container.style.right,
            bottom: container.style.bottom,
            dockPosition: container.dataset.dockPosition || DOCK_POSITIONS.NONE,
            windowWidth: window.innerWidth,
            windowHeight: window.innerHeight
        };
        GM_setValue('containerPosition', position);
    }

    function loadPosition(container) {
        const savedPosition = GM_getValue('containerPosition');
        if (savedPosition) {
            const currentWindowRatio = window.innerWidth / savedPosition.windowWidth;
            const heightRatio = window.innerHeight / (savedPosition.windowHeight || window.innerHeight);

            if (savedPosition.dockPosition === DOCK_POSITIONS.LEFT) {
                dockToLeft(container);
            } else if (savedPosition.dockPosition === DOCK_POSITIONS.RIGHT) {
                dockToRight(container);
            } else {
                // 计算新位置时考虑容器尺寸
                const containerWidth = container.offsetWidth;
                const containerHeight = container.offsetHeight;

                // 计算并约束水平位置
                const left = parseInt(savedPosition.left) * currentWindowRatio;
                const maxLeft = window.innerWidth - containerWidth;
                const safeLeft = Math.max(0, Math.min(left, maxLeft));

                // 计算并约束垂直位置
                const rawTop = parseInt(savedPosition.top);
                let safeTop;

                if (rawTop * heightRatio > window.innerHeight - containerHeight) {
                    // 如果计算后的位置会超出窗口底部,则放置在可见区域内
                    safeTop = window.innerHeight - containerHeight - 20; // 20px作为底部边距
                } else {
                    // 否则保持相对位置
                    safeTop = Math.max(0, Math.min(rawTop * heightRatio, window.innerHeight - containerHeight));
                }

                // 应用安全位置
                container.style.left = `${safeLeft}px`;
                container.style.top = `${safeTop}px`;
                container.style.right = 'auto';
                container.style.bottom = 'auto';
            }
        }
    }

    function initializeDrag(container, dragHandle, shadow) {
        let isDragging = false;
        let currentX;
        let currentY;
        let initialX;
        let initialY;
        let foldTimeout;

        const style = document.createElement('style');
        style.textContent = `
            .ai-summary-container {
                transition: transform 0.3s ease;
            }
            .ai-summary-container.docked {
                transition: all 0.3s ease;
            }
            .ai-drag-handle {
                pointer-events: auto !important;
            }
            .ai-summary-container.docked .ai-summary-btn {
                width: 0;
                padding: 0;
                opacity: 0;
                overflow: hidden;
                border-color: rgba(75, 85, 99, 0);
                transition: all 0.3s ease, border-color 0.3s ease;
            }
            .ai-summary-container.docked.show-btn .ai-summary-btn {
                width: 80px;
                padding: 5px 15px;
                opacity: 1;
            }
            .ai-summary-container.docked:hover .ai-summary-btn {
                width: 80px;
                padding: 5px 15px;
                opacity: 1;
            }
            .ai-summary-container.right-dock {
                right: 0 !important;
                left: auto !important;
            }
            .ai-summary-container.left-dock {
                left: 0 !important;
                right: auto !important;
            }
        `;
        shadow.appendChild(style);

        // 鼠标进入和离开事件处理
        container.addEventListener('mouseenter', () => {
            clearTimeout(foldTimeout); // 清除之前的折叠计时器
            if (container.classList.contains('docked')) {
                container.classList.add('show-btn');
            }
        });

        container.addEventListener('mouseleave', () => {
            if (container.classList.contains('docked')) {
                // 设置延迟折叠
                foldTimeout = setTimeout(() => {
                    container.classList.remove('show-btn');
                }, FOLD_DELAY);
            }
        });

        // 防抖函数
        function debounce(func, wait) {
            let timeout;
            return function executedFunction(...args) {
                const later = () => {
                    clearTimeout(timeout);
                    func(...args);
                };
                clearTimeout(timeout);
                timeout = setTimeout(later, wait);
            };
        }

        loadPosition(container);

        dragHandle.addEventListener('mousedown', (e) => {
            isDragging = true;
            const rect = container.getBoundingClientRect();
            initialX = e.clientX - rect.left;
            initialY = e.clientY - rect.top;

            // 开始拖动时,先记录当前位置
            if (container.classList.contains('right-dock')) {
                currentX = window.innerWidth - container.offsetWidth;
            } else if (container.classList.contains('left-dock')) {
                currentX = 0;
            } else {
                currentX = rect.left;
            }
            currentY = rect.top;

            container.classList.remove('docked', 'right-dock', 'left-dock', 'show-btn');
            container.dataset.dockPosition = DOCK_POSITIONS.NONE;
            document.body.style.userSelect = 'none';
        });

        document.addEventListener('mousemove', (e) => {
            if (!isDragging) return;
            e.preventDefault();

            const newX = e.clientX - initialX;
            const newY = e.clientY - initialY;
            const containerWidth = container.offsetWidth;
            const containerHeight = container.offsetHeight;

            if (e.clientX < DOCK_THRESHOLD) {
                dockToLeft(container);
                container.classList.add('show-btn'); // 贴靠时立即显示按钮
            }
            else if (e.clientX > window.innerWidth - DOCK_THRESHOLD) {
                dockToRight(container);
                container.classList.add('show-btn'); // 贴靠时立即显示按钮
            }
            else {
                const maxX = window.innerWidth - containerWidth;
                const maxY = window.innerHeight - containerHeight;

                currentX = Math.max(0, Math.min(newX, maxX));
                currentY = Math.max(0, Math.min(newY, maxY));

                container.style.left = `${currentX}px`;
                container.style.top = `${currentY}px`;
                container.style.right = 'auto';
                container.dataset.dockPosition = DOCK_POSITIONS.NONE;
                container.classList.remove('docked', 'right-dock', 'left-dock', 'show-btn');
            }
        });

        document.addEventListener('mouseup', () => {
            if (isDragging) {
                isDragging = false;
                document.body.style.userSelect = 'auto';
                savePosition(container);
            }
        });

        // 使用防抖处理窗口调整
        const debouncedLoadPosition = debounce(() => {
            loadPosition(container);
        }, DEBOUNCE_TIME);

        window.addEventListener('resize', debouncedLoadPosition);
    }

    function dockToLeft(container) {
        container.classList.add('docked', 'left-dock');
        container.dataset.dockPosition = DOCK_POSITIONS.LEFT;
        container.style.left = '0';
        container.style.right = 'auto';
    }

    function dockToRight(container) {
        container.classList.add('docked', 'right-dock');
        container.dataset.dockPosition = DOCK_POSITIONS.RIGHT;
        container.style.right = '0';
        container.style.left = 'auto';
    }

    // 1. 加载配置
    loadConfig();

    // 2. 创建元素
    const elements = createElements();

    // 3. 初始化事件
    initializeEvents(elements);

    // 4. 检查配置是否完整
    if (!CONFIG.API_URL || !CONFIG.API_KEY) {
        elements.settingsPanel.style.display = 'block';
        elements.shadow.querySelector('.ai-summary-overlay').style.display = 'block';
        alert('请先配置API URL和API Key。');
    }
})();