char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Aleksander Grygierui: Stores architecture improvements (#26910)094e53db1

char/aliceai-t5-moe
2.9 KiB109 linesraw
1/**
2 * File upload lifecycle for the ChatScreen form.
3 *
4 * Owns the queue of processed `ChatUploadedFile`, the rejection-by-capability
5 * dialog state, and the dual-layer validation pipeline (general format +
6 * model modality). The caller provides the active model's capabilities and ID
7 * as reactive getters so validation tracks the model in real time.
8 */
9
10import { filterFilesByModalities, isFileTypeSupported } from '$lib/utils';
11import { processFilesToChatUploaded } from '$lib/utils/browser-only';
12
13interface UseChatScreenFileUploadOptions {
14	capabilities: () => { hasVision: boolean; hasAudio: boolean; hasVideo: boolean };
15	activeModelId: () => string | null | undefined;
16}
17
18export interface FileErrorData {
19	generallyUnsupported: File[];
20	modalityUnsupported: File[];
21	modalityReasons: Record<string, string>;
22	supportedTypes: string[];
23}
24
25export function useChatScreenFileUpload(options: UseChatScreenFileUploadOptions) {
26	let uploadedFiles = $state<ChatUploadedFile[]>([]);
27	let showFileErrorDialog = $state(false);
28	let fileErrorData = $state<FileErrorData>({
29		generallyUnsupported: [],
30		modalityReasons: {},
31		modalityUnsupported: [],
32		supportedTypes: []
33	});
34
35	async function processFiles(files: File[]) {
36		const generallySupported: File[] = [];
37		const generallyUnsupported: File[] = [];
38
39		for (const file of files) {
40			if (isFileTypeSupported(file.name, file.type)) {
41				generallySupported.push(file);
42			} else {
43				generallyUnsupported.push(file);
44			}
45		}
46
47		const { modalityReasons, supportedFiles, unsupportedFiles } = filterFilesByModalities(
48			generallySupported,
49			options.capabilities()
50		);
51		const allUnsupportedFiles = [...generallyUnsupported, ...unsupportedFiles];
52
53		if (allUnsupportedFiles.length > 0) {
54			const supportedTypes: string[] = ['text files', 'PDFs'];
55			const caps = options.capabilities();
56
57			if (caps.hasVision) supportedTypes.push('images');
58
59			if (caps.hasAudio) supportedTypes.push('audio files');
60
61			if (caps.hasVideo) supportedTypes.push('video files');
62
63			fileErrorData = {
64				generallyUnsupported,
65				modalityReasons,
66				modalityUnsupported: unsupportedFiles,
67				supportedTypes
68			};
69			showFileErrorDialog = true;
70		}
71
72		if (supportedFiles.length > 0) {
73			const processed = await processFilesToChatUploaded(
74				supportedFiles,
75				options.activeModelId() ?? undefined
76			);
77
78			uploadedFiles = [...uploadedFiles, ...processed];
79		}
80	}
81
82	function handleFileUpload(files: File[]) {
83		return processFiles(files);
84	}
85
86	function handleFileRemove(fileId: string) {
87		uploadedFiles = uploadedFiles.filter((f) => f.id !== fileId);
88	}
89
90	return {
91		get fileErrorData() {
92			return fileErrorData;
93		},
94		handleFileRemove,
95		handleFileUpload,
96		get showFileErrorDialog() {
97			return showFileErrorDialog;
98		},
99		set showFileErrorDialog(value) {
100			showFileErrorDialog = value;
101		},
102		get uploadedFiles() {
103			return uploadedFiles;
104		},
105		set uploadedFiles(value) {
106			uploadedFiles = value;
107		}
108	};
109}