80 lines
2.6 KiB
TypeScript
80 lines
2.6 KiB
TypeScript
/**
|
|
* Chat export utilities — JSON file download & Markdown clipboard copy
|
|
*/
|
|
|
|
import { toast } from 'sonner';
|
|
import type { ChatMessage } from './types';
|
|
import type { LogEntry } from '@/contexts/LogContext';
|
|
|
|
export function exportChatAsJson(
|
|
messages: ChatMessage[],
|
|
chatLogs: LogEntry[],
|
|
provider: string,
|
|
model: string,
|
|
systemPrompt: string,
|
|
) {
|
|
const exportData = {
|
|
exported_at: new Date().toISOString(),
|
|
model: `${provider}/${model}`,
|
|
system_prompt: systemPrompt,
|
|
messages: messages.map(m => ({
|
|
role: m.role,
|
|
content: m.content,
|
|
timestamp: m.timestamp,
|
|
...(m.images?.length ? { images: m.images.map(img => img.url) } : {}),
|
|
...(m.toolName ? { tool: m.toolName } : {}),
|
|
})),
|
|
logs: chatLogs.map(l => ({
|
|
level: l.level,
|
|
message: l.message,
|
|
timestamp: l.timestamp.toISOString(),
|
|
})),
|
|
};
|
|
const json = JSON.stringify(exportData, null, 2);
|
|
|
|
// Copy to clipboard
|
|
navigator.clipboard.writeText(json).catch(() => { });
|
|
|
|
// Download file
|
|
const blob = new Blob([json], { type: 'application/json' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = `chat-${new Date().toISOString().slice(0, 16).replace(/:/g, '-')}.json`;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
toast.success('Chat exported as JSON (also copied to clipboard)');
|
|
}
|
|
|
|
export function exportChatAsMarkdown(
|
|
messages: ChatMessage[],
|
|
provider: string,
|
|
model: string,
|
|
systemPrompt: string,
|
|
) {
|
|
const lines: string[] = [
|
|
`# Chat Export`,
|
|
`> ${provider}/${model} — ${new Date().toLocaleString()}`,
|
|
'',
|
|
];
|
|
if (systemPrompt) {
|
|
lines.push('## System Prompt', '', systemPrompt, '');
|
|
}
|
|
lines.push('---', '');
|
|
for (const m of messages) {
|
|
const ts = new Date(m.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
const role = m.role === 'user' ? '🧑 User' : m.role === 'tool' ? `🔧 ${m.toolName || 'Tool'}` : '🤖 Assistant';
|
|
lines.push(`### ${role} \`${ts}\``, '');
|
|
if (m.content) lines.push(m.content, '');
|
|
if (m.images?.length) {
|
|
for (const img of m.images) {
|
|
lines.push(``, '');
|
|
}
|
|
}
|
|
lines.push('---', '');
|
|
}
|
|
navigator.clipboard.writeText(lines.join('\n')).then(() => {
|
|
toast.success('Chat copied as Markdown');
|
|
});
|
|
}
|