Files
Claude-Conversation-Exporte…/utils.js
T
2025-08-23 07:05:07 -07:00

129 lines
3.8 KiB
JavaScript

// Shared utility functions for Claude Exporter
// Helper function to reconstruct the current branch from the message tree
function getCurrentBranch(data) {
if (!data.chat_messages || !data.current_leaf_message_uuid) {
return [];
}
// Create a map of UUID to message for quick lookup
const messageMap = new Map();
data.chat_messages.forEach(msg => {
messageMap.set(msg.uuid, msg);
});
// Trace back from the current leaf to the root
const branch = [];
let currentUuid = data.current_leaf_message_uuid;
while (currentUuid && messageMap.has(currentUuid)) {
const message = messageMap.get(currentUuid);
branch.unshift(message); // Add to beginning to maintain order
currentUuid = message.parent_message_uuid;
// Stop if we hit the root (parent UUID that doesn't exist in our messages)
if (!messageMap.has(currentUuid)) {
break;
}
}
return branch;
}
// Convert to markdown format
function convertToMarkdown(data, includeMetadata) {
let markdown = `# ${data.name || 'Untitled Conversation'}\n\n`;
if (includeMetadata) {
markdown += `**Created:** ${new Date(data.created_at).toLocaleString()}\n`;
markdown += `**Updated:** ${new Date(data.updated_at).toLocaleString()}\n`;
markdown += `**Model:** ${data.model}\n\n`;
markdown += '---\n\n';
}
// Get only the current branch messages
const branchMessages = getCurrentBranch(data);
for (const message of branchMessages) {
const sender = message.sender === 'human' ? '**You**' : '**Claude**';
markdown += `${sender}:\n\n`;
if (message.content) {
for (const content of message.content) {
if (content.text) {
markdown += `${content.text}\n\n`;
}
}
} else if (message.text) {
markdown += `${message.text}\n\n`;
}
if (includeMetadata && message.created_at) {
markdown += `*${new Date(message.created_at).toLocaleString()}*\n\n`;
}
markdown += '---\n\n';
}
return markdown;
}
// Convert to plain text
function convertToText(data, includeMetadata) {
let text = '';
// Add metadata header if requested
if (includeMetadata) {
text += `${data.name || 'Untitled Conversation'}\n`;
text += `Created: ${new Date(data.created_at).toLocaleString()}\n`;
text += `Updated: ${new Date(data.updated_at).toLocaleString()}\n`;
text += `Model: ${data.model}\n\n`;
text += '---\n\n';
}
// Get only the current branch messages
const branchMessages = getCurrentBranch(data);
// Use simplified format
branchMessages.forEach((message, index) => {
const sender = message.sender === 'human' ? 'Human' : 'Assistant';
// Get the message text
let messageText = '';
if (message.content) {
for (const content of message.content) {
if (content.text) {
messageText += content.text;
}
}
} else if (message.text) {
messageText = message.text;
}
// Use abbreviated format after first occurrence
const senderLabel = message.sender === 'human'
? (index === 0 || branchMessages[index - 1].sender !== 'human' ? 'Human' : 'H')
: (index === 0 || branchMessages[index - 1].sender !== 'assistant' ? 'Assistant' : 'A');
text += `${senderLabel}: ${messageText}\n\n`;
});
return text.trim();
}
// Download file utility
function downloadFile(content, filename, type = 'application/json') {
const blob = new Blob([content], { type });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
// Functions are available globally in the browser context
// No need for module.exports in browser extensions