135 lines
3.7 KiB
JavaScript
135 lines
3.7 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
|
|
let humanSeen = false;
|
|
let assistantSeen = false;
|
|
|
|
branchMessages.forEach((message) => {
|
|
// 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 full label on first occurrence, then abbreviate
|
|
let senderLabel;
|
|
if (message.sender === 'human') {
|
|
senderLabel = humanSeen ? 'H' : 'Human';
|
|
humanSeen = true;
|
|
} else {
|
|
senderLabel = assistantSeen ? 'A' : 'Assistant';
|
|
assistantSeen = true;
|
|
}
|
|
|
|
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
|