大模型中文翻译助手

选中文本后调用 OpenAI Compatible API 将其翻译为中文,支持历史记录、收藏夹及整页翻译

目前為 2025-03-17 提交的版本,檢視 最新版本

// ==UserScript==
// @name         大模型中文翻译助手
// @name:en      LLM powered WebPage Translator to Chinese
// @namespace    http://tampermonkey.net/
// @version      1.3.4
// @description  选中文本后调用 OpenAI Compatible API 将其翻译为中文,支持历史记录、收藏夹及整页翻译
// @description:en Select text and call OpenAI Compatible API to translate it to Chinese, supports history, favorites and full page translation
// @author       tzh
// @match        *://*/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    // 可配置的设置
    const defaultSettings = {
        apiEndpoint: 'https://api.deepseek.com/v1/chat/completions', // 默认 OpenAI API 端点
        apiKey: '', // 设置您的 API 密钥
        model: 'deepseek-chat', // 可以根据需要更改为其他模型
        systemPrompt: '你是一个翻译助手,请将以下文本准确地翻译成中文,保持原文的意思、风格和格式,在充分保留原文的意思的情况下使用符合中文习惯的表达。只返回翻译结果,不需要解释。',
        useStreaming: false, // 默认启用流式响应
        temperature: 0.3, // 控制翻译结果的随机性,值越低越准确,值越高越有创意
        maxHistoryItems: 50, // 最大历史记录数
        maxFavoritesItems: 100, // 最大收藏数
        showSourceLanguage: true, // 是否显示源语言
        autoDetectLanguage: true, // 是否自动检测语言
        detectArticleContent: true, // 是否自动识别文章主体内容
        fullPageTranslationSelector: 'body', // 整页翻译时的选择器
        fullPageMaxSegmentLength: 2000, // 整页翻译时的最大分段长度
        excludeSelectors: 'script, style, noscript, iframe, img, svg, canvas, [role="banner"], [role="navigation"]', // 翻译时排除的元素
        apiConfigs: [ // 多API配置
            {
                name: 'DeepSeek',
                apiEndpoint: 'https://api.deepseek.com/v1/chat/completions',
                apiKey: '',
                model: 'deepseek-chat',
            }
        ],
        currentApiIndex: 0, // 当前使用的API索引
    };

    // 初始化设置
    let settings = GM_getValue('translatorSettings', defaultSettings);

    // 全文翻译相关状态
    let isTranslatingFullPage = false; // 是否正在进行全文翻译
    let isTranslationPaused = false; // 是否已暂停翻译
    let translationSegments = []; // 存储页面分段内容
    let lastTranslatedIndex = -1; // 最后翻译的段落索引
    let originalTexts = []; // 存储原始文本

    // 确保设置中包含apiConfigs字段
    if (!settings.apiConfigs) {
        settings.apiConfigs = [
            {
                name: '默认API',
                apiEndpoint: settings.apiEndpoint,
                apiKey: settings.apiKey,
                model: settings.model,
            }
        ];
        settings.currentApiIndex = 0;
        GM_setValue('translatorSettings', settings);
    }

    // 从当前选择的API配置中同步主要设置
    function syncApiSettings() {
        if (settings.apiConfigs && settings.apiConfigs.length > 0 && settings.currentApiIndex >= 0 && settings.currentApiIndex < settings.apiConfigs.length) {
            const currentApi = settings.apiConfigs[settings.currentApiIndex];
            settings.apiEndpoint = currentApi.apiEndpoint;
            settings.apiKey = currentApi.apiKey;
            settings.model = currentApi.model;
            GM_setValue('translatorSettings', settings);
        }
    }

    // 初始同步
    syncApiSettings();

    let translationHistory = GM_getValue('translationHistory', []);
    let translationFavorites = GM_getValue('translationFavorites', []);

    // 跟踪当前活跃的翻译按钮
    let activeTranslateButton = null;
    let lastSelectedText = '';
    let lastSelectionRect = null;

    // 监听整个文档的mousedown事件,防止点击翻译按钮时丢失选择
    document.addEventListener('mousedown', function (e) {
        // 检查点击是否发生在翻译按钮上
        if (e.target.classList.contains('translate-button') || e.target.closest('.translate-button')) {
            e.stopPropagation();
            e.preventDefault();
        }
    }, true);  // 使用捕获阶段,确保在其他处理程序之前执行

    // 语言检测函数
    function detectLanguage(text) {
        // 简单的语言检测逻辑
        const chineseRegex = /[\u4e00-\u9fa5]/;
        const englishRegex = /[a-zA-Z]/;
        const japaneseRegex = /[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FAF]/;
        const koreanRegex = /[\uAC00-\uD7AF\u1100-\u11FF]/;

        if (chineseRegex.test(text)) return '中文';
        if (englishRegex.test(text)) return '英语';
        if (japaneseRegex.test(text)) return '日语';
        if (koreanRegex.test(text)) return '韩语';
        return '未知';
    }

    // 创建设置面板
    function createSettingsPanel() {
        const settingsPanel = document.createElement('div');
        settingsPanel.id = 'translator-settings-panel';
        settingsPanel.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 500px;
            padding: 20px;
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
            z-index: 10000;
            display: none;
            max-height: 90vh;
            overflow-y: auto;
        `;

        // 创建Tab栏
        const tabsHtml = `
            <div class="settings-tabs" style="margin-bottom: 20px; border-bottom: 1px solid #eee;">
                <div class="tab-buttons" style="display: flex; margin-bottom: -1px;">
                    <button id="general-tab-btn" class="tab-btn active" style="padding: 8px 15px; background: none; border: 1px solid #eee; border-bottom: none; margin-right: 5px; cursor: pointer; border-radius: 4px 4px 0 0; background-color: ${settings.currentTab === 'general' ? '#f0f0f0' : 'white'};">常规设置</button>
                    <button id="api-tab-btn" class="tab-btn" style="padding: 8px 15px; background: none; border: 1px solid #eee; border-bottom: none; cursor: pointer; border-radius: 4px 4px 0 0; background-color: ${settings.currentTab === 'api' ? '#f0f0f0' : 'white'};">API 管理</button>
                </div>
            </div>
        `;

        // 常规设置Tab内容
        const generalTabHtml = `
            <div id="general-tab" class="tab-content" style="display: ${settings.currentTab === 'general' ? 'block' : 'none'};">
                <h2 style="margin-top: 0;">翻译设置</h2>
                <div style="margin-bottom: 15px;">
                    <label for="systemPrompt">系统提示词:</label>
                    <textarea id="systemPrompt" style="width: 100%; height: 80px; padding: 5px; margin-top: 5px;">${settings.systemPrompt}</textarea>
                </div>
                <div style="margin-bottom: 15px;">
                    <label for="temperature">随机性(Temperature)</label>
                    <div style="display: flex; align-items: center; margin-top: 5px;">
                        <input type="range" id="temperature" min="0" max="1" step="0.1" value="${settings.temperature}" style="flex-grow: 1;">
                        <span id="temperature-value" style="margin-left: 10px; min-width: 30px; text-align: center;">${settings.temperature}</span>
                    </div>
                    <div style="font-size: 12px; color: #666; margin-top: 5px;">
                        值越低翻译越准确,值越高结果越具有创意性。翻译任务建议使用较低的值。
                    </div>
                </div>
                <div style="margin-bottom: 15px;">
                    <label style="display: flex; align-items: center;">
                        <input type="checkbox" id="useStreaming" ${settings.useStreaming ? 'checked' : ''} style="margin-right: 8px;">
                        启用流式响应(实时显示翻译结果)
                    </label>
                    <div style="font-size: 12px; color: #666; margin-top: 5px;">
                        如果遇到翻译失败问题,可以尝试关闭此选项
                    </div>
                </div>
                <div style="margin-bottom: 15px;">
                    <label style="display: flex; align-items: center;">
                        <input type="checkbox" id="detectArticleContent" ${settings.detectArticleContent ? 'checked' : ''} style="margin-right: 8px;">
                        自动识别文章主体内容
                    </label>
                    <div style="font-size: 12px; color: #666; margin-top: 5px;">
                        启用后将尝试自动识别网页中的文章主体,只翻译主要内容。如识别失败将回退为常规翻译
                    </div>
                </div>
                <div style="margin-bottom: 15px;">
                    <label for="fullPageTranslationSelector">整页翻译选择器:</label>
                    <input type="text" id="fullPageTranslationSelector" style="width: 100%; padding: 5px; margin-top: 5px;" value="${settings.fullPageTranslationSelector}">
                    <div style="font-size: 12px; color: #666; margin-top: 5px;">
                        CSS选择器,用于指定翻译哪些区域的内容
                    </div>
                </div>
                <div style="margin-bottom: 15px;">
                    <label for="excludeSelectors">排除翻译的元素:</label>
                    <input type="text" id="excludeSelectors" style="width: 100%; padding: 5px; margin-top: 5px;" value="${settings.excludeSelectors}">
                    <div style="font-size: 12px; color: #666; margin-top: 5px;">
                        CSS选择器,指定要排除翻译的元素
                    </div>
                </div>
            </div>
        `;

        // API管理Tab内容
        let apiListHtml = '';
        settings.apiConfigs.forEach((api, index) => {
            apiListHtml += `
                <div class="api-item" style="margin-bottom: 15px; padding: 10px; border: 1px solid #eee; border-radius: 4px; position: relative; ${index === settings.currentApiIndex ? 'background-color: #f0f8ff;' : ''}">
                    <div style="position: absolute; top: 10px; right: 10px;">
                        ${index === settings.currentApiIndex ?
                    '<span style="color: #4CAF50; font-weight: bold;">✓ 当前使用</span>' :
                    `<button class="use-api-btn" data-index="${index}" style="padding: 3px 8px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; margin-right: 5px;">使用</button>`
                }
                        <button class="edit-api-btn" data-index="${index}" style="padding: 3px 8px; background-color: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer; margin-right: 5px;">编辑</button>
                        ${settings.apiConfigs.length > 1 ?
                    `<button class="delete-api-btn" data-index="${index}" style="padding: 3px 8px; background-color: #f44336; color: white; border: none; border-radius: 4px; cursor: pointer;">删除</button>` : ''
                }
                    </div>
                    <div style="margin-bottom: 5px;"><strong>名称:</strong> ${api.name}</div>
                    <div style="margin-bottom: 5px;"><strong>端点:</strong> ${api.apiEndpoint}</div>
                    <div style="margin-bottom: 5px;"><strong>密钥:</strong> ${api.apiKey ? '******' + api.apiKey.substring(api.apiKey.length - 4) : '未设置'}</div>
                    <div><strong>模型:</strong> ${api.model}</div>
                </div>
            `;
        });

        const apiTabHtml = `
            <div id="api-tab" class="tab-content" style="display: ${settings.currentTab === 'api' ? 'block' : 'none'};">
                <h2 style="margin-top: 0; margin-bottom: 15px;">API 管理</h2>
                <div style="margin-bottom: 20px;">
                    <button id="add-api-btn" style="padding: 8px 15px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; width: 100%;">+ 添加新 API</button>
                </div>
                <div id="api-list">
                    ${apiListHtml}
                </div>
            </div>
        `;

        // 编辑API的表单
        const apiFormHtml = `
            <div id="api-form" style="display: none;">
                <h2 id="api-form-title" style="margin-top: 0;">添加 API</h2>
                <input type="hidden" id="api-form-index" value="-1">
                <div style="margin-bottom: 15px;">
                    <label for="api-name">API 名称:</label>
                    <input type="text" id="api-name" style="width: 100%; padding: 5px; margin-top: 5px;" placeholder="例如:OpenAI、Azure、DeepSeek">
                </div>
                <div style="margin-bottom: 15px;">
                    <label for="api-endpoint">API 端点:</label>
                    <input type="text" id="api-endpoint" style="width: 100%; padding: 5px; margin-top: 5px;" placeholder="例如:https://api.openai.com/v1/chat/completions">
                </div>
                <div style="margin-bottom: 15px;">
                    <label for="api-key">API 密钥:</label>
                    <input type="password" id="api-key" style="width: 100%; padding: 5px; margin-top: 5px;" placeholder="输入您的API密钥">
                    <div style="font-size: 12px; color: #666; margin-top: 5px;">
                        编辑现有API时,如不需要修改密钥请留空
                    </div>
                </div>
                <div style="margin-bottom: 15px;">
                    <label for="api-model">模型名称:</label>
                    <input type="text" id="api-model" style="width: 100%; padding: 5px; margin-top: 5px;" placeholder="例如:gpt-3.5-turbo">
                </div>
                <div style="display: flex; justify-content: flex-end; gap: 10px;">
                    <button id="cancel-api-form" style="padding: 8px 15px;">取消</button>
                    <button id="save-api-form" style="padding: 8px 15px; background-color: #4285f4; color: white; border: none; border-radius: 4px;">保存</button>
                </div>
            </div>
        `;

        const footerHtml = `
            <div style="display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px;">
                <button id="cancel-settings" style="padding: 8px 15px;">取消</button>
                <button id="save-settings" style="padding: 8px 15px; background-color: #4285f4; color: white; border: none; border-radius: 4px;">保存</button>
            </div>
        `;

        settingsPanel.innerHTML = tabsHtml + generalTabHtml + apiTabHtml + apiFormHtml + footerHtml;
        document.body.appendChild(settingsPanel);

        // 添加温度滑块的实时更新
        const temperatureSlider = document.getElementById('temperature');
        const temperatureValue = document.getElementById('temperature-value');
        temperatureSlider.addEventListener('input', function () {
            temperatureValue.textContent = this.value;
        });

        // Tab切换逻辑
        document.getElementById('general-tab-btn').addEventListener('click', function () {
            document.getElementById('general-tab').style.display = 'block';
            document.getElementById('api-tab').style.display = 'none';
            document.getElementById('api-form').style.display = 'none';
            document.getElementById('general-tab-btn').style.backgroundColor = '#f0f0f0';
            document.getElementById('api-tab-btn').style.backgroundColor = 'white';
            settings.currentTab = 'general';
        });

        document.getElementById('api-tab-btn').addEventListener('click', function () {
            document.getElementById('general-tab').style.display = 'none';
            document.getElementById('api-tab').style.display = 'block';
            document.getElementById('api-form').style.display = 'none';
            document.getElementById('general-tab-btn').style.backgroundColor = 'white';
            document.getElementById('api-tab-btn').style.backgroundColor = '#f0f0f0';
            settings.currentTab = 'api';
        });

        // 添加新API按钮
        document.getElementById('add-api-btn').addEventListener('click', function () {
            document.getElementById('api-tab').style.display = 'none';
            document.getElementById('api-form').style.display = 'block';
            document.getElementById('api-form-title').textContent = '添加 API';
            document.getElementById('api-form-index').value = '-1';
            document.getElementById('api-name').value = '';
            document.getElementById('api-endpoint').value = '';
            document.getElementById('api-key').value = '';
            document.getElementById('api-key').placeholder = '输入您的API密钥';
            document.getElementById('api-model').value = '';
        });

        // 取消API表单
        document.getElementById('cancel-api-form').addEventListener('click', function () {
            document.getElementById('api-form').style.display = 'none';
            document.getElementById('api-tab').style.display = 'block';
        });

        // 保存API设置
        document.getElementById('save-api-form').addEventListener('click', function () {
            const name = document.getElementById('api-name').value.trim();
            const endpoint = document.getElementById('api-endpoint').value.trim();
            const apiKey = document.getElementById('api-key').value.trim();
            const model = document.getElementById('api-model').value.trim();
            const index = parseInt(document.getElementById('api-form-index').value);

            if (!name || !endpoint || !model) {
                alert('请填写所有必填字段:名称、端点和模型');
                return;
            }

            if (index >= 0) {
                // 编辑现有API
                settings.apiConfigs[index] = {
                    name: name,
                    apiEndpoint: endpoint,
                    apiKey: apiKey || settings.apiConfigs[index].apiKey,
                    model: model
                };
            } else {
                // 添加新API
                settings.apiConfigs.push({
                    name: name,
                    apiEndpoint: endpoint,
                    apiKey: apiKey,
                    model: model
                });
            }

            // 更新UI
            document.getElementById('api-form').style.display = 'none';
            document.getElementById('api-tab').style.display = 'block';
            updateApiList();
        });

        // API列表的按钮事件(编辑、删除、使用)
        document.addEventListener('click', function (e) {
            // 编辑API
            if (e.target.classList.contains('edit-api-btn')) {
                const index = parseInt(e.target.getAttribute('data-index'));
                const api = settings.apiConfigs[index];

                document.getElementById('api-tab').style.display = 'none';
                document.getElementById('api-form').style.display = 'block';
                document.getElementById('api-form-title').textContent = '编辑 API';
                document.getElementById('api-form-index').value = index;
                document.getElementById('api-name').value = api.name;
                document.getElementById('api-endpoint').value = api.apiEndpoint;
                document.getElementById('api-key').value = ''; // 出于安全考虑,不回显密钥
                document.getElementById('api-key').placeholder = '不修改请留空 (当前已保存密钥)';
                document.getElementById('api-model').value = api.model;
            }

            // 删除API
            if (e.target.classList.contains('delete-api-btn')) {
                const index = parseInt(e.target.getAttribute('data-index'));
                if (confirm(`确定要删除 "${settings.apiConfigs[index].name}" 吗?`)) {
                    settings.apiConfigs.splice(index, 1);

                    // 如果删除的是当前选中的API,则切换到第一个API
                    if (index === settings.currentApiIndex) {
                        settings.currentApiIndex = 0;
                        syncApiSettings();
                    } else if (index < settings.currentApiIndex) {
                        // 如果删除的是当前选中API之前的API,调整索引
                        settings.currentApiIndex--;
                    }

                    updateApiList();
                }
            }

            // 切换使用的API
            if (e.target.classList.contains('use-api-btn')) {
                const index = parseInt(e.target.getAttribute('data-index'));
                settings.currentApiIndex = index;
                syncApiSettings();
                updateApiList();
            }
        });

        // 更新API列表UI
        function updateApiList() {
            const apiList = document.getElementById('api-list');
            if (!apiList) return;

            let apiListHtml = '';
            settings.apiConfigs.forEach((api, index) => {
                apiListHtml += `
                    <div class="api-item" style="margin-bottom: 15px; padding: 10px; border: 1px solid #eee; border-radius: 4px; position: relative; ${index === settings.currentApiIndex ? 'background-color: #f0f8ff;' : ''}">
                        <div style="position: absolute; top: 10px; right: 10px;">
                            ${index === settings.currentApiIndex ?
                        '<span style="color: #4CAF50; font-weight: bold;">✓ 当前使用</span>' :
                        `<button class="use-api-btn" data-index="${index}" style="padding: 3px 8px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; margin-right: 5px;">使用</button>`
                    }
                            <button class="edit-api-btn" data-index="${index}" style="padding: 3px 8px; background-color: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer; margin-right: 5px;">编辑</button>
                            ${settings.apiConfigs.length > 1 ?
                        `<button class="delete-api-btn" data-index="${index}" style="padding: 3px 8px; background-color: #f44336; color: white; border: none; border-radius: 4px; cursor: pointer;">删除</button>` : ''
                    }
                        </div>
                        <div style="margin-bottom: 5px;"><strong>名称:</strong> ${api.name}</div>
                        <div style="margin-bottom: 5px;"><strong>端点:</strong> ${api.apiEndpoint}</div>
                        <div style="margin-bottom: 5px;"><strong>密钥:</strong> ${api.apiKey ? '******' + api.apiKey.substring(api.apiKey.length - 4) : '未设置'}</div>
                        <div><strong>模型:</strong> ${api.model}</div>
                    </div>
                `;
            });

            apiList.innerHTML = apiListHtml;
        }

        // 保存设置
        document.getElementById('save-settings').addEventListener('click', function () {
            settings = {
                ...settings,
                systemPrompt: document.getElementById('systemPrompt').value,
                useStreaming: document.getElementById('useStreaming').checked,
                detectArticleContent: document.getElementById('detectArticleContent').checked,
                temperature: parseFloat(document.getElementById('temperature').value),
                fullPageTranslationSelector: document.getElementById('fullPageTranslationSelector').value,
                excludeSelectors: document.getElementById('excludeSelectors').value
            };

            // 同步当前API设置
            syncApiSettings();

            GM_setValue('translatorSettings', settings);
            settingsPanel.style.display = 'none';
        });

        // 取消设置
        document.getElementById('cancel-settings').addEventListener('click', function () {
            settingsPanel.style.display = 'none';
        });

        return settingsPanel;
    }

    // 创建设置按钮
    function createSettingsButton() {
        const settingsButton = document.createElement('div');
        settingsButton.id = 'translator-settings-button';
        settingsButton.innerHTML = '⚙️';
        settingsButton.title = '翻译设置';
        settingsButton.style.cssText = `
            position: fixed;
            bottom: 20px;
            right: 20px;
            width: 40px;
            height: 40px;
            background-color: rgba(66, 133, 244, 0.8);
            color: white;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 20px;
            cursor: pointer;
            z-index: 9999;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
        `;

        document.body.appendChild(settingsButton);

        const settingsPanel = createSettingsPanel();

        settingsButton.addEventListener('click', function () {
            settingsPanel.style.display = 'block';

            // 默认显示常规设置标签
            if (!settings.currentTab) {
                settings.currentTab = 'general';
                document.getElementById('general-tab').style.display = 'block';
                document.getElementById('api-tab').style.display = 'none';
                document.getElementById('general-tab-btn').style.backgroundColor = '#f0f0f0';
                document.getElementById('api-tab-btn').style.backgroundColor = 'white';
            } else if (settings.currentTab === 'general') {
                document.getElementById('general-tab').style.display = 'block';
                document.getElementById('api-tab').style.display = 'none';
                document.getElementById('general-tab-btn').style.backgroundColor = '#f0f0f0';
                document.getElementById('api-tab-btn').style.backgroundColor = 'white';
            } else if (settings.currentTab === 'api') {
                document.getElementById('general-tab').style.display = 'none';
                document.getElementById('api-tab').style.display = 'block';
                document.getElementById('general-tab-btn').style.backgroundColor = 'white';
                document.getElementById('api-tab-btn').style.backgroundColor = '#f0f0f0';
            }
        });

        return settingsButton;
    }

    // 创建翻译整页按钮
    function createTranslatePageButton() {
        const button = document.createElement('div');
        button.id = 'translate-page-button';
        button.innerHTML = '翻译整页';
        button.title = '翻译当前页面内容';
        button.style.cssText = `
            position: fixed;
            bottom: 20px;
            right: 70px;
            padding: 8px 12px;
            background-color: rgba(66, 133, 244, 0.8);
            color: white;
            border-radius: 20px;
            font-size: 14px;
            cursor: pointer;
            z-index: 9999;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
            display: flex;
            align-items: center;
            justify-content: center;
        `;

        document.body.appendChild(button);

        button.addEventListener('click', function () {
            if (isTranslatingFullPage) {
                alert('正在翻译中,请稍候...');
                return;
            }
            translateFullPage();
        });

        return button;
    }

    // 创建翻译进度条
    function createProgressBar() {
        const progressContainer = document.createElement('div');
        progressContainer.id = 'translation-progress-container';
        progressContainer.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 4px;
            background-color: #f3f3f3;
            z-index: 10001;
            display: none;
        `;

        const progressBar = document.createElement('div');
        progressBar.id = 'translation-progress-bar';
        progressBar.style.cssText = `
            height: 100%;
            width: 0%;
            background-color: #4285f4;
            transition: width 0.3s;
        `;

        progressContainer.appendChild(progressBar);
        document.body.appendChild(progressContainer);

        return progressContainer;
    }

    // 深度优先遍历DOM树
    function extractTextNodesFromElement(element, textSegments, depth = 0, excludeElements = null, isInReferencesSection = false, referencesSectionElement = null) {
        // 如果没有传入排除元素,使用全局的
        if (excludeElements === null) {
            excludeElements = settings.excludeSelectors ?
                Array.from(document.querySelectorAll(settings.excludeSelectors)) : [];
        }
        
        // 检查是否进入了参考文献区域
        if (element === referencesSectionElement) {
            isInReferencesSection = true;
        }

        // 如果这个元素在排除列表中,跳过
        if (excludeElements.includes(element)) {
            return;
        }

        try {
            // 只对元素节点检查样式
            if (element.nodeType === Node.ELEMENT_NODE) {
                // 检查元素是否隐藏
                const style = window.getComputedStyle(element);
                if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') {
                    return;
                }

                // 特殊处理参考文献条目
                // 参考文献条目通常以数字加方括号开头,如 [1], [2] 等
                if (isInReferencesSection && /^\s*\[\d+\]/.test(element.textContent)) {
                    console.log("检测到参考文献条目:", element.textContent.substring(0, 50));
                    textSegments.push({
                        text: element.textContent,
                        element: element,
                        htmlContent: element.innerHTML,
                        isReferenceItem: true,
                        isInReferencesSection: true,
                        original: element.textContent
                    });
                    return; // 参考文献条目作为整体处理,不再递归子节点
                }

                // 对于块级元素,我们在处理完所有子节点后添加换行标记
                const isBlockElement = style.display === 'block' || 
                                     style.display === 'flex' || 
                                     style.display === 'grid' || 
                                     element.tagName === 'DIV' || 
                                     element.tagName === 'P' || 
                                     element.tagName === 'SECTION' || 
                                     element.tagName === 'ARTICLE' ||
                                     element.tagName === 'LI';
                
                // 递归处理子节点
                for (let i = 0; i < element.childNodes.length; i++) {
                    extractTextNodesFromElement(element.childNodes[i], textSegments, depth + 1, excludeElements, isInReferencesSection, referencesSectionElement);
                }

                // 添加换行标记
                if (isBlockElement && element.textContent.trim() && element.childNodes.length > 0) {
                    textSegments.push({ isNewLine: true });
                }
            } else if (element.nodeType === Node.TEXT_NODE) {
                // 文本节点
                const text = element.textContent.trim();
                if (text) {
                    textSegments.push({
                        text: text,
                        node: element,
                        original: element.textContent,
                        parentElement: element.parentElement,
                        isInReferencesSection: isInReferencesSection
                    });
                }
            }
        } catch (error) {
            console.warn("处理元素时出错:", error);
        }
    }
    
    // 合并文本段落,特殊处理参考文献条目
    function mergeTextSegments(textSegments) {
        // 合并相邻文本段落,特殊处理参考文献条目
        const mergedSegments = [];
        let currentSegment = { text: '', nodes: [], isReferenceItem: false };
        let referenceItems = [];

        for (const segment of textSegments) {
            // 如果是参考文献条目,单独处理
            if (segment.isReferenceItem) {
                // 如果当前段落有内容,先保存
                if (currentSegment.text.trim()) {
                    mergedSegments.push({ ...currentSegment });
                    currentSegment = { text: '', nodes: [], isReferenceItem: false };
                }

                // 添加参考文献条目
                referenceItems.push(segment);
                mergedSegments.push({
                    text: segment.text,
                    element: segment.element,
                    htmlContent: segment.htmlContent,
                    isReferenceItem: true,
                    nodes: [{ node: segment.element, original: segment.original }]
                });

                continue;
            }

            // 如果是参考文献区域但非条目,可能需要特殊处理
            if (segment.isInReferencesSection && !segment.isNewLine) {
                // 可能属于参考文献区域的普通文本,保持段落结构
                if (currentSegment.isInReferencesSection !== true) {
                    // 如果当前段落不是参考文献区域,创建新段落
                    if (currentSegment.text.trim()) {
                        mergedSegments.push({ ...currentSegment });
                    }
                    currentSegment = {
                        text: segment.text,
                        nodes: segment.node ? [{ node: segment.node, original: segment.original }] : [],
                        isInReferencesSection: true
                    };
                } else {
                    // 属于同一参考文献区域段落,合并文本
                    currentSegment.text += (currentSegment.text ? ' ' : '') + segment.text;
                    if (segment.node) {
                        currentSegment.nodes.push({
                            node: segment.node,
                            original: segment.original,
                            parentElement: segment.parentElement
                        });
                    }
                }
                continue;
            }

            if (segment.isNewLine) {
                if (currentSegment.text.trim()) {
                    mergedSegments.push({ ...currentSegment });
                    currentSegment = { text: '', nodes: [], isReferenceItem: false };
                }
                continue;
            }

            currentSegment.text += (currentSegment.text ? ' ' : '') + segment.text;
            if (segment.node) {
                currentSegment.nodes.push({
                    node: segment.node,
                    original: segment.original,
                    parentElement: segment.parentElement
                });
            }

            // 如果当前段落已经足够长,创建新段落
            if (currentSegment.text.length >= settings.fullPageMaxSegmentLength) {
                mergedSegments.push({ ...currentSegment });
                currentSegment = { text: '', nodes: [], isReferenceItem: false };
            }
        }

        // 添加最后一个段落
        if (currentSegment.text.trim()) {
            mergedSegments.push(currentSegment);
        }

        console.log(`提取到${mergedSegments.length}个文本段落,其中参考文献条目${referenceItems.length}个`);
        return mergedSegments;
    }
    
    // 修改extractPageContent函数,使用合并函数
    function extractPageContent() {
        console.log("开始提取页面内容");
        
        // 如果启用了自动识别文章主体,尝试识别
        if (settings.detectArticleContent) {
            const rawSegments = detectMainContent();
            if (rawSegments) {
                console.log("成功识别到文章主体内容");
                return mergeTextSegments(rawSegments);
            } else {
                console.log("未能识别出文章主体,回退到常规翻译模式");
            }
        }
        
        const contentSelector = settings.fullPageTranslationSelector || 'body';
        const contentElement = document.querySelector(contentSelector);

        if (!contentElement) {
            console.error(`未找到匹配选择器的元素: ${contentSelector}`);
            return [];
        }

        // 获取所有需要排除的元素
        const excludeElements = settings.excludeSelectors ?
            Array.from(document.querySelectorAll(settings.excludeSelectors)) : [];

        // 检测参考文献区域
        const referencesElements = Array.from(document.querySelectorAll('h2, h3, h4')).filter(el =>
            el.textContent.toLowerCase().includes('reference') ||
            el.textContent.toLowerCase().includes('bibliography') ||
            el.textContent.includes('参考文献')
        );

        let isInReferencesSection = false;
        let referencesSectionElement = null;

        if (referencesElements.length > 0) {
            referencesSectionElement = referencesElements[0];
            console.log("检测到参考文献区域:", referencesSectionElement.textContent);
        }
        
        // 存储提取的文本段落
        const textSegments = [];
        
        // 深度优先遍历DOM树
        extractTextNodesFromElement(contentElement, textSegments);
        
        // 合并相邻文本段落
        return mergeTextSegments(textSegments);
    }
    
    // 识别网页中的文章主体内容
    function detectMainContent() {
        // 可能的文章主体容器选择器
        const possibleArticleSelectors = [
            'article',
            '.article', 
            '.post', 
            '.content', 
            '.post-content',
            '.article-content', 
            '.entry-content',
            '.main-content',
            'main',
            '#main',
            '#content',
            '.story',
            '[itemprop="articleBody"]',
            '[role="main"]',
            // 添加Divi主题常用的内容容器选择器
            '.et_pb_post_content',
            '.et_pb_module.et_pb_post_content',
            '.et_pb_text_inner',
            '.et_pb_post_content_0_tb_body',
            '.et_builder_inner_content',
            // 添加更多通用选择器
            '.single-content',
            '.single-post-content',
            '.page-content',
            '.post-text'
        ];
        
        // 尝试这些选择器,寻找包含最多内容的元素
        let bestElement = null;
        let maxTextLength = 0;
        
        for (const selector of possibleArticleSelectors) {
            const elements = document.querySelectorAll(selector);
            
            for (const element of elements) {
                // 计算文本内容长度
                const textLength = element.textContent.trim().length;
                
                // 如果比之前找到的更长,更新最佳元素
                if (textLength > maxTextLength) {
                    maxTextLength = textLength;
                    bestElement = element;
                }
            }
        }
        
        // 如果找到了合适的元素
        if (bestElement && maxTextLength > 300) { // 降低阈值,从500改为300个字符,更容易识别较短的文章
            console.log(`检测到文章主体: ${bestElement.tagName}${bestElement.id ? '#'+bestElement.id : ''}${bestElement.className ? '.'+bestElement.className.replace(/\s+/g, '.') : ''}`);
            
            // 获取所有需要排除的元素
            const excludeElements = settings.excludeSelectors ?
                Array.from(document.querySelectorAll(settings.excludeSelectors)) : [];
                
            // 检测参考文献区域
            const referencesElements = Array.from(bestElement.querySelectorAll('h2, h3, h4')).filter(el =>
                el.textContent.toLowerCase().includes('reference') ||
                el.textContent.toLowerCase().includes('bibliography') ||
                el.textContent.includes('参考文献')
            );
            
            let isInReferencesSection = false;
            let referencesSectionElement = null;
            
            if (referencesElements.length > 0) {
                referencesSectionElement = referencesElements[0];
                console.log("在文章主体中检测到参考文献区域:", referencesSectionElement.textContent);
            }
            
            // 存储提取的文本段落
            const textSegments = [];
            
            // 深度优先遍历DOM树
            extractTextNodesFromElement(bestElement, textSegments, 0, excludeElements, isInReferencesSection, referencesSectionElement);
            
            return textSegments.length > 0 ? textSegments : null;
        }
        
        // 尝试基于内容区域比例的检测策略
        if (!bestElement) {
            console.log("尝试使用内容区域比例检测策略");
            // 获取所有段落和文本块
            const textBlocks = Array.from(document.querySelectorAll('p, article, .post, .content, div > h1 + p, div > h2 + p'));
            
            // 按照父元素对文本块进行分组
            const contentGroups = {};
            for (const block of textBlocks) {
                if (!block.textContent.trim()) continue;
                
                // 获取所有父元素,直到body
                let parent = block.parentElement;
                while (parent && parent.tagName !== 'BODY') {
                    const key = parent.tagName + (parent.id ? '#' + parent.id : '') + 
                                (parent.className ? '.' + parent.className.replace(/\s+/g, '.') : '');
                    
                    contentGroups[key] = contentGroups[key] || { element: parent, textLength: 0 };
                    contentGroups[key].textLength += block.textContent.trim().length;
                    
                    parent = parent.parentElement;
                }
            }
            
            // 找出包含最多文本内容的容器
            let bestContentGroup = null;
            let maxGroupTextLength = 0;
            
            for (const key in contentGroups) {
                if (contentGroups[key].textLength > maxGroupTextLength) {
                    maxGroupTextLength = contentGroups[key].textLength;
                    bestContentGroup = contentGroups[key];
                }
            }
            
            if (bestContentGroup && maxGroupTextLength > 300) {
                console.log(`通过内容区域比例检测到文章主体: ${bestContentGroup.element.tagName}${bestContentGroup.element.id ? '#'+bestContentGroup.element.id : ''}${bestContentGroup.element.className ? '.'+bestContentGroup.element.className.replace(/\s+/g, '.') : ''}`);
                
                // 获取所有需要排除的元素
                const excludeElements = settings.excludeSelectors ?
                    Array.from(document.querySelectorAll(settings.excludeSelectors)) : [];
                
                // 存储提取的文本段落
                const textSegments = [];
                
                // 深度优先遍历DOM树
                extractTextNodesFromElement(bestContentGroup.element, textSegments, 0, excludeElements, false, null);
                
                return textSegments.length > 0 ? textSegments : null;
            }
        }
        
        return null;
    }

    // 翻译整个页面
    function translateFullPage() {
        if (!settings.apiKey) {
            alert('请先在设置中配置API密钥');
            const settingsPanel = document.getElementById('translator-settings-panel') || createSettingsPanel();
            settingsPanel.style.display = 'block';
            return;
        }

        // 如果当前已经在翻译中但被暂停了,则恢复翻译
        if (isTranslatingFullPage && isTranslationPaused) {
            isTranslationPaused = false;
            const pauseBtn = document.getElementById('pause-translation-button');
            if (pauseBtn) {
                pauseBtn.textContent = '暂停翻译';
                pauseBtn.title = '暂停当前的翻译任务';
            }
            // 恢复翻译,从最后翻译的段落的下一段开始
            translateNextSegment(lastTranslatedIndex + 1);
            return;
        }

        // 如果当前正在翻译且未暂停,则不做任何操作
        if (isTranslatingFullPage && !isTranslationPaused) {
            alert('正在翻译中,请稍候...');
            return;
        }

        // 开始新的翻译任务
        isTranslatingFullPage = true;
        isTranslationPaused = false;
        lastTranslatedIndex = -1;
        
        // 清除可能存在的暂停/停止按钮
        removeControlButtons();
        
        // 清除可能存在的状态提示元素
        const existingStatusElement = document.getElementById('translation-status');
        if (existingStatusElement) {
            existingStatusElement.remove();
        }
        
        // 提取页面内容
        translationSegments = extractPageContent();

        if (translationSegments.length === 0) {
            alert('未找到可翻译的内容');
            isTranslatingFullPage = false;
            return;
        }

        // 显示进度条
        const progressContainer = document.getElementById('translation-progress-container') || createProgressBar();
        const progressBar = document.getElementById('translation-progress-bar');
        progressContainer.style.display = 'block';
        progressBar.style.width = '0%';

        // 创建一个状态提示
        const statusElement = document.createElement('div');
        statusElement.id = 'translation-status';
        statusElement.style.cssText = `
            position: fixed;
            top: 10px;
            left: 50%;
            transform: translateX(-50%);
            background-color: rgba(66, 133, 244, 0.9);
            color: white;
            padding: 8px 15px;
            border-radius: 20px;
            font-size: 14px;
            z-index: 10001;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
            transition: background-color 0.3s;
            min-width: 200px;
            text-align: center;
        `;
        statusElement.textContent = `正在翻译 (0/${translationSegments.length})`;
        document.body.appendChild(statusElement);

        // 记录所有段落的原始文本,用于恢复
        originalTexts = translationSegments.map(segment => ({
            nodes: segment.nodes.map(n => ({ node: n.node, text: n.original }))
        }));

        // 创建用于切换原文/译文的按钮
        createToggleButton();
        
        // 创建暂停和停止按钮
        createControlButtons();

        // 开始翻译第一个段落
        translateNextSegment(0);
    }
    
    // 创建暂停和停止按钮
    function createControlButtons() {
        // 创建暂停按钮
        const pauseButton = document.createElement('div');
        pauseButton.id = 'pause-translation-button';
        pauseButton.style.cssText = `
            position: fixed;
            bottom: 20px;
            right: 310px;
            padding: 8px 12px;
            background-color: rgba(255, 152, 0, 0.8);
            color: white;
            border-radius: 20px;
            font-size: 14px;
            cursor: pointer;
            z-index: 9999;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
        `;
        pauseButton.textContent = '暂停翻译';
        pauseButton.title = '暂停当前的翻译任务';
        document.body.appendChild(pauseButton);

        // 创建停止按钮
        const stopButton = document.createElement('div');
        stopButton.id = 'stop-translation-button';
        stopButton.style.cssText = `
            position: fixed;
            bottom: 20px;
            right: 240px;
            padding: 8px 12px;
            background-color: rgba(244, 67, 54, 0.8);
            color: white;
            border-radius: 20px;
            font-size: 14px;
            cursor: pointer;
            z-index: 9999;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
        `;
        stopButton.textContent = '停止翻译';
        stopButton.title = '停止当前的翻译任务';
        document.body.appendChild(stopButton);

        // 绑定暂停按钮事件
        pauseButton.addEventListener('click', function() {
            if (!isTranslatingFullPage) return;

            isTranslationPaused = !isTranslationPaused;
            if (isTranslationPaused) {
                pauseButton.textContent = '继续翻译';
                pauseButton.title = '继续未完成的翻译任务';
                
                // 更新状态提示
                const statusElement = document.getElementById('translation-status');
                if (statusElement) {
                    statusElement.textContent = `翻译已暂停 (${lastTranslatedIndex + 1}/${translationSegments.length})`;
                }
                
                // 显示切换按钮,允许在暂停时切换查看原文/译文
                const toggleButton = document.getElementById('toggle-translation-button');
                if (toggleButton) toggleButton.style.display = 'block';
            } else {
                pauseButton.textContent = '暂停翻译';
                pauseButton.title = '暂停当前的翻译任务';
                
                // 恢复翻译
                translateNextSegment(lastTranslatedIndex + 1);
            }
        });

        // 绑定停止按钮事件
        stopButton.addEventListener('click', function() {
            if (!isTranslatingFullPage) return;

            // 确认是否要停止翻译
            if (confirm('确定要停止翻译吗?已翻译的内容将保留。')) {
                // 停止翻译
                isTranslatingFullPage = false;
                isTranslationPaused = false;
                
                // 更新状态提示
                const statusElement = document.getElementById('translation-status');
                if (statusElement) {
                    statusElement.textContent = `翻译已停止 (${lastTranslatedIndex + 1}/${translationSegments.length})`;
                    
                    // 添加关闭按钮
                    if (!statusElement.querySelector('.close-btn')) {
                        const closeButton = document.createElement('span');
                        closeButton.className = 'close-btn';
                        closeButton.style.cssText = `
                            margin-left: 10px;
                            cursor: pointer;
                            font-weight: bold;
                        `;
                        closeButton.textContent = '×';
                        closeButton.addEventListener('click', function() {
                            statusElement.remove();
                            const progressContainer = document.getElementById('translation-progress-container');
                            if (progressContainer) progressContainer.style.display = 'none';
                        });
                        statusElement.appendChild(closeButton);
                    }
                }
                
                // 显示切换按钮
                const toggleButton = document.getElementById('toggle-translation-button');
                if (toggleButton) toggleButton.style.display = 'block';
                
                // 删除控制按钮
                removeControlButtons();
            }
        });
    }
    
    // 移除控制按钮
    function removeControlButtons() {
        const pauseButton = document.getElementById('pause-translation-button');
        if (pauseButton) pauseButton.remove();
        
        const stopButton = document.getElementById('stop-translation-button');
        if (stopButton) stopButton.remove();
    }
    
    // 创建切换按钮
    function createToggleButton() {
        // 检查是否已存在切换按钮
        let toggleButton = document.getElementById('toggle-translation-button');
        
        if (!toggleButton) {
            toggleButton = document.createElement('div');
            toggleButton.id = 'toggle-translation-button';
            toggleButton.style.cssText = `
                position: fixed;
                bottom: 20px;
                right: 180px;
                padding: 8px 12px;
                background-color: rgba(66, 133, 244, 0.8);
                color: white;
                border-radius: 20px;
                font-size: 14px;
                cursor: pointer;
                z-index: 9999;
                box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
                display: none;
            `;
            toggleButton.textContent = '查看原文';
            toggleButton.dataset.showing = 'translation';
            document.body.appendChild(toggleButton);

            // 用于跟踪当前显示状态
            let isShowingTranslation = true;

            // 创建映射,用于跟踪每个节点的翻译状态
            const nodeTranslationMap = new Map();

            toggleButton.addEventListener('click', function () {
                isShowingTranslation = !isShowingTranslation;
                toggleButton.textContent = isShowingTranslation ? '查看原文' : '查看译文';
                toggleButton.dataset.showing = isShowingTranslation ? 'translation' : 'original';

                if (isShowingTranslation) {
                    // 恢复译文
                    translationSegments.forEach((segment, index) => {
                        // 特殊处理参考文献条目
                        if (segment.isReferenceItem && segment.translation && segment.element) {
                            segment.element.innerHTML = segment.translation;
                            return;
                        }

                        if (segment.translation) {
                            if (segment.nodes.length === 1) {
                                // 单节点情况,直接应用翻译
                                const nodeInfo = segment.nodes[0];
                                if (nodeInfo.node && nodeInfo.node.nodeType === Node.TEXT_NODE) {
                                    nodeInfo.node.textContent = segment.translation;
                                    // 记录这个节点已经被翻译过
                                    nodeTranslationMap.set(nodeInfo.node, true);
                                }
                            } else {
                                // 多节点情况,使用比例分配
                                const totalOriginalLength = segment.nodes.reduce(
                                    (sum, nodeInfo) => sum + (nodeInfo.original ? nodeInfo.original.length : 0), 0);

                                if (totalOriginalLength > 0) {
                                    let startPos = 0;
                                    for (let i = 0; i < segment.nodes.length; i++) {
                                        const nodeInfo = segment.nodes[i];
                                        if (nodeInfo.node && nodeInfo.node.nodeType === Node.TEXT_NODE && nodeInfo.original) {
                                            // 计算该节点在原始文本中的比例
                                            const ratio = nodeInfo.original.length / totalOriginalLength;
                                            // 计算应该分配给该节点的翻译文本长度
                                            const chunkLength = Math.round(segment.translation.length * ratio);
                                            // 提取翻译文本的一部分
                                            let chunk = '';
                                            if (i === segment.nodes.length - 1) {
                                                // 最后一个节点,获取剩余所有文本
                                                chunk = segment.translation.substring(startPos);
                                            } else {
                                                // 非最后节点,按比例获取
                                                chunk = segment.translation.substring(startPos, startPos + chunkLength);
                                                startPos += chunkLength;
                                            }

                                            // 更新节点文本
                                            nodeInfo.node.textContent = chunk;
                                            // 记录这个节点已经被翻译过
                                            nodeTranslationMap.set(nodeInfo.node, true);
                                        }
                                    }
                                }
                            }
                        }
                    });
                } else {
                    // 恢复原文 - 使用原始数据而不是依赖当前DOM状态
                    nodeTranslationMap.clear(); // 清除翻译状态记录

                    // 先处理参考文献条目
                    translationSegments.forEach((segment) => {
                        if (segment.isReferenceItem && segment.element && segment.originalHtml) {
                            segment.element.innerHTML = segment.originalHtml;
                        }
                    });

                    // 再处理普通段落
                    originalTexts.forEach((originalSegment) => {
                        originalSegment.nodes.forEach(nodeInfo => {
                            if (nodeInfo.node && nodeInfo.node.nodeType === Node.TEXT_NODE) {
                                nodeInfo.node.textContent = nodeInfo.text;
                            }
                        });
                    });
                }
            });
        }
        
        return toggleButton;
    }

    // 添加一个专门用于翻译参考文献条目的函数
    function translateReferenceItem(referenceItem, callback) {
        if (!referenceItem || !referenceItem.text) {
            callback(null);
            return;
        }

        console.log("翻译参考文献条目:", referenceItem.text.substring(0, 50) + "...");

        // 如果有HTML内容,使用更精确的方法
        if (referenceItem.htmlContent) {
            // 提取HTML中的纯文本部分
            const tempDiv = document.createElement('div');
            tempDiv.innerHTML = referenceItem.htmlContent;

            // 递归处理HTML元素,只翻译文本节点
            function processNode(node, callback) {
                if (node.nodeType === Node.TEXT_NODE) {
                    const text = node.textContent.trim();
                    if (text && text.length > 1) {
                        // 翻译文本节点
                        translateText(text, function (result) {
                            if (result.type === 'complete' || result.type === 'stream-end') {
                                node.textContent = result.content;
                                callback(true);
                            } else {
                                // 保持原文
                                callback(false);
                            }
                        }, false);
                    } else {
                        callback(true); // 空文本,直接继续
                    }
                } else if (node.nodeType === Node.ELEMENT_NODE) {
                    // 对于元素节点,递归处理其子节点
                    const childNodes = Array.from(node.childNodes);
                    processNodeSequentially(childNodes, 0, function () {
                        callback(true);
                    });
                } else {
                    callback(true); // 其他类型节点,直接继续
                }
            }

            // 按顺序处理节点列表
            function processNodeSequentially(nodes, index, finalCallback) {
                if (index >= nodes.length) {
                    finalCallback();
                    return;
                }

                processNode(nodes[index], function (success) {
                    // 无论成功与否,继续处理下一个节点
                    setTimeout(() => processNodeSequentially(nodes, index + 1, finalCallback), 10);
                });
            }

            // 开始处理整个HTML片段
            processNodeSequentially(Array.from(tempDiv.childNodes), 0, function () {
                // 处理完成后,返回完整的翻译后HTML
                callback(tempDiv.innerHTML);
            });
        } else {
            // 如果没有HTML内容,直接翻译文本
            translateText(referenceItem.text, function (result) {
                if (result.type === 'complete' || result.type === 'stream-end') {
                    callback(result.content);
                } else {
                    callback(null);
                }
            }, false);
        }
    }

    // 创建翻译按钮
    function createTranslateButton() {
        const button = document.createElement('div');
        button.className = 'translate-button';
        button.innerHTML = '翻译';
        button.style.cssText = `
            position: absolute;
            background-color: rgba(66, 133, 244, 0.8);
            color: white;
            padding: 5px 10px;
            border-radius: 4px;
            font-size: 14px;
            cursor: pointer;
            z-index: 9999;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
            opacity: 0.8;
            transition: opacity 0.2s;
        `;

        button.addEventListener('mouseover', function () {
            button.style.opacity = '1';
        });

        button.addEventListener('mouseout', function () {
            button.style.opacity = '0.8';
        });

        return button;
    }

    // 创建历史记录面板
    function createHistoryPanel() {
        const panel = document.createElement('div');
        panel.id = 'translator-history-panel';
        panel.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 600px;
            max-height: 80vh;
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
            z-index: 10000;
            display: none;
            padding: 20px;
            overflow-y: auto;
        `;

        panel.innerHTML = `
            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
                <h2 style="margin: 0;">翻译历史</h2>
                <div style="display: flex; gap: 10px;">
                    <button id="clear-history" style="padding: 5px 10px; color: #666;">清除历史</button>
                    <div id="close-history" style="cursor: pointer; font-size: 20px; color: #666;">×</div>
                </div>
            </div>
            <div id="history-list"></div>
        `;

        document.body.appendChild(panel);

        // 清除历史记录按钮
        document.getElementById('clear-history').addEventListener('click', function () {
            if (confirm('确定要清除所有翻译历史吗?')) {
                translationHistory = [];
                GM_setValue('translationHistory', []);
                updateHistoryList();
            }
        });

        // 关闭按钮
        document.getElementById('close-history').addEventListener('click', function () {
            panel.style.display = 'none';
        });

        return panel;
    }

    // 创建收藏夹面板
    function createFavoritesPanel() {
        const panel = document.createElement('div');
        panel.id = 'translator-favorites-panel';
        panel.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 600px;
            max-height: 80vh;
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
            z-index: 10000;
            display: none;
            padding: 20px;
            overflow-y: auto;
        `;

        panel.innerHTML = `
            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
                <h2 style="margin: 0;">收藏夹</h2>
                <div style="display: flex; gap: 10px;">
                    <button id="clear-favorites" style="padding: 5px 10px; color: #666;">清除收藏</button>
                    <div id="close-favorites" style="cursor: pointer; font-size: 20px; color: #666;">×</div>
                </div>
            </div>
            <div id="favorites-list"></div>
        `;

        document.body.appendChild(panel);

        // 清除收藏按钮
        document.getElementById('clear-favorites').addEventListener('click', function () {
            if (confirm('确定要清除所有收藏吗?')) {
                translationFavorites = [];
                GM_setValue('translationFavorites', []);
                updateFavoritesList();
            }
        });

        // 关闭按钮
        document.getElementById('close-favorites').addEventListener('click', function () {
            panel.style.display = 'none';
        });

        return panel;
    }

    // 更新历史记录列表
    function updateHistoryList() {
        const historyList = document.getElementById('history-list');
        if (!historyList) return;

        if (translationHistory.length === 0) {
            historyList.innerHTML = '<div style="text-align: center; color: #666; padding: 20px;">暂无翻译历史</div>';
            return;
        }

        // 清除之前的内容
        historyList.innerHTML = '';

        // 为每个历史记录创建DOM元素
        translationHistory.forEach((item, index) => {
            const historyItem = document.createElement('div');
            historyItem.style.cssText = 'border-bottom: 1px solid #eee; padding: 10px 0;';

            const header = document.createElement('div');
            header.style.cssText = 'display: flex; justify-content: space-between; margin-bottom: 5px;';

            const timestamp = document.createElement('span');
            timestamp.style.color = '#666';
            timestamp.textContent = item.timestamp;

            const buttons = document.createElement('div');

            const copyBtn = document.createElement('button');
            copyBtn.textContent = '复制';
            copyBtn.style.cssText = 'padding: 2px 5px; margin-right: 5px;';
            copyBtn.addEventListener('click', function () {
                copyTranslation(index);
            });

            const favoriteBtn = document.createElement('button');
            favoriteBtn.textContent = '收藏';
            favoriteBtn.style.cssText = 'padding: 2px 5px;';
            favoriteBtn.addEventListener('click', function () {
                addToFavorites(translationHistory[index]);
                favoriteBtn.textContent = '已收藏';
                favoriteBtn.disabled = true;
            });

            buttons.appendChild(copyBtn);
            buttons.appendChild(favoriteBtn);

            header.appendChild(timestamp);
            header.appendChild(buttons);

            const sourceDiv = document.createElement('div');
            sourceDiv.style.marginBottom = '5px';
            sourceDiv.innerHTML = `<strong>原文:</strong>${item.source}`;

            const translationDiv = document.createElement('div');
            translationDiv.innerHTML = `<strong>译文:</strong>${item.translation}`;

            historyItem.appendChild(header);
            historyItem.appendChild(sourceDiv);
            historyItem.appendChild(translationDiv);

            historyList.appendChild(historyItem);
        });
    }

    // 更新收藏夹列表
    function updateFavoritesList() {
        const favoritesList = document.getElementById('favorites-list');
        if (!favoritesList) return;

        if (translationFavorites.length === 0) {
            favoritesList.innerHTML = '<div style="text-align: center; color: #666; padding: 20px;">暂无收藏内容</div>';
            return;
        }

        // 清除之前的内容
        favoritesList.innerHTML = '';

        // 为每个收藏项创建DOM元素
        translationFavorites.forEach((item, index) => {
            const favoriteItem = document.createElement('div');
            favoriteItem.style.cssText = 'border-bottom: 1px solid #eee; padding: 10px 0;';

            const header = document.createElement('div');
            header.style.cssText = 'display: flex; justify-content: space-between; margin-bottom: 5px;';

            const timestamp = document.createElement('span');
            timestamp.style.color = '#666';
            timestamp.textContent = item.timestamp;

            const buttons = document.createElement('div');

            const copyBtn = document.createElement('button');
            copyBtn.textContent = '复制';
            copyBtn.style.cssText = 'padding: 2px 5px; margin-right: 5px;';
            copyBtn.addEventListener('click', function () {
                copyFavorite(index);
            });

            const deleteBtn = document.createElement('button');
            deleteBtn.textContent = '删除';
            deleteBtn.style.cssText = 'padding: 2px 5px;';
            deleteBtn.addEventListener('click', function () {
                removeFromFavorites(index);
            });

            buttons.appendChild(copyBtn);
            buttons.appendChild(deleteBtn);

            header.appendChild(timestamp);
            header.appendChild(buttons);

            const sourceDiv = document.createElement('div');
            sourceDiv.style.marginBottom = '5px';
            sourceDiv.innerHTML = `<strong>原文:</strong>${item.source}`;

            const translationDiv = document.createElement('div');
            translationDiv.style.marginBottom = '5px';
            translationDiv.innerHTML = `<strong>译文:</strong>${item.translation}`;

            const sourceUrlDiv = document.createElement('div');
            sourceUrlDiv.style.cssText = 'font-size: 12px; color: #666;';

            const sourceTitleDiv = document.createElement('div');
            sourceTitleDiv.style.marginBottom = '2px';
            sourceTitleDiv.innerHTML = '<strong>来源:</strong>';

            const sourceLink = document.createElement('a');
            sourceLink.href = item.url;
            sourceLink.target = '_blank';
            sourceLink.style.cssText = 'color: #4285f4; text-decoration: none;';
            sourceLink.textContent = item.title || item.url;

            sourceTitleDiv.appendChild(sourceLink);

            const urlDiv = document.createElement('div');
            urlDiv.style.wordBreak = 'break-all';
            urlDiv.textContent = item.url;

            sourceUrlDiv.appendChild(sourceTitleDiv);
            sourceUrlDiv.appendChild(urlDiv);

            favoriteItem.appendChild(header);
            favoriteItem.appendChild(sourceDiv);
            favoriteItem.appendChild(translationDiv);
            favoriteItem.appendChild(sourceUrlDiv);

            favoritesList.appendChild(favoriteItem);
        });
    }

    // 添加到历史记录
    function addToHistory(source, translation) {
        const timestamp = new Date().toLocaleString();
        translationHistory.unshift({ source, translation, timestamp });

        // 限制历史记录数量
        if (translationHistory.length > settings.maxHistoryItems) {
            translationHistory.pop();
        }

        GM_setValue('translationHistory', translationHistory);
        updateHistoryList();
    }

    // 添加到收藏夹
    function addToFavorites(item) {
        // 添加URL信息
        item.url = window.location.href;
        item.title = document.title;

        // 检查是否已存在
        if (!translationFavorites.some(fav => fav.source === item.source)) {
            translationFavorites.unshift(item);

            // 限制收藏数量
            if (translationFavorites.length > settings.maxFavoritesItems) {
                translationFavorites.pop();
            }

            GM_setValue('translationFavorites', translationFavorites);
            updateFavoritesList();
        }
    }

    // 从收藏夹移除
    function removeFromFavorites(index) {
        translationFavorites.splice(index, 1);
        GM_setValue('translationFavorites', translationFavorites);
        updateFavoritesList();
    }

    // 复制翻译结果
    function copyTranslation(index) {
        const item = translationHistory[index];
        if (item) {
            navigator.clipboard.writeText(item.translation).then(() => {
                alert('已复制到剪贴板!');
            });
        }
    }

    // 复制收藏的翻译
    function copyFavorite(index) {
        const item = translationFavorites[index];
        if (item) {
            navigator.clipboard.writeText(item.translation).then(() => {
                alert('已复制到剪贴板!');
            });
        }
    }

    // 注册(不可用)菜单命令
    GM_registerMenuCommand('翻译整页', translateFullPage);
    GM_registerMenuCommand('查看翻译历史', function () {
        const panel = document.getElementById('translator-history-panel') || createHistoryPanel();
        panel.style.display = 'block';
        updateHistoryList();
    });
    GM_registerMenuCommand('查看收藏夹', function () {
        const panel = document.getElementById('translator-favorites-panel') || createFavoritesPanel();
        panel.style.display = 'block';
        updateFavoritesList();
    });

    // 创建翻译弹窗
    function createTranslationPopup() {
        const popup = document.createElement('div');
        popup.className = 'translation-popup';
        popup.style.cssText = `
            position: absolute;
            background-color: white;
            min-width: 200px;
            max-width: 400px;
            max-height: 80vh;
            overflow-y: auto;
            padding: 15px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
            z-index: 10000;
            font-size: 14px;
            line-height: 1.5;
        `;

        const header = document.createElement('div');
        header.style.cssText = `
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 10px;
            padding-bottom: 5px;
            border-bottom: 1px solid #eee;
        `;

        const sourceLanguage = document.createElement('div');
        sourceLanguage.className = 'source-language';
        sourceLanguage.style.color = '#666';
        sourceLanguage.style.fontSize = '12px';

        const closeButton = document.createElement('div');
        closeButton.innerHTML = '×';
        closeButton.style.cssText = `
            font-size: 18px;
            cursor: pointer;
            color: #666;
        `;

        const content = document.createElement('div');
        content.className = 'translation-content';
        content.style.marginTop = '5px';
        content.style.whiteSpace = 'pre-wrap';
       

        const footer = document.createElement('div');
        footer.style.cssText = `
            display: flex;
            justify-content: flex-end;
            gap: 10px;
            margin-top: 10px;
            padding-top: 5px;
            border-top: 1px solid #eee;
        `;

        const copyButton = document.createElement('button');
        copyButton.textContent = '复制译文';
        copyButton.style.cssText = `
            padding: 5px 10px;
            background-color: #4285f4;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        `;

        const favoriteButton = document.createElement('button');
        favoriteButton.textContent = '收藏';
        favoriteButton.style.cssText = `
            padding: 5px 10px;
            background-color: #f8f9fa;
            color: #666;
            border: 1px solid #ddd;
            border-radius: 4px;
            cursor: pointer;
        `;

        header.appendChild(sourceLanguage);
        header.appendChild(closeButton);
        footer.appendChild(copyButton);
        footer.appendChild(favoriteButton);

        popup.appendChild(header);
        popup.appendChild(content);
        popup.appendChild(footer);

        closeButton.addEventListener('click', function () {
            document.body.removeChild(popup);
        });

        copyButton.addEventListener('click', function () {
            navigator.clipboard.writeText(content.textContent).then(() => {
                alert('已复制到剪贴板!');
            });
        });

        favoriteButton.addEventListener('click', function () {
            addToFavorites({
                source: lastSelectedText,
                translation: content.textContent,
                timestamp: new Date().toLocaleString()
            });
            favoriteButton.textContent = '已收藏';
            favoriteButton.disabled = true;
        });

        return popup;
    }

    // 创建加载动画
    function createLoadingAnimation() {
        const loading = document.createElement('div');
        loading.className = 'loading-animation';
        loading.style.cssText = `
            display: inline-block;
            width: 20px;
            height: 20px;
            border: 3px solid rgba(0, 0, 0, 0.1);
            border-radius: 50%;
            border-top-color: #4285f4;
            animation: spin 1s ease-in-out infinite;
            margin-right: 10px;
        `;

        const style = document.createElement('style');
        style.textContent = `
            @keyframes spin {
                0% { transform: rotate(0deg); }
                100% { transform: rotate(360deg); }
            }
        `;

        document.head.appendChild(style);

        return loading;
    }

    // 调用 API 进行翻译
    function translateText(text, callback, retryWithoutStreaming = false) {
        if (!settings.apiKey) {
            callback({
                type: 'error',
                content: '错误:请先设置 API 密钥'
            });
            return;
        }

        // 调试模式
        const debugMode = true;
        const debugLog = debugMode ? console.log : function () { };

        // 创建内容收集器和状态跟踪
        let collectedContent = '';
        let lastProcessedLength = 0; // 跟踪上次处理的响应长度
        let responseBuffer = ''; // 用于存储部分响应,解决跨块JSON问题

        // 确定是否使用流式响应
        const useStreaming = retryWithoutStreaming ? false : settings.useStreaming;

        // 通知回调开始处理
        if (useStreaming) {
            callback({
                type: 'stream-start',
                content: ''
            });
        }

        debugLog(`开始翻译请求,文本长度: ${text.length}, 使用流式响应: ${useStreaming}, 模型: ${settings.model}`);

        GM_xmlhttpRequest({
            method: 'POST',
            url: settings.apiEndpoint,
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${settings.apiKey}`
            },
            responseType: useStreaming ? 'stream' : '',  // 根据设置决定是否使用流式响应
            timeout: 60000,  // 设置更长的超时时间
            data: JSON.stringify({
                model: settings.model,
                messages: [
                    {
                        role: "system",
                        content: settings.systemPrompt + " 请保持原文本的段落格式,每个段落之间应当保留一个空行。"
                    },
                    {
                        role: "user",
                        content: text
                    }
                ],
                temperature: settings.temperature,  // 使用用户设置的temperature值
                stream: useStreaming,  // 根据设置决定是否使用流式响应
                // 一些API提供者可能需要额外参数或不同的参数名
                top_p: 1,
                frequency_penalty: 0,
                presence_penalty: 0,
                max_tokens: 4000  // 设置合理的最大输出长度
            }),
            onloadstart: function () {
                if (useStreaming) {
                    debugLog("流式请求已开始");
                } else {
                    debugLog("标准请求已开始");
                    debugLog(settings.temperature)
                }
            },
            onprogress: function (response) {
                if (!useStreaming) return; // 非流式模式不处理进度更新

                try {
                    // 获取完整响应文本
                    const responseText = response.responseText || '';

                    // 如果响应没变长,不处理
                    if (!responseText || responseText.length <= lastProcessedLength) {
                        return;
                    }

                    debugLog(`进度更新: 响应总长度=${responseText.length}, 上次处理位置=${lastProcessedLength}`);

                    // 获取新增内容
                    const newChunk = responseText.substring(lastProcessedLength);
                    debugLog(`接收新数据: ${newChunk.length}字节`);

                    // 更新处理位置要放在处理数据前,防止数据处理期间发生新的onprogress事件
                    lastProcessedLength = responseText.length;

                    // 追加到缓冲区并处理
                    responseBuffer += newChunk;

                    // 不同API可能有不同的流式输出格式,我们需要支持多种格式
                    // 1. OpenAI风格: "data: {\"id\":\"...\",\"choices\":[{\"delta\":{\"content\":\"文本片段\"}}]}\n"
                    // 2. 简单文本块风格: 直接是文本内容

                    let newContent = '';
                    let dataMatches = [];

                    // 尝试提取所有"data: {...}"格式的行
                    const regex = /data: ({.+?})\n/g;
                    let match;

                    // 收集所有匹配项
                    while ((match = regex.exec(responseBuffer)) !== null) {
                        dataMatches.push(match[0]);

                        try {
                            // 提取JSON部分并解析
                            const jsonStr = match[1];
                            const data = JSON.parse(jsonStr);

                            // 从JSON提取文本内容
                            if (data.choices && data.choices[0]) {
                                if (data.choices[0].delta && data.choices[0].delta.content) {
                                    // OpenAI风格的delta格式
                                    newContent += data.choices[0].delta.content;
                                } else if (data.choices[0].text) {
                                    // 有些API使用text字段
                                    newContent += data.choices[0].text;
                                } else if (data.choices[0].message && data.choices[0].message.content) {
                                    // 完整消息格式
                                    newContent += data.choices[0].message.content;
                                }
                            }
                        } catch (parseError) {
                            // 解析出错,记录但继续处理
                            debugLog(`JSON解析失败: ${parseError.message}, 内容: ${match[0].substring(0, 50)}...`);
                        }
                    }

                    // 检查是否找到了标准格式的数据行
                    if (dataMatches.length > 0) {
                        // 从缓冲区中移除已处理的部分,但保留可能不完整的最后部分
                        const lastMatchEndIndex = regex.lastIndex;
                        if (lastMatchEndIndex > 0 && lastMatchEndIndex < responseBuffer.length) {
                            responseBuffer = responseBuffer.substring(lastMatchEndIndex);
                        } else {
                            responseBuffer = '';
                        }

                        debugLog(`找到${dataMatches.length}个数据块,提取了${newContent.length}字符的内容`);
                    } else {
                        // 如果没有找到标准格式,尝试按行分割处理
                        const lines = responseBuffer.split('\n');

                        // 保留最后一行作为可能的不完整行
                        responseBuffer = lines.pop() || '';

                        // 处理每一行
                        for (const line of lines) {
                            // 尝试提取"data: "后面的内容
                            if (line.trim().startsWith('data: ')) {
                                try {
                                    const content = line.substring(6).trim();
                                    if (content === '[DONE]') {
                                        debugLog("收到流结束标记");
                                        continue;
                                    }

                                    // 尝试解析JSON
                                    const data = JSON.parse(content);
                                    if (data.choices && data.choices[0]) {
                                        if (data.choices[0].delta && data.choices[0].delta.content) {
                                            newContent += data.choices[0].delta.content;
                                        } else if (data.choices[0].text) {
                                            newContent += data.choices[0].text;
                                        } else if (data.choices[0].message && data.choices[0].message.content) {
                                            newContent += data.choices[0].message.content;
                                        }
                                    }
                                } catch (e) {
                                    // JSON解析失败,可能是普通文本或特殊格式
                                    debugLog(`处理行出错: ${e.message}, 行内容: ${line.substring(0, 50)}...`);
                                }
                            } else if (line.trim() && !line.includes('event:') && !line.includes('id:')) {
                                // 如果不是控制行且非空,可能是直接的文本内容
                                // 一些API直接发送文本而不是JSON
                                newContent += line + '\n';
                            }
                        }
                    }

                    // 如果有新内容
                    if (newContent) {
                        collectedContent += newContent;
                        debugLog(`新增内容: ${newContent.length}字符, 当前总内容: ${collectedContent.length}字符`);

                        // 发送更新
                        callback({
                            type: 'stream-progress',
                            content: collectedContent
                        });
                    } else if (dataMatches.length > 0 || responseBuffer.includes('data:')) {
                        // 找到了数据行但没有提取到内容,可能是API发送的是控制消息
                        debugLog("收到数据但未提取到新内容,可能是控制消息");
                    } else {
                        debugLog("本次更新没有提取到新内容");
                    }
                } catch (e) {
                    console.error("处理流数据错误:", e);
                    debugLog("错误详情:", e.stack);

                    // 即使出错也更新位置,防止重复处理导致死循环
                    if (response && response.responseText) {
                        lastProcessedLength = response.responseText.length;
                    }
                }
            },
            onload: function (response) {
                try {
                    // 检查HTTP状态码
                    if (response.status && response.status !== 200) {
                        // 非200状态码,记录错误但不替换原文
                        console.error(`API返回非200状态码: ${response.status}`);
                        let errorMsg = `API返回错误状态码: ${response.status}`;
                        
                        // 尝试从响应中提取更详细的错误信息
                        if (response.responseText) {
                            try {
                                const errorData = JSON.parse(response.responseText);
                                if (errorData.error) {
                                    errorMsg += ` - ${errorData.error.message || errorData.error.type || JSON.stringify(errorData.error)}`;
                                }
                            } catch (e) {
                                // 无法解析JSON,使用原始响应内容
                                if (response.responseText.length < 100) {
                                    errorMsg += ` - ${response.responseText}`;
                                }
                            }
                        }
                        
                        callback({
                            type: 'error',
                            content: errorMsg,
                            statusCode: response.status
                        });
                        return;
                    }
                    
                    // 检查是否已经收集到内容(通过流式API)
                    if (useStreaming && collectedContent) {
                        // 已收集到了内容 - 直接使用收集到的内容
                        debugLog("onload: 使用已收集的流式内容,长度:", collectedContent.length);
                        callback({
                            type: 'stream-end',
                            content: collectedContent
                        });
                        return;
                    }

                    debugLog(`onload: ${useStreaming ? '没有收集到流式内容' : '使用标准响应'}, 尝试处理完整响应`);

                    // 在流式模式下,如果没有responseText但我们仍然到达onload,这可能是一个API限制
                    if (useStreaming && (!response || typeof response.responseText !== 'string' || response.responseText.trim() === '')) {
                        // 检查是否有响应头,可能表明API连接是成功的
                        if (response && response.responseHeaders) {
                            // 尝试从缓冲区中恢复,有时onload触发时缓冲区仍有未处理的内容
                            if (responseBuffer.trim()) {
                                debugLog("onload: 从缓冲区恢复内容,尝试解析");
                                try {
                                    // 处理缓冲区中的内容
                                    let content = '';
                                    const lines = responseBuffer.split('\n').filter(line => line.trim());

                                    for (const line of lines) {
                                        if (line.startsWith('data: ') && line !== 'data: [DONE]') {
                                            try {
                                                const jsonStr = line.substring(6).trim();
                                                const data = JSON.parse(jsonStr);
                                                if (data.choices && data.choices[0]) {
                                                    if (data.choices[0].delta && data.choices[0].delta.content) {
                                                        content += data.choices[0].delta.content;
                                                    } else if (data.choices[0].message && data.choices[0].message.content) {
                                                        content += data.choices[0].message.content;
                                                    }
                                                }
                                            } catch (e) {
                                                debugLog("缓冲区解析出错:", e.message);
                                            }
                                        }
                                    }

                                    if (content) {
                                        // 找到了内容,使用它
                                        callback({
                                            type: 'complete',
                                            content: content.trim()
                                        });
                                        return;
                                    }
                                } catch (e) {
                                    debugLog("缓冲区处理失败:", e.message);
                                }
                            }

                            if (response.responseHeaders.includes("content-type:text/event-stream")) {
                                debugLog("onload: 检测到有效的SSE响应头,但无responseText。尝试使用非流式模式重试...");

                                // 自动重试:使用非流式模式
                                if (!retryWithoutStreaming) {
                                    debugLog("切换到非流式模式重试翻译请求");
                                    translateText(text, callback, true);
                                    return;
                                } else {
                                    // 如果这是重试尝试但仍然失败,则报告错误
                                    throw new Error("即使在非流式模式下,API也未能返回翻译内容。请检查API密钥和网络连接。");
                                }
                            } else {
                                // 其他内容类型,可能是API错误
                                throw new Error(`响应没有包含预期的内容。响应头: ${response.responseHeaders.substring(0, 100)}...`);
                            }
                        } else {
                            // 完全无效的响应
                            throw new Error("响应对象无效或不包含内容。请检查API端点和密钥是否正确。");
                        }
                    }

                    // 有responseText,处理它
                    const responseText = response.responseText;
                    debugLog(`获取到响应文本,长度: ${responseText.length}`);

                    // 检查是否是SSE格式(以'data: '开头)
                    if (responseText.trim().startsWith('data: ')) {
                        debugLog("检测到SSE格式响应,解析数据...");
                        // 处理SSE格式
                        const lines = responseText.split('\n');
                        let fullContent = '';
                        let processedCount = 0;

                        for (let i = 0; i < lines.length; i++) {
                            const line = lines[i].trim();
                            if (line.startsWith('data: ') && line !== 'data: [DONE]') {
                                try {
                                    // 提取JSON部分
                                    const jsonData = line.substring(6);
                                    const data = JSON.parse(jsonData);
                                    processedCount++;

                                    if (data.choices && data.choices[0]) {
                                        // 对于非流式响应中的SSE格式,提取content
                                        if (data.choices[0].delta && data.choices[0].delta.content) {
                                            fullContent += data.choices[0].delta.content;
                                        }
                                        // 支持普通响应格式
                                        else if (data.choices[0].message && data.choices[0].message.content) {
                                            fullContent += data.choices[0].message.content;
                                        }
                                        // 支持一些API的不同格式
                                        else if (data.choices[0].text) {
                                            fullContent += data.choices[0].text;
                                        }
                                    }
                                } catch (e) {
                                    console.error("处理单行SSE数据出错:", e, "行内容:", line);
                                }
                            }
                        }

                        debugLog(`解析了${processedCount}行SSE数据,提取了${fullContent.length}字符的内容`);

                        if (fullContent) {
                            callback({
                                type: 'complete',
                                content: fullContent.trim()
                            });
                            return;
                        } else {
                            throw new Error("无法从SSE响应中提取内容");
                        }
                    }

                    // 尝试作为单个JSON对象解析
                    try {
                        debugLog("尝试解析为标准JSON响应");
                        const data = JSON.parse(responseText);
                        if (data.error) {
                            callback({
                                type: 'error',
                                content: `错误:${data.error.message || JSON.stringify(data.error)}`
                            });
                        } else if (data.choices && data.choices[0]) {
                            // 提取不同格式的内容
                            let content = '';
                            if (data.choices[0].message && data.choices[0].message.content) {
                                content = data.choices[0].message.content;
                            } else if (data.choices[0].text) {
                                content = data.choices[0].text;
                            }

                            if (content) {
                                callback({
                                    type: 'complete',
                                    content: content.trim()
                                });
                            } else {
                                throw new Error("API响应中未找到内容字段");
                            }
                        } else {
                            throw new Error("API响应格式不符合预期");
                        }
                    } catch (e) {
                        // JSON解析失败,可能是纯文本响应或其他格式
                        debugLog("JSON解析失败,尝试其他格式:", e.message);

                        // 如果响应看起来像纯文本,直接使用
                        if (responseText && !responseText.startsWith('{') && !responseText.startsWith('[') && !responseText.includes('<!DOCTYPE')) {
                            debugLog("响应似乎是纯文本,直接返回");
                            callback({
                                type: 'complete',
                                content: responseText.trim()
                            });
                            return;
                        }

                        // 其他情况下,报告错误
                        throw new Error(`非标准响应格式: ${e.message}`);
                    }
                } catch (e) {
                    // 安全地获取响应预览,避免undefined错误
                    let responsePreview = "无法获取响应内容";
                    try {
                        if (response && typeof response.responseText === 'string') {
                            responsePreview = response.responseText.substring(0, 200);
                        } else if (response) {
                            // 尝试获取响应头信息作为调试参考
                            responsePreview = JSON.stringify(response).substring(0, 300);
                        }
                    } catch (previewError) {
                        responsePreview = `获取响应预览时出错: ${previewError.message}`;
                    }

                    console.error("响应处理错误:", e.message);
                    console.error("错误详情:", e.stack);
                    console.error("响应信息:", responsePreview);

                    // 给用户一些有用的建议
                    let errorMessage = e.message;
                    if (e.message.includes("API返回了成功响应") || e.message.includes("无法从SSE响应中提取内容")) {
                        errorMessage += "<br><br>建议:<br>1. 检查API密钥是否有足够的使用额度<br>2. 尝试减少翻译文本长度<br>3. <b>在设置面板中禁用流式响应</b>";
                    } else if (e.message.includes("非标准响应格式")) {
                        errorMessage += "<br><br>可能原因:<br>1. API响应格式与脚本不兼容<br>2. API返回了错误信息<br>3. API密钥可能无效";
                    }

                    callback({
                        type: 'error',
                        content: `解析响应时出错:${errorMessage}<br><br><small>响应信息: ${escapeHtml(responsePreview)}</small>`
                    });
                }
            },
            onerror: function (error) {
                console.error("API请求错误:", error);

                // 获取状态码
                const statusCode = error.status || 0;
                let errorMessage = error.statusText || '无法连接到 API';
                
                // 添加状态码到错误信息
                if (statusCode > 0) {
                    errorMessage = `(${statusCode}) ${errorMessage}`;
                }
                
                // 如果是流式请求失败,尝试非流式请求
                if (useStreaming && !retryWithoutStreaming) {
                    debugLog(`流式请求失败,状态码: ${statusCode},尝试使用非流式模式重试...`);
                    translateText(text, callback, true);
                    return;
                }

                callback({
                    type: 'error',
                    content: `请求错误:${errorMessage}`,
                    statusCode: statusCode
                });
            }
        });
    }

    // 辅助函数:转义HTML,防止XSS
    function escapeHtml(text) {
        return text
            .replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;")
            .replace(/"/g, "&quot;")
            .replace(/'/g, "&#039;");
    }

    // 显示翻译结果
    function showTranslation(text, rect) {
        // 移除之前的弹窗
        const oldPopups = document.querySelectorAll('.translation-popup');
        oldPopups.forEach(popup => popup.remove());

        const popup = createTranslationPopup();
        const content = popup.querySelector('.translation-content');

        // 先添加到DOM,以便获取尺寸
        document.body.appendChild(popup);

        // 获取窗口尺寸和弹窗尺寸
        const windowWidth = window.innerWidth;
        const windowHeight = window.innerHeight;
        const popupWidth = popup.offsetWidth;
        const popupHeight = popup.offsetHeight;

        // 计算初始位置(选中文字的右侧)
        let left = window.scrollX + rect.right + 10; // 右侧间隔10px
        let top = window.scrollY + rect.top;

        // 检查右侧空间是否足够,如果不够则改为左侧显示
        if (left + popupWidth > window.scrollX + windowWidth) {
            left = window.scrollX + rect.left - popupWidth - 10; // 左侧间隔10px
        }

        // 如果左侧也没有足够空间,则居中显示
        if (left < window.scrollX) {
            left = window.scrollX + (windowWidth - popupWidth) / 2;
        }

        // 确保弹窗不超出视窗底部
        if (top + popupHeight > window.scrollY + windowHeight) {
            top = window.scrollY + windowHeight - popupHeight - 10;
        }

        // 确保弹窗不超出视窗顶部
        if (top < window.scrollY) {
            top = window.scrollY + 10;
        }

        // 设置最终位置
        popup.style.top = `${top}px`;
        popup.style.left = `${left}px`;

        // 显示加载动画
        content.innerHTML = '';
        const loading = createLoadingAnimation();
        content.appendChild(loading);
        content.appendChild(document.createTextNode('正在翻译...'));

        // 光标元素
        const cursor = document.createElement('span');
        cursor.className = 'typing-cursor';
        cursor.textContent = '▌';
        cursor.style.animation = 'blink 1s step-end infinite';

        // 添加光标样式
        const cursorStyle = document.createElement('style');
        cursorStyle.textContent = `
            @keyframes blink {
                0%, 100% { opacity: 1; }
                50% { opacity: 0; }
            }
        `;
        document.head.appendChild(cursorStyle);

        console.log("开始翻译:", text.substring(0, 50) + "...");

        // 检测源语言
        if (settings.autoDetectLanguage) {
            const sourceLanguage = detectLanguage(text);
            popup.querySelector('.source-language').textContent = `源语言:${sourceLanguage}`;
        }

        // 进行翻译
        translateText(text, function (result) {
            console.log("收到翻译结果类型:", result.type, "内容长度:", result.content ? result.content.length : 0);
            if (result.type === 'stream-start') {
                // 清除加载动画,准备接收流式内容
                content.innerHTML = '';
                content.appendChild(cursor);
            }
            else if (result.type === 'stream-progress') {
                // 更新内容,保持光标在末尾
                const formattedResult = result.content.replace(/\n\n+/g, '<br><br>').replace(/\n/g, '<br>');
                content.innerHTML = formattedResult;
                content.appendChild(cursor);
            }
            else if (result.type === 'stream-end' || result.type === 'complete') {
                // 最终内容,移除光标
                const formattedResult = result.content.replace(/\n\n+/g, '<br><br>').replace(/\n/g, '<br>');
                content.innerHTML = formattedResult;
                content.dataset.translated = 'true';
                content.className = 'translation-content translated-text';
                console.log("翻译完成");

                // 添加到历史记录
                addToHistory(text, result.content);
            }
            else if (result.type === 'error') {
                // 显示错误
                content.innerHTML = `<span style="color: red;">${result.content}</span>`;
                console.error("翻译出错:", result.content);
            }
        });
    }

    // 监听选择事件
    document.addEventListener('mouseup', function (e) {
        // 如果点击的是翻译按钮或翻译弹窗,不处理
        if (e.target.classList.contains('translate-button') ||
            e.target.closest('.translate-button') ||
            e.target.classList.contains('translation-popup') ||
            e.target.closest('.translation-popup')) {
            return;
        }

        const selection = window.getSelection();
        const selectedText = selection.toString().trim();

        // 清除之前的翻译按钮
        if (activeTranslateButton) {
            activeTranslateButton.remove();
            activeTranslateButton = null;
        }

        if (selectedText.length > 0) {
            const range = selection.getRangeAt(0);
            const rect = range.getBoundingClientRect();

            // 保存最后选择的文本和位置
            lastSelectedText = selectedText;
            lastSelectionRect = {
                top: rect.top,
                left: rect.left,
                bottom: rect.bottom,
                right: rect.right
            };

            const translateButton = createTranslateButton();
            translateButton.style.top = `${window.scrollY + rect.bottom + 5}px`;
            translateButton.style.left = `${window.scrollX + rect.right - 50}px`;

            translateButton.addEventListener('click', function (event) {
                event.stopPropagation();
                event.preventDefault();

                // 显示翻译
                showTranslation(lastSelectedText, lastSelectionRect);
            });

            document.body.appendChild(translateButton);
            activeTranslateButton = translateButton;
        }
    });

    // 在初始化时创建UI组件
    function initUI() {
        createSettingsButton();
        createTranslatePageButton();
        createProgressBar();
        
    }

    // 初始化UI
    initUI();
    
    // 重试失败的翻译
    function retryFailedTranslations() {
        // 确认有段落需要翻译
        if (!translationSegments || translationSegments.length === 0) {
            alert('没有找到需要重试的翻译段落');
            return;
        }
        
        // 收集失败项
        const failedSegments = [];
        for (let i = 0; i < translationSegments.length; i++) {
            if (translationSegments[i].error) {
                failedSegments.push(i);
            }
        }
        
        if (failedSegments.length === 0) {
            alert('没有找到失败的翻译段落');
            return;
        }
        
        // 确认是否重试
        if (!confirm(`找到${failedSegments.length}个失败的翻译段落,是否重试?`)) {
            return;
        }
        
        // 更新状态
        const statusElement = document.getElementById('translation-status');
        if (statusElement) {
            statusElement.textContent = `正在重试失败的翻译 (0/${failedSegments.length})`;
            
            // 移除之前的错误摘要
            const oldSummary = statusElement.querySelector('.error-summary');
            if (oldSummary) oldSummary.remove();
        }
        
        // 重置错误计数
        translationSegments.errorCount = 0;
        
        // 开始重试
        isTranslatingFullPage = true;
        isTranslationPaused = false;
        
        // 创建控制按钮
        createControlButtons();
        
        // 递归重试
        function retryNext(index) {
            if (index >= failedSegments.length) {
                // 重试完成
                if (statusElement) {
                    const newErrors = translationSegments.errorCount || 0;
                    statusElement.textContent = `重试完成 (${failedSegments.length}/${failedSegments.length})${newErrors > 0 ? ` (仍有${newErrors}个错误)` : ''}`;
                }
                isTranslatingFullPage = false;
                return;
            }
            
            // 如果暂停,不继续
            if (isTranslationPaused || !isTranslatingFullPage) {
                return;
            }
            
            // 更新状态
            if (statusElement) {
                statusElement.textContent = `正在重试失败的翻译 (${index + 1}/${failedSegments.length})`;
            }
            
            // 获取当前要重试的段落索引
            const segmentIndex = failedSegments[index];
            
            // 清除之前的错误标记
            if (translationSegments[segmentIndex].nodes && translationSegments[segmentIndex].nodes.length > 0) {
                const nodeInfo = translationSegments[segmentIndex].nodes[0];
                if (nodeInfo.node && nodeInfo.node.parentElement) {
                    const errorMark = nodeInfo.node.parentElement.querySelector('.translation-error-mark');
                    if (errorMark) errorMark.remove();
                }
            }
            
            // 清除错误状态
            delete translationSegments[segmentIndex].error;
            
            // 翻译该段落
            translateText(translationSegments[segmentIndex].text, function (result) {
                if (result.type === 'complete' || result.type === 'stream-end') {
                    // 翻译成功,更新
                    translationSegments[segmentIndex].translation = result.content;
                    
                    // 更新DOM
                    if (translationSegments[segmentIndex].nodes && translationSegments[segmentIndex].nodes.length > 0) {
                        // 复用现有逻辑更新DOM
                        if (translationSegments[segmentIndex].nodes.length === 1) {
                            const nodeInfo = translationSegments[segmentIndex].nodes[0];
                            if (nodeInfo.node && nodeInfo.node.nodeType === Node.TEXT_NODE) {
                                nodeInfo.node.textContent = result.content;
                                if (nodeInfo.node.parentElement) {
                                    nodeInfo.node.parentElement.style.fontWeight = 'inherit';
                                    nodeInfo.node.parentElement.dataset.translated = 'true';
                                }
                            }
                        } else {
                            // 复杂节点结构的处理略过,会在前面代码相同逻辑处理
                        }
                    }
                    
                    // 继续下一个
                    setTimeout(() => retryNext(index + 1), 50);
                } else if (result.type === 'error') {
                    // 仍然出错
                    console.error(`重试段落 ${segmentIndex + 1} 翻译失败:`, result.content);
                    translationSegments[segmentIndex].error = result.content;
                    
                    // 错误计数
                    translationSegments.errorCount = (translationSegments.errorCount || 0) + 1;
                    
                    // 添加错误标记
                    if (translationSegments[segmentIndex].nodes && translationSegments[segmentIndex].nodes.length > 0) {
                        const nodeInfo = translationSegments[segmentIndex].nodes[0];
                        if (nodeInfo.node && nodeInfo.node.parentElement) {
                            // 在段落旁创建错误标记
                            const errorMark = document.createElement('span');
                            errorMark.className = 'translation-error-mark';
                            errorMark.innerHTML = '⚠️';
                            errorMark.title = `翻译失败: ${result.content}`;
                            errorMark.style.cssText = `
                                color: #ff4d4f;
                                cursor: pointer;
                                margin-left: 5px;
                                font-size: 16px;
                            `;
                            errorMark.addEventListener('click', function() {
                                alert(`翻译错误: ${result.content}`);
                            });
                            
                            nodeInfo.node.parentElement.appendChild(errorMark);
                            
                            // 确保不修改原文内容,防止错误码替换原文
                            if (nodeInfo.original && nodeInfo.node.nodeType === Node.TEXT_NODE) {
                                if (nodeInfo.node.textContent !== nodeInfo.original) {
                                    nodeInfo.node.textContent = nodeInfo.original;
                                }
                            }
                        }
                    }
                    
                    // 继续下一个
                    setTimeout(() => retryNext(index + 1), 50);
                }
            }, false);
        }
        
        // 开始重试第一个
        retryNext(0);
    }

    // 递归翻译段落
    let translatedCount = 0;
    // 添加一些全局错误处理和减速变量
    let consecutiveErrors = 0;
    let translationDelay = 50; // 初始延迟时间(ms)
    
    function translateNextSegment(index) {
        // 如果已暂停,不继续翻译
        if (isTranslationPaused) {
            return;
        }
        
        // 记录最后翻译的索引
        lastTranslatedIndex = index - 1;
        
        // 获取进度条和状态元素
        const progressBar = document.getElementById('translation-progress-bar');
        const statusElement = document.getElementById('translation-status');
        
        if (index >= translationSegments.length) {
            // 全部翻译完成
            if (progressBar) progressBar.style.width = '100%';
            
            // 获取错误统计
            const totalErrors = translationSegments.errorCount || 0;
            const errorInfo = totalErrors > 0 ? ` (${totalErrors}个错误)` : '';
            
            if (statusElement) {
                statusElement.textContent = `翻译完成 (${translationSegments.length}/${translationSegments.length})${errorInfo}`;
                
                // 如果有错误,添加错误摘要信息
                if (totalErrors > 0) {
                    // 移除之前的错误警告(如果有)
                    const oldWarning = statusElement.querySelector('.error-warning');
                    if (oldWarning) oldWarning.remove();
                    
                    const errorSummary = document.createElement('div');
                    errorSummary.className = 'error-summary';
                    errorSummary.style.cssText = `
                        margin-top: 10px;
                        color: #ff4d4f;
                        font-size: 13px;
                        padding: 8px;
                        background-color: rgba(255, 77, 79, 0.1);
                        border-radius: 4px;
                    `;
                    
                    // 创建错误摘要内容
                    let summaryText = `翻译过程中遇到了${totalErrors}个错误。`;
                    
                    // 添加解决建议
                    if (totalErrors > 5) {
                        summaryText += `可能原因:<br>
                        1. API密钥额度不足或API限制<br>
                        2. 网络连接不稳定<br>
                        3. 翻译内容过长或API不兼容<br><br>
                        建议:<br>
                        · 检查API设置和密钥<br>
                        · 在设置中禁用流式响应<br>
                        · 尝试使用不同的API提供商`;
                    }
                    
                    errorSummary.innerHTML = summaryText;
                    statusElement.appendChild(errorSummary);
                    
                    // 添加重试错误项按钮
                    const retryButton = document.createElement('button');
                    retryButton.textContent = '重试失败项';
                    retryButton.style.cssText = `
                        margin-top: 10px;
                        padding: 5px 10px;
                        background-color: #ff4d4f;
                        color: white;
                        border: none;
                        border-radius: 4px;
                        cursor: pointer;
                    `;
                    retryButton.addEventListener('click', function() {
                        retryFailedTranslations();
                    });
                    errorSummary.appendChild(retryButton);
                }
            }

            // 添加一个关闭按钮
            if (statusElement && !statusElement.querySelector('.close-btn')) {
                const closeButton = document.createElement('span');
                closeButton.className = 'close-btn';
                closeButton.style.cssText = `
                    margin-left: 10px;
                    cursor: pointer;
                    font-weight: bold;
                `;
                closeButton.textContent = '×';
                closeButton.addEventListener('click', function () {
                    statusElement.remove();
                    const progressContainer = document.getElementById('translation-progress-container');
                    if (progressContainer) progressContainer.style.display = 'none';
                });
                statusElement.appendChild(closeButton);
            }

            // 显示切换按钮
            const toggleButton = document.getElementById('toggle-translation-button');
            if (toggleButton) toggleButton.style.display = 'block';
            
            // 移除控制按钮
            removeControlButtons();

            isTranslatingFullPage = false;
            return;
        }

        // 更新进度
        const progress = Math.round((index / translationSegments.length) * 100);
        if (progressBar) progressBar.style.width = `${progress}%`;
        if (statusElement) statusElement.textContent = `正在翻译 (${index}/${translationSegments.length})`;

        // 如果段落文本为空,直接跳到下一个
        if (!translationSegments[index].text.trim()) {
            translateNextSegment(index + 1);
            return;
        }

        // 处理参考文献条目 - 特殊处理以保留格式
        if (translationSegments[index].isReferenceItem) {
            translateReferenceItem(translationSegments[index], function (translatedHtml) {
                if (translatedHtml) {
                    // 保存翻译结果
                    translationSegments[index].translation = translatedHtml;

                    // 保存原始HTML以便切换回来
                    if (!translationSegments[index].originalHtml && translationSegments[index].element) {
                        translationSegments[index].originalHtml = translationSegments[index].element.innerHTML;
                    }

                    // 更新DOM显示翻译结果
                    if (translationSegments[index].element) {
                        // 将翻译后的HTML设置到元素中
                        translationSegments[index].element.innerHTML = translatedHtml;
                    }

                    // 更新最后翻译的索引
                    lastTranslatedIndex = index;
                    
                    // 继续翻译下一个段落
                    setTimeout(() => translateNextSegment(index + 1), 50);
                } else {
                    // 翻译失败时继续下一个
                    console.error(`参考文献条目 ${index + 1} 翻译失败`);
                    
                    // 更新最后翻译的索引
                    lastTranslatedIndex = index;
                    
                    setTimeout(() => translateNextSegment(index + 1), 50);
                }
            });
            return;
        }

        // 常规段落翻译
        translateText(translationSegments[index].text, function (result) {
            // 如果已暂停或停止,不处理翻译结果
            if (isTranslationPaused || !isTranslatingFullPage) {
                return;
            }
            
            if (result.type === 'complete' || result.type === 'stream-end') {
                // 翻译成功
                translatedCount++;
                translationSegments[index].translation = result.content;

                // 更新DOM中的文本,保留原始样式
                if (translationSegments[index].nodes && translationSegments[index].nodes.length > 0) {
                    // 使用更智能的方式分配翻译结果
                    if (translationSegments[index].nodes.length === 1) {
                        // 只有一个节点的简单情况
                        const nodeInfo = translationSegments[index].nodes[0];
                        if (nodeInfo.node && nodeInfo.node.nodeType === Node.TEXT_NODE) {
                            nodeInfo.node.textContent = result.content;
                            
                        }
                    } else {
                        // 多个节点的情况,尝试保留原始结构
                        // 计算原始内容中每个节点文本的比例
                        const totalOriginalLength = translationSegments[index].nodes.reduce(
                            (sum, nodeInfo) => sum + (nodeInfo.original ? nodeInfo.original.length : 0), 0);

                        if (totalOriginalLength > 0) {
                            // 按照原始文本长度比例分配翻译后的文本
                            let startPos = 0;
                            for (let i = 0; i < translationSegments[index].nodes.length; i++) {
                                const nodeInfo = translationSegments[index].nodes[i];
                                if (nodeInfo.node && nodeInfo.node.nodeType === Node.TEXT_NODE && nodeInfo.original) {
                                    // 计算该节点在原始文本中的比例
                                    const ratio = nodeInfo.original.length / totalOriginalLength;
                                    // 计算应该分配给该节点的翻译文本长度
                                    const chunkLength = Math.round(result.content.length * ratio);
                                    // 提取翻译文本的一部分
                                    let chunk = '';
                                    if (i === translationSegments[index].nodes.length - 1) {
                                        // 最后一个节点,获取剩余所有文本
                                        chunk = result.content.substring(startPos);
                                    } else {
                                        // 非最后节点,按比例获取
                                        chunk = result.content.substring(startPos, startPos + chunkLength);
                                        startPos += chunkLength;
                                    }
                                    // 更新节点文本
                                    nodeInfo.node.textContent = chunk;
                                   
                                }
                            }
                        } else {
                            // 回退方案:如果无法计算比例,则将所有文本放在第一个节点
                            let foundFirstNode = false;
                            for (let i = 0; i < translationSegments[index].nodes.length; i++) {
                                const nodeInfo = translationSegments[index].nodes[i];
                                if (nodeInfo.node && nodeInfo.node.nodeType === Node.TEXT_NODE) {
                                    if (!foundFirstNode) {
                                        nodeInfo.node.textContent = result.content;
                                        foundFirstNode = true;
                                    } else {
                                        nodeInfo.node.textContent = '';
                                    }
                                }
                            }
                        }
                    }
                }
                
                // 更新最后翻译的索引
                lastTranslatedIndex = index;
                
                // 重置连续错误计数,因为成功了一次
                consecutiveErrors = 0;
                
                // 如果之前增加了延迟,且现在连续成功,则尝试逐步恢复
                if (translationDelay > 50 && translatedCount % 5 === 0) {
                    // 逐步减少延迟,但不低于初始值
                    translationDelay = Math.max(50, translationDelay * 0.8);
                    console.log(`连续翻译成功,减少延迟至${translationDelay}ms`);
                    
                    // 更新延迟信息显示
                    if (statusElement && statusElement.querySelector('.delay-info')) {
                        statusElement.querySelector('.delay-info').textContent = `已自动调整延迟至${Math.round(translationDelay)}ms`;
                        
                        // 如果延迟已经降回正常,移除通知并恢复颜色
                        if (translationDelay <= 60) {
                            statusElement.querySelector('.delay-info').remove();
                            statusElement.style.backgroundColor = 'rgba(66, 133, 244, 0.9)';
                        }
                    }
                }

                // 继续下一个段落
                setTimeout(() => translateNextSegment(index + 1), translationDelay);
            } else if (result.type === 'error') {
                // 翻译出错,记录错误并继续下一个
                console.error(`段落 ${index + 1} 翻译失败:`, result.content);
                translationSegments[index].error = result.content;
                
                // 更新最后翻译的索引
                lastTranslatedIndex = index;
                
                // 错误计数
                translationSegments.errorCount = (translationSegments.errorCount || 0) + 1;
                consecutiveErrors++;
                
                // 如果连续错误过多,自动增加延迟
                if (consecutiveErrors >= 3) {
                    // 增加延迟,但最大不超过2秒
                    translationDelay = Math.min(2000, translationDelay * 1.5);
                    console.log(`检测到连续错误,自动增加翻译延迟至${translationDelay}ms`);
                    
                    // 更新状态显示
                    if (statusElement && !statusElement.querySelector('.delay-info')) {
                        const delayInfo = document.createElement('div');
                        delayInfo.className = 'delay-info';
                        delayInfo.style.cssText = `
                            font-size: 12px;
                            margin-top: 5px;
                        `;
                        delayInfo.textContent = `已自动增加延迟至${translationDelay}ms以减轻API负载`;
                        statusElement.appendChild(delayInfo);
                    } else if (statusElement && statusElement.querySelector('.delay-info')) {
                        statusElement.querySelector('.delay-info').textContent = `已自动增加延迟至${translationDelay}ms以减轻API负载`;
                    }
                    
                    // 改变状态颜色提示错误
                    statusElement.style.backgroundColor = 'rgba(255, 152, 0, 0.9)';
                }
                
                // 显示错误提示标记在段落旁
                if (translationSegments[index].nodes && translationSegments[index].nodes.length > 0) {
                    const nodeInfo = translationSegments[index].nodes[0];
                    if (nodeInfo.node && nodeInfo.node.parentElement) {
                        // 在段落旁创建错误标记
                        const errorMark = document.createElement('span');
                        errorMark.className = 'translation-error-mark';
                        errorMark.innerHTML = '⚠️';
                        errorMark.title = `翻译失败: ${result.content}`;
                        errorMark.style.cssText = `
                            color: #ff4d4f;
                            cursor: pointer;
                            margin-left: 5px;
                            font-size: 16px;
                        `;
                        errorMark.addEventListener('click', function() {
                            alert(`翻译错误: ${result.content}`);
                        });
                        
                        nodeInfo.node.parentElement.appendChild(errorMark);
                        
                        // 重要:确保不修改原文内容,防止错误码替换原文
                        // 如果有通过错误处理设置了节点文本,恢复原始文本
                        if (nodeInfo.original && nodeInfo.node.nodeType === Node.TEXT_NODE) {
                            if (nodeInfo.node.textContent !== nodeInfo.original) {
                                nodeInfo.node.textContent = nodeInfo.original;
                            }
                        }
                    }
                }
                
                // 更新状态面板显示总体进度和错误信息
                if (statusElement) {
                    const totalErrors = translationSegments.errorCount;
                    const errorInfo = totalErrors > 0 ? ` (${totalErrors}个错误)` : '';
                    statusElement.textContent = `正在翻译 (${index + 1}/${translationSegments.length})${errorInfo}`;
                    
                    // 如果错误超过阈值,添加暂停建议
                    if (totalErrors > 5 && !statusElement.querySelector('.error-warning')) {
                        const warningElement = document.createElement('div');
                        warningElement.className = 'error-warning';
                        warningElement.style.cssText = `
                            margin-top: 5px;
                            color: #ff4d4f;
                            font-size: 12px;
                        `;
                        warningElement.textContent = `检测到多处翻译错误,可能是API限制或网络问题。考虑暂停翻译后再继续。`;
                        statusElement.appendChild(warningElement);
                    }
                }
                
                // 继续下一个段落
                setTimeout(() => translateNextSegment(index + 1), translationDelay);
            }
        }, false); // 使用非流式翻译,避免更新DOM过于频繁
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址