char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
521a64cd0
char/aliceai-t5-moe
1import { heicFileToJpegDataURL , isHeicMimeType } from './heic-to-jpeg' ; 2import { convertPDFToText } from './pdf-processing' ; 3import { isSvgMimeType , svgBase64UrlToPngDataURL } from './svg-to-png' ; 4import { isWebpMimeType , webpBase64UrlToPngDataURL } from './webp-to-png' ; 5import { SETTINGS_KEYS } from '$lib/constants' ; 6import { FileTypeCategory } from '$lib/enums' ; 7import { modelsStore } from '$lib/stores/models/index.svelte' ; 8import { settingsStore } from '$lib/stores/settings/index.svelte' ; 9import { getFileTypeCategory } from '$lib/utils' ; 10import { toast } from 'svelte-sonner' ; 11 12/** 13* Read a file as a data URL (base64 encoded) 14* @param file - The file to read 15* @returns Promise resolving to the data URL string 16*/ 17function readFileAsDataURL ( file :File ) :Promise < string > { 18return new Promise (( resolve , reject ) => { 19const reader = new FileReader (); 20 21reader . onload = () => resolve ( reader . result as string ); 22reader . onerror = () => reject ( reader . error ); 23reader . readAsDataURL ( file ); 24}); 25} 26 27/** 28* Read a file as UTF-8 text 29* @param file - The file to read 30* @returns Promise resolving to the text content 31*/ 32function readFileAsUTF8 ( file :File ) :Promise < string > { 33return new Promise (( resolve , reject ) => { 34const reader = new FileReader (); 35 36reader . onload = () => resolve ( reader . result as string ); 37reader . onerror = () => reject ( reader . error ); 38reader . readAsText ( file ); 39}); 40} 41 42/** 43* Process uploaded files into ChatUploadedFile format with previews and content 44* 45* This function processes various file types and generates appropriate previews: 46* - Images: Base64 data URLs with format normalization (SVG/WebP → PNG) 47* - Text files: UTF-8 content extraction 48* - PDFs: Metadata only (processed later in conversion pipeline) 49* - Audio: Base64 data URLs for preview 50* 51* @param files - Array of File objects to process 52* @returns Promise resolving to array of ChatUploadedFile objects 53*/ 54export async function processFilesToChatUploaded ( 55files :File [], 56activeModelId ?:string 57) :Promise < ChatUploadedFile []> { 58const results :ChatUploadedFile [] = []; 59 60for ( const file of files ) { 61const id = Date . now (). toString () + Math . random (). toString ( 36 ). substr ( 2 , 9 ); 62const base :ChatUploadedFile = { 63 file, 64 id, 65name :file . name , 66size :file . size , 67type :file . type 68}; 69 70try { 71if ( getFileTypeCategory ( file . type ) === FileTypeCategory . IMAGE ) { 72let preview = await readFileAsDataURL ( file ); 73 74// Normalize SVG and WebP to PNG, and HEIC to compressed JPEG, in previews 75if ( isSvgMimeType ( file . type )) { 76try { 77preview = await svgBase64UrlToPngDataURL ( preview ); 78} catch ( err ) { 79console . error ( 'Failed to convert SVG to PNG:' , err ); 80} 81} else if ( isWebpMimeType ( file . type )) { 82try { 83preview = await webpBase64UrlToPngDataURL ( preview ); 84} catch ( err ) { 85console . error ( 'Failed to convert WebP to PNG:' , err ); 86} 87} else if ( isHeicMimeType ( file . type )) { 88try { 89preview = await heicFileToJpegDataURL ( file ); 90} catch ( err ) { 91console . error ( 'Failed to convert HEIC to PNG:' , err ); 92 93continue ; 94} 95} 96 97results . push ({ ...base , preview}); 98} else if ( getFileTypeCategory ( file . type ) === FileTypeCategory . ) { 99// Extract text content from PDF for preview 100try { 101const textContent = await convertPDFToText ( file ); 102 103results . push ({ ...base , textContent}); 104} catch ( err ) { 105console . warn ( 'Failed to extract text from PDF, adding without content:' , err ); 106results . push ( base ); 107} 108 109// Show suggestion toast if vision model is available but PDF as image is disabled 110const hasVisionSupport = activeModelId 111 ?modelsStore . props . modelSupportsVision ( activeModelId ) 112 :false ; 113const currentConfig = settingsStore . config ; 114 115if ( hasVisionSupport && ! currentConfig . pdfAsImage ) { 116toast . info ( `You can enable parsing PDF as images with vision models.` , { 117action :{ 118label :'Enable PDF as Images' , 119onClick :() => { 120settingsStore . updateConfig ( SETTINGS_KEYS . PDF_AS_IMAGE , true ); 121toast . success ( 'PDF parsing as images enabled!' , { 122duration :3000 123}); 124} 125}, 126duration :8000 127}); 128} 129} else if ( getFileTypeCategory ( file . type ) === FileTypeCategory . AUDIO ) { 130// Generate preview URL for audio files 131const preview = await readFileAsDataURL ( file ); 132 133results . push ({ ...base , preview}); 134} else if ( getFileTypeCategory ( file . type ) === FileTypeCategory . VIDEO ) { 135// Generate preview URL for video files 136const preview = await readFileAsDataURL ( file ); 137 138results . push ({ ...base , preview}); 139} else { 140// Fallback: treat unknown files as text 141try { 142const textContent = await readFileAsUTF8 ( file ); 143 144results . push ({ ...base , textContent}); 145} catch ( err ) { 146console . warn ( 'Failed to read file as text, adding without content:' , err ); 147results . push ( base ); 148} 149} 150} catch ( error ) { 151console . error ( 'Error processing file' , file . name , error ); 152results . push ( base ); 153} 154} 155 156return results ; 157}