Greasy Fork

Greasy Fork is available in English.

Deepseek Chat Assistant Plus

增强版Deepseek API对话助手,支持历史记录和更多参数设置

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

// ==UserScript==
// @name         Deepseek Chat Assistant Plus
// @namespace    shy
// @version      1.1
// @description  增强版Deepseek API对话助手,支持历史记录和更多参数设置
// @author       shy
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_xmlhttpRequest
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @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: #007bff;
            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.1);
            transition: transform 0.2s, box-shadow 0.2s;
            z-index: 9999;
        }
        .ds-chat-icon:hover {
            transform: scale(1.05);
            box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
        }
        .ds-chat-window {
            position: fixed;
            bottom: 80px;
            right: 20px;
            width: 350px;
            height: 450px;
            background-color: #f9f9f9;
            border: 1px solid #ddd;
            border-radius: 15px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
            display: none;
            flex-direction: column;
            overflow: hidden;
            transition: opacity 0.3s, transform 0.3s;
            opacity: 0;
            transform: translateY(20px);
            z-index: 9998;
        }
        .ds-chat-window.active {
            display: flex;
            opacity: 1;
            transform: translateY(0);
        }
        .ds-chat-header {
            padding: 10px 15px;
            background-color: #007bff;
            color: white;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .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: #fff;
            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: #e3f2fd;
            margin-left: 20%;
        }
        .ds-ai-message {
            background-color: #f1f1f1;
            margin-right: 20%;
        }
        .ds-chat-input-area {
            padding: 10px;
            display: flex;
            flex-direction: column;
        }
        .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;
        }
    `);

    // 初始化配置
    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', [])
    };

    // 创建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 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');
    });

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

    // 设置按钮事件
    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);
        }
    });

    // 清空历史按钮事件
    clearBtn.addEventListener('click', () => {
        if (confirm('确定要清空聊天历史吗?')) {
            config.chatHistory = [];
            GM_setValue('chatHistory', config.chatHistory);
            chatContent.innerHTML = '';
        }
    });

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

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

        // 添加用户消息到历史和UI
        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);

        // 添加AI思考中的提示
        const thinkingMsgDiv = document.createElement('div');
        thinkingMsgDiv.className = 'ds-chat-message ds-thinking';
        thinkingMsgDiv.innerText = '思考中...';
        chatContent.appendChild(thinkingMsgDiv);

        chatContent.scrollTop = chatContent.scrollHeight;

        // 准备API请求数据
        const requestData = {
            model: config.model,
            messages: config.chatHistory,
            temperature: config.temperature,
            max_tokens: config.maxTokens
        };

        // 发送API请求
        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);

                        // 添加AI响应到历史和UI
                        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';
                        aiMsgDiv.innerText = aiMessage;
                        chatContent.appendChild(aiMsgDiv);
                    } 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());
})();