Claude.ai Chat Exporter (Updated)

Adds "Export Chat" button to Claude.ai (current as of Sonnet 3.7)

// ==UserScript==
// @name         Claude.ai Chat Exporter (Updated)
// @description  Adds "Export Chat" button to Claude.ai (current as of Sonnet 3.7)
// @version      1.1
// @author       Merlin McKean 
// @namespace    
// @match        https://claude.ai/*
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const API_BASE_URL = 'https://claude.ai/api';

    // Updated function to make API requests with new headers
    function apiRequest(method, endpoint, data = null) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: method,
                url: `${API_BASE_URL}${endpoint}`,
                headers: {
                    'Content-Type': 'application/json',
                    'Accept': 'application/json',
                    // Add any required authentication headers here
                },
                data: data ? JSON.stringify(data) : null,
                onload: (response) => {
                    if (response.status >= 200 && response.status < 300) {
                        resolve(JSON.parse(response.responseText));
                    } else {
                        reject(new Error(`API request failed with status ${response.status}`));
                    }
                },
                onerror: (error) => {
                    reject(error);
                },
            });
        });
    }

    // Function to get the organization ID - updated for new API
    async function getOrganizationId() {
        try {
            const organizations = await apiRequest('GET', '/organizations');
            return organizations[0]?.uuid;
        } catch (error) {
            console.error('Error getting organization ID:', error);
            throw error;
        }
    }

    // Updated function to get conversation history
    async function getConversationHistory(orgId, chatId) {
        return await apiRequest('GET', `/organizations/${orgId}/chat_conversations/${chatId}`);
    }

    // Function to download data as a file
    function downloadData(data, filename, format) {
        let content = '';
        if (format === 'json') {
            content = JSON.stringify(data, null, 2);
        } else if (format === 'txt') {
            content = convertToTxtFormat(data);
        }

        const blob = new Blob([content], { type: 'text/plain' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = filename;
        a.style.display = 'none';
        document.body.appendChild(a);
        a.click();

        setTimeout(() => {
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        }, 100);
    }

    // Updated function to convert conversation data to TXT format
    function convertToTxtFormat(data) {
        let txtContent = `Chat Title: ${data.name}\nDate: ${new Date().toISOString()}\n\n`;
        data.chat_messages.forEach((message) => {
            const sender = message.sender === 'human' ? 'User' : 'Claude';
            txtContent += `${sender}:\n${message.text}\n\n`;
        });
        return txtContent.trim();
    }

    // Updated function to create a modern-styled button
    function createButton(text, onClick) {
        const button = document.createElement('button');
        button.textContent = text;
        button.style.cssText = `
            position: fixed;
            bottom: 80px;
            right: 20px;
            padding: 10px 20px;
            background-color: #4a5568;
            color: white;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
            z-index: 9999;
            font-family: system-ui, -apple-system, sans-serif;
            transition: all 0.2s;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        `;

        button.addEventListener('mouseover', () => {
            button.style.backgroundColor = '#2d3748';
        });

        button.addEventListener('mouseout', () => {
            button.style.backgroundColor = '#4a5568';
        });

        button.addEventListener('click', onClick);
        document.body.appendChild(button);
        return button;
    }

    // Updated function to initialize the export functionality
    async function initExportFunctionality() {
        const currentUrl = window.location.href;
        const chatIdMatch = currentUrl.match(/\/chat\/([a-f0-9-]+)/);

        if (chatIdMatch) {
            const chatId = chatIdMatch[1];
            try {
                const orgId = await getOrganizationId();
                const button = createButton('Export Chat', async () => {
                    const format = prompt('Enter export format (json or txt):', 'json');
                    if (format === 'json' || format === 'txt') {
                        try {
                            const chatData = await getConversationHistory(orgId, chatId);
                            const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
                            const filename = `claude-chat_${timestamp}.${format}`;
                            downloadData(chatData, filename, format);
                            alert(`Chat exported successfully in ${format.toUpperCase()} format!`);
                        } catch (error) {
                            alert('Error exporting chat. Please try again.');
                            console.error('Export error:', error);
                        }
                    } else {
                        alert('Invalid format. Please enter either "json" or "txt".');
                    }
                });
            } catch (error) {
                console.error('Error initializing export functionality:', error);
            }
        }
    }

    // Function to observe URL changes
    function observeUrlChanges() {
        let lastUrl = location.href;
        new MutationObserver(() => {
            const url = location.href;
            if (url !== lastUrl) {
                lastUrl = url;
                initExportFunctionality();
            }
        }).observe(document, { subtree: true, childList: true });
    }

    // Initialize the script when the page is ready
    function init() {
        initExportFunctionality();
        observeUrlChanges();
    }

    // Start the script when the DOM is fully loaded
    if (document.readyState === 'complete') {
        init();
    } else {
        window.addEventListener('load', init);
    }
})();

QingJ © 2025

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