Spaces:
Running
Running
File size: 7,111 Bytes
9bd422a | 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 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | /**
* Validators - Input and data validation utilities
* Provides functions for validating ONNX files, SafeTensors files, model data, and user inputs.
* Requirements: 3.3, 9.3, 36.1, 36.3, 36.5
*/
const Validators = (function () {
// βββ ONNX File Validation βββββββββββββββββββββββββββββββββββββββββββββββββ
/**
* ONNX protobuf magic bytes (first 2 bytes of a valid serialised protobuf
* message with field 1 = irVersion). We accept any non-empty ArrayBuffer
* whose first byte is 0x08 (field 1, wire type 0 = varint) as a minimal
* heuristic, since ONNX models always start with the irVersion field.
*
* A stricter check would require a full protobuf parse; this is intentionally
* lightweight for a browser-side static app.
*/
const ONNX_MAGIC_BYTE = 0x08;
/**
* Validate that a File object is a valid ONNX file.
* Checks:
* 1. The file has a .onnx extension (case-insensitive).
* 2. The file is not empty.
*
* @param {File} file - Browser File object
* @returns {{ valid: boolean, error?: string }}
*/
function isValidOnnxFile(file) {
if (!file) {
return { valid: false, error: 'No file provided.' };
}
// Extension check
const name = file.name || '';
if (!name.toLowerCase().endsWith('.onnx')) {
return {
valid: false,
error: `Invalid file type "${name}". Only .onnx files are accepted.`,
};
}
// Empty file check
if (file.size === 0) {
return { valid: false, error: 'The file is empty.' };
}
return { valid: true };
}
/**
* Validate the raw bytes of an ONNX file (ArrayBuffer).
* Performs a lightweight magic-byte check.
*
* @param {ArrayBuffer} buffer
* @returns {{ valid: boolean, error?: string }}
*/
function isValidOnnxBuffer(buffer) {
if (!(buffer instanceof ArrayBuffer) || buffer.byteLength === 0) {
return { valid: false, error: 'Invalid or empty buffer.' };
}
const view = new Uint8Array(buffer, 0, Math.min(4, buffer.byteLength));
if (view[0] !== ONNX_MAGIC_BYTE) {
return {
valid: false,
error: 'File does not appear to be a valid ONNX model (unexpected header bytes).',
};
}
return { valid: true };
}
// βββ SafeTensors File Validation ββββββββββββββββββββββββββββββββββββββββββββ
/**
* Validate that a File object is a valid SafeTensors file.
* Checks:
* 1. The file has a .safetensors extension (case-insensitive).
* 2. The file is not empty.
*
* @param {File} file - Browser File object
* @returns {{ valid: boolean, error?: string }}
*/
function isValidSafeTensorsFile(file) {
if (!file) {
return { valid: false, error: 'No file provided.' };
}
// Extension check
const name = file.name || '';
if (!name.toLowerCase().endsWith('.safetensors')) {
return {
valid: false,
error: `Invalid file type "${name}". Only .safetensors files are accepted.`,
};
}
// Empty file check
if (file.size === 0) {
return { valid: false, error: 'The file is empty.' };
}
return { valid: true };
}
// βββ Model Data Validation ββββββββββββββββββββββββββββββββββββββββββββββββ
/**
* Validate a parsed model data object returned by ONNXParser.
* Ensures the required top-level fields are present and non-null.
*
* @param {Object} data - ParsedModel object
* @returns {{ valid: boolean, error?: string }}
*/
function isValidModelData(data) {
if (!data || typeof data !== 'object') {
return { valid: false, error: 'Model data is null or not an object.' };
}
const required = ['metadata', 'graph', 'inputs', 'outputs'];
for (const field of required) {
if (!(field in data) || data[field] == null) {
return { valid: false, error: `Model data is missing required field: "${field}".` };
}
}
if (!Array.isArray(data.inputs)) {
return { valid: false, error: 'Model data "inputs" must be an array.' };
}
if (!Array.isArray(data.outputs)) {
return { valid: false, error: 'Model data "outputs" must be an array.' };
}
return { valid: true };
}
// βββ Input / Search Validation ββββββββββββββββββββββββββββββββββββββββββββ
/**
* Validate a generic user input string.
* Returns false for null/undefined; trims and checks length.
*
* @param {*} input
* @param {{ minLength?: number, maxLength?: number, required?: boolean }} [opts]
* @returns {{ valid: boolean, error?: string }}
*/
function isValidInput(input, opts = {}) {
const { minLength = 0, maxLength = 1000, required = false } = opts;
if (input == null || input === '') {
if (required) {
return { valid: false, error: 'This field is required.' };
}
return { valid: true }; // empty is OK when not required
}
const str = String(input).trim();
if (required && str.length === 0) {
return { valid: false, error: 'This field cannot be blank.' };
}
if (str.length < minLength) {
return { valid: false, error: `Input must be at least ${minLength} characters.` };
}
if (str.length > maxLength) {
return { valid: false, error: `Input must not exceed ${maxLength} characters.` };
}
return { valid: true };
}
/**
* Validate a search query string.
* Allows empty strings (clears the filter); rejects excessively long ones.
*
* @param {string} query
* @returns {{ valid: boolean, error?: string }}
*/
function isValidSearchQuery(query) {
return isValidInput(query, { maxLength: 200 });
}
/**
* Validate a model path string (must be non-empty and end with .onnx or .safetensors).
* @param {string} path
* @returns {{ valid: boolean, error?: string }}
*/
function isValidModelPath(path) {
if (!path || typeof path !== 'string' || path.trim() === '') {
return { valid: false, error: 'Model path must be a non-empty string.' };
}
const lower = path.toLowerCase();
if (!lower.endsWith('.onnx') && !lower.endsWith('.safetensors')) {
return { valid: false, error: 'Model path must point to an .onnx or .safetensors file.' };
}
return { valid: true };
}
// βββ Public API βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
return {
isValidOnnxFile,
isValidOnnxBuffer,
isValidSafeTensorsFile,
isValidModelData,
isValidInput,
isValidSearchQuery,
isValidModelPath,
};
})();
// Export for global access in vanilla JS context
window.Validators = Validators;
|