ChatGPT 导出聊天为 Markdown (.md)

在 ChatGPT 单个对话页面添加导出按钮,将聊天记录导出为 Markdown 文件

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         ChatGPT 导出聊天为 Markdown (.md)
// @namespace    https://chat.openai.com/
// @version      1.0
// @description  在 ChatGPT 单个对话页面添加导出按钮,将聊天记录导出为 Markdown 文件
// @author       GPT
// @match        https://chatgpt.com/*
// @grant        none
// @license            MIT
// ==/UserScript==

(function () {
    'use strict';

    // 等待元素加载完毕
    function waitForElement(selector, callback) {
        const el = document.querySelector(selector);
        if (el) {
            callback(el);
        } else {
            setTimeout(() => waitForElement(selector, callback), 500);
        }
    }

    // 提取聊天记录
    function extractChatToMarkdown() {
        const messages = document.querySelectorAll('[data-message-author-role]');
        let md = '# ChatGPT 对话记录\n\n';

        messages.forEach((msg) => {
            const role = msg.getAttribute('data-message-author-role');
            let content = msg.textContent.trim();

            if (!content) return;

            if (role === 'user') {
                md += `\n\n## 🧑 用户提问\n\n${content}\n`;
            } else if (role === 'assistant') {
                // 检查是否含代码块
                const preTags = msg.querySelectorAll('pre');
                if (preTags.length > 0) {
                    preTags.forEach((pre) => {
                        const code = pre.textContent.trim();
                        content = content.replace(code, `\n\`\`\`\n${code}\n\`\`\`\n`);
                    });
                }
                md += `\n\n## 🤖 ChatGPT 回答\n\n${content}\n`;
            }
        });

        return md;
    }

    // 创建按钮
    function createExportButton() {
        const btn = document.createElement('button');
        btn.innerText = '📄 导出为 Markdown';
        btn.style.position = 'fixed';
        btn.style.bottom = '20px';
        btn.style.right = '20px';
        btn.style.zIndex = '9999';
        btn.style.padding = '10px 15px';
        btn.style.backgroundColor = '#10a37f';
        btn.style.color = '#fff';
        btn.style.border = 'none';
        btn.style.borderRadius = '8px';
        btn.style.cursor = 'pointer';
        btn.style.boxShadow = '0 2px 10px rgba(0,0,0,0.2)';
        btn.style.fontSize = '14px';

        btn.onclick = () => {
            const mdContent = extractChatToMarkdown();
            const blob = new Blob([mdContent], { type: 'text/markdown;charset=utf-8' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;

            const timestamp = new Date().toISOString().slice(0, 19).replace(/[:T]/g, '-');
            a.download = `ChatGPT-导出-${timestamp}.md`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        };

        document.body.appendChild(btn);
    }

    waitForElement('main', createExportButton);
})();