Spaces:
Running
Running
| /** | |
| * 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; | |