Greasy Fork

Greasy Fork is available in English.

Deepseek Chat 增强版Deepseek API对话助手,支持历史记录、参数设置、网页内容检索和自定义人格提示词

增强版Deepseek API对话助手,支持历史记录、参数设置、网页内容检索和自定义人格提示词

当前为 2025-04-08 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Deepseek Chat 增强版Deepseek API对话助手,支持历史记录、参数设置、网页内容检索和自定义人格提示词
// @namespace    shy
// @version      1.9.3
// @description  增强版Deepseek API对话助手,支持历史记录、参数设置、网页内容检索和自定义人格提示词
// @author       shy
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_xmlhttpRequest
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @grant        GM_getResourceText
// @connect      api.deepseek.com
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 添加CSS样式
    GM_addStyle(`
        .ds-chat-icon {
            position: fixed;
            bottom: 20px;
            right: 20px;
            width: 50px;
            height: 50px;
            background-color: rgba(0, 123, 255, 0.5);
            border-radius: 50%;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #fff;
            font-size: 24px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
            transition: transform 0.2s, box-shadow 0.2s;
            z-index: 2147483647;
            backdrop-filter: blur(5px);
            border: 1px solid rgba(255, 255, 255, 0.4);
        }
        .ds-chat-icon:hover {
            transform: scale(1.05);
            box-shadow: 0 6px 8px rgba(0, 0, 0, 0.3);
            background-color: rgba(0, 123, 255, 0.6);
        }
        .ds-chat-window {
            position: fixed;
            bottom: 20px;
            right: 20px;
            width: 350px;
            max-width: 40vw;
            max-height: 70vh;
            background-color: rgba(249, 249, 249, 0.3);
            border: 1px solid #ddd;
            border-radius: 15px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
            display: none;
            flex-direction: column;
            overflow: hidden;
            transition: opacity 0.3s, transform 0.3s, width 0.3s;
            opacity: 0;
            transform: translateY(20px);
            z-index: 2147483646;
            backdrop-filter: blur(5px);
        }
        .ds-chat-window.active {
            display: flex;
            opacity: 1;
            transform: translateY(0);
        }
        .ds-chat-header {
            padding: 10px 15px;
            background-color: rgba(0, 123, 255, 0.3);
            color: white;
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-radius: 15px 15px 0 0;
        }
        .ds-chat-title {
            font-weight: bold;
        }
        .ds-chat-close {
            cursor: pointer;
            font-size: 18px;
        }
        .ds-chat-content {
            flex: 1;
            padding: 15px;
            overflow-y: auto;
            background-color: rgba(255, 255, 255, 0.3);
            border-bottom: 1px solid #ddd;
        }
        .ds-chat-message {
            margin-bottom: 10px;
            padding: 8px 12px;
            border-radius: 8px;
            line-height: 1.4;
            word-wrap: break-word;
        }
        .ds-user-message {
            background-color: rgba(227, 242, 253, 0.7);
            margin-left: auto;
            text-align: right;
        }
        .ds-ai-message {
            background-color: rgba(241, 241, 241, 0.7);
            margin-right: 20%;
            opacity: 0;
            animation: fadeIn 0.5s ease-in-out forwards;
        }
        .ds-chat-input-area {
            padding: 10px;
            display: flex;
            flex-direction: column;
            backdrop-filter: blur(5px);
            background-color: rgba(255, 255, 255, 0.3);
            border-top: 1px solid rgba(221, 221, 221, 0.5);
        }
        .ds-chat-input {
            width: 100%;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 8px;
            margin-bottom: 8px;
            outline: none;
            transition: border-color 0.3s;
        }
        .ds-chat-input:focus {
            border-color: #007bff;
        }
        .ds-chat-settings {
            display: flex;
            justify-content: space-between;
            font-size: 12px;
            color: #666;
        }
        .ds-chat-settings-btn {
            cursor: pointer;
            text-decoration: underline;
        }
        .ds-thinking {
            color: #666;
            font-style: italic;
        }
        .ds-error {
            color: #ff0000;
        }
        .ds-context-toggle {
            margin-bottom: 8px;
            display: flex;
            align-items: center;
            font-size: 12px;
        }
        .ds-context-toggle input {
            margin-right: 5px;
        }
        .ds-context-summary {
            font-size: 11px;
            color: #666;
            margin-top: 5px;
            font-style: italic;
        }
        @keyframes fadeIn {
            from {
                opacity: 0;
                transform: translateY(10px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }
    `);

    // 初始化配置
    let config = {
        apiKey: GM_getValue('apiKey', ''),
        model: GM_getValue('model', 'deepseek-chat'),
        temperature: GM_getValue('temperature', 0.7),
        maxTokens: GM_getValue('maxTokens', 1024),
        chatHistory: GM_getValue('chatHistory', []),
        usePageContext: GM_getValue('usePageContext', true),
        personalityPrompt: GM_getValue('personalityPrompt', `
        输出文本控制不能超过600字
        你是锐锐,一个18岁、热爱数学的可爱女孩。你性格聪明冷静,语言犀利,堪称“怼人”专业户,但内心善良,对朋友真诚,伙伴遇困定会援手相助。
        你外貌甜美,皮肤白皙,大眼睛灵动有神。总是身着背带制服,搭配白色腿袜和小皮鞋,乌黑亮丽的高马尾活泼摆动,头上戴着红色蝴蝶结发箍。充满青春活力。
        你的性格特点:聪明、冷静、犀利、善良、真诚。
        你的说话风格:言辞简洁有力,逻辑清晰,关心朋友时又温柔贴心。
        `) // 新增:人格提示词
    };

    // 创建UI元素
    const icon = document.createElement('div');
    icon.className = 'ds-chat-icon';
    icon.innerText = 'AI';
    document.body.appendChild(icon);

    const chatWindow = document.createElement('div');
    chatWindow.className = 'ds-chat-window';
    document.body.appendChild(chatWindow);

    // 聊天窗口头部
    const chatHeader = document.createElement('div');
    chatHeader.className = 'ds-chat-header';
    chatWindow.appendChild(chatHeader);

    const chatTitle = document.createElement('div');
    chatTitle.className = 'ds-chat-title';
    chatTitle.innerText = 'Deepseek Chat';
    chatHeader.appendChild(chatTitle);

    const closeBtn = document.createElement('div');
    closeBtn.className = 'ds-chat-close';
    closeBtn.innerText = '×';
    chatHeader.appendChild(closeBtn);

    // 聊天内容区域
    const chatContent = document.createElement('div');
    chatContent.className = 'ds-chat-content';
    chatWindow.appendChild(chatContent);

    // 输入区域
    const inputArea = document.createElement('div');
    inputArea.className = 'ds-chat-input-area';
    chatWindow.appendChild(inputArea);

    // 添加网页上下文开关
    const contextToggle = document.createElement('div');
    contextToggle.className = 'ds-context-toggle';
    inputArea.appendChild(contextToggle);

    const contextCheckbox = document.createElement('input');
    contextCheckbox.type = 'checkbox';
    contextCheckbox.id = 'ds-context-checkbox';
    contextCheckbox.checked = config.usePageContext;
    contextToggle.appendChild(contextCheckbox);

    const contextLabel = document.createElement('label');
    contextLabel.htmlFor = 'ds-context-checkbox';
    contextLabel.innerText = '包含当前网页内容';
    contextToggle.appendChild(contextLabel);

    const contextSummary = document.createElement('div');
    contextSummary.className = 'ds-context-summary';
    contextSummary.innerText = '当前网页: ' + document.title;
    inputArea.appendChild(contextSummary);

    const inputBox = document.createElement('textarea');
    inputBox.className = 'ds-chat-input';
    inputBox.placeholder = '输入你的问题...';
    inputBox.rows = 3;
    inputArea.appendChild(inputBox);

    const settingsArea = document.createElement('div');
    settingsArea.className = 'ds-chat-settings';
    inputArea.appendChild(settingsArea);

    const settingsBtn = document.createElement('span');
    settingsBtn.className = 'ds-chat-settings-btn';
    settingsBtn.innerText = '⚙️';
    settingsArea.appendChild(settingsBtn);

    const clearBtn = document.createElement('span');
    clearBtn.className = 'ds-chat-settings-btn';
    clearBtn.innerText = '🗑️';
    settingsArea.appendChild(clearBtn);

    // 显示历史消息
    function displayHistory() {
        chatContent.innerHTML = '';
        config.chatHistory.forEach(msg => {
            const msgDiv = document.createElement('div');
            msgDiv.className = `ds-chat-message ds-${msg.role}-message`;
            msgDiv.innerText = msg.content;
            chatContent.appendChild(msgDiv);
        });
        chatContent.scrollTop = chatContent.scrollHeight;
    }

    // 初始化显示历史消息
    displayHistory();

    // 图标点击事件
    icon.addEventListener('click', () => {
        chatWindow.classList.toggle('active');
        icon.style.display = 'none';
    });

    // 关闭按钮事件
    closeBtn.addEventListener('click', () => {
        chatWindow.classList.remove('active');
        icon.style.display = 'flex';
    });

    // 上下文开关事件
    contextCheckbox.addEventListener('change', () => {
        config.usePageContext = contextCheckbox.checked;
        GM_setValue('usePageContext', config.usePageContext);
    });

    // 设置按钮事件
    settingsBtn.addEventListener('click', () => {
        const newApiKey = prompt('DeepSeek API密钥:', config.apiKey);
        if (newApiKey !== null) {
            config.apiKey = newApiKey;
            GM_setValue('apiKey', config.apiKey);
        }

        const newModel = prompt('模型 (deepseek-chat, deepseek-coder等):', config.model);
        if (newModel !== null) {
            config.model = newModel;
            GM_setValue('model', config.model);
        }

        const newTemp = parseFloat(prompt('Temperature (0-2):', config.temperature));
        if (!isNaN(newTemp) && newTemp >= 0 && newTemp <= 2) {
            config.temperature = newTemp;
            GM_setValue('temperature', config.temperature);
        }

        const newMaxTokens = parseInt(prompt('最大令牌数:', config.maxTokens));
        if (!isNaN(newMaxTokens) && newMaxTokens > 0) {
            config.maxTokens = newMaxTokens;
            GM_setValue('maxTokens', config.maxTokens);
        }

        // 新增:自定义人格提示词设置
        const newPersonalityPrompt = prompt('自定义人格提示词(例如性格、外貌、说话风格等):', config.personalityPrompt);
        if (newPersonalityPrompt !== null) {
            config.personalityPrompt = newPersonalityPrompt;
            GM_setValue('personalityPrompt', config.personalityPrompt);
        }
    });

    // 清空历史按钮事件
    clearBtn.addEventListener('click', () => {
        config.chatHistory = [];
        GM_setValue('chatHistory', config.chatHistory);
        chatContent.innerHTML = '';
    });

    // 获取网页主要内容
    function getPageContent() {
        const mainContent = document.querySelector('main, article, .main, .content, #content') || document.body;
        const clone = mainContent.cloneNode(true);
        const elementsToRemove = clone.querySelectorAll('script, style, noscript, iframe, nav, footer, header, aside');
        elementsToRemove.forEach(el => el.remove());
        let text = clone.textContent
            .replace(/\s+/g, ' ')
            .trim()
            .substring(0, 5000);
        return {
            url: window.location.href,
            title: document.title,
            content: text
        };
    }

    // 获取网页HTML内容
    function getPageHTML() {
        const mainContent = document.querySelector('main, article, .main, .content, #content') || document.body;
        const clone = mainContent.cloneNode(true);
        const elementsToRemove = clone.querySelectorAll('script, style, noscript, iframe, nav, footer, header, aside');
        elementsToRemove.forEach(el => el.remove());
        return clone.innerHTML;
    }

    // 获取网页图片名称
    function getImageNames() {
        const images = document.querySelectorAll('img');
        const imageNames = [];
        images.forEach(img => {
            const src = img.src;
            const name = src.split('/').pop();
            imageNames.push(name);
        });
        return imageNames.join(', ');
    }

    // 调整对话框宽度
    function adjustChatWindowWidth(text) {
        const chatWindow = document.querySelector('.ds-chat-window');
        const maxWidth = window.innerWidth * 0.4;
        const minWidth = 350;
        const textLength = text.length;
        let newWidth = minWidth + (textLength * 5);
        newWidth = Math.min(newWidth, maxWidth);
        chatWindow.style.width = `${newWidth}px`;
    }

    // 逐行显示AI回答
    function typeMessage(message, container) {
        const lines = message.split('\n');
        let index = 0;
        const interval = setInterval(() => {
            if (index < lines.length) {
                const line = document.createElement('div');
                line.innerText = lines[index];
                container.appendChild(line);
                chatContent.scrollTop = chatContent.scrollHeight;
                index++;
            } else {
                clearInterval(interval);
            }
        }, 200);
    }

    // 发送消息函数
    function sendMessage(message) {
        if (!message.trim()) return;

        if (!config.apiKey) {
            alert('请先设置API密钥!');
            settingsBtn.click();
            return;
        }

        let finalMessage = message;
        if (config.usePageContext) {
            const pageContent = getPageContent();
            const pageHTML = getPageHTML();
            const imageNames = getImageNames();
            finalMessage = `[当前网页信息]
标题: ${pageContent.title}
URL: ${pageContent.url}
内容摘要: ${pageContent.content}
HTML内容: ${pageHTML}
图片名称: ${imageNames}

基于以上网页内容,请回答以下问题:
${message}`;
        }

        const userMsg = { role: 'user', content: message };
        config.chatHistory.push(userMsg);
        GM_setValue('chatHistory', config.chatHistory);

        const userMsgDiv = document.createElement('div');
        userMsgDiv.className = 'ds-chat-message ds-user-message';
        userMsgDiv.innerText = message;
        chatContent.appendChild(userMsgDiv);

        const thinkingMsgDiv = document.createElement('div');
        thinkingMsgDiv.className = 'ds-chat-message ds-thinking';
        thinkingMsgDiv.innerText = '思考中...';
        chatContent.appendChild(thinkingMsgDiv);

        chatContent.scrollTop = chatContent.scrollHeight;

        const requestData = {
            model: config.model,
            messages: [
                { role: 'system', content: config.personalityPrompt }, // 使用自定义人格提示词
                ...config.chatHistory.map(msg => ({
                    role: msg.role,
                    content: msg.role === 'user' && config.usePageContext ? finalMessage : msg.content
                }))
            ],
            temperature: config.temperature,
            max_tokens: config.maxTokens
        };

        GM_xmlhttpRequest({
            method: 'POST',
            url: 'https://api.deepseek.com/v1/chat/completions',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${config.apiKey}`
            },
            data: JSON.stringify(requestData),
            onload: function(response) {
                try {
                    const data = JSON.parse(response.responseText);
                    if (data.choices && data.choices[0]) {
                        const aiMessage = data.choices[0].message.content;
                        chatContent.removeChild(thinkingMsgDiv);
                        const aiMsg = { role: 'assistant', content: aiMessage };
                        config.chatHistory.push(aiMsg);
                        GM_setValue('chatHistory', config.chatHistory);
                        const aiMsgDiv = document.createElement('div');
                        aiMsgDiv.className = 'ds-chat-message ds-ai-message';
                        typeMessage(aiMessage, aiMsgDiv);
                        chatContent.appendChild(aiMsgDiv);
                        adjustChatWindowWidth(aiMessage); // 调整对话框宽度
                    } else {
                        throw new Error('无效的API响应');
                    }
                } catch (e) {
                    showError(`错误: ${e.message}`);
                }
                chatContent.scrollTop = chatContent.scrollHeight;
            },
            onerror: function(error) {
                showError(`请求失败: ${error.statusText || '网络错误'}`);
            }
        });
    }

    // 显示错误消息
    function showError(message) {
        const errorMsgDiv = document.createElement('div');
        errorMsgDiv.className = 'ds-chat-message ds-error';
        errorMsgDiv.innerText = message;
        chatContent.appendChild(errorMsgDiv);
        chatContent.scrollTop = chatContent.scrollHeight;
    }

    // 输入框事件
    inputBox.addEventListener('keydown', (e) => {
        if (e.key === 'Enter' && !e.shiftKey) {
            e.preventDefault();
            const message = inputBox.value.trim();
            if (message) {
                sendMessage(message);
                inputBox.value = '';
            }
        }
    });

    // 注册菜单命令
    GM_registerMenuCommand("设置DeepSeek API", () => settingsBtn.click());
    GM_registerMenuCommand("清空聊天历史", () => clearBtn.click());
    GM_registerMenuCommand("切换网页上下文", () => {
        contextCheckbox.checked = !contextCheckbox.checked;
        config.usePageContext = contextCheckbox.checked;
        GM_setValue('usePageContext', config.usePageContext);
    });
    GM_registerMenuCommand("设置自定义人格提示词", () => {
        const newPersonalityPrompt = prompt('请输入自定义人格提示词:', config.personalityPrompt);
        if (newPersonalityPrompt !== null) {
            config.personalityPrompt = newPersonalityPrompt;
            GM_setValue('personalityPrompt', config.personalityPrompt);
        }
    });
})();