Greasy Fork

AI Page Summarizer Pro

网页内容智能总结,支持自定义API和提示词

目前为 2025-03-15 提交的版本。查看 最新版本

// ==UserScript==
// @name         AI Page Summarizer Pro
// @namespace    http://tampermonkey.net/
// @version      0.9.8
// @description  网页内容智能总结,支持自定义API和提示词
// @author       Your Name
// @match        *://*/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @require      https://cdn.jsdelivr.net/npm/[email protected]/marked.min.js
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    // 配置项
    let config = {
        apiUrl: GM_getValue('apiUrl', 'https://api.openai.com/v1/chat/completions'),
        apiKey: GM_getValue('apiKey', ''),
        model: GM_getValue('model', 'gpt-3.5-turbo'),
        prompt: GM_getValue('prompt', `You are a professional content summarizer in chinese. Your task is to create a clear, concise, and well-structured summary of the webpage content. Follow these guidelines:

1. Output Format:
   - Use Markdown formatting
   - Start with a brief overview
   - Use appropriate headings (h2, h3)
   - Include bullet points for key points
   - Use bold for important terms
   - Use blockquotes for notable quotes
   - Use code blocks for technical content

2. Content Structure:
   - Main Topic/Title
   - Key Points
   - Important Details
   - Conclusions/Summary

3. Writing Style:
   - Clear and concise language
   - Professional tone
   - Logical flow
   - Easy to understand
   - Focus on essential information

4. Important Rules:
   - DO NOT show your reasoning process
   - DO NOT include meta-commentary
   - DO NOT explain your methodology
   - DO NOT use phrases like "this summary shows" or "the content indicates"
   - Start directly with the content summary

5. Length Guidelines:
   - Overview: 1-2 sentences
   - Key Points: 3-5 bullet points
   - Important Details: 2-3 paragraphs
   - Summary: 1-2 sentences

Remember: Focus on delivering the information directly without any meta-analysis or explanation of your process.`),
        iconPosition: GM_getValue('iconPosition', { y: 20 }),
        shortcut: GM_getValue('shortcut', 'option+a')
    };

    // DOM 元素引用
    const elements = {
        icon: null,
        container: null,
        settings: null,
        backdrop: null
    };

    // 全局变量用于判断是否已经监听了键盘事件
    let keyboardListenerActive = false;

    // 快捷键处理
    const keyManager = {
        setup() {
            try {
                // 移除旧的监听器
                if (keyboardListenerActive) {
                    document.removeEventListener('keydown', this._handleKeyDown);
                }

                // 添加新的监听器,使用普通函数而非方法
                this._handleKeyDown = (e) => {
                    // 忽略输入框中的按键
                    if (e.target.tagName === 'INPUT' || 
                        e.target.tagName === 'TEXTAREA' || 
                        e.target.isContentEditable ||
                        e.target.getAttribute('role') === 'textbox') {
                        return;
                    }

                    // 解析配置的快捷键
                    const shortcutParts = config.shortcut.toLowerCase().split('+');
                    
                    // 获取主键(非修饰键)
                    const mainKey = shortcutParts.filter(part => 
                        !['alt', 'option', 'ctrl', 'control', 'shift', 'cmd', 'command', 'meta']
                        .includes(part)
                    )[0] || 'a';
                    
                    // 检查所需的修饰键
                    const needAlt = shortcutParts.some(p => p === 'alt' || p === 'option');
                    const needCtrl = shortcutParts.some(p => p === 'ctrl' || p === 'control');
                    const needShift = shortcutParts.some(p => p === 'shift');
                    const needMeta = shortcutParts.some(p => p === 'cmd' || p === 'command' || p === 'meta');
                    
                    // 检查按键是否匹配 - 同时检查key和code
                    const isMainKeyMatched = 
                        e.key.toLowerCase() === mainKey || 
                        (e.code && e.code.toLowerCase() === 'key' + mainKey);
                        
                    // 检查修饰键是否匹配
                    if (isMainKeyMatched && 
                        e.altKey === needAlt && 
                        e.ctrlKey === needCtrl && 
                        e.shiftKey === needShift && 
                        e.metaKey === needMeta) {
                        
                        console.log('快捷键触发成功:', config.shortcut);
                        e.preventDefault();
                        e.stopPropagation();
                        showSummary();
                        return false;
                    }
                };
                
                // 使用捕获阶段来确保我们能先捕获到事件
                document.addEventListener('keydown', this._handleKeyDown, true);
                keyboardListenerActive = true;
                
                // 设置全局访问方法
                window.activateSummary = showSummary;
                
                console.log('快捷键已设置:', config.shortcut);
                return true;
            } catch (error) {
                console.error('设置快捷键失败:', error);
                return false;
            }
        },
        
        // 测试快捷键是否工作
        test() {
            try {
                if (!keyboardListenerActive) {
                    console.warn('键盘监听器未激活,请先调用 keyManager.setup()');
                    return false;
                }
                
                // 解析当前快捷键
                const parts = config.shortcut.toLowerCase().split('+');
                const mainKey = parts.filter(part => 
                    !['alt', 'option', 'ctrl', 'control', 'shift', 'cmd', 'command', 'meta']
                    .includes(part)
                )[0] || 'a';
                
                // 创建事件对象
                const eventOptions = {
                    key: mainKey,
                    code: 'Key' + mainKey.toUpperCase(),
                    altKey: parts.includes('alt') || parts.includes('option'),
                    ctrlKey: parts.includes('ctrl') || parts.includes('control'),
                    shiftKey: parts.includes('shift'),
                    metaKey: parts.includes('cmd') || parts.includes('command') || parts.includes('meta'),
                    bubbles: true,
                    cancelable: true
                };
                
                console.log('模拟快捷键按下:', JSON.stringify(eventOptions));
                
                const event = new KeyboardEvent('keydown', eventOptions);
                
                // 由于 KeyboardEvent 的限制,某些属性可能无法正确设置,所以我们通过这种方式确认
                if (!event.altKey && eventOptions.altKey) {
                    console.warn('注意: 无法在模拟事件中设置 altKey 属性');
                }
                
                // 分发事件
                document.dispatchEvent(event);
                
                // 因为可能无法模拟事件,所以直接提供一个调用方法
                console.log('您也可以通过控制台调用 window.activateSummary() 来直接触发');
                
                return true;
            } catch (error) {
                console.error('测试快捷键失败:', error);
                return false;
            }
        }
    };

    // 等待依赖库加载
    function waitForDependencies(callback) {
        if (window.marked) {
            window.marked.setOptions({ breaks: true, gfm: true });
            callback();
            return;
        }
        setTimeout(() => waitForDependencies(callback), 100);
    }

    // 创建图标
    function createIcon() {
        const icon = document.createElement('div');
        icon.id = 'website-summary-icon';
        
        // Mac风格书本图标
        icon.innerHTML = `
            <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
                <defs>
                    <linearGradient id="ws-grad" x1="0%" y1="0%" x2="100%" y2="100%">
                        <stop offset="0%" style="stop-color:#4299e1;stop-opacity:1" />
                        <stop offset="100%" style="stop-color:#3182ce;stop-opacity:1" />
                    </linearGradient>
                    <filter id="ws-shadow" x="-10%" y="-10%" width="120%" height="120%">
                        <feDropShadow dx="0" dy="1" stdDeviation="1" flood-color="#000000" flood-opacity="0.2"/>
                    </filter>
                    <linearGradient id="ws-page-grad" x1="0%" y1="0%" x2="0%" y2="100%">
                        <stop offset="0%" style="stop-color:#ffffff;stop-opacity:1" />
                        <stop offset="100%" style="stop-color:#f7fafc;stop-opacity:1" />
                    </linearGradient>
                </defs>
                
                <!-- 背景圆 -->
                <circle cx="20" cy="20" r="18" fill="url(#ws-grad)" filter="url(#ws-shadow)" />
                
                <!-- 书本 -->
                <g transform="translate(10, 10) scale(0.8)">
                    <!-- 书本封面 -->
                    <path d="M5 6 L5 27 L23 27 C25 27 25 24 23 24 L8 24 L8 9 L23 9 C25 9 25 6 23 6 Z" 
                          fill="#ffffff" stroke="#ffffff" stroke-width="1" />
                    
                    <!-- 书本纸张 -->
                    <path d="M8 9 L8 24 L23 24 C21 24 21 9 23 9 Z" 
                          fill="url(#ws-page-grad)" stroke="#e2e8f0" stroke-width="0.5" />
                    
                    <!-- 书脊 -->
                    <path d="M5 6 L5 27" stroke="#ffffff" stroke-width="2" stroke-linecap="round" />
                    
                    <!-- 装饰线1 -->
                    <path d="M11 14 L19 14" stroke="#3182ce" stroke-width="0.75" stroke-linecap="round" />
                    
                    <!-- 装饰线2 -->
                    <path d="M11 17 L17 17" stroke="#3182ce" stroke-width="0.75" stroke-linecap="round" />
                    
                    <!-- 装饰线3 -->
                    <path d="M11 20 L19 20" stroke="#3182ce" stroke-width="0.75" stroke-linecap="round" />
                </g>
            </svg>
        `;
        
        icon.style.cssText = `
            position: fixed;
            z-index: 999999;
            width: 40px;
            height: 40px;
            border-radius: 20px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            transition: transform 0.2s ease, box-shadow 0.2s ease;
            backdrop-filter: blur(5px);
            right: 20px;
            top: ${config.iconPosition.y || 20}px;
            touch-action: none;
            will-change: transform;
        `;

        icon.addEventListener('mouseover', () => {
            icon.style.transform = 'scale(1.1)';
            icon.style.boxShadow = '0 4px 12px rgba(49, 130, 206, 0.3)';
        });

        icon.addEventListener('mouseout', () => {
            icon.style.transform = 'scale(1)';
            icon.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.1)';
        });

        icon.addEventListener('click', showSummary);
        icon.addEventListener('contextmenu', (e) => {
            e.preventDefault();
            showSettings();
        });
        
        makeDraggable(icon);
        document.body.appendChild(icon);
        elements.icon = icon;
        return icon;
    }

    // 显示设置界面
    function showSettings() {
        const settings = elements.settings || createSettingsUI();
        settings.style.display = 'block';
    }

    // 显示摘要
    async function showSummary() {
        const container = elements.container || createSummaryUI();
        const content = container.querySelector('#website-summary-content');
        
        // 显示容器和背景
        showBackdrop();
        container.style.display = 'block';
        setTimeout(() => container.style.opacity = '1', 10);
        
        // 显示加载中
        content.innerHTML = '<p style="text-align: center; color: #666;">正在获取总结...</p>';
        
        try {
            const pageContent = getPageContent();
            if (!pageContent) throw new Error('无法获取页面内容');
            
            const summary = await getSummary(pageContent);
            if (!summary) throw new Error('获取总结失败');
            
            renderContent(summary);
        } catch (error) {
            content.innerHTML = `
                <p style="text-align: center; color: #ff4444;">
                    获取总结失败:${error.message}<br>
                    请检查API配置是否正确
                </p>`;
        }
    }

    // 创建/显示背景
    function showBackdrop() {
        if (!elements.backdrop) {
            const backdrop = document.createElement('div');
            backdrop.id = 'website-summary-backdrop';
            backdrop.style.cssText = `
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background-color: rgba(250, 250, 252, 0.75);
                backdrop-filter: blur(5px);
                z-index: 999997;
                display: none;
                opacity: 0;
                transition: opacity 0.3s ease;
            `;
            
            backdrop.addEventListener('click', (e) => {
                if (e.target === backdrop) {
                    hideUI();
                }
            });
            
            document.body.appendChild(backdrop);
            elements.backdrop = backdrop;
        }
        
        elements.backdrop.style.display = 'block';
        setTimeout(() => elements.backdrop.style.opacity = '1', 10);
    }

    // 隐藏UI
    function hideUI() {
        // 隐藏背景
        if (elements.backdrop) {
            elements.backdrop.style.opacity = '0';
            setTimeout(() => elements.backdrop.style.display = 'none', 300);
        }
        
        // 隐藏摘要容器
        if (elements.container) {
            elements.container.style.opacity = '0';
            setTimeout(() => elements.container.style.display = 'none', 300);
        }
    }

    // 创建摘要UI
    function createSummaryUI() {
        const container = document.createElement('div');
        container.id = 'website-summary-container';
        container.style.cssText = `
            position: fixed;
            z-index: 999998;
            background: rgba(255, 255, 255, 0.9);
            border-radius: 12px;
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
            padding: 16px;
            width: 80%;
            max-width: 800px;
            max-height: 80vh;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            display: none;
            backdrop-filter: blur(10px);
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            overflow: hidden;
            opacity: 0;
            transition: opacity 0.3s ease;
        `;

        // 标题栏
        const header = document.createElement('div');
        header.style.cssText = `
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 12px;
            cursor: move;
            padding-bottom: 8px;
            border-bottom: 1px solid #eee;
        `;

        // 标题
        const title = document.createElement('h3');
        title.textContent = '网页总结';
        title.style.cssText = 'margin: 0; font-size: 18px; color: #333;';

        // 按钮容器
        const buttonContainer = document.createElement('div');
        buttonContainer.style.cssText = 'display: flex; gap: 8px; align-items: center;';

        // 复制按钮
        const copyBtn = document.createElement('button');
        copyBtn.textContent = '复制';
        copyBtn.style.cssText = `
            background: #4CAF50;
            color: white;
            border: none;
            padding: 6px 12px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
            transition: background-color 0.2s;
        `;

        copyBtn.addEventListener('mouseover', () => copyBtn.style.backgroundColor = '#45a049');
        copyBtn.addEventListener('mouseout', () => copyBtn.style.backgroundColor = '#4CAF50');
        copyBtn.addEventListener('click', () => {
            const content = document.getElementById('website-summary-content').innerText;
            navigator.clipboard.writeText(content).then(() => {
                copyBtn.textContent = '已复制';
                setTimeout(() => copyBtn.textContent = '复制', 2000);
            });
        });

        // 关闭按钮
        const closeBtn = document.createElement('button');
        closeBtn.textContent = '×';
        closeBtn.style.cssText = `
            background: none;
            border: none;
            font-size: 24px;
            cursor: pointer;
            padding: 0 8px;
            color: #666;
            transition: color 0.2s;
        `;

        closeBtn.addEventListener('mouseover', () => closeBtn.style.color = '#ff4444');
        closeBtn.addEventListener('mouseout', () => closeBtn.style.color = '#666');
        closeBtn.addEventListener('click', hideUI);

        // 内容区域
        const content = document.createElement('div');
        content.id = 'website-summary-content';
        content.style.cssText = `
            max-height: calc(80vh - 60px);
            overflow-y: auto;
            font-size: 14px;
            line-height: 1.6;
            padding: 8px 0;
        `;

        // 组装界面
        buttonContainer.appendChild(copyBtn);
        buttonContainer.appendChild(closeBtn);
        header.appendChild(title);
        header.appendChild(buttonContainer);
        container.appendChild(header);
        container.appendChild(content);
        document.body.appendChild(container);
        
        makeDraggable(container);
        elements.container = container;
        return container;
    }

    // 创建设置界面
    function createSettingsUI() {
        const settingsContainer = document.createElement('div');
        settingsContainer.id = 'website-summary-settings';
        settingsContainer.style.cssText = `
            position: fixed;
            z-index: 1000000;
            background: rgba(255, 255, 255, 0.98);
            border-radius: 12px;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
            padding: 20px;
            width: 400px;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            display: none;
            backdrop-filter: blur(10px);
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
        `;

        // 标题栏
        const header = document.createElement('div');
        header.style.cssText = 'display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; cursor: move;';

        const title = document.createElement('h3');
        title.textContent = '设置';
        title.style.margin = '0';

        const closeBtn = document.createElement('button');
        closeBtn.textContent = '×';
        closeBtn.style.cssText = 'background: none; border: none; font-size: 24px; cursor: pointer; padding: 0 8px; color: #666;';
        closeBtn.addEventListener('click', () => settingsContainer.style.display = 'none');

        // 表单
        const form = document.createElement('form');
        form.style.cssText = 'display: flex; flex-direction: column; gap: 16px;';
        
        // 创建输入字段函数
        function createField(id, label, value, type = 'text', placeholder = '') {
            const container = document.createElement('div');
            container.style.cssText = 'display: flex; flex-direction: column; gap: 4px;';
            
            const labelElem = document.createElement('label');
            labelElem.textContent = label;
            labelElem.style.cssText = 'font-size: 14px; color: #333; font-weight: 500;';
            
            const input = document.createElement(type === 'textarea' ? 'textarea' : 'input');
            if (type !== 'textarea') input.type = type;
            input.id = id;
            input.value = value;
            input.placeholder = placeholder;
            input.autocomplete = 'off';
            input.setAttribute('data-form-type', 'other');
            
            const baseStyle = 'width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 6px; font-family: inherit;';
            input.style.cssText = type === 'textarea' ? baseStyle + 'height: 100px; resize: vertical;' : baseStyle;
            
            container.appendChild(labelElem);
            container.appendChild(input);
            return { container, input };
        }
        
        // 创建字段
        const apiUrlField = createField('apiUrl', 'API URL', config.apiUrl, 'text', '输入API URL');
        const apiKeyField = createField('apiKey', 'API Key', config.apiKey, 'text', '输入API Key');
        const modelField = createField('model', 'AI 模型', config.model, 'text', '输入AI模型名称');
        const shortcutField = createField('shortcut', '快捷键', config.shortcut, 'text', '例如: option+a, ctrl+shift+s');
        const promptField = createField('prompt', '提示词', config.prompt, 'textarea', '输入提示词');
        
        // 添加字段到表单
        form.appendChild(apiUrlField.container);
        form.appendChild(apiKeyField.container);
        form.appendChild(modelField.container);
        form.appendChild(shortcutField.container);
        form.appendChild(promptField.container);
        
        // 保存按钮
        const saveBtn = document.createElement('button');
        saveBtn.textContent = '保存设置';
        saveBtn.type = 'button';
        saveBtn.style.cssText = `
            background: #007AFF;
            color: white;
            border: none;
            padding: 10px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 500;
            transition: background-color 0.2s;
        `;

        saveBtn.addEventListener('mouseover', () => saveBtn.style.backgroundColor = '#0056b3');
        saveBtn.addEventListener('mouseout', () => saveBtn.style.backgroundColor = '#007AFF');
        
        // 保存逻辑
        saveBtn.addEventListener('click', (e) => {
            e.preventDefault();
            
            // 获取并验证表单值
            const newApiUrl = apiUrlField.input.value.trim();
            const newApiKey = apiKeyField.input.value.trim();
            const newModel = modelField.input.value.trim();
            const newPrompt = promptField.input.value.trim();
            const newShortcut = shortcutField.input.value.trim();
            
            if (!newApiUrl || !newApiKey) {
                alert('请至少填写API URL和API Key');
                return;
            }

            // 保存到存储
            GM_setValue('apiUrl', newApiUrl);
            GM_setValue('apiKey', newApiKey);
            GM_setValue('model', newModel);
            GM_setValue('prompt', newPrompt);
            GM_setValue('shortcut', newShortcut);

            // 更新内存配置
            config.apiUrl = newApiUrl;
            config.apiKey = newApiKey;
            config.model = newModel;
            config.prompt = newPrompt;
            config.shortcut = newShortcut;
            
            // 更新快捷键
            keyManager.setup();

            // 显示成功提示
            showToast('设置已保存');
            
            // 关闭设置
            settingsContainer.style.display = 'none';
        });

        // 组装界面
        header.appendChild(title);
        header.appendChild(closeBtn);
        form.appendChild(saveBtn);
        settingsContainer.appendChild(header);
        settingsContainer.appendChild(form);
        document.body.appendChild(settingsContainer);

        makeDraggable(settingsContainer);
        elements.settings = settingsContainer;
        return settingsContainer;
    }

    // 显示提示消息
    function showToast(message) {
        const toast = document.createElement('div');
        toast.textContent = message;
        toast.style.cssText = `
            position: fixed;
            top: 20px;
            left: 50%;
            transform: translateX(-50%);
            background: #4CAF50;
            color: white;
            padding: 10px 20px;
            border-radius: 4px;
            z-index: 1000001;
            font-size: 14px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.2);
        `;
        document.body.appendChild(toast);
        setTimeout(() => toast.remove(), 2000);
    }

    // 拖拽功能
    function makeDraggable(element) {
        const header = element.querySelector('div') || element;
        let startX = 0, startY = 0;
        let elementX = 0, elementY = 0;
        let dragging = false;
        
        // 鼠标事件
        header.addEventListener('mousedown', startDrag);
        
        // 触摸事件
        header.addEventListener('touchstart', (e) => {
            const touch = e.touches[0];
            startDrag({ clientX: touch.clientX, clientY: touch.clientY, preventDefault: () => e.preventDefault() });
        }, { passive: false });
        
        function startDrag(e) {
            e.preventDefault();
            dragging = true;
            
            // 记录起始位置
            startX = e.clientX;
            startY = e.clientY;
            elementX = element.offsetLeft;
            elementY = element.offsetTop;
            
            // 设置样式
            if (element.id === 'website-summary-icon') {
                element.style.transition = 'none';
                element.style.opacity = '0.9';
            }
            
            // 添加移动和结束事件
            document.addEventListener('mousemove', onDrag);
            document.addEventListener('touchmove', onTouchDrag, { passive: false });
            document.addEventListener('mouseup', stopDrag);
            document.addEventListener('touchend', stopDrag);
        }
        
        function onDrag(e) {
            if (!dragging) return;
            move(e.clientX, e.clientY);
        }
        
        function onTouchDrag(e) {
            if (!dragging) return;
            e.preventDefault();
            const touch = e.touches[0];
            move(touch.clientX, touch.clientY);
        }
        
        function move(clientX, clientY) {
            // 计算新位置
            const deltaX = clientX - startX;
            const deltaY = clientY - startY;
            
            if (element.id === 'website-summary-icon') {
                // 仅垂直移动图标
                const newY = elementY + deltaY;
                const maxY = window.innerHeight - element.offsetHeight - 10;
                element.style.top = Math.max(10, Math.min(newY, maxY)) + 'px';
            } else {
                // 自由移动其他元素
                element.style.left = (elementX + deltaX) + 'px';
                element.style.top = (elementY + deltaY) + 'px';
                
                // 重置transform以避免与translate(-50%, -50%)冲突
                element.style.transform = 'none';
            }
        }
        
        function stopDrag() {
            if (!dragging) return;
            dragging = false;
            
            // 恢复样式
            if (element.id === 'website-summary-icon') {
                element.style.transition = 'transform 0.2s ease, box-shadow 0.2s ease';
                element.style.opacity = '1';
                
                // 保存图标位置
                config.iconPosition = { y: element.offsetTop };
                GM_setValue('iconPosition', config.iconPosition);
            }
            
            // 移除事件监听器
            document.removeEventListener('mousemove', onDrag);
            document.removeEventListener('touchmove', onTouchDrag);
            document.removeEventListener('mouseup', stopDrag);
            document.removeEventListener('touchend', stopDrag);
        }
    }

    // 获取页面内容
    function getPageContent() {
        try {
            const clone = document.body.cloneNode(true);
            const elementsToRemove = clone.querySelectorAll('script, style, iframe, nav, header, footer, .ad, .advertisement, .social-share, .comment, .related-content');
            elementsToRemove.forEach(el => el.remove());
            return clone.innerText.replace(/\s+/g, ' ').trim().slice(0, 5000);
        } catch (error) {
            return document.body.innerText.slice(0, 5000);
        }
    }

    // 调用API获取总结
    function getSummary(content) {
        return new Promise((resolve, reject) => {
            const apiKey = config.apiKey.trim();
            
            if (!apiKey) {
                resolve('请先设置API Key');
                return;
            }

            const requestData = {
                model: config.model,
                messages: [
                    {
                        role: 'system',
                        content: '你是一个专业的网页内容总结助手,善于使用markdown格式来组织信息。'
                    },
                    {
                        role: 'user',
                        content: config.prompt + '\n\n' + content
                    }
                ],
                temperature: 0.7
            };

            GM_xmlhttpRequest({
                method: 'POST',
                url: config.apiUrl,
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${apiKey}`
                },
                data: JSON.stringify(requestData),
                onload: function(response) {
                    try {
                        const data = JSON.parse(response.responseText);
                        if (data.error) {
                            resolve('API调用失败: ' + data.error.message);
                            return;
                        }
                        if (data.choices && data.choices[0] && data.choices[0].message) {
                            resolve(data.choices[0].message.content);
                        } else {
                            resolve('API响应格式错误,请检查配置。');
                        }
                    } catch (error) {
                        resolve('解析API响应失败,请检查网络连接。');
                    }
                },
                onerror: function() {
                    resolve('API调用失败,请检查网络连接和API配置。');
                }
            });
        });
    }

    // 渲染Markdown内容
    function renderContent(content) {
        const container = document.getElementById('website-summary-content');
        if (!container) return;
        
        try {
            if (!content) throw new Error('内容为空');

            // 渲染Markdown
            let html = window.marked.parse(content);
            container.innerHTML = html;

            // 添加样式
            addMarkdownStyles();
        } catch (error) {
            container.innerHTML = '<p style="text-align: center; color: #ff4444;">渲染内容失败,请刷新页面重试。</p>';
        }
    }

    // 添加Markdown样式
    function addMarkdownStyles() {
        const styleId = 'website-summary-styles';
        if (document.getElementById(styleId)) return;
        
        const style = document.createElement('style');
        style.id = styleId;
        style.textContent = `
            #website-summary-content {
                font-size: 14px;
                line-height: 1.6;
                color: #333;
            }
            #website-summary-content h1, #website-summary-content h2, #website-summary-content h3 {
                margin-top: 20px;
                margin-bottom: 10px;
                color: #222;
            }
            #website-summary-content p {
                margin: 10px 0;
            }
            #website-summary-content code {
                background: #f5f5f5;
                padding: 2px 4px;
                border-radius: 3px;
                font-family: monospace;
            }
            #website-summary-content pre {
                background: #f5f5f5;
                padding: 15px;
                border-radius: 5px;
                overflow-x: auto;
            }
            #website-summary-content blockquote {
                border-left: 4px solid #ddd;
                margin: 10px 0;
                padding-left: 15px;
                color: #666;
            }
            #website-summary-content ul, #website-summary-content ol {
                margin: 10px 0;
                padding-left: 20px;
            }
            #website-summary-content li {
                margin: 5px 0;
            }
            #website-summary-content table {
                border-collapse: collapse;
                width: 100%;
                margin: 10px 0;
            }
            #website-summary-content th, #website-summary-content td {
                border: 1px solid #ddd;
                padding: 8px;
                text-align: left;
            }
            #website-summary-content th {
                background: #f5f5f5;
            }
        `;
        document.head.appendChild(style);
    }

    // 添加菜单命令
    function registerMenuCommands() {
        try {
            GM_registerMenuCommand('显示网页总结 (快捷键: ' + config.shortcut + ')', showSummary);
            GM_registerMenuCommand('打开设置', showSettings);
        } catch (error) {
            console.log('注册菜单命令失败:', error);
        }
    }

    // 初始化
    function init() {
        // 等待页面完全加载
        if (document.readyState !== 'complete') {
            window.addEventListener('load', init);
            return;
        }

        createIcon();
        
        // 设置快捷键
        const keySetupSuccess = keyManager.setup();
        
        // 在页面获得焦点时重新注册快捷键
        window.addEventListener('focus', () => keyManager.setup());
        
        // 注册菜单命令
        registerMenuCommands();
        
        console.log('AI Page Summarizer Pro 初始化完成');
        console.log('快捷键:', config.shortcut);
        
        // 在页面加载完成后测试快捷键
        setTimeout(() => {
            keyManager.test();
            console.log('快捷键使用提示: 按下 ' + config.shortcut + ' 触发网页总结,或右键点击图标打开设置');
            console.log('也可以通过控制台调用 window.activateSummary() 直接触发');
        }, 2000);
    }

    // 启动应用
    waitForDependencies(init);
})();