/* * exporters.ts * Zyquo Cloud Web * * Author: Simon-Pierre Boucher * Mail: contact@spboucher.ai * * Single-conversation exports (Markdown / JSON) and the all-data backup * download — client-side file downloads, no server. */ import { exportAll } from '../storage/backup' import type { Conversation } from '../types' function download(filename: string, content: string, type: string): void { const blob = new Blob([content], { type }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = filename a.click() URL.revokeObjectURL(url) } function safeName(title: string): string { return title.replace(/[/\\:*?"<>|]/g, '-').slice(0, 80) } export function exportConversationMarkdown(conversation: Conversation): void { const lines: string[] = [`# ${conversation.title}`, ''] lines.push(`*Model: ${conversation.modelID} (${conversation.provider})*`, '') if (conversation.systemPrompt) { lines.push(`> **System:** ${conversation.systemPrompt}`, '') } for (const message of conversation.messages) { const label = message.role === 'user' ? '**You**' : `**Assistant** (${message.modelID ?? ''})` lines.push(`${label}:`, '', message.text, '') if (message.citations && message.citations.length > 0) { lines.push( ...message.citations.map((c) => `[${c.index}]: ${c.url}${c.title ? ` "${c.title}"` : ''}`), '' ) } } download(`${safeName(conversation.title)}.md`, lines.join('\n'), 'text/markdown') } export function exportConversationJSON(conversation: Conversation): void { download( `${safeName(conversation.title)}.json`, JSON.stringify(conversation, null, 2), 'application/json' ) } export async function downloadBackup(includeKeys: boolean): Promise { const data = await exportAll(includeKeys) const stamp = new Date().toISOString().slice(0, 10) download(`zyquo-cloud-backup-${stamp}.json`, JSON.stringify(data, null, 2), 'application/json') }