File size: 5,394 Bytes
4d35814
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/**
 * File validation utilities based on model modalities
 * Ensures only compatible file types are processed based on model capabilities
 */

import { getFileTypeCategory } from '$lib/utils/file-type';
import { supportsVision, supportsAudio } from '$lib/stores/server.svelte';
import {
	FileExtensionAudio,
	FileExtensionImage,
	FileExtensionPdf,
	FileExtensionText,
	MimeTypeAudio,
	MimeTypeImage,
	MimeTypeApplication,
	MimeTypeText,
	FileTypeCategory
} from '$lib/enums/files';

/**
 * Check if a file type is supported by the current model's modalities
 * @param filename - The filename to check
 * @param mimeType - The MIME type of the file
 * @returns true if the file type is supported by the current model
 */
export function isFileTypeSupportedByModel(filename: string, mimeType?: string): boolean {
	const category = mimeType ? getFileTypeCategory(mimeType) : null;

	// If we can't determine the category from MIME type, fall back to general support check
	if (!category) {
		// For unknown types, only allow if they might be text files
		// This is a conservative approach for edge cases
		return true; // Let the existing isFileTypeSupported handle this
	}

	switch (category) {
		case FileTypeCategory.TEXT:
			// Text files are always supported
			return true;

		case FileTypeCategory.PDF:
			// PDFs are always supported (will be processed as text for non-vision models)
			return true;

		case FileTypeCategory.IMAGE:
			// Images require vision support
			return supportsVision();

		case FileTypeCategory.AUDIO:
			// Audio files require audio support
			return supportsAudio();

		default:
			// Unknown categories - be conservative and allow
			return true;
	}
}

/**
 * Filter files based on model modalities and return supported/unsupported lists
 * @param files - Array of files to filter
 * @returns Object with supportedFiles and unsupportedFiles arrays
 */
export function filterFilesByModalities(files: File[]): {
	supportedFiles: File[];
	unsupportedFiles: File[];
	modalityReasons: Record<string, string>;
} {
	const supportedFiles: File[] = [];
	const unsupportedFiles: File[] = [];
	const modalityReasons: Record<string, string> = {};

	const hasVision = supportsVision();
	const hasAudio = supportsAudio();

	for (const file of files) {
		const category = getFileTypeCategory(file.type);
		let isSupported = true;
		let reason = '';

		switch (category) {
			case FileTypeCategory.IMAGE:
				if (!hasVision) {
					isSupported = false;
					reason = 'Images require a vision-capable model';
				}
				break;

			case FileTypeCategory.AUDIO:
				if (!hasAudio) {
					isSupported = false;
					reason = 'Audio files require an audio-capable model';
				}
				break;

			case FileTypeCategory.TEXT:
			case FileTypeCategory.PDF:
				// Always supported
				break;

			default:
				// For unknown types, check if it's a generally supported file type
				// This handles edge cases and maintains backward compatibility
				break;
		}

		if (isSupported) {
			supportedFiles.push(file);
		} else {
			unsupportedFiles.push(file);
			modalityReasons[file.name] = reason;
		}
	}

	return { supportedFiles, unsupportedFiles, modalityReasons };
}

/**
 * Generate a user-friendly error message for unsupported files
 * @param unsupportedFiles - Array of unsupported files
 * @param modalityReasons - Reasons why files are unsupported
 * @returns Formatted error message
 */
export function generateModalityErrorMessage(
	unsupportedFiles: File[],
	modalityReasons: Record<string, string>
): string {
	if (unsupportedFiles.length === 0) return '';

	const hasVision = supportsVision();
	const hasAudio = supportsAudio();

	let message = '';

	if (unsupportedFiles.length === 1) {
		const file = unsupportedFiles[0];
		const reason = modalityReasons[file.name];
		message = `The file "${file.name}" cannot be uploaded: ${reason}.`;
	} else {
		const fileNames = unsupportedFiles.map((f) => f.name).join(', ');
		message = `The following files cannot be uploaded: ${fileNames}.`;
	}

	// Add helpful information about what is supported
	const supportedTypes: string[] = ['text files', 'PDFs'];
	if (hasVision) supportedTypes.push('images');
	if (hasAudio) supportedTypes.push('audio files');

	message += ` This model supports: ${supportedTypes.join(', ')}.`;

	return message;
}

/**
 * Generate file input accept string based on current model modalities
 * @returns Accept string for HTML file input element
 */
export function generateModalityAwareAcceptString(): string {
	const hasVision = supportsVision();
	const hasAudio = supportsAudio();

	const acceptedExtensions: string[] = [];
	const acceptedMimeTypes: string[] = [];

	// Always include text files and PDFs
	acceptedExtensions.push(...Object.values(FileExtensionText));
	acceptedMimeTypes.push(...Object.values(MimeTypeText));
	acceptedExtensions.push(...Object.values(FileExtensionPdf));
	acceptedMimeTypes.push(...Object.values(MimeTypeApplication));

	// Include images only if vision is supported
	if (hasVision) {
		acceptedExtensions.push(...Object.values(FileExtensionImage));
		acceptedMimeTypes.push(...Object.values(MimeTypeImage));
	}

	// Include audio only if audio is supported
	if (hasAudio) {
		acceptedExtensions.push(...Object.values(FileExtensionAudio));
		acceptedMimeTypes.push(...Object.values(MimeTypeAudio));
	}

	return [...acceptedExtensions, ...acceptedMimeTypes].join(',');
}