Spaces:
Running
Running
| /** | |
| * InitializerDisplay - Displays model initializers (constant tensors / weights) | |
| * Requirements: 7.1, 7.2, 7.3, 7.4, 7.5 | |
| */ | |
| class InitializerDisplay { | |
| /** | |
| * @param {string} containerId - ID of the container element | |
| */ | |
| constructor(containerId) { | |
| this._containerId = containerId; | |
| this._container = document.getElementById(containerId); | |
| if (!this._container) { | |
| console.warn(`[InitializerDisplay] Container #${containerId} not found`); | |
| } | |
| } | |
| // βββ Private ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| /** | |
| * 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; | |
| } | |
| /** | |
| * Format a shape array to a readable string. | |
| * @param {Array<number>} shape | |
| * @returns {string} | |
| */ | |
| _formatShape(shape) { | |
| if (!shape || shape.length === 0) return '[]'; | |
| return `[${shape.join(', ')}]`; | |
| } | |
| /** | |
| * Resolve a numeric data type to its string name. | |
| * @param {number|string} dataType | |
| * @returns {string} | |
| */ | |
| _resolveDataType(dataType) { | |
| if (typeof dataType === 'string') return dataType; | |
| if (CONFIG && CONFIG.DATA_TYPES && CONFIG.DATA_TYPES[dataType]) { | |
| return CONFIG.DATA_TYPES[dataType]; | |
| } | |
| return String(dataType); | |
| } | |
| /** | |
| * Format a byte count to a human-readable string (e.g. "4.2 KB"). | |
| * @param {number} bytes | |
| * @returns {string} | |
| */ | |
| _formatBytes(bytes) { | |
| if (bytes === 0) return '0 B'; | |
| const k = 1024; | |
| const sizes = ['B', 'KB', 'MB', 'GB']; | |
| const i = Math.floor(Math.log(bytes) / Math.log(k)); | |
| return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`; | |
| } | |
| /** | |
| * Compute the size label for an initializer. | |
| * Prefer size in bytes; fall back to element count. | |
| * @param {InitializerInfo} init | |
| * @returns {string} | |
| */ | |
| _sizeLabel(init) { | |
| if (init.size && init.size > 0) { | |
| return this._formatBytes(init.size); | |
| } | |
| if (init.elementCount && init.elementCount > 0) { | |
| return `${init.elementCount.toLocaleString()} elements`; | |
| } | |
| // Compute element count from shape if available | |
| if (init.shape && init.shape.length > 0) { | |
| const count = init.shape.reduce((acc, d) => acc * (d || 1), 1); | |
| return `${count.toLocaleString()} elements`; | |
| } | |
| return 'Unknown size'; | |
| } | |
| /** | |
| * Build the HTML for a single initializer item. | |
| * @param {InitializerInfo} init | |
| * @returns {string} | |
| */ | |
| _buildItem(init) { | |
| const shape = this._formatShape(init.shape); | |
| const dtype = this._resolveDataType(init.dataType); | |
| const size = this._sizeLabel(init); | |
| return ` | |
| <div class="initializer-item border rounded p-2 mb-2 cursor-pointer" | |
| role="button" | |
| tabindex="0" | |
| data-init-name="${this._escapeHtml(init.name)}" | |
| title="Click to highlight in graph" | |
| aria-label="Initializer ${this._escapeHtml(init.name)}"> | |
| <div class="fw-medium text-truncate mb-1">${this._escapeHtml(init.name)}</div> | |
| <div class="small text-muted d-flex flex-wrap gap-2"> | |
| <span><i class="fas fa-shapes me-1"></i>${this._escapeHtml(shape)}</span> | |
| <span><i class="fas fa-tag me-1"></i>${this._escapeHtml(dtype)}</span> | |
| <span><i class="fas fa-database me-1"></i>${this._escapeHtml(size)}</span> | |
| </div> | |
| </div>`; | |
| } | |
| /** | |
| * Attach click and keyboard handlers to initializer items. | |
| */ | |
| _attachItemHandlers() { | |
| if (!this._container) return; | |
| const items = this._container.querySelectorAll('.initializer-item'); | |
| items.forEach((item) => { | |
| const handler = () => { | |
| const name = item.dataset.initName; | |
| if (name && window.EventBus) { | |
| window.EventBus.emit(CONFIG.EVENTS.NODE_SELECTED, { nodeId: name, source: 'initializer' }); | |
| } | |
| if (name && window.StateManager) { | |
| window.StateManager.setSelectedNodeId(name); | |
| } | |
| }; | |
| item.addEventListener('click', handler); | |
| item.addEventListener('keydown', (e) => { | |
| if (e.key === 'Enter' || e.key === ' ') { | |
| e.preventDefault(); | |
| handler(); | |
| } | |
| }); | |
| }); | |
| } | |
| // βββ Public API βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| /** | |
| * Render the initializer list for a parsed model. | |
| * @param {ParsedModel} model | |
| */ | |
| render(model) { | |
| if (!this._container) return; | |
| const initializers = (model && model.initializers) | |
| ? model.initializers | |
| : (model && model.graph && model.graph.initializers) | |
| ? model.graph.initializers | |
| : []; | |
| if (initializers.length === 0) { | |
| this._container.innerHTML = ` | |
| <p class="text-muted"> | |
| <i class="fas fa-info-circle me-1"></i>No initializers found in this model. | |
| </p>`; | |
| return; | |
| } | |
| const header = `<p class="text-secondary small mb-2">${initializers.length} initializer${initializers.length !== 1 ? 's' : ''}</p>`; | |
| const items = initializers.map((init) => this._buildItem(init)).join(''); | |
| this._container.innerHTML = header + items; | |
| this._attachItemHandlers(); | |
| } | |
| /** | |
| * Clear the display. | |
| */ | |
| clear() { | |
| if (!this._container) return; | |
| this._container.innerHTML = '<p class="text-muted">Select a model to view initializers</p>'; | |
| } | |
| } | |
| window.InitializerDisplay = InitializerDisplay; | |