/** * OpsetChecker - Displays opset compatibility information for a loaded ONNX model * Shows current opset version, compares against standard versions, lists domains and custom operators. * Requirements: 22.1, 22.2, 22.3, 22.4, 22.5 */ class OpsetChecker { /** * Standard ONNX opset versions to compare against. * @type {number[]} */ static STANDARD_OPSETS = [7, 9, 11, 13, 15, 17, 18, 19, 20, 21]; /** * @param {string} containerId - ID of the container element */ constructor(containerId) { this._containerId = containerId; this._container = document.getElementById(containerId); this._data = null; if (!this._container) { console.warn(`[OpsetChecker] Container #${containerId} not found`); } this._setupEventListeners(); } // ─── Private ────────────────────────────────────────────────────────────── /** * Listen for model:loaded events to auto-update. */ _setupEventListeners() { if (window.EventBus && typeof CONFIG !== 'undefined' && CONFIG.EVENTS) { window.EventBus.on(CONFIG.EVENTS.MODEL_LOADED, (data) => { if (data && data.model) { const result = this.compute(data.model); this.render(result); } }); } } /** * Escape HTML special characters. * @param {string} str * @returns {string} */ _escapeHtml(str) { const div = document.createElement('div'); div.appendChild(document.createTextNode(String(str))); return div.innerHTML; } // ─── Public API ─────────────────────────────────────────────────────────── /** * Compute opset compatibility data from a parsed model. * @param {object} parsedModel * @returns {{ modelOpset: number, compatibility: Array<{version: number, compatible: boolean}>, domains: Array<{domain: string, version: number}>, customOperators: Array<{name: string, domain: string}>, allStandard: boolean }} */ compute(parsedModel) { const modelOpset = (parsedModel && parsedModel.metadata && parsedModel.metadata.opsetVersion) || 0; // Compare against standard opset versions // Compatible means the standard version >= model's opset (runtime can run the model) const compatibility = OpsetChecker.STANDARD_OPSETS.map((version) => ({ version, compatible: version >= modelOpset, })); // Extract all domains and versions from opset_import const opsetImport = (parsedModel && parsedModel.metadata && Array.isArray(parsedModel.metadata.opsetImport)) ? parsedModel.metadata.opsetImport : []; const domains = opsetImport.map((op) => ({ domain: op.domain || 'ai.onnx (default)', version: op.version || 0, })); // Find custom domain operators from graph nodes const nodes = (parsedModel && parsedModel.graph && parsedModel.graph.nodes) || []; const customOperators = []; const seen = new Set(); for (const node of nodes) { if (node.domain && node.domain !== '' && node.domain !== 'ai.onnx') { const key = `${node.domain}::${node.opType}`; if (!seen.has(key)) { seen.add(key); customOperators.push({ name: node.opType || 'Unknown', domain: node.domain }); } } } const allStandard = customOperators.length === 0; this._data = { modelOpset, compatibility, domains, customOperators, allStandard }; return this._data; } /** * Render the opset compatibility information into the container. * @param {{ modelOpset: number, compatibility: Array, domains: Array, customOperators: Array, allStandard: boolean }} data */ render(data) { if (!this._container) return; if (!data) { this._container.innerHTML = '
No opset information available.
'; return; } const { modelOpset, compatibility, domains, customOperators, allStandard } = data; let html = ''; // Current opset version html += `| Domain | Version |
|---|---|
| ${this._escapeHtml(d.domain)} | ${d.version} |
| Operator | Domain |
|---|---|
| ${this._escapeHtml(op.name)} | ${this._escapeHtml(op.domain)} |
Select a model to view opset compatibility
'; } /** * Get the last computed data. * @returns {object|null} */ getData() { return this._data; } } window.OpsetChecker = OpsetChecker;