元宝 & DeepSeek 对话导出工具 | Yuanbao & DeepSeek Chat Exporter

支持元宝和 DeepSeek 对话导出,支持 JSON 和 Markdown 格式。Export Yuanbao and DeepSeek chat history with JSON and Markdown formats.

// ==UserScript==
// @name         元宝 & DeepSeek 对话导出工具 | Yuanbao & DeepSeek Chat Exporter
// @namespace    http://tampermonkey.net/
// @version      1.0.7
// @description  支持元宝和 DeepSeek 对话导出,支持 JSON 和 Markdown 格式。Export Yuanbao and DeepSeek chat history with JSON and Markdown formats.
// @author       dst1213
// @license      MIT
// @match        https://yuanbao.tencent.com/chat/*
// @match        https://*.deepseek.com/a/chat/s/*
// @grant        none
// ==/UserScript==
 
(function () {
    'use strict';
 
    let state = {
        targetResponse: null,
        lastUpdateTime: null,
        convertedMd: null,
        isYuanbao: window.location.href.includes('yuanbao.tencent.com'),
        isDeepSeek: window.location.href.includes('deepseek.com')
    };
 
    const log = {
        info: (msg) => console.log(`[Chat Exporter] ${msg}`),
        error: (msg, e) => console.error(`[Chat Exporter] ${msg}`, e)
    };
 
    function processTargetResponse() {
        try {
            if (state.isYuanbao) {
                const messages = extractYuanbaoMessages();
                if (messages.length > 0) {
                    state.targetResponse = JSON.stringify({ messages }, null, 2);
                    state.lastUpdateTime = new Date().toLocaleTimeString();
                    state.convertedMd = convertJsonToMd({ messages });
                    updateButtonStatus();
                    log.info('成功提取元宝对话内容');
                }
            } else if (state.isDeepSeek) {
                // DeepSeek 的逻辑保持不变
                // ...
            }
        } catch (e) {
            log.error('处理对话内容时出错:', e);
        }
    }
 
    function extractYuanbaoMessages() {
        const messages = [];
        const messageElements = document.querySelectorAll('.agent-chat__list__item');
        messageElements.forEach(el => {
            const role = el.classList.contains('agent-chat__list__item--human') ? 'human' : 'ai';
            const content = el.querySelector('.hyc-content-text, .hyc-content-md')?.innerText || '';
            messages.push({ role, content });
        });
        return messages;
    }
 
    function convertJsonToMd(data) {
        let mdContent = [];
        if (state.isYuanbao) {
            data.messages.forEach(msg => {
                const role = msg.role === 'human' ? 'Human' : 'Assistant';
                mdContent.push(`### ${role}`);
                mdContent.push(msg.content + '\n');
            });
        } else if (state.isDeepSeek) {
            // DeepSeek 的逻辑保持不变
            // ...
        }
        return mdContent.join('\n');
    }
 
    function updateButtonStatus() {
        const jsonButton = document.getElementById('downloadJsonButton');
        const mdButton = document.getElementById('downloadMdButton');
        if (jsonButton && mdButton) {
            const hasResponse = state.targetResponse !== null;
            jsonButton.style.backgroundColor = hasResponse ? '#28a745' : '#007bff';
            mdButton.style.backgroundColor = state.convertedMd ? '#28a745' : '#007bff';
            const statusText = hasResponse ? `最后更新: ${state.lastUpdateTime}\n数据已准备好` : '等待目标响应中...';
            jsonButton.title = statusText;
            mdButton.title = statusText;
        }
    }
 
    function createDownloadButtons() {
        const buttonContainer = document.createElement('div');
        const jsonButton = document.createElement('button');
        const mdButton = document.createElement('button');
 
        Object.assign(buttonContainer.style, {
            position: 'fixed',
            top: '45%',
            right: '10px',
            zIndex: '9999',
            display: 'flex',
            flexDirection: 'column',
            gap: '10px',
            opacity: '0.5',
            transition: 'opacity 0.3s ease',
            cursor: 'move'
        });
 
        const buttonStyles = {
            padding: '8px 12px',
            backgroundColor: '#007bff',
            color: '#ffffff',
            border: 'none',
            borderRadius: '5px',
            cursor: 'pointer',
            transition: 'all 0.3s ease',
            fontFamily: 'Arial, sans-serif',
            boxShadow: '0 2px 5px rgba(0,0,0,0.2)',
            whiteSpace: 'nowrap',
            fontSize: '14px'
        };
 
        jsonButton.id = 'downloadJsonButton';
        jsonButton.innerText = 'JSON';
        mdButton.id = 'downloadMdButton';
        mdButton.innerText = 'MD';
 
        Object.assign(jsonButton.style, buttonStyles);
        Object.assign(mdButton.style, buttonStyles);
 
        buttonContainer.onmouseenter = () => buttonContainer.style.opacity = '1';
        buttonContainer.onmouseleave = () => buttonContainer.style.opacity = '0.5';
 
        let isDragging = false;
        let currentX;
        let currentY;
        let initialX;
        let initialY;
        let xOffset = 0;
        let yOffset = 0;
 
        buttonContainer.onmousedown = dragStart;
        document.onmousemove = drag;
        document.onmouseup = dragEnd;
 
        function dragStart(e) {
            initialX = e.clientX - xOffset;
            initialY = e.clientY - yOffset;
            if (e.target === buttonContainer) {
                isDragging = true;
            }
        }
 
        function drag(e) {
            if (isDragging) {
                e.preventDefault();
                currentX = e.clientX - initialX;
                currentY = e.clientY - initialY;
                xOffset = currentX;
                yOffset = currentY;
                setTranslate(currentX, currentY, buttonContainer);
            }
        }
 
        function dragEnd() {
            isDragging = false;
        }
 
        function setTranslate(xPos, yPos, el) {
            el.style.transform = `translate(${xPos}px, ${yPos}px)`;
        }
 
        jsonButton.onclick = function () {
            if (!state.targetResponse) {
                alert('还没有发现有效的对话记录。\n请等待目标响应或进行一些对话。');
                return;
            }
            try {
                const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
                const chatName = state.isYuanbao ? `Yuanbao - Chat` : `DeepSeek - Chat`;
                const fileName = `${chatName}_${timestamp}.json`;
 
                const blob = new Blob([state.targetResponse], { type: 'application/json' });
                const link = document.createElement('a');
                link.href = URL.createObjectURL(blob);
                link.download = fileName;
                link.click();
 
                log.info(`成功下载文件: ${fileName}`);
            } catch (e) {
                log.error('下载过程中出错:', e);
                alert('下载过程中发生错误,请查看控制台了解详情。');
            }
        };
 
        mdButton.onclick = function () {
            if (!state.convertedMd) {
                alert('还没有发现有效的对话记录。\n请等待目标响应或进行一些对话。');
                return;
            }
            try {
                const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
                const chatName = state.isYuanbao ? `Yuanbao - Chat` : `DeepSeek - Chat`;
                const fileName = `${chatName}_${timestamp}.md`;
 
                const blob = new Blob([state.convertedMd], { type: 'text/markdown' });
                const link = document.createElement('a');
                link.href = URL.createObjectURL(blob);
                link.download = fileName;
                link.click();
 
                log.info(`成功下载文件: ${fileName}`);
            } catch (e) {
                log.error('下载过程中出错:', e);
                alert('下载过程中发生错误,请查看控制台了解详情。');
            }
        };
 
        buttonContainer.appendChild(jsonButton);
        buttonContainer.appendChild(mdButton);
        document.body.appendChild(buttonContainer);
 
        updateButtonStatus();
    }
 
    window.addEventListener('load', function () {
        createDownloadButtons();
 
        const observer = new MutationObserver(() => {
            processTargetResponse();
        });
 
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
 
        log.info('对话导出脚本已启动');
    });
})();

QingJ © 2025

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