tahamajs/RR / Docs /visualizer /src /ui /tree_explorer.js
tahamajs's picture
download
raw
7.24 kB
/**
* ui/tree_explorer.js
* ===================
* Hierarchical Layer Explorer Tree & Real-time Filter Engine.
*/
/**
* Builds the hierarchical DOM tree of layers and sublayers.
* @param {string} modelKey - Active model
* @param {string} moduleKey - Active module
* @param {object} modelData - Model spatial dataset
* @param {Function} onSelectNodeId - Callback when node is clicked
*/
export function buildHierarchicalTree(modelKey, moduleKey, modelData, onSelectNodeId) {
const container = document.getElementById('layer-tree-container');
const countEl = document.getElementById('insp-layer-count');
if (!container || !modelData) return;
container.innerHTML = '';
const moduleInfo = (modelData.modules && modelData.modules[moduleKey]) || modelData;
const layersMap = new Map();
const processStream = (nodes, streamType) => {
if (!nodes) return;
nodes.forEach(node => {
const lIdx = node.parent_layer_index ?? 999;
const lName = node.parent_layer_name || (lIdx === 999 ? 'Global Projections' : `Layer ${lIdx}`);
if (!layersMap.has(lIdx)) {
layersMap.set(lIdx, {
name: lName,
index: lIdx,
baseline: [],
compressed: []
});
}
layersMap.get(lIdx)[streamType].push(node);
});
};
processStream(modelData.baseline_nodes, 'baseline');
processStream(moduleInfo.compressed_nodes, 'compressed');
const totalNodes = (modelData.baseline_nodes ? modelData.baseline_nodes.length : 0) +
(moduleInfo.compressed_nodes ? moduleInfo.compressed_nodes.length : 0);
if (countEl) countEl.innerText = `${totalNodes} modules`;
const rootEl = document.createElement('div');
rootEl.className = 'tree-model-root';
const rootHeader = document.createElement('div');
rootHeader.className = 'tree-model-header';
rootHeader.innerHTML = `<span>⚡</span> <span>${modelKey.toUpperCase()} · ${moduleInfo.name || moduleKey.toUpperCase()}</span>`;
rootEl.appendChild(rootHeader);
const sortedLayers = Array.from(layersMap.values()).sort((a, b) => a.index - b.index);
sortedLayers.forEach((layerGroup, idx) => {
const layerNode = document.createElement('div');
layerNode.className = `tree-layer-node ${idx === 0 ? 'open' : ''}`;
layerNode.dataset.layerIndex = layerGroup.index;
const layerHeader = document.createElement('div');
layerHeader.className = 'tree-layer-header';
layerHeader.innerHTML = `
<span class="tree-chevron">▶</span>
<span class="tree-layer-title">${layerGroup.name}</span>
<small style="color: var(--text-faint); margin-left: auto;">(${layerGroup.baseline.length + layerGroup.compressed.length})</small>
`;
layerHeader.addEventListener('click', (e) => {
e.stopPropagation();
layerNode.classList.toggle('open');
if (window.navigateToLayer) {
window.navigateToLayer(layerGroup.index);
}
});
const layerContent = document.createElement('div');
layerContent.className = 'tree-layer-content';
if (layerGroup.baseline.length > 0) {
const bGroup = document.createElement('div');
bGroup.className = 'tree-stream-group';
bGroup.innerHTML = `<div class="tree-stream-label">Dense Baseline</div>`;
layerGroup.baseline.sort((a, b) => a.sequence_index - b.sequence_index).forEach(n => {
bGroup.appendChild(createLeafNode(n, false, onSelectNodeId));
});
layerContent.appendChild(bGroup);
}
if (layerGroup.compressed.length > 0) {
const cGroup = document.createElement('div');
cGroup.className = 'tree-stream-group';
cGroup.innerHTML = `<div class="tree-stream-label">${moduleInfo.name || 'Compressed'}</div>`;
layerGroup.compressed.sort((a, b) => a.sequence_index - b.sequence_index).forEach(n => {
cGroup.appendChild(createLeafNode(n, true, onSelectNodeId));
});
layerContent.appendChild(cGroup);
}
layerNode.appendChild(layerHeader);
layerNode.appendChild(layerContent);
rootEl.appendChild(layerNode);
});
container.appendChild(rootEl);
setupTreeFilter();
}
function createLeafNode(node, isCompressed, onSelectNodeId) {
const leaf = document.createElement('div');
leaf.className = `tree-leaf ${isCompressed ? 'type-svd' : 'type-dense'}`;
leaf.dataset.id = node.id;
leaf.dataset.label = (node.label || node.id).toLowerCase();
let cleanLabel = node.label || node.id;
cleanLabel = cleanLabel.replace(/^(transformer|encoder|model)?\.?layer(s)?\.\d+\./, '');
cleanLabel = cleanLabel.replace(/^h\.\d+\./, '');
let badgeText = 'Dense';
if (isCompressed) {
if (node.sub_type === 'v_factor') badgeText = 'V-Rank';
else if (node.sub_type === 'u_factor') badgeText = 'U-Exp';
else if (node.sub_type === 'router') badgeText = 'Router';
else if (node.sub_type === 'expert') badgeText = 'Expert';
else if (node.sub_type === 'latent_kv') badgeText = 'Latent';
else if (node.sub_type === 'sliced_linear') badgeText = 'Sliced';
else badgeText = 'Comp';
}
leaf.innerHTML = `
<span class="leaf-name" title="${node.label}">${cleanLabel}</span>
<span class="leaf-badge">${badgeText}</span>
`;
leaf.addEventListener('click', (e) => {
e.stopPropagation();
if (onSelectNodeId) onSelectNodeId(node.id);
});
return leaf;
}
function setupTreeFilter() {
const searchInput = document.getElementById('tree-search-input');
const clearBtn = document.getElementById('btn-tree-clear');
if (!searchInput) return;
const filterTree = () => {
const query = searchInput.value.trim().toLowerCase();
const leaves = document.querySelectorAll('.tree-leaf');
const layerNodes = document.querySelectorAll('.tree-layer-node');
if (!query) {
leaves.forEach(l => l.style.display = '');
layerNodes.forEach(ln => ln.style.display = '');
return;
}
layerNodes.forEach(ln => {
let hasVisibleLeaf = false;
const lnLeaves = ln.querySelectorAll('.tree-leaf');
lnLeaves.forEach(leaf => {
const label = leaf.dataset.label || '';
const id = leaf.dataset.id || '';
const match = label.includes(query) || id.includes(query);
leaf.style.display = match ? '' : 'none';
if (match) hasVisibleLeaf = true;
});
ln.style.display = hasVisibleLeaf ? '' : 'none';
if (hasVisibleLeaf) ln.classList.add('open');
});
};
searchInput.addEventListener('input', filterTree);
if (clearBtn) {
clearBtn.addEventListener('click', () => {
searchInput.value = '';
filterTree();
searchInput.focus();
});
}
}

Xet Storage Details

Size:
7.24 kB
·
Xet hash:
5b12c4796d0efced723749c341f628c6a29542bb503e55d7403f942dae23550d

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.