DeepSeek API聊天

在任意网站上添加 DeepSeek 聊天窗口:窗口默认隐藏,仅通过快捷键 Ctrl+Alt+D 显示;通过官方API 输入,支持聊天、历史记录管理、新对话、模型切换与记忆功能。API 输出支持 Markdown 渲染。

当前为 2025-03-22 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         DeepSeek API聊天
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  在任意网站上添加 DeepSeek 聊天窗口:窗口默认隐藏,仅通过快捷键 Ctrl+Alt+D 显示;通过官方API 输入,支持聊天、历史记录管理、新对话、模型切换与记忆功能。API 输出支持 Markdown 渲染。
// @author       AMT
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

// 加载 marked 库用于 Markdown 渲染(若尚未加载)
(function loadMarked(callback) {
    if (typeof marked !== 'undefined') {
        if(callback) callback();
    } else {
        let script = document.createElement('script');
        script.src = "https://cdn.jsdelivr.net/npm/marked/marked.min.js";
        script.onload = function() {
            if(callback) callback();
        };
        document.head.appendChild(script);
    }
})();

(function() {
    'use strict';

    /***************** 全局变量与存储 *****************/
    let apiKey = GM_getValue('deepseek_api', '');
    // 内部仍使用完整模型名用于 API 调用,但按钮显示简写
    let currentModel = "deepseek-chat";
    const modelDisplay = {
        "deepseek-chat": "Chat",
        "deepseek-reasoner": "Reasoner"
    };
    let memoryEnabled = false;  // 记忆功能状态
    // 聊天历史记录:数组,每个会话记录包含 id、messages(数组)和 timestamp
    let chatHistory = JSON.parse(GM_getValue('deepseek_history', '[]'));
    // 当前会话记录
    let currentSession = [];
    let currentSessionId = Date.now();
    let isSending = false; // 是否正在等待 API 响应

    // 保存当前会话到历史记录
    function saveCurrentSession() {
        if (currentSession.length > 0) {
            let idx = chatHistory.findIndex(s => s.id === currentSessionId);
            const sessionRecord = {
                id: currentSessionId,
                messages: currentSession,
                timestamp: new Date().toLocaleString()
            };
            if (idx === -1) {
                chatHistory.push(sessionRecord);
            } else {
                chatHistory[idx] = sessionRecord;
            }
            GM_setValue('deepseek_history', JSON.stringify(chatHistory));
        }
    }

    // 加载指定历史记录作为当前会话
    function loadSession(sessionRecord) {
        currentSession = sessionRecord.messages;
        currentSessionId = sessionRecord.id;
        renderConversation();
    }

    /***************** 主窗口与UI *****************/
    // 创建主聊天窗口容器(背景深灰色)
    const chatContainer = document.createElement('div');
    chatContainer.id = 'deepseek-chat-ui';
    chatContainer.style.position = 'fixed';
    chatContainer.style.right = '0';
    chatContainer.style.top = '50%';
    chatContainer.style.transform = 'translateY(-50%)';
    chatContainer.style.width = apiKey ? '35vw':'15vw';
    // API 未输入时高度约16.67vh,输入后为75vh
    chatContainer.style.height = apiKey ? '75vh' : '16.67vh';
    chatContainer.style.backgroundColor = '#333';
    chatContainer.style.borderRadius = '10px';
    chatContainer.style.boxShadow = '0 2px 8px rgba(0,0,0,0.2)';
    chatContainer.style.zIndex = '9999';
    chatContainer.style.transition = 'opacity 0.3s, transform 0.3s';
    // 默认隐藏(仅通过快捷键显示)
    chatContainer.style.opacity = '0';
    document.body.appendChild(chatContainer);
    // 阻止窗口内部点击冒泡,同时若历史记录面板打开且点击区域不在面板内,则关闭历史记录面板
    chatContainer.addEventListener('click', (e) => {
        e.stopPropagation();
        if(historyPanel && !historyPanel.contains(e.target)) { hideHistoryPanel(); }
    });

    // 内部主内容区域
    const contentDiv = document.createElement('div');
    contentDiv.style.width = '100%';
    contentDiv.style.height = '100%';
    contentDiv.style.display = 'flex';
    contentDiv.style.flexDirection = 'column';
    contentDiv.style.boxSizing = 'border-box';
    contentDiv.style.color = 'white';
    contentDiv.style.padding = '1em';
    chatContainer.appendChild(contentDiv);

    /***************** 历史记录面板 *****************/
    let historyPanel;  // 历史记录面板引用
    function showHistoryPanel() {
        if(historyPanel) return;
        historyPanel = document.createElement('div');
        historyPanel.id = 'history-panel';
        historyPanel.style.zIndex = '10000';  // 最高图层
        // 与主窗口同高,宽度为主窗口的 40%
        historyPanel.style.position = 'absolute';
        historyPanel.style.left = '0';
        historyPanel.style.top = '0';
        historyPanel.style.height = '100%';
        historyPanel.style.width = '40%';
        historyPanel.style.backgroundColor = '#222';  // 更深的灰色
        historyPanel.style.borderTopLeftRadius = '10px';
        historyPanel.style.borderBottomLeftRadius = '10px';
        historyPanel.style.overflowY = 'auto';
        historyPanel.style.padding = '0.5em';
        historyPanel.style.boxSizing = 'border-box';
        // 头部:包含【返回】按钮、标题、【清空所有】按钮
        const header = document.createElement('div');
        header.style.display = 'flex';
        header.style.justifyContent = 'space-between';
        header.style.alignItems = 'center';
        header.style.marginBottom = '0.5em';
        const backBtn = document.createElement('button');
        backBtn.innerText = '返回';
        backBtn.style.fontSize = '1em';
        backBtn.style.padding = '0.2em 0.5em';
        backBtn.style.border = '1px solid white';
        backBtn.style.borderRadius = '10px';
        backBtn.style.backgroundColor = '#444';
        backBtn.style.color = 'white';
        backBtn.style.cursor = 'pointer';
        backBtn.addEventListener('click', () => { hideHistoryPanel(); });
        header.appendChild(backBtn);
        const title = document.createElement('span');
        title.innerText = '聊天历史';
        header.appendChild(title);
        const clearBtn = document.createElement('button');
        clearBtn.innerText = '清空所有';
        clearBtn.style.fontSize = '1em';
        clearBtn.style.padding = '0.2em 0.5em';
        clearBtn.style.border = '1px solid white';
        clearBtn.style.borderRadius = '10px';
        clearBtn.style.backgroundColor = '#444';
        clearBtn.style.color = 'white';
        clearBtn.style.cursor = 'pointer';
        clearBtn.addEventListener('click', () => {
            if(confirm("确定清空所有聊天记录吗?")) {
                chatHistory = [];
                GM_setValue('deepseek_history', JSON.stringify(chatHistory));
                renderHistoryPanel();
                // 同时清空当前会话
                currentSession = [];
                currentSessionId = Date.now();
                if(conversationDiv) { conversationDiv.innerHTML = ''; }
            }
        });
        header.appendChild(clearBtn);
        historyPanel.appendChild(header);
        renderHistoryPanel();
        chatContainer.appendChild(historyPanel);
    }
    function hideHistoryPanel() {
        if(historyPanel && historyPanel.parentNode) {
            chatContainer.removeChild(historyPanel);
            historyPanel = null;
        }
    }
    // 渲染历史记录列表
    function renderHistoryPanel() {
        if(!historyPanel) return;
        while(historyPanel.childNodes.length > 1) {
            historyPanel.removeChild(historyPanel.lastChild);
        }
        chatHistory.forEach(session => {
            const item = document.createElement('div');
            let summary = session.timestamp;
            if(session.messages.length > 0) {
                const firstMsg = session.messages.find(m => m.role === 'user');
                if(firstMsg) {
                    summary += " - " + firstMsg.content.substring(0, 20) + "...";
                }
            }
            item.innerText = summary;
            item.style.padding = '0.3em';
            item.style.borderBottom = '1px solid #666';
            item.style.cursor = 'pointer';
            item.addEventListener('click', () => {
                loadSession(session);
                renderConversation();
                hideHistoryPanel();
            });
            // 右键删除该记录,若为当前会话则同时清空对话区
            item.addEventListener('contextmenu', (e) => {
                e.preventDefault();
                if(confirm("删除该聊天记录?")) {
                    if(session.id === currentSessionId) {
                        currentSession = [];
                        currentSessionId = Date.now();
                        if(conversationDiv) { conversationDiv.innerHTML = ''; }
                    }
                    chatHistory = chatHistory.filter(s => s.id !== session.id);
                    GM_setValue('deepseek_history', JSON.stringify(chatHistory));
                    renderHistoryPanel();
                }
            });
            historyPanel.appendChild(item);
        });
    }

    /***************** 对话区与输入区 *****************/
    let conversationDiv; // 对话显示区引用
    let messageInput;    // 文本输入框引用

    // 渲染对话区(加载当前会话记录)
    function renderConversation() {
        if(!conversationDiv) return;
        conversationDiv.innerHTML = '';
        currentSession.forEach(msgObj => {
            // 仅显示消息内容,不显示角色前缀
            addChatBubble(msgObj.role === 'user', msgObj.content);
        });
    }

    // 添加聊天气泡,支持 Markdown 渲染,并强制字体为黑色
    function addChatBubble(isUser, text) {
        const bubble = document.createElement('div');
        bubble.style.padding = '0.5em';
        bubble.style.borderRadius = '10px';
        bubble.style.maxWidth = '70%';
        bubble.style.wordWrap = 'break-word';
        bubble.style.fontSize = '1.2em';
        if(isUser) {
            bubble.style.backgroundColor = '#E6E6FA';
            bubble.style.color = 'black';
            bubble.style.alignSelf = 'flex-end';
            bubble.innerText = text;
        } else {
            bubble.style.backgroundColor = '#D3D3D3';
            bubble.style.color = 'black';
            bubble.style.alignSelf = 'flex-start';
            if(typeof marked !== 'undefined') {
                bubble.innerHTML = marked.parse(text);
                // 强制所有内部元素字体颜色为黑色
                const elems = bubble.querySelectorAll("*");
                elems.forEach(el => { el.style.color = 'black'; });
            } else {
                bubble.innerText = text;
            }
        }
        conversationDiv.appendChild(bubble);
        conversationDiv.scrollTop = conversationDiv.scrollHeight;
    }

    /***************** 渲染整个界面 *****************/
    function renderUI() {
        contentDiv.innerHTML = '';

        if (!apiKey) {
            // API 输入界面
            const promptText = document.createElement('div');
            promptText.innerText = 'DeepSeek';
            promptText.style.textAlign = 'center';
            promptText.style.fontSize = '2em';
            promptText.style.marginBottom = '0.5em';
            contentDiv.appendChild(promptText);

            const apiInput = document.createElement('input');
            apiInput.type = 'text';
            apiInput.placeholder = '请输入api key';
            apiInput.style.width = '100%';
            apiInput.style.fontSize = '1.5em';
            apiInput.style.padding = '0.5em';
            apiInput.style.boxSizing = 'border-box';
            apiInput.style.borderRadius = '10px';
            apiInput.style.border = '1px solid white';
            apiInput.style.backgroundColor = '#444';
            apiInput.style.color = 'white';
            apiInput.style.marginBottom = '0.5em';
            contentDiv.appendChild(apiInput);

            const confirmBtn = document.createElement('button');
            confirmBtn.innerText = '确认';
            confirmBtn.style.width = '100%';
            confirmBtn.style.fontSize = '1.5em';
            confirmBtn.style.padding = '0.5em';
            confirmBtn.style.borderRadius = '10px';
            confirmBtn.style.border = '1px solid white';
            confirmBtn.style.backgroundColor = '#444';
            confirmBtn.style.color = 'white';
            confirmBtn.style.cursor = 'pointer';
            contentDiv.appendChild(confirmBtn);

            confirmBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                const value = apiInput.value.trim();
                if (value) {
                    apiKey = value;
                    GM_setValue('deepseek_api', apiKey);
                    chatContainer.style.height = '75vh';
                    chatContainer.style.width = '35vw';
                    // 初始化当前会话
                    currentSession = [];
                    currentSessionId = Date.now();
                    renderUI();
                }
            });
        } else {
            // 聊天界面
            // 头部区域:左侧放【历史记录】和【开启新对话】按钮,右侧【重新输入api】按钮
            const headerDiv = document.createElement('div');
            headerDiv.style.display = 'flex';
            headerDiv.style.justifyContent = 'space-between';
            headerDiv.style.alignItems = 'center';
            headerDiv.style.marginBottom = '0.5em';
            contentDiv.appendChild(headerDiv);

            const leftHeader = document.createElement('div');
            leftHeader.style.display = 'flex';
            leftHeader.style.gap = '0.5em';
            headerDiv.appendChild(leftHeader);

            const historyBtn = document.createElement('button');
            historyBtn.innerText = '历史记录';
            historyBtn.style.fontSize = '1em';
            historyBtn.style.padding = '0.3em';
            historyBtn.style.borderRadius = '10px';
            historyBtn.style.border = '1px solid white';
            historyBtn.style.backgroundColor = '#444';
            historyBtn.style.color = 'white';
            historyBtn.style.cursor = 'pointer';
            historyBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                if(historyPanel) {
                    hideHistoryPanel();
                } else {
                    showHistoryPanel();
                }
            });
            leftHeader.appendChild(historyBtn);

            const newConvBtn = document.createElement('button');
            newConvBtn.innerText = '开启新对话';
            newConvBtn.style.fontSize = '1em';
            newConvBtn.style.padding = '0.3em';
            newConvBtn.style.borderRadius = '10px';
            newConvBtn.style.border = '1px solid white';
            newConvBtn.style.backgroundColor = '#444';
            newConvBtn.style.color = 'white';
            newConvBtn.style.cursor = 'pointer';
            newConvBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                saveCurrentSession();
                currentSession = [];
                currentSessionId = Date.now();
                if(conversationDiv) { conversationDiv.innerHTML = ''; }
            });
            leftHeader.appendChild(newConvBtn);

            const reenterBtn = document.createElement('button');
            reenterBtn.innerText = '重新输入api';
            reenterBtn.style.fontSize = '1em';
            reenterBtn.style.padding = '0.3em';
            reenterBtn.style.borderRadius = '10px';
            reenterBtn.style.border = '1px solid white';
            reenterBtn.style.backgroundColor = '#444';
            reenterBtn.style.color = 'white';
            reenterBtn.style.cursor = 'pointer';
            reenterBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                hideHistoryPanel();  // 关闭历史记录面板
                saveCurrentSession();
                apiKey = '';
                GM_setValue('deepseek_api', '');
                chatContainer.style.height = '16.67vh';
                chatContainer.style.width = '15vw';
                renderUI();
            });
            headerDiv.appendChild(reenterBtn);

            // 对话显示区
            conversationDiv = document.createElement('div');
            conversationDiv.style.flex = '1';
            conversationDiv.style.overflowY = 'auto';
            conversationDiv.style.marginBottom = '0.5em';
            conversationDiv.style.padding = '0.5em';
            conversationDiv.style.boxSizing = 'border-box';
            conversationDiv.style.backgroundColor = '#333';
            conversationDiv.style.display = 'flex';
            conversationDiv.style.flexDirection = 'column';
            conversationDiv.style.gap = '0.5em';
            contentDiv.appendChild(conversationDiv);
            renderConversation();

            // 输入区域(固定在底部,内嵌按钮)
            const inputContainer = document.createElement('div');
            inputContainer.style.position = 'relative';
            inputContainer.style.width = '100%';
            inputContainer.style.boxSizing = 'border-box';
            inputContainer.style.height = '10vh';
            contentDiv.appendChild(inputContainer);

            // 文本输入框(固定底部,向上扩展,最大20vh)
            messageInput = document.createElement('textarea');
            messageInput.placeholder = '给deepseek发送消息';
            messageInput.style.position = 'absolute';
            messageInput.style.left = '0';
            messageInput.style.right = '0';
            messageInput.style.bottom = '0';
            messageInput.style.height = '10vh';
            // 内边距:上0.5em,右预留6em(两个按钮),下预留3em(按钮区域),左0.5em
            messageInput.style.padding = '0.5em 6em 3em 0.5em';
            messageInput.style.fontSize = '1.2em';
            messageInput.style.boxSizing = 'border-box';
            messageInput.style.borderRadius = '10px';
            messageInput.style.border = '1px solid white';
            messageInput.style.backgroundColor = '#444';
            messageInput.style.color = 'white';
            messageInput.style.overflowY = 'hidden';
            messageInput.style.resize = 'none';
            inputContainer.appendChild(messageInput);
            // 添加一个覆盖在底部按钮区域的遮罩层,防止文本显示在按钮所在区域
            const inputOverlay = document.createElement('div');
            inputOverlay.style.position = 'absolute';
            inputOverlay.style.left = '0.5em';
            inputOverlay.style.right = '1.2em';
            inputOverlay.style.bottom = '0.1em';
            inputOverlay.style.height = '3em';
            inputOverlay.style.backgroundColor = '#444';
            inputOverlay.style.pointerEvents = 'none';
            inputContainer.appendChild(inputOverlay);

            function autoResize() {
                const initialHeight = window.innerHeight * 0.10;
                messageInput.style.height = 'auto';
                let newHeight = messageInput.scrollHeight;
                if (newHeight < initialHeight) newHeight = initialHeight;
                const maxHeight = window.innerHeight * 0.25;
                if (newHeight > maxHeight) {
                    inputContainer.style.height = messageInput.style.height = maxHeight + 'px';
                    messageInput.style.overflowY = 'auto';
                } else {
                    inputContainer.style.height = messageInput.style.height = newHeight + 'px';
                    messageInput.style.overflowY = 'hidden';
                }
            }
            messageInput.addEventListener('input', autoResize);

            // 输入区域内按钮——均固定在底部,与文本框底部间隔约1px
            // 模型切换按钮(左下角)——显示简写
            const modelBtn = document.createElement('button');
            modelBtn.innerText = "深度思考R1";
            modelBtn.style.position = 'absolute';
            modelBtn.style.left = '0.5em';
            modelBtn.style.bottom = '0.5em';
            modelBtn.style.width = '8em';
            modelBtn.style.height = '2em';
            modelBtn.style.fontSize = '1em';
            modelBtn.style.lineHeight = '2em';
            modelBtn.style.textAlign = 'center';
            modelBtn.style.borderRadius = '10px';
            modelBtn.style.border = '1px solid white';
            modelBtn.style.backgroundColor = '#444';
            modelBtn.style.color = 'white';
            modelBtn.style.cursor = 'pointer';
            modelBtn.style.zIndex = '10';
            modelBtn.addEventListener('click', () => {
                currentModel = (currentModel === 'deepseek-chat' ? 'deepseek-reasoner' : 'deepseek-chat');
                // 修改为普通蓝色 (#87CEFA)
                modelBtn.style.backgroundColor = currentModel === 'deepseek-reasoner' ? '#87CEFA' : '#444';
            });
            inputContainer.appendChild(modelBtn);

            // “记忆”按钮
            const memoryBtn = document.createElement('button');
            memoryBtn.innerText = '记忆';
            memoryBtn.style.position = 'absolute';
            memoryBtn.style.left = '9em';
            memoryBtn.style.bottom = '0.5em';
            memoryBtn.style.width = '3em';
            memoryBtn.style.height = '2em';
            memoryBtn.style.fontSize = '1em';
            memoryBtn.style.lineHeight = '2em';
            memoryBtn.style.textAlign = 'center';
            memoryBtn.style.borderRadius = '10px';
            memoryBtn.style.border = '1px solid white';
            memoryBtn.style.backgroundColor = memoryEnabled ? '#87CEFA' : '#444';
            memoryBtn.style.color = 'white';
            memoryBtn.style.cursor = 'pointer';
            memoryBtn.style.zIndex = '10';
            memoryBtn.addEventListener('click', () => {
                memoryEnabled = !memoryEnabled;
                memoryBtn.style.backgroundColor = memoryEnabled ? '#87CEFA' : '#444';
            });
            inputContainer.appendChild(memoryBtn);

            // 发送按钮(右下角)
            const sendBtn = document.createElement('button');
            sendBtn.innerText = '发送';
            sendBtn.style.position = 'absolute';
            sendBtn.style.right = '1.2em';
            sendBtn.style.bottom = '0.5em';
            sendBtn.style.width = '3em';
            sendBtn.style.height = '2em';
            sendBtn.style.fontSize = '1em';
            sendBtn.style.lineHeight = '2em';
            sendBtn.style.textAlign = 'center';
            sendBtn.style.borderRadius = '10px';
            sendBtn.style.border = '1px solid white';
            sendBtn.style.backgroundColor = '#444';
            sendBtn.style.color = 'white';
            sendBtn.style.cursor = 'pointer';
            sendBtn.style.zIndex = '10';
            inputContainer.appendChild(sendBtn);

            // 发送消息函数
            async function sendMessage() {
                if (isSending) return; // 避免重复发送
                isSending = true;
                messageInput.disabled = true;
                sendBtn.disabled = true;
                const msg = messageInput.value.trim();
                if (!msg) return;
                addChatBubble(true, msg);
                currentSession.push({ role: "user", content: msg });
                saveCurrentSession();
                messageInput.value = '';
                autoResize();
                const waitingBubble = document.createElement('div');
                waitingBubble.innerText = '思考中...';
                waitingBubble.style.padding = '0.5em';
                waitingBubble.style.borderRadius = '10px';
                waitingBubble.style.maxWidth = '70%';
                waitingBubble.style.backgroundColor = '#D3D3D3';
                waitingBubble.style.color = 'black';
                waitingBubble.style.alignSelf = 'flex-start';
                conversationDiv.appendChild(waitingBubble);
                conversationDiv.scrollTop = conversationDiv.scrollHeight;
                try {
                    let messagesPayload = [
                        { role: "system", content: "You are a helpful assistant." }
                    ];
                    if(memoryEnabled && currentSession.length > 0) {
                        messagesPayload = messagesPayload.concat(currentSession);
                    }
                    if(!memoryEnabled) {
                        messagesPayload.push({ role: "user", content: msg });
                    }
                    const response = await fetch('https://api.deepseek.com/chat/completions', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'Authorization': 'Bearer ' + apiKey
                        },
                        body: JSON.stringify({
                            messages: messagesPayload,
                            model: currentModel
                        })
                    });
                    const data = await response.json();
                    conversationDiv.removeChild(waitingBubble);
                    if (data && data.choices && data.choices[0] && data.choices[0].message) {
                        const reply = data.choices[0].message.content;
                        addChatBubble(false, reply);
                        currentSession.push({ role: "assistant", content: reply });
                        saveCurrentSession();
                    } else {
                        addChatBubble(false, '无回复或返回格式错误');
                    }
                } catch (err) {
                    conversationDiv.removeChild(waitingBubble);
                    addChatBubble(false, '调用API错误: ' + err);
                }
                isSending = false;
                messageInput.disabled = false;
                sendBtn.disabled = false;
                conversationDiv.scrollTop = conversationDiv.scrollHeight;
            }
            sendBtn.addEventListener('click', sendMessage);
            messageInput.addEventListener('keydown', (e) => {
                if (e.key === 'Enter' && !e.shiftKey) {
                    e.preventDefault();
                    if (!isSending) sendMessage();
                }
            });
        }
    }

    renderUI();

    /***************** 显示与隐藏窗口 *****************/
    // 使用快捷键 Ctrl+Alt+D 显示窗口
    document.addEventListener('keydown', (e) => {
        if (e.ctrlKey && e.altKey && e.key.toLowerCase() === 'd') {
            chatContainer.style.opacity = '1';
            e.stopPropagation();
        }
    });
    // 点击窗口外部时隐藏窗口及历史记录面板
    document.addEventListener('click', () => {
        chatContainer.style.opacity = '0';
        hideHistoryPanel();
    });
})();