AI网页内容总结脚本来了!

效果图

设置面板

废话不多说,直接上源码

// ==UserScript==
// @name         AI网页内容总结
// @namespace    https://linux.do/u/f-droid
// @version      1.0
// @description  支持多语言和使用自定义API总结网页内容的AI网页内容总结脚本。
// @author       F-Droid
// @icon         https://linux.do/user_avatar/linux.do/f-droid/144/228666_2.png
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @connect      *
// @require      https://cdn.jsdelivr.net/npm/marked/marked.min.js
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const DEFAULT_CONFIG_NAME = '默认配置';
    const DEFAULT_CONFIG = {
        API_URL: 'https://api.openai.com/v1/chat/completions',
        API_KEY: 'yourapikey',
        MAX_TOKENS: 8192,
        MODEL: 'gpt-4o',
        TEMPERATURE: 0.5,
        PROMPT: '请总结以下内容,简要概括主要观点和重要细节,不要进行任何对话形式的回答。',
        LANGUAGE: '自动',
        RETRY_COUNT: 3,
        RETRY_INTERVAL: 3000 
    };

    let CONFIGS = loadConfigs();
    let currentConfigName = getCurrentConfigName();
    let CONFIG = CONFIGS[currentConfigName] || DEFAULT_CONFIG;
    let lastSummaryMarkdown = ''; 
    const summaryButton = document.createElement('button');
    summaryButton.textContent = '总结网页';
    summaryButton.style.position = 'fixed';
    summaryButton.style.bottom = '20px';
    summaryButton.style.right = '150px';
    summaryButton.style.backgroundColor = '#28A745';
    summaryButton.style.color = 'white';
    summaryButton.style.border = 'none';
    summaryButton.style.borderRadius = '5px';
    summaryButton.style.padding = '10px 20px';
    summaryButton.style.cursor = 'pointer';
    summaryButton.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
    summaryButton.style.zIndex = 1000;
    document.body.appendChild(summaryButton);

    const mainButton = document.createElement('button');
    mainButton.textContent = '控制面板';
    mainButton.style.position = 'fixed';
    mainButton.style.bottom = '20px';
    mainButton.style.right = '20px';
    mainButton.style.backgroundColor = '#007BFF';
    mainButton.style.color = 'white';
    mainButton.style.border = 'none';
    mainButton.style.borderRadius = '5px';
    mainButton.style.padding = '10px 20px';
    mainButton.style.cursor = 'pointer';
    mainButton.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
    mainButton.style.zIndex = 1000;
    document.body.appendChild(mainButton);

    const panel = document.createElement('div');
    panel.style.display = 'none';
    panel.style.position = 'fixed';
    panel.style.top = '50%';
    panel.style.left = '50%';
    panel.style.transform = 'translate(-50%, -50%)';
    panel.style.backgroundColor = 'white';
    panel.style.padding = '20px';
    panel.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.3)';
    panel.style.zIndex = 1001;
    panel.style.width = '75%';
    panel.style.height = '75%';
    panel.style.borderRadius = '10px';
    panel.style.overflowY = 'auto';
    document.body.appendChild(panel);

    const mainView = document.createElement('div');
    mainView.style.display = 'block';

    const settingsView = document.createElement('div');
    settingsView.style.display = 'none';

    panel.appendChild(mainView);
    panel.appendChild(settingsView);

    const createPanelHeader = (titleText, onClose) => {
        const header = document.createElement('div');
        header.style.display = 'flex';
        header.style.justifyContent = 'space-between';
        header.style.alignItems = 'center';

        const title = document.createElement('h3');
        title.textContent = titleText;
        title.style.marginBottom = '15px';
        title.style.textAlign = 'center';
        header.appendChild(title);

        const closeButton = document.createElement('button');
        closeButton.textContent = '关闭';
        closeButton.style.backgroundColor = '#6C757D';
        closeButton.style.color = 'white';
        closeButton.style.border = 'none';
        closeButton.style.padding = '5px 10px';
        closeButton.style.borderRadius = '5px';
        closeButton.style.cursor = 'pointer';
        closeButton.addEventListener('click', onClose);
        header.appendChild(closeButton);

        return header;
    };

    mainView.appendChild(createPanelHeader('AI总结控制面板', () => {
        panel.style.display = 'none';
    }));

    const buttonContainer = document.createElement('div');
    buttonContainer.style.display = 'flex';
    buttonContainer.style.justifyContent = 'center';
    buttonContainer.style.gap = '10px';
    buttonContainer.style.marginBottom = '15px';
    mainView.appendChild(buttonContainer);

    const panelSummaryButton = document.createElement('button');
    panelSummaryButton.textContent = '获取网页总结';
    panelSummaryButton.style.backgroundColor = '#28A745';
    panelSummaryButton.style.color = 'white';
    panelSummaryButton.style.border = 'none';
    panelSummaryButton.style.padding = '10px 15px';
    panelSummaryButton.style.borderRadius = '5px';
    panelSummaryButton.style.cursor = 'pointer';
    buttonContainer.appendChild(panelSummaryButton);

    const settingsButton = document.createElement('button');
    settingsButton.textContent = '设置';
    settingsButton.style.backgroundColor = '#FFC107';
    settingsButton.style.color = 'white';
    settingsButton.style.border = 'none';
    settingsButton.style.padding = '10px 15px';
    settingsButton.style.borderRadius = '5px';
    settingsButton.style.cursor = 'pointer';
    settingsButton.addEventListener('click', () => {
        mainView.style.display = 'none';
        settingsView.style.display = 'block';
    });
    buttonContainer.appendChild(settingsButton);

    const resultArea = document.createElement('div');
    resultArea.style.width = '100%';
    resultArea.style.height = '60%';
    resultArea.style.marginTop = '10px';
    resultArea.style.marginBottom = '15px'; 
    resultArea.style.borderRadius = '5px';
    resultArea.style.border = '1px solid #ced4da';
    resultArea.style.padding = '10px';
    resultArea.style.boxSizing = 'border-box';
    resultArea.style.overflowY = 'auto';
    mainView.appendChild(resultArea);

    const copyButton = document.createElement('button');
    copyButton.textContent = '复制总结';
    copyButton.style.backgroundColor = '#007BFF';
    copyButton.style.color = 'white';
    copyButton.style.border = 'none';
    copyButton.style.padding = '10px 20px';
    copyButton.style.marginTop = '10px';
    copyButton.style.borderRadius = '5px';
    copyButton.style.cursor = 'pointer';
    mainView.appendChild(copyButton);

    const footer = document.createElement('div');
    footer.style.marginTop = '15px';
    footer.style.textAlign = 'center';
    footer.innerHTML = `© ${new Date().getFullYear()} <a href="https://linux.do/u/f-droid" target="_blank" style="color: #007BFF; text-decoration: none;">F-Droid</a>. All rights reserved.<br>如果您喜欢这个工具,请给作者点个赞吧!😊`;
    mainView.appendChild(footer);

    settingsView.appendChild(createPanelHeader('设置', () => {
        settingsView.style.display = 'none';
        mainView.style.display = 'block';
    }));

    const form = document.createElement('form');
    form.style.display = 'flex';
    form.style.flexDirection = 'column';
    form.style.rowGap = '10px';
    form.style.padding = '0 20px';
    settingsView.appendChild(form);

    const configSelectButton = document.createElement('button');
    configSelectButton.textContent = '选择配置';
    configSelectButton.style.backgroundColor = '#007BFF';
    configSelectButton.style.color = 'white';
    configSelectButton.style.border = 'none';
    configSelectButton.style.padding = '10px 20px';
    configSelectButton.style.borderRadius = '5px';
    configSelectButton.style.cursor = 'pointer';
    configSelectButton.style.marginBottom = '10px';
    configSelectButton.addEventListener('click', () => {
        showConfigSelectDialog();
    });
    form.appendChild(configSelectButton);

    const createInputField = (labelText, inputName, inputType = 'text', placeholder = '', value = '') => {
        const fieldContainer = document.createElement('div');
        fieldContainer.style.display = 'flex';
        fieldContainer.style.flexDirection = 'column';
        fieldContainer.style.marginBottom = '15px';
        fieldContainer.style.position = 'relative';

        const label = document.createElement('label');
        label.textContent = labelText;
        label.htmlFor = inputName;
        label.style.marginBottom = '5px';

        const input = document.createElement('input');
        input.type = inputType;
        input.name = inputName;
        input.placeholder = placeholder;
        input.value = value;
        input.style.padding = '10px';
        input.style.border = '1px solid #ced4da';
        input.style.borderRadius = '5px';
        input.style.width = '100%';
        input.style.boxSizing = 'border-box';

        if (inputName === 'api_key') {
            const toggleVisibilityButton = document.createElement('button');
            toggleVisibilityButton.textContent = '👁️';
            toggleVisibilityButton.style.position = 'absolute';
            toggleVisibilityButton.style.right = '10px';
            toggleVisibilityButton.style.top = '35px';
            toggleVisibilityButton.style.border = 'none';
            toggleVisibilityButton.style.background = 'none';
            toggleVisibilityButton.style.cursor = 'pointer';
            toggleVisibilityButton.addEventListener('click', (event) => {
                event.preventDefault();
                input.type = input.type === 'password' ? 'text' : 'password';
            });
            fieldContainer.appendChild(toggleVisibilityButton);
        }

        fieldContainer.appendChild(label);
        fieldContainer.appendChild(input);

        return fieldContainer;
    };

    form.appendChild(createInputField('API地址', 'api_url', 'text', '请输入您的API地址', CONFIG.API_URL));
    form.appendChild(createInputField('API密钥', 'api_key', 'password', '请输入您的API密钥', CONFIG.API_KEY));
    form.appendChild(createInputField('AI模型', 'model', 'text', '请输入AI模型名称', CONFIG.MODEL));
    form.appendChild(createInputField('最大字数', 'max_tokens', 'number', '请输入最大字数', CONFIG.MAX_TOKENS));
    form.appendChild(createInputField('温度', 'temperature', 'number', '请输入温度(0到1之间)', CONFIG.TEMPERATURE));
    form.appendChild(createInputField('提示词', 'prompt', 'text', '请输入新的总结提示词', CONFIG.PROMPT));
    form.appendChild(createInputField('总结语言', 'language', 'text', '请输入总结语言(默认自动)', CONFIG.LANGUAGE));
    form.appendChild(createInputField('重试次数', 'retry_count', 'number', '请输入重试次数', CONFIG.RETRY_COUNT));
    form.appendChild(createInputField('重试间隔(毫秒)', 'retry_interval', 'number', '请输入重试间隔', CONFIG.RETRY_INTERVAL));

    const buttonGroup = document.createElement('div');
    buttonGroup.style.display = 'flex';
    buttonGroup.style.justifyContent = 'flex-start';
    buttonGroup.style.gap = '10px';
    settingsView.appendChild(buttonGroup);

    const saveButton = document.createElement('button');
    saveButton.textContent = '保存设置';
    saveButton.style.backgroundColor = '#007BFF';
    saveButton.style.color = 'white';
    saveButton.style.border = 'none';
    saveButton.style.padding = '10px 20px';
    saveButton.style.borderRadius = '5px';
    saveButton.style.cursor = 'pointer';
    buttonGroup.appendChild(saveButton);

    const addConfigButton = document.createElement('button');
    addConfigButton.textContent = '添加新配置';
    addConfigButton.style.backgroundColor = '#28A745';
    addConfigButton.style.color = 'white';
    addConfigButton.style.border = 'none';
    addConfigButton.style.padding = '10px 20px';
    addConfigButton.style.borderRadius = '5px';
    addConfigButton.style.cursor = 'pointer';
    buttonGroup.appendChild(addConfigButton);

    const renameButton = document.createElement('button');
    renameButton.textContent = '重命名配置';
    renameButton.style.backgroundColor = '#FFC107';
    renameButton.style.color = 'white';
    renameButton.style.border = 'none';
    renameButton.style.padding = '10px 20px';
    renameButton.style.borderRadius = '5px';
    renameButton.style.cursor = 'pointer';
    buttonGroup.appendChild(renameButton);

    const deleteButton = document.createElement('button');
    deleteButton.textContent = '删除配置';
    deleteButton.style.backgroundColor = '#DC3545';
    deleteButton.style.color = 'white';
    deleteButton.style.border = 'none';
    deleteButton.style.padding = '10px 20px';
    deleteButton.style.borderRadius = '5px';
    deleteButton.style.cursor = 'pointer';
    buttonGroup.appendChild(deleteButton);

    const applyButton = document.createElement('button');
    applyButton.textContent = '应用配置';
    applyButton.style.backgroundColor = '#17A2B8';
    applyButton.style.color = 'white';
    applyButton.style.border = 'none';
    applyButton.style.padding = '10px 20px';
    applyButton.style.borderRadius = '5px';
    applyButton.style.cursor = 'pointer';
    buttonGroup.appendChild(applyButton);

    mainButton.addEventListener('click', () => {
        panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
    });

    summaryButton.addEventListener('click', async () => {
        try {
            const pageContent = getPageContent();
            const summary = await summarizeWithRetries(pageContent);
            lastSummaryMarkdown = summary; // Store the original Markdown
            resultArea.innerHTML = marked.parse(summary);
            panel.style.display = 'block';
        } catch (error) {
            showErrorDialog(error.message);
        }
    });

    panelSummaryButton.addEventListener('click', async () => {
        try {
            const pageContent = getPageContent();
            const summary = await summarizeWithRetries(pageContent);
            lastSummaryMarkdown = summary; // Store the original Markdown
            resultArea.innerHTML = marked.parse(summary);
        } catch (error) {
            showErrorDialog(error.message);
        }
    });

    saveButton.addEventListener('click', (event) => {
        event.preventDefault();
        const formData = new FormData(form);

        CONFIG.API_URL = formData.get('api_url');
        CONFIG.API_KEY = formData.get('api_key');
        CONFIG.MODEL = formData.get('model');
        CONFIG.MAX_TOKENS = parseInt(formData.get('max_tokens'), 10);
        CONFIG.TEMPERATURE = parseFloat(formData.get('temperature'));
        CONFIG.PROMPT = formData.get('prompt');
        CONFIG.LANGUAGE = formData.get('language');
        CONFIG.RETRY_COUNT = parseInt(formData.get('retry_count'), 10);
        CONFIG.RETRY_INTERVAL = parseInt(formData.get('retry_interval'), 10);

        CONFIGS[currentConfigName] = CONFIG;
        saveConfigs(CONFIGS);
        showInfoDialog('设置已更新。', true);
    });

    addConfigButton.addEventListener('click', () => {
        showInputDialog('请输入新配置名称:', `配置${Object.keys(CONFIGS).length + 1}`, (newConfigName) => {
            if (newConfigName && !CONFIGS[newConfigName]) {
                CONFIGS[newConfigName] = { ...DEFAULT_CONFIG };
                currentConfigName = newConfigName;
                CONFIG = CONFIGS[currentConfigName];
                saveConfigs(CONFIGS);
                updateConfigSelect();
                updateFormFields();
                showInfoDialog('新配置已添加。', true);
            }
        });
    });

    renameButton.addEventListener('click', () => {
        if (currentConfigName !== DEFAULT_CONFIG_NAME) {
            showInputDialog('请输入新的配置名称:', currentConfigName, (newName) => {
                if (newName && newName !== currentConfigName && !CONFIGS[newName]) {
                    CONFIGS[newName] = CONFIGS[currentConfigName];
                    delete CONFIGS[currentConfigName];
                    currentConfigName = newName;
                    saveConfigs(CONFIGS);
                    updateConfigSelect();
                    showInfoDialog('配置已重命名。', true);
                }
            });
        } else {
            showInfoDialog('默认配置无法重命名。', true);
        }
    });

    deleteButton.addEventListener('click', () => {
        if (currentConfigName !== DEFAULT_CONFIG_NAME) {
            showConfirmDialog(`确定要删除配置 "${currentConfigName}" 吗?`, () => {
                delete CONFIGS[currentConfigName];
                currentConfigName = DEFAULT_CONFIG_NAME;
                CONFIG = CONFIGS[currentConfigName];
                saveConfigs(CONFIGS);
                updateConfigSelect();
                updateFormFields();
                showInfoDialog(`配置已删除,已切换到默认配置。`, true);
            });
        } else {
            showInfoDialog('默认配置无法删除。', true);
        }
    });

    applyButton.addEventListener('click', () => {
        setCurrentConfigName(currentConfigName);
        showInfoDialog('当前配置已应用,下次启动将使用此配置。', true);
    });

    copyButton.addEventListener('click', () => {
        navigator.clipboard.writeText(lastSummaryMarkdown).then(() => {
            showInfoDialog('总结内容已复制到剪贴板(Markdown格式)。', true);
        }).catch(() => {
            showInfoDialog('复制失败,请手动复制内容。', true);
        });
    });

    function showConfigSelectDialog() {
        const dialog = document.createElement('div');
        dialog.style.position = 'fixed';
        dialog.style.top = '50%';
        dialog.style.left = '50%';
        dialog.style.transform = 'translate(-50%, -50%)';
        dialog.style.backgroundColor = 'white';
        dialog.style.padding = '20px';
        dialog.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.3)';
        dialog.style.zIndex = 1002;
        dialog.style.width = '50%';
        dialog.style.borderRadius = '10px';
        dialog.style.textAlign = 'center';

        const dialogHeader = createPanelHeader('选择配置', () => {
            dialog.remove();
        });
        dialog.appendChild(dialogHeader);

        const configList = document.createElement('div');
        configList.style.display = 'flex';
        configList.style.flexDirection = 'column';
        configList.style.alignItems = 'center';
        configList.style.maxHeight = '200px';
        configList.style.overflowY = 'auto';
        configList.style.marginBottom = '15px';

        Object.keys(CONFIGS).forEach(name => {
            const configItem = document.createElement('button');
            configItem.textContent = name;
            configItem.style.padding = '10px';
            configItem.style.marginBottom = '5px';
            configItem.style.border = '1px solid #ced4da';
            configItem.style.borderRadius = '5px';
            configItem.style.width = '80%';
            configItem.style.cursor = 'pointer';
            configItem.style.backgroundColor = name === currentConfigName ? '#007BFF' : '#f8f9fa';
            configItem.style.color = name === currentConfigName ? 'white' : 'black';
            configItem.addEventListener('click', () => {
                currentConfigName = name;
                CONFIG = CONFIGS[currentConfigName];
                updateFormFields();
                dialog.remove();
                showInfoDialog(`已选择配置:${name}`, true);
            });
            configList.appendChild(configItem);
        });

        dialog.appendChild(configList);
        document.body.appendChild(dialog);
    }

    function updateFormFields() {
        form.elements.api_url.value = CONFIG.API_URL;
        form.elements.api_key.value = CONFIG.API_KEY;
        form.elements.model.value = CONFIG.MODEL;
        form.elements.max_tokens.value = CONFIG.MAX_TOKENS;
        form.elements.temperature.value = CONFIG.TEMPERATURE;
        form.elements.prompt.value = CONFIG.PROMPT;
        form.elements.language.value = CONFIG.LANGUAGE;
        form.elements.retry_count.value = CONFIG.RETRY_COUNT;
        form.elements.retry_interval.value = CONFIG.RETRY_INTERVAL;
    }

    function showErrorDialog(message) {
        showInfoDialog(message, false, '错误');
    }

    function showInfoDialog(message, autoClose = false, title = '信息') {
        const dialog = document.createElement('div');
        dialog.style.position = 'fixed';
        dialog.style.top = '50%';
        dialog.style.left = '50%';
        dialog.style.transform = 'translate(-50%, -50%)';
        dialog.style.backgroundColor = 'white';
        dialog.style.padding = '20px';
        dialog.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.3)';
        dialog.style.zIndex = 1002;
        dialog.style.width = '50%';
        dialog.style.borderRadius = '10px';
        dialog.style.textAlign = 'center';

        const dialogHeader = createPanelHeader(title, () => {
            dialog.remove();
        });
        dialog.appendChild(dialogHeader);

        const messagePara = document.createElement('p');
        messagePara.textContent = message;
        dialog.appendChild(messagePara);

        const returnButton = document.createElement('button');
        returnButton.textContent = '返回面板';
        returnButton.style.backgroundColor = '#007BFF';
        returnButton.style.color = 'white';
        returnButton.style.border = 'none';
        returnButton.style.padding = '10px 20px';
        returnButton.style.borderRadius = '5px';
        returnButton.style.cursor = 'pointer';
        returnButton.style.marginTop = '15px';
        returnButton.addEventListener('click', () => {
            dialog.remove();
            panel.style.display = 'block';
        });
        dialog.appendChild(returnButton);

        document.body.appendChild(dialog);

        if (autoClose) {
            setTimeout(() => dialog.remove(), 3000);
        }
    }

    function showInputDialog(title, defaultValue, callback) {
        const dialog = document.createElement('div');
        dialog.style.position = 'fixed';
        dialog.style.top = '50%';
        dialog.style.left = '50%';
        dialog.style.transform = 'translate(-50%, -50%)';
        dialog.style.backgroundColor = 'white';
        dialog.style.padding = '20px';
        dialog.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.3)';
        dialog.style.zIndex = 1002;
        dialog.style.width = '50%';
        dialog.style.borderRadius = '10px';
        dialog.style.textAlign = 'center';

        const dialogHeader = createPanelHeader(title, () => {
            dialog.remove();
        });
        dialog.appendChild(dialogHeader);

        const input = document.createElement('input');
        input.type = 'text';
        input.value = defaultValue;
        input.style.padding = '10px';
        input.style.border = '1px solid #ced4da';
        input.style.borderRadius = '5px';
        input.style.width = '80%';
        input.style.marginBottom = '15px';
        dialog.appendChild(input);

        const confirmButton = document.createElement('button');
        confirmButton.textContent = '确认';
        confirmButton.style.backgroundColor = '#007BFF';
        confirmButton.style.color = 'white';
        confirmButton.style.border = 'none';
        confirmButton.style.padding = '10px 20px';
        confirmButton.style.borderRadius = '5px';
        confirmButton.style.cursor = 'pointer';
        confirmButton.addEventListener('click', () => {
            callback(input.value);
            dialog.remove();
        });
        dialog.appendChild(confirmButton);

        document.body.appendChild(dialog);
    }

    function showConfirmDialog(message, callback) {
        const dialog = document.createElement('div');
        dialog.style.position = 'fixed';
        dialog.style.top = '50%';
        dialog.style.left = '50%';
        dialog.style.transform = 'translate(-50%, -50%)';
        dialog.style.backgroundColor = 'white';
        dialog.style.padding = '20px';
        dialog.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.3)';
        dialog.style.zIndex = 1002;
        dialog.style.width = '50%';
        dialog.style.borderRadius = '10px';
        dialog.style.textAlign = 'center';

        const dialogHeader = createPanelHeader('确认', () => {
            dialog.remove();
        });
        dialog.appendChild(dialogHeader);

        const messagePara = document.createElement('p');
        messagePara.textContent = message;
        dialog.appendChild(messagePara);

        const confirmButton = document.createElement('button');
        confirmButton.textContent = '确认';
        confirmButton.style.backgroundColor = '#007BFF';
        confirmButton.style.color = 'white';
        confirmButton.style.border = 'none';
        confirmButton.style.padding = '10px 20px';
        confirmButton.style.borderRadius = '5px';
        confirmButton.style.cursor = 'pointer';
        confirmButton.addEventListener('click', () => {
            callback();
            dialog.remove();
        });
        dialog.appendChild(confirmButton);

        document.body.appendChild(dialog);
    }

    function getPageContent() {
        const title = document.title;
        const bodyText = document.body.innerText;
        return `${title}\n\n${bodyText}`;
    }

    async function summarizeWithRetries(content) {
        let attempts = 0;
        while (attempts < CONFIG.RETRY_COUNT) {
            try {
                return await summarizeContent(content);
            } catch (error) {
                if (attempts < CONFIG.RETRY_COUNT - 1) {
                    await new Promise(resolve => setTimeout(resolve, CONFIG.RETRY_INTERVAL));
                } else {
                    throw new Error('所有重试均失败,请稍后再试。');
                }
            }
            attempts++;
        }
    }

    async function summarizeContent(content) {
        const languageSetting = CONFIG.LANGUAGE !== '自动' ? `请用${CONFIG.LANGUAGE}总结。` : '';
        const promptWithLanguage = `${CONFIG.PROMPT} ${languageSetting}`;

        const response = await new Promise((resolve, reject) => {
            const timeout = setTimeout(() => reject(new Error('请求超时')), 60000);
            GM_xmlhttpRequest({
                method: 'POST',
                url: CONFIG.API_URL,
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${CONFIG.API_KEY}`
                },
                data: JSON.stringify({
                    model: CONFIG.MODEL,
                    messages: [
                        { role: 'system', content: promptWithLanguage },
                        { role: 'user', content: content }
                    ],
                    max_tokens: CONFIG.MAX_TOKENS,
                    temperature: CONFIG.TEMPERATURE
                }),
                onload: response => {
                    clearTimeout(timeout);
                    if (response.status === 429) {
                        reject(new Error('请求次数太多,请稍后再试。'));
                    } else if (response.status >= 200 && response.status < 300) {
                        try {
                            const data = JSON.parse(response.responseText);
                            resolve(data);
                        } catch (e) {
                            reject(new Error('无法解析响应'));
                        }
                    } else {
                        reject(new Error(`状态码: ${response.status}`));
                    }
                },
                onerror: () => {
                    clearTimeout(timeout);
                    reject(new Error('请求失败,请检查您的网络连接。'));
                }
            });
        });

        if (response.choices && response.choices[0] && response.choices[0].message) {
            return response.choices[0].message.content;
        } else {
            throw new Error('响应格式错误');
        }
    }

    function loadConfigs() {
        return GM_getValue('CONFIGS', { [DEFAULT_CONFIG_NAME]: DEFAULT_CONFIG });
    }

    function saveConfigs(configs) {
        GM_setValue('CONFIGS', configs);
    }

    function getCurrentConfigName() {
        return GM_getValue('CURRENT_CONFIG_NAME', DEFAULT_CONFIG_NAME);
    }

    function setCurrentConfigName(name) {
        GM_setValue('CURRENT_CONFIG_NAME', name);
    }
})();

这个脚本还有很多可以改进的地方,希望有大佬能够在我的基础上进行修改完善。如果各位有更满意的改进版本,恳请将代码分享在下方,方便大家共同学习和使用。让我们一起来完善这个脚本吧!

15 个赞

感谢佬友分享

1 个赞

大佬太强了 :tieba_087:

1 个赞

感谢分享,这个真的爽

1 个赞

感谢分享 !!!

1 个赞

感谢大佬分享tieba34

1 个赞

感谢你的分享

1 个赞

希望有个成品,造福小白

1 个赞

太强了,大佬!

1 个赞

感谢分享大佬厉害啊

1 个赞

直接用侧边栏就好了 还能对聊

1 个赞

厉害了试试看

1 个赞

大佬厉害,学习一下

1 个赞