diff --git a/src/lib/components/chat/FileNav/FilePreview.svelte b/src/lib/components/chat/FileNav/FilePreview.svelte index 2b9ac9cdbd..6aba5da66a 100644 --- a/src/lib/components/chat/FileNav/FilePreview.svelte +++ b/src/lib/components/chat/FileNav/FilePreview.svelte @@ -19,14 +19,60 @@ export let onDownload: () => void = () => {}; const MD_EXTS = new Set(['md', 'markdown', 'mdx']); + const CSV_EXTS = new Set(['csv', 'tsv']); const getExt = (path: string | null) => path?.split('.').pop()?.toLowerCase() ?? ''; $: isMarkdown = MD_EXTS.has(getExt(selectedFile)); + $: isCsv = CSV_EXTS.has(getExt(selectedFile)); + $: csvDelimiter = getExt(selectedFile) === 'tsv' ? '\t' : ','; $: renderedHtml = isMarkdown && fileContent ? DOMPurify.sanitize(marked.parse(fileContent, { async: false }) as string) : ''; + // Simple CSV parser that handles quoted fields + const parseCsv = (text: string, delimiter: string): string[][] => { + const rows: string[][] = []; + let row: string[] = []; + let field = ''; + let inQuotes = false; + for (let i = 0; i < text.length; i++) { + const ch = text[i]; + if (inQuotes) { + if (ch === '"') { + if (text[i + 1] === '"') { + field += '"'; + i++; + } else { + inQuotes = false; + } + } else { + field += ch; + } + } else if (ch === '"') { + inQuotes = true; + } else if (ch === delimiter) { + row.push(field); + field = ''; + } else if (ch === '\n' || (ch === '\r' && text[i + 1] === '\n')) { + if (ch === '\r') i++; + row.push(field); + field = ''; + if (row.some((c) => c !== '')) rows.push(row); + row = []; + } else { + field += ch; + } + } + row.push(field); + if (row.some((c) => c !== '')) rows.push(row); + return rows; + }; + + $: csvRows = isCsv && fileContent ? parseCsv(fileContent, csvDelimiter) : []; + $: csvHeader = csvRows.length > 0 ? csvRows[0] : []; + $: csvBody = csvRows.length > 1 ? csvRows.slice(1) : []; + let showRaw = false; $: selectedFile, (showRaw = false); // reset to preview mode when switching files @@ -77,7 +123,7 @@ {/if} - {#if isMarkdown && fileContent !== null} + {#if (isMarkdown || isCsv) && fileContent !== null}