model-explorer / js /app.js
mr4's picture
Upload 65 files
8ff6981 verified
/**
* ONNX Model Explorer - Application Integration Hub
* Wires all components together and manages the startup flow.
* Requirements: 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 8.1–8.6, 16–25
*/
(function () {
'use strict';
// ─── Component References ─────────────────────────────────────────────────
let modelLoader = null;
let onnxParser = null;
let graphProcessor = null;
let modelListDisplay = null;
let metadataDisplay = null;
let inputOutputDisplay = null;
let initializerDisplay = null;
let graphVisualizer = null;
let fileUploadHandler = null;
let searchFilter = null;
let exportHandler = null;
let nodeDetailPanel = null;
let graphMinimap = null;
let graphPathHighlighter = null;
let layerStats = null;
let modelComplexity = null;
let tensorShapeInspector = null;
let opsetChecker = null;
let recentModels = null;
let graphExport = null;
let shareableURL = null;
let fullscreenManager = null;
let sidebarToggle = null;
let helpTooltip = null;
let guidedTour = null;
let graphSearch = null;
let graphLayoutSwitcher = null;
let nodeGrouping = null;
let graphAnnotation = null;
let flopsEstimator = null;
let languageSwitcher = null;
let safeTensorsParser = null;
let safeTensorsViewer = null;
let tfliteParser = null;
let tfliteViewer = null;
let printHandler = null;
// ─── Performance: In-Memory Parsed Model Cache ────────────────────────────
// Keyed by model path; avoids re-parsing the same model on repeated selection.
const _parsedModelCache = new Map();
const _CACHE_MAX_SIZE = (typeof CONFIG !== 'undefined' && CONFIG.PERFORMANCE)
? CONFIG.PERFORMANCE.CACHE_SIZE
: 10;
// ─── Startup Flow ─────────────────────────────────────────────────────────
/**
* Main entry point – runs after DOMContentLoaded.
*/
async function init() {
console.log('[App] Initializing ONNX Model Explorer…');
// 1. Initialize core services
_initCoreServices();
// 2. Initialize UI components
_initUIComponents();
// 3. Wire EventBus β†’ component handlers
_wireEvents();
// 4. Load model list and render it
await _loadAndRenderModelList();
// 5. Restore user preferences (zoom level, etc.)
_restoreUserPreferences();
// 6. Restore previously selected model (if any)
_restoreSelection();
console.log('[App] Ready.');
}
// ─── Initialization Helpers ───────────────────────────────────────────────
/**
* Instantiate core business-logic services.
*/
function _initCoreServices() {
// ModelLoader
if (window.ModelLoader) {
modelLoader = new window.ModelLoader();
} else {
console.warn('[App] ModelLoader not available');
}
// ONNXParser
if (window.ONNXParser) {
onnxParser = new window.ONNXParser();
} else {
console.warn('[App] ONNXParser not available');
}
// GraphProcessor
if (window.GraphProcessor) {
graphProcessor = new window.GraphProcessor();
} else {
console.warn('[App] GraphProcessor not available');
}
// GraphPathHighlighter
if (window.GraphPathHighlighter) {
graphPathHighlighter = new window.GraphPathHighlighter();
}
// ShareableURL
if (window.ShareableURL) {
shareableURL = new window.ShareableURL();
}
// SafeTensorsParser
if (window.SafeTensorsParser) {
safeTensorsParser = new window.SafeTensorsParser();
} else {
console.warn('[App] SafeTensorsParser not available');
}
// TFLiteParser
if (window.TFLiteParser) {
tfliteParser = new window.TFLiteParser();
} else {
console.warn('[App] TFLiteParser not available');
}
// Warn if protobuf.js is missing (graceful degradation)
if (typeof protobuf === 'undefined') {
console.warn('[App] protobuf.js not loaded – model parsing will be unavailable.');
if (window.ErrorHandler) {
window.ErrorHandler.handleWarning(
'protobuf.js library could not be loaded. Model parsing is unavailable.',
'App'
);
}
}
// Warn if Cytoscape is missing
if (typeof cytoscape === 'undefined') {
console.warn('[App] Cytoscape.js not loaded – graph visualization will be unavailable.');
}
}
/**
* Instantiate and configure all UI components.
*/
function _initUIComponents() {
// ErrorDisplay subscribes to StateManager.error automatically (see errorDisplay.js)
// ModelListDisplay
if (window.ModelListDisplay) {
modelListDisplay = new window.ModelListDisplay('modelListContainer');
}
// MetadataDisplay
if (window.MetadataDisplay) {
metadataDisplay = new window.MetadataDisplay('metadataContainer');
}
// InputOutputDisplay
if (window.InputOutputDisplay) {
inputOutputDisplay = new window.InputOutputDisplay('inputOutputContainer');
}
// InitializerDisplay
if (window.InitializerDisplay) {
initializerDisplay = new window.InitializerDisplay('initializerContainer');
}
// GraphVisualizer
if (window.GraphVisualizer) {
graphVisualizer = new window.GraphVisualizer();
}
// FileUploadHandler
if (window.FileUploadHandler) {
fileUploadHandler = new window.FileUploadHandler('uploadBtn', 'fileInput', 'app');
}
// SearchFilter
if (window.SearchFilter) {
searchFilter = new window.SearchFilter('searchInput');
}
// ExportHandler
if (window.ExportHandler) {
exportHandler = new window.ExportHandler('exportBtn');
}
// NodeDetailPanel
if (window.NodeDetailPanel) {
nodeDetailPanel = new window.NodeDetailPanel('nodeDetailContainer');
}
// GraphMinimap
if (window.GraphMinimap) {
graphMinimap = new window.GraphMinimap('graphContainer');
}
// LayerStats
if (window.LayerStats) {
layerStats = new window.LayerStats('layerStatsContainer');
}
// ModelComplexity
if (window.ModelComplexity) {
modelComplexity = new window.ModelComplexity('modelComplexityContainer');
}
// TensorShapeInspector
if (window.TensorShapeInspector) {
tensorShapeInspector = new window.TensorShapeInspector();
}
// OpsetChecker
if (window.OpsetChecker) {
opsetChecker = new window.OpsetChecker('opsetCheckerContainer');
}
// RecentModels
if (window.RecentModels) {
recentModels = new window.RecentModels('recentModelsContainer');
}
// GraphExport
if (window.GraphExport) {
graphExport = new window.GraphExport('graphExportContainer');
}
// FullscreenManager
if (window.FullscreenManager) {
fullscreenManager = new window.FullscreenManager('#graphContainer');
fullscreenManager.init();
}
// SidebarToggle
if (window.SidebarToggle) {
sidebarToggle = new window.SidebarToggle('.col-lg-3.col-md-4', '.col-lg-9.col-md-8');
sidebarToggle.init();
}
// HelpTooltip
if (window.HelpTooltip) {
helpTooltip = new window.HelpTooltip();
helpTooltip.init();
}
// LanguageSwitcher (before GuidedTour so tour button picks up correct lang)
if (window.LanguageSwitcher) {
languageSwitcher = new window.LanguageSwitcher();
languageSwitcher.init();
}
// GuidedTour
if (window.GuidedTour) {
guidedTour = new window.GuidedTour();
guidedTour.init();
}
// GraphSearch
if (window.GraphSearch) {
graphSearch = new window.GraphSearch('#graphContainer');
}
// GraphLayoutSwitcher
if (window.GraphLayoutSwitcher) {
graphLayoutSwitcher = new window.GraphLayoutSwitcher();
}
// NodeGrouping
if (window.NodeGrouping) {
nodeGrouping = new window.NodeGrouping();
}
// GraphAnnotation
if (window.GraphAnnotation) {
graphAnnotation = new window.GraphAnnotation('#graphContainer');
graphAnnotation.init();
}
// FlopsEstimator
if (window.FlopsEstimator) {
flopsEstimator = new window.FlopsEstimator('flopsEstimatorContainer');
}
// SafeTensorsViewer
if (window.SafeTensorsViewer) {
safeTensorsViewer = new window.SafeTensorsViewer('modelDetailsContainer');
}
// TFLiteViewer
if (window.TFLiteViewer) {
tfliteViewer = new window.TFLiteViewer('modelDetailsContainer');
}
// PrintHandler
if (window.PrintHandler) {
printHandler = new window.PrintHandler('printBtn', 'print-header');
}
// Subscribe ModelListDisplay to filteredModelList changes
if (modelListDisplay && window.StateManager) {
window.StateManager.subscribe('filteredModelList', function (filteredList) {
modelListDisplay.render(filteredList);
});
}
}
// ─── Event Wiring ─────────────────────────────────────────────────────────
/**
* Connect EventBus events to component handlers.
*/
function _wireEvents() {
if (!window.EventBus) {
console.warn('[App] EventBus not available – events will not be wired');
return;
}
// model:selected β†’ load + parse + update all displays
window.EventBus.on(CONFIG.EVENTS.MODEL_SELECTED, _onModelSelected);
// file:uploaded β†’ parse + update all displays
window.EventBus.on(CONFIG.EVENTS.FILE_UPLOADED, _onFileUploaded);
// node:selected β†’ highlight in graph
window.EventBus.on(CONFIG.EVENTS.NODE_SELECTED, _onNodeSelected);
// search:updated β†’ re-render model list (SearchFilter already updates
// StateManager.filteredModelList; the subscription above handles re-render)
// layerstats:highlight β†’ highlight all nodes of that opType in the graph
window.EventBus.on('layerstats:highlight', _onLayerStatsHighlight);
// Copy Link button β†’ ShareableURL
var copyLinkBtn = document.getElementById('copyLinkBtn');
if (copyLinkBtn && shareableURL) {
copyLinkBtn.addEventListener('click', function() {
shareableURL.copyToClipboard().then(function(ok) {
if (ok && window.ErrorDisplay) {
window.ErrorDisplay.show('Link copied to clipboard!', 'info');
}
});
});
}
}
// ─── Event Handlers ───────────────────────────────────────────────────────
/**
* Handle model:selected event from ModelListDisplay.
* Flow: check cache β†’ load file β†’ parse β†’ cache β†’ update StateManager β†’ update all UI components
* @param {ModelInfo} model
*/
async function _onModelSelected(model) {
if (!model || !model.path) {
console.warn('[App] model:selected fired with invalid model', model);
return;
}
// Hide SafeTensors viewer when selecting an ONNX model from the list
if (safeTensorsViewer) {
safeTensorsViewer.hide();
}
// Hide TFLite viewer when selecting an ONNX model from the list
if (tfliteViewer) {
tfliteViewer.hide();
}
// Re-enable Export button
if (exportHandler && exportHandler._exportBtn) {
exportHandler._exportBtn.disabled = false;
exportHandler._exportBtn.title = '';
}
_showLoading(CONFIG.INFO.LOADING_MODEL);
try {
// 1. Check in-memory cache first (lazy loading: only parse when needed)
const cacheKey = model.path;
let parsedModel = _parsedModelCache.get(cacheKey);
if (parsedModel) {
console.log('[App] Cache hit for model:', cacheKey);
} else {
// 2. Load the model file
if (!modelLoader) throw new Error('ModelLoader is not initialized');
const buffer = await modelLoader.loadModelFile(model.path);
// 3. Parse the model
_showLoading(CONFIG.INFO.PARSING_MODEL);
parsedModel = await _parseModel(buffer, {
fileName: model.name || model.path,
fileSize: model.size || buffer.byteLength
});
// 4. Store in cache (evict oldest if over limit)
if (_parsedModelCache.size >= _CACHE_MAX_SIZE) {
const firstKey = _parsedModelCache.keys().next().value;
_parsedModelCache.delete(firstKey);
}
_parsedModelCache.set(cacheKey, parsedModel);
}
// 5. Update StateManager
window.StateManager.setCurrentModel(parsedModel);
window.StateManager.setLoading(false);
// 6. Persist last selected model path to localStorage
_saveUserPreference(CONFIG.STORAGE.SELECTED_MODEL, cacheKey);
// 7. Update all UI components
_updateAllDisplays(parsedModel);
// 8. Emit model:loaded
window.EventBus.emit(CONFIG.EVENTS.MODEL_LOADED, { model: parsedModel });
// 9. Load annotations for the model
if (graphAnnotation && parsedModel.metadata && parsedModel.metadata.fileName) {
graphAnnotation.loadAnnotations(parsedModel.metadata.fileName);
}
_clearLoading();
} catch (err) {
window.StateManager.setLoading(false);
_handleError(err, 'model:selected');
}
}
/**
* Handle file:uploaded event from FileUploadHandler.
* Flow: parse β†’ update StateManager β†’ update all UI components
* @param {{ file: File, data: ArrayBuffer, fileName: string }} payload
*/
async function _onFileUploaded(payload) {
if (!payload || !payload.data) {
console.warn('[App] file:uploaded fired with invalid payload', payload);
return;
}
var fileName = payload.fileName || (payload.file && payload.file.name) || 'uploaded.onnx';
var isSafeTensors = fileName.toLowerCase().endsWith('.safetensors');
var isTFLite = fileName.toLowerCase().endsWith('.tflite');
if (isTFLite) {
// ── TFLite pipeline ──
_showLoading(CONFIG.INFO.PARSING_MODEL);
try {
if (!tfliteParser) throw new Error('TFLiteParser is not initialized');
var result = tfliteParser.parse(payload.data);
if (!result.success) {
throw new Error(result.error || 'Failed to parse TFLite file');
}
// Hide SafeTensors viewer if visible
if (safeTensorsViewer) {
safeTensorsViewer.hide();
}
// Render TFLite viewer (also hides ONNX panels internally)
if (tfliteViewer) {
tfliteViewer.render(result.data, fileName);
}
// Disable Export button (Req 6.4)
if (exportHandler && exportHandler._exportBtn) {
exportHandler._exportBtn.disabled = true;
exportHandler._exportBtn.title = 'Export is not available for TFLite files';
}
// Update RecentModels (Req 6.3)
if (recentModels && typeof recentModels.addEntry === 'function') {
recentModels.addEntry(
fileName,
payload.file ? payload.file.size : payload.data.byteLength
);
}
_clearLoading();
} catch (err) {
_clearLoading();
_handleError(err, 'file:uploaded (tflite)');
}
} else if (isSafeTensors) {
// ── SafeTensors pipeline ──
_showLoading(CONFIG.INFO.PARSING_MODEL);
try {
if (!safeTensorsParser) throw new Error('SafeTensorsParser is not initialized');
var result = safeTensorsParser.parse(payload.data);
if (!result.success) {
throw new Error(result.error || 'Failed to parse SafeTensors file');
}
// Render SafeTensors viewer (also hides ONNX panels internally)
if (safeTensorsViewer) {
safeTensorsViewer.render(result.data, fileName);
}
// Disable Export button (Req 43.6)
if (exportHandler && exportHandler._exportBtn) {
exportHandler._exportBtn.disabled = true;
exportHandler._exportBtn.title = 'Export is not available for SafeTensors files';
}
// Update RecentModels
if (recentModels && typeof recentModels.addEntry === 'function') {
recentModels.addEntry(
fileName,
payload.file ? payload.file.size : payload.data.byteLength
);
}
_clearLoading();
} catch (err) {
_clearLoading();
_handleError(err, 'file:uploaded (safetensors)');
}
} else {
// ── ONNX pipeline (existing) ──
// Hide SafeTensors viewer if visible
if (safeTensorsViewer) {
safeTensorsViewer.hide();
}
// Hide TFLite viewer if visible
if (tfliteViewer) {
tfliteViewer.hide();
}
// Re-enable Export button
if (exportHandler && exportHandler._exportBtn) {
exportHandler._exportBtn.disabled = false;
exportHandler._exportBtn.title = '';
}
_showLoading(CONFIG.INFO.PARSING_MODEL);
try {
const parsedModel = await _parseModel(payload.data, {
fileName: fileName,
fileSize: payload.file ? payload.file.size : payload.data.byteLength
});
window.StateManager.setCurrentModel(parsedModel);
window.StateManager.setLoading(false);
_updateAllDisplays(parsedModel);
window.EventBus.emit(CONFIG.EVENTS.MODEL_LOADED, { model: parsedModel });
// Load annotations for the uploaded model
if (graphAnnotation && parsedModel.metadata && parsedModel.metadata.fileName) {
graphAnnotation.loadAnnotations(parsedModel.metadata.fileName);
}
_clearLoading();
} catch (err) {
window.StateManager.setLoading(false);
_handleError(err, 'file:uploaded');
}
}
}
/**
* Handle node:selected event – highlight the node in the graph.
* @param {{ nodeId: string, source?: string }} payload
*/
function _onNodeSelected(payload) {
if (!payload || !payload.nodeId) return;
if (graphVisualizer) {
graphVisualizer.highlightNode(payload.nodeId);
}
}
/**
* Handle layerstats:highlight event – highlight all nodes of a given opType.
* @param {{ opType: string }} payload
*/
function _onLayerStatsHighlight(payload) {
if (!payload || !payload.opType || !graphVisualizer || !graphVisualizer._cy) return;
var cy = graphVisualizer._cy;
cy.elements().removeClass('highlighted');
cy.nodes().forEach(function (node) {
if (node.data('opType') === payload.opType) {
node.addClass('highlighted');
}
});
}
// ─── Model Processing ─────────────────────────────────────────────────────
/**
* Parse an ONNX model buffer using ONNXParser.
* @param {ArrayBuffer} buffer
* @param {{ fileName: string, fileSize: number }} options
* @returns {Promise<ParsedModel>}
*/
async function _parseModel(buffer, options) {
if (!onnxParser) throw new Error('ONNXParser is not initialized');
return onnxParser.parseModel(buffer, options);
}
/**
* Update all UI display components with a parsed model.
* Also processes the graph and initializes the GraphVisualizer.
* @param {ParsedModel} parsedModel
*/
function _updateAllDisplays(parsedModel) {
// Metadata
if (metadataDisplay) {
metadataDisplay.render(parsedModel);
}
// Inputs / Outputs
if (inputOutputDisplay) {
inputOutputDisplay.render(parsedModel);
}
// Initializers
if (initializerDisplay) {
initializerDisplay.render(parsedModel);
}
// Node Detail Panel – reset to guidance on new model load
if (nodeDetailPanel) {
nodeDetailPanel.clear();
}
// Render new analysis panels directly
if (layerStats) {
var stats = layerStats.compute(parsedModel);
layerStats.render(stats);
}
if (modelComplexity) {
var metrics = modelComplexity.compute(parsedModel);
modelComplexity.render(metrics);
}
if (opsetChecker) {
var opsetData = opsetChecker.compute(parsedModel);
opsetChecker.render(opsetData);
}
// FlopsEstimator
if (flopsEstimator) {
flopsEstimator.compute(parsedModel);
flopsEstimator.render();
}
// Update TensorShapeInspector with new model data
if (tensorShapeInspector) {
tensorShapeInspector.updateModel(parsedModel);
}
// Graph
if (graphProcessor && graphVisualizer) {
_showLoading(CONFIG.INFO.RENDERING_GRAPH);
const { elements } = graphProcessor.processGraph(parsedModel);
const container = document.getElementById('graphContainer');
if (container) {
// Clear placeholder text
container.innerHTML = '';
graphVisualizer.initialize(container, elements);
// Attach graph-dependent handlers
var cy = graphVisualizer._cy;
if (cy) {
if (graphPathHighlighter) {
graphPathHighlighter.attachCytoscapeHandlers(cy);
}
if (tensorShapeInspector) {
tensorShapeInspector.attachToCytoscape(cy);
}
}
// Emit graph:rendered event
window.EventBus.emit(CONFIG.EVENTS.GRAPH_RENDERED, { cy: cy });
// Initialize graph-dependent UI components
if (graphSearch) {
graphSearch.init();
}
if (graphLayoutSwitcher) {
graphLayoutSwitcher.init();
}
if (nodeGrouping) {
nodeGrouping.init();
}
// Refresh minimap
if (graphMinimap) {
setTimeout(function() { graphMinimap.refresh(); }, 300);
}
// Restore pending zoom preference if any
if (window._onnxApp && window._onnxApp._pendingZoom) {
requestAnimationFrame(function () {
graphVisualizer.zoom(window._onnxApp._pendingZoom);
window._onnxApp._pendingZoom = null;
});
}
}
_clearLoading();
}
}
// ─── Model List Loading ───────────────────────────────────────────────────
/**
* Load models.json and populate StateManager + ModelListDisplay.
*/
async function _loadAndRenderModelList() {
try {
if (!modelLoader) {
console.warn('[App] ModelLoader not available – skipping model list load');
return;
}
const models = await modelLoader.loadModelList();
window.StateManager.setModelList(models);
window.StateManager.setFilteredModelList(models.slice());
// Initial render (subscription will handle subsequent updates)
if (modelListDisplay) {
modelListDisplay.render(models);
}
console.log(`[App] Loaded ${models.length} model(s)`);
// Initialize ShareableURL with the model list
if (shareableURL) {
shareableURL.init(models);
}
} catch (err) {
_handleError(err, 'loadModelList');
}
}
// ─── Selection Restore ────────────────────────────────────────────────────
/**
* Restore the previously selected model from URL hash or localStorage (if any).
*/
function _restoreSelection() {
// 1. Check ShareableURL hash first (takes priority)
if (shareableURL) {
var hashResult = shareableURL.readHash();
if (hashResult.error && window.ErrorDisplay) {
window.ErrorDisplay.show(hashResult.error, 'warning');
}
if (hashResult.model && window.EventBus) {
console.log('[App] Restoring model from URL hash:', hashResult.model.id);
window.EventBus.emit(CONFIG.EVENTS.MODEL_SELECTED, hashResult.model);
return;
}
}
// 2. Fall back to localStorage persisted selection
const persistedId = window.StateManager
? window.StateManager.getPersistedSelectedModelId()
: null;
if (!persistedId) return;
const modelList = window.StateManager.getModelList();
const model = modelList.find(
(m) => m.id === persistedId || m.path === persistedId || m.name === persistedId
);
if (model && window.EventBus) {
console.log('[App] Restoring previously selected model:', persistedId);
window.EventBus.emit(CONFIG.EVENTS.MODEL_SELECTED, model);
}
}
// ─── UI Helpers ───────────────────────────────────────────────────────────
/**
* Show a loading indicator in the error container.
* @param {string} message
*/
function _showLoading(message) {
window.StateManager.setLoading(true);
if (window.ErrorDisplay) {
window.ErrorDisplay.show(message, 'info', false);
}
}
/**
* Clear the loading indicator.
*/
function _clearLoading() {
window.StateManager.setLoading(false);
if (window.ErrorDisplay) {
window.ErrorDisplay.hide();
}
}
/**
* Handle an error using ErrorHandler and display it.
* @param {Error|string} err
* @param {string} context
*/
function _handleError(err, context) {
if (window.ErrorHandler) {
window.ErrorHandler.handleError(err, context);
} else {
console.error(`[App][${context}]`, err);
if (window.ErrorDisplay) {
window.ErrorDisplay.showError(
(err && err.message) ? err.message : String(err)
);
}
}
}
// ─── User Preferences (localStorage) ─────────────────────────────────────
/**
* Save a user preference to localStorage.
* @param {string} key
* @param {*} value
*/
function _saveUserPreference(key, value) {
try {
localStorage.setItem(key, typeof value === 'string' ? value : JSON.stringify(value));
} catch (_) { /* ignore quota/security errors */ }
}
/**
* Load a user preference from localStorage.
* @param {string} key
* @param {*} [defaultValue=null]
* @returns {*}
*/
function _loadUserPreference(key, defaultValue) {
try {
const raw = localStorage.getItem(key);
if (raw === null) return defaultValue !== undefined ? defaultValue : null;
try { return JSON.parse(raw); } catch (_) { return raw; }
} catch (_) {
return defaultValue !== undefined ? defaultValue : null;
}
}
/**
* Restore user preferences (zoom level) from localStorage.
*/
function _restoreUserPreferences() {
const prefs = _loadUserPreference(CONFIG.STORAGE.USER_PREFERENCES, {});
if (prefs && typeof prefs.zoomLevel === 'number' && graphVisualizer) {
// Zoom will be applied after graph is initialized; store for later use
window._onnxApp._pendingZoom = prefs.zoomLevel;
}
}
// ─── Bootstrap ────────────────────────────────────────────────────────────
document.addEventListener('DOMContentLoaded', function () {
init().catch(function (err) {
console.error('[App] Fatal initialization error:', err);
const container = document.getElementById('errorContainer');
if (container) {
container.innerHTML =
'<div class="alert alert-danger">' +
'<i class="fas fa-times-circle me-2"></i>' +
'Application failed to initialize. Please refresh the page.' +
'</div>';
}
});
});
// Expose for debugging
window._onnxApp = {
getModelLoader: () => modelLoader,
getOnnxParser: () => onnxParser,
getGraphProcessor: () => graphProcessor,
getModelListDisplay: () => modelListDisplay,
getMetadataDisplay: () => metadataDisplay,
getInputOutputDisplay:() => inputOutputDisplay,
getInitializerDisplay:() => initializerDisplay,
getGraphVisualizer: () => graphVisualizer,
getFileUploadHandler: () => fileUploadHandler,
getSearchFilter: () => searchFilter,
getExportHandler: () => exportHandler,
getNodeDetailPanel: () => nodeDetailPanel,
getGraphMinimap: () => graphMinimap,
getGraphPathHighlighter: () => graphPathHighlighter,
getLayerStats: () => layerStats,
getModelComplexity: () => modelComplexity,
getTensorShapeInspector: () => tensorShapeInspector,
getOpsetChecker: () => opsetChecker,
getRecentModels: () => recentModels,
getGraphExport: () => graphExport,
getShareableURL: () => shareableURL,
getFullscreenManager: () => fullscreenManager,
getSidebarToggle: () => sidebarToggle,
getHelpTooltip: () => helpTooltip,
getGuidedTour: () => guidedTour,
getGraphSearch: () => graphSearch,
getGraphLayoutSwitcher: () => graphLayoutSwitcher,
getNodeGrouping: () => nodeGrouping,
getGraphAnnotation: () => graphAnnotation,
getFlopsEstimator: () => flopsEstimator,
getLanguageSwitcher: () => languageSwitcher,
getSafeTensorsParser: () => safeTensorsParser,
getSafeTensorsViewer: () => safeTensorsViewer,
getTFLiteParser: () => tfliteParser,
getTFLiteViewer: () => tfliteViewer,
getPrintHandler: () => printHandler,
getParsedModelCache: () => _parsedModelCache,
clearParsedModelCache:() => _parsedModelCache.clear(),
_pendingZoom: null,
};
})();