diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-02-12 20:57:17 +0100 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-02-12 20:57:17 +0100 |
| commit | b333b06772c89d96aacb5490d6a219fba7c09cc6 (patch) | |
| tree | 211df60083a5946baa2ed61d33d8121b7e251b06 /llama.cpp/tools/server/webui/src/lib/utils/process-uploaded-files.ts | |
| download | llmnpc-b333b06772c89d96aacb5490d6a219fba7c09cc6.tar.gz | |
Engage!
Diffstat (limited to 'llama.cpp/tools/server/webui/src/lib/utils/process-uploaded-files.ts')
| -rw-r--r-- | llama.cpp/tools/server/webui/src/lib/utils/process-uploaded-files.ts | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/llama.cpp/tools/server/webui/src/lib/utils/process-uploaded-files.ts b/llama.cpp/tools/server/webui/src/lib/utils/process-uploaded-files.ts new file mode 100644 index 0000000..0342dce --- /dev/null +++ b/llama.cpp/tools/server/webui/src/lib/utils/process-uploaded-files.ts @@ -0,0 +1,136 @@ +import { isSvgMimeType, svgBase64UrlToPngDataURL } from './svg-to-png'; +import { isWebpMimeType, webpBase64UrlToPngDataURL } from './webp-to-png'; +import { FileTypeCategory } from '$lib/enums'; +import { modelsStore } from '$lib/stores/models.svelte'; +import { settingsStore } from '$lib/stores/settings.svelte'; +import { toast } from 'svelte-sonner'; +import { getFileTypeCategory } from '$lib/utils'; +import { convertPDFToText } from './pdf-processing'; + +/** + * Read a file as a data URL (base64 encoded) + * @param file - The file to read + * @returns Promise resolving to the data URL string + */ +function readFileAsDataURL(file: File): Promise<string> { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result as string); + reader.onerror = () => reject(reader.error); + reader.readAsDataURL(file); + }); +} + +/** + * Read a file as UTF-8 text + * @param file - The file to read + * @returns Promise resolving to the text content + */ +function readFileAsUTF8(file: File): Promise<string> { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result as string); + reader.onerror = () => reject(reader.error); + reader.readAsText(file); + }); +} + +/** + * Process uploaded files into ChatUploadedFile format with previews and content + * + * This function processes various file types and generates appropriate previews: + * - Images: Base64 data URLs with format normalization (SVG/WebP → PNG) + * - Text files: UTF-8 content extraction + * - PDFs: Metadata only (processed later in conversion pipeline) + * - Audio: Base64 data URLs for preview + * + * @param files - Array of File objects to process + * @returns Promise resolving to array of ChatUploadedFile objects + */ +export async function processFilesToChatUploaded( + files: File[], + activeModelId?: string +): Promise<ChatUploadedFile[]> { + const results: ChatUploadedFile[] = []; + + for (const file of files) { + const id = Date.now().toString() + Math.random().toString(36).substr(2, 9); + const base: ChatUploadedFile = { + id, + name: file.name, + size: file.size, + type: file.type, + file + }; + + try { + if (getFileTypeCategory(file.type) === FileTypeCategory.IMAGE) { + let preview = await readFileAsDataURL(file); + + // Normalize SVG and WebP to PNG in previews + if (isSvgMimeType(file.type)) { + try { + preview = await svgBase64UrlToPngDataURL(preview); + } catch (err) { + console.error('Failed to convert SVG to PNG:', err); + } + } else if (isWebpMimeType(file.type)) { + try { + preview = await webpBase64UrlToPngDataURL(preview); + } catch (err) { + console.error('Failed to convert WebP to PNG:', err); + } + } + + results.push({ ...base, preview }); + } else if (getFileTypeCategory(file.type) === FileTypeCategory.PDF) { + // Extract text content from PDF for preview + try { + const textContent = await convertPDFToText(file); + results.push({ ...base, textContent }); + } catch (err) { + console.warn('Failed to extract text from PDF, adding without content:', err); + results.push(base); + } + + // Show suggestion toast if vision model is available but PDF as image is disabled + const hasVisionSupport = activeModelId + ? modelsStore.modelSupportsVision(activeModelId) + : false; + const currentConfig = settingsStore.config; + if (hasVisionSupport && !currentConfig.pdfAsImage) { + toast.info(`You can enable parsing PDF as images with vision models.`, { + duration: 8000, + action: { + label: 'Enable PDF as Images', + onClick: () => { + settingsStore.updateConfig('pdfAsImage', true); + toast.success('PDF parsing as images enabled!', { + duration: 3000 + }); + } + } + }); + } + } else if (getFileTypeCategory(file.type) === FileTypeCategory.AUDIO) { + // Generate preview URL for audio files + const preview = await readFileAsDataURL(file); + results.push({ ...base, preview }); + } else { + // Fallback: treat unknown files as text + try { + const textContent = await readFileAsUTF8(file); + results.push({ ...base, textContent }); + } catch (err) { + console.warn('Failed to read file as text, adding without content:', err); + results.push(base); + } + } + } catch (error) { + console.error('Error processing file', file.name, error); + results.push(base); + } + } + + return results; +} |
