-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathutils.js
More file actions
134 lines (110 loc) · 3.74 KB
/
utils.js
File metadata and controls
134 lines (110 loc) · 3.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// 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