Spaces:
Running
Running
| /** | |
| * ModelLoader - Bộ Tải Mô Hình | |
| * Tải danh sách mô hình từ models/models.json và các tệp mô hình ONNX | |
| * Requirements: 1.1, 1.2, 1.3, 1.5, 3.1, 3.2 | |
| */ | |
| class ModelLoader { | |
| constructor() { | |
| /** @type {Array|null} In-memory cache for the model list */ | |
| this._modelListCache = null; | |
| } | |
| /** | |
| * Tải danh sách mô hình từ tệp cấu hình JSON | |
| * @param {string} configPath - Đường dẫn đến tệp models.json | |
| * @returns {Promise<Array<{id, name, description, path, category, version, size, labelsFile?}>>} | |
| */ | |
| async loadModelList(configPath = CONFIG.MODELS_CONFIG_FILE) { | |
| // Return cached list if available (Requirement 15.4) | |
| if (this._modelListCache !== null) { | |
| console.log('[ModelLoader] Returning cached model list'); | |
| return this._modelListCache; | |
| } | |
| try { | |
| const response = await fetch(configPath); | |
| if (!response.ok) { | |
| throw new Error(`HTTP ${response.status}: ${response.statusText}`); | |
| } | |
| const json = await response.json(); | |
| if (!json || !Array.isArray(json.models)) { | |
| throw new Error('Invalid models.json format: missing "models" array'); | |
| } | |
| const models = json.models.map(model => ({ | |
| id: model.id || '', | |
| name: model.name || '', | |
| description: model.description || '', | |
| path: model.path || '', | |
| category: model.category || '', | |
| version: model.version || '', | |
| size: model.size || 0, | |
| labelsFile: model.labelsFile || null | |
| })); | |
| // Cache the result in memory | |
| this._modelListCache = models; | |
| return models; | |
| } catch (error) { | |
| console.error('[ModelLoader] Failed to load model list:', error); | |
| return []; | |
| } | |
| } | |
| /** | |
| * Tải tệp mô hình ONNX từ đường dẫn | |
| * @param {string} filePath - Đường dẫn đến tệp .onnx | |
| * @returns {Promise<ArrayBuffer>} | |
| * @throws {Error} Nếu không thể tải tệp | |
| */ | |
| async loadModelFile(filePath) { | |
| const response = await fetch(filePath); | |
| if (!response.ok) { | |
| throw new Error(`Failed to load model file "${filePath}": HTTP ${response.status} ${response.statusText}`); | |
| } | |
| const buffer = await response.arrayBuffer(); | |
| return buffer; | |
| } | |
| /** | |
| * Xử lý tải lên tệp từ người dùng | |
| * @param {File} file - Đối tượng File từ input hoặc drag-and-drop | |
| * @returns {Promise<{success: boolean, data?: ArrayBuffer, error?: string}>} | |
| */ | |
| async handleFileUpload(file) { | |
| // Xác thực tệp tồn tại | |
| if (!file) { | |
| return { success: false, error: 'No file provided.' }; | |
| } | |
| // Xác thực phần mở rộng tệp | |
| const fileName = file.name || ''; | |
| const hasValidExtension = CONFIG.FILE.ALLOWED_EXTENSIONS.some(ext => | |
| fileName.toLowerCase().endsWith(ext) | |
| ); | |
| if (!hasValidExtension) { | |
| const allowed = CONFIG.FILE.ALLOWED_EXTENSIONS.join(', '); | |
| return { | |
| success: false, | |
| error: `Invalid file type. Only ${allowed} files are supported.` | |
| }; | |
| } | |
| // Xác thực kích thước tệp | |
| if (file.size > CONFIG.FILE.MAX_FILE_SIZE) { | |
| const maxMB = Math.round(CONFIG.FILE.MAX_FILE_SIZE / (1024 * 1024)); | |
| return { | |
| success: false, | |
| error: `File is too large. Maximum allowed size is ${maxMB}MB.` | |
| }; | |
| } | |
| // Đọc tệp dưới dạng ArrayBuffer | |
| try { | |
| const data = await this._readFileAsArrayBuffer(file); | |
| return { success: true, data }; | |
| } catch (error) { | |
| console.error('[ModelLoader] Failed to read uploaded file:', error); | |
| return { | |
| success: false, | |
| error: `Failed to read file: ${error.message || CONFIG.ERRORS.UPLOAD_ERROR}` | |
| }; | |
| } | |
| } | |
| /** | |
| * Đọc File object dưới dạng ArrayBuffer | |
| * @param {File} file | |
| * @returns {Promise<ArrayBuffer>} | |
| * @private | |
| */ | |
| _readFileAsArrayBuffer(file) { | |
| return new Promise((resolve, reject) => { | |
| const reader = new FileReader(); | |
| reader.onload = (event) => resolve(event.target.result); | |
| reader.onerror = () => reject(new Error(reader.error ? reader.error.message : 'FileReader error')); | |
| reader.readAsArrayBuffer(file); | |
| }); | |
| } | |
| } | |
| // Export as global for browser usage | |
| window.ModelLoader = ModelLoader; | |