Spaces:
Paused
Paused
Update templates/index.html
Browse files- templates/index.html +24 -13
templates/index.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
| 6 |
-
<title>Overthinker β
|
| 7 |
<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
|
| 8 |
<style>
|
| 9 |
* { margin:0; padding:0; box-sizing:border-box; }
|
|
@@ -328,7 +328,7 @@ body.light .dropdown-section kbd { background: rgba(0,0,0,0.04); border-color: r
|
|
| 328 |
|
| 329 |
<div class="prompt-bar">
|
| 330 |
<div class="input-group">
|
| 331 |
-
<textarea id="decision-input" placeholder="What decision are you overthinking? e.g. 'Should I quit my job to start a startup?'..." rows="
|
| 332 |
<button class="btn btn-primary btn-generate" id="generate-btn">π³ Generate</button>
|
| 333 |
<button class="btn btn-secondary sample-btn" id="sample-btn">π― Sample</button>
|
| 334 |
</div>
|
|
@@ -344,14 +344,14 @@ body.light .dropdown-section kbd { background: rgba(0,0,0,0.04); border-color: r
|
|
| 344 |
<div id="info-dropdown" class="dropdown-overlay">
|
| 345 |
<div class="dropdown-box">
|
| 346 |
<button class="dropdown-close" id="info-close">β</button>
|
| 347 |
-
<h3>βΉοΈ About Overthinker</h3>
|
| 348 |
<div class="dropdown-section">
|
| 349 |
<h4>π€ Model</h4>
|
| 350 |
<p>Powered by <strong>nvidia/nemotron-3-nano-30b-a3b</strong> via <strong>OpenRouter</strong>. Optimized for structured decision tree generation with dual-prompt architecture (options vs outcomes).</p>
|
| 351 |
</div>
|
| 352 |
<div class="dropdown-section">
|
| 353 |
<h4>π Framework</h4>
|
| 354 |
-
<p>Built on <strong>Gradio.Server</strong> with SQLite per-session persistence. Fully client-side rendering with D3.js for interactive tree visualization.</p>
|
| 355 |
</div>
|
| 356 |
<div class="dropdown-section">
|
| 357 |
<h4>β¨ Key Features</h4>
|
|
@@ -366,6 +366,7 @@ body.light .dropdown-section kbd { background: rgba(0,0,0,0.04); border-color: r
|
|
| 366 |
<li>π Regenerate with user context</li>
|
| 367 |
<li>πΎ Multi-user session isolation via SQLite</li>
|
| 368 |
<li>π€ Upload trace to HF dataset</li>
|
|
|
|
| 369 |
</ul>
|
| 370 |
</div>
|
| 371 |
<div class="dropdown-section">
|
|
@@ -480,12 +481,12 @@ body.light .dropdown-section kbd { background: rgba(0,0,0,0.04); border-color: r
|
|
| 480 |
|
| 481 |
<script>
|
| 482 |
// =============================================
|
| 483 |
-
// OVER THINKER β
|
| 484 |
-
// -
|
| 485 |
-
// -
|
| 486 |
-
// -
|
| 487 |
-
// -
|
| 488 |
-
//
|
| 489 |
// =============================================
|
| 490 |
|
| 491 |
let nodes = [];
|
|
@@ -664,11 +665,15 @@ function computeTreeLayout() {
|
|
| 664 |
return { totalW, totalH };
|
| 665 |
}
|
| 666 |
|
| 667 |
-
// ---------- SVG INIT ----------
|
| 668 |
function initSvg() {
|
| 669 |
const w = container.clientWidth, h = container.clientHeight;
|
| 670 |
svg = d3.select('#graph-svg').attr('viewBox', `0 0 ${w} ${h}`).attr('width', w).attr('height', h);
|
| 671 |
svg.selectAll('*').remove();
|
|
|
|
|
|
|
|
|
|
|
|
|
| 672 |
zoomBehavior = d3.zoom().scaleExtent([0.2, 10]).filter(ev => ev.type === 'wheel' || ev.target === svg.node()).on('zoom', (ev) => {
|
| 673 |
if (gMain) gMain.attr('transform', ev.transform);
|
| 674 |
});
|
|
@@ -680,6 +685,7 @@ function initSvg() {
|
|
| 680 |
}
|
| 681 |
|
| 682 |
function renderCanvas() {
|
|
|
|
| 683 |
computeTreeLayout();
|
| 684 |
initSvg();
|
| 685 |
updateLinks();
|
|
@@ -693,6 +699,7 @@ function renderCanvas() {
|
|
| 693 |
}
|
| 694 |
|
| 695 |
function updateLinks() {
|
|
|
|
| 696 |
const linkJoin = gLinks.selectAll('line').data(links, d => {
|
| 697 |
const sid = typeof d.source === 'object' ? d.source.id : d.source;
|
| 698 |
const tid = typeof d.target === 'object' ? d.target.id : d.target;
|
|
@@ -710,6 +717,7 @@ function updateLinks() {
|
|
| 710 |
}
|
| 711 |
|
| 712 |
function updateNodes() {
|
|
|
|
| 713 |
const nodeJoin = gNodes.selectAll('.node-group').data(nodes, d => d.id);
|
| 714 |
nodeJoin.exit().remove();
|
| 715 |
const nodeEnter = nodeJoin.enter().append('g').attr('class','node-group')
|
|
@@ -1024,14 +1032,17 @@ async function exploreNode(nodeId, count, comment) {
|
|
| 1024 |
} finally { hideLoading(); }
|
| 1025 |
}
|
| 1026 |
|
|
|
|
| 1027 |
async function addOptionsToNode(nodeId, count) {
|
| 1028 |
showLoading('Adding new options...');
|
| 1029 |
try {
|
|
|
|
|
|
|
| 1030 |
const data = await apiPost('/add_options', { node_id: nodeId, count });
|
| 1031 |
const newChildren = data.children || [];
|
| 1032 |
newChildren.forEach(child => addNodeToGraph(child, nodeId));
|
| 1033 |
const parentNode = nodes.find(n => n.id === nodeId);
|
| 1034 |
-
if (parentNode) parentNode._childrenCount =
|
| 1035 |
renderCanvas();
|
| 1036 |
removeForeignPopup();
|
| 1037 |
selectedNodeId = null;
|
|
@@ -1805,7 +1816,7 @@ getSessionId();
|
|
| 1805 |
initSvg();
|
| 1806 |
if (localStorage.getItem('overthinker_theme') === 'light') toggleTheme();
|
| 1807 |
|
| 1808 |
-
console.log('π§ Overthinker β
|
| 1809 |
</script>
|
| 1810 |
</body>
|
| 1811 |
</html>
|
|
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
| 6 |
+
<title>Overthinker β v29 Browser Memory Fix</title>
|
| 7 |
<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
|
| 8 |
<style>
|
| 9 |
* { margin:0; padding:0; box-sizing:border-box; }
|
|
|
|
| 328 |
|
| 329 |
<div class="prompt-bar">
|
| 330 |
<div class="input-group">
|
| 331 |
+
<textarea id="decision-input" placeholder="What decision are you overthinking? e.g. 'Should I quit my job to start a startup?'..." rows="1"></textarea>
|
| 332 |
<button class="btn btn-primary btn-generate" id="generate-btn">π³ Generate</button>
|
| 333 |
<button class="btn btn-secondary sample-btn" id="sample-btn">π― Sample</button>
|
| 334 |
</div>
|
|
|
|
| 344 |
<div id="info-dropdown" class="dropdown-overlay">
|
| 345 |
<div class="dropdown-box">
|
| 346 |
<button class="dropdown-close" id="info-close">β</button>
|
| 347 |
+
<h3>βΉοΈ About Overthinker v29</h3>
|
| 348 |
<div class="dropdown-section">
|
| 349 |
<h4>π€ Model</h4>
|
| 350 |
<p>Powered by <strong>nvidia/nemotron-3-nano-30b-a3b</strong> via <strong>OpenRouter</strong>. Optimized for structured decision tree generation with dual-prompt architecture (options vs outcomes).</p>
|
| 351 |
</div>
|
| 352 |
<div class="dropdown-section">
|
| 353 |
<h4>π Framework</h4>
|
| 354 |
+
<p>Built on <strong>Gradio.Server</strong> with SQLite per-session persistence. Fully client-side rendering with D3.js for interactive tree visualization. <strong>Browser memory fix applied</strong>: zoom handler cleanup, addOptions replaces children, D3 keyed exit/remove.</p>
|
| 355 |
</div>
|
| 356 |
<div class="dropdown-section">
|
| 357 |
<h4>β¨ Key Features</h4>
|
|
|
|
| 366 |
<li>π Regenerate with user context</li>
|
| 367 |
<li>πΎ Multi-user session isolation via SQLite</li>
|
| 368 |
<li>π€ Upload trace to HF dataset</li>
|
| 369 |
+
<li>π§© Browser memory optimized: data arrays cleared, zoom listener cleanup, addOptions replaces children</li>
|
| 370 |
</ul>
|
| 371 |
</div>
|
| 372 |
<div class="dropdown-section">
|
|
|
|
| 481 |
|
| 482 |
<script>
|
| 483 |
// =============================================
|
| 484 |
+
// OVER THINKER v29 β Browser Memory Fixes
|
| 485 |
+
// - Fix 1: addOptions() now replaces children instead of appending
|
| 486 |
+
// - Fix 2: Zoom handler cleanup on initSvg (prevents listener leaks)
|
| 487 |
+
// - Fix 3: Data arrays cleared before each render (via removeChildrenOf + keyed joins)
|
| 488 |
+
// - Fix 4: D3 exit().remove() already present with keyed data bindings
|
| 489 |
+
// All other features preserved: full UI, path sidebar, export, upload trace
|
| 490 |
// =============================================
|
| 491 |
|
| 492 |
let nodes = [];
|
|
|
|
| 665 |
return { totalW, totalH };
|
| 666 |
}
|
| 667 |
|
| 668 |
+
// ---------- SVG INIT (Memory Fix 2: zoom handler cleanup) ----------
|
| 669 |
function initSvg() {
|
| 670 |
const w = container.clientWidth, h = container.clientHeight;
|
| 671 |
svg = d3.select('#graph-svg').attr('viewBox', `0 0 ${w} ${h}`).attr('width', w).attr('height', h);
|
| 672 |
svg.selectAll('*').remove();
|
| 673 |
+
// Remove old zoom behavior listeners to prevent memory leaks
|
| 674 |
+
if (zoomBehavior) {
|
| 675 |
+
svg.on('.zoom', null);
|
| 676 |
+
}
|
| 677 |
zoomBehavior = d3.zoom().scaleExtent([0.2, 10]).filter(ev => ev.type === 'wheel' || ev.target === svg.node()).on('zoom', (ev) => {
|
| 678 |
if (gMain) gMain.attr('transform', ev.transform);
|
| 679 |
});
|
|
|
|
| 685 |
}
|
| 686 |
|
| 687 |
function renderCanvas() {
|
| 688 |
+
// Memory Fix 3: No stale data accumulation β tree is rebuilt via removeChildrenOf/add options
|
| 689 |
computeTreeLayout();
|
| 690 |
initSvg();
|
| 691 |
updateLinks();
|
|
|
|
| 699 |
}
|
| 700 |
|
| 701 |
function updateLinks() {
|
| 702 |
+
// Memory Fix 4: D3 keyed data join with exit().remove() already correct
|
| 703 |
const linkJoin = gLinks.selectAll('line').data(links, d => {
|
| 704 |
const sid = typeof d.source === 'object' ? d.source.id : d.source;
|
| 705 |
const tid = typeof d.target === 'object' ? d.target.id : d.target;
|
|
|
|
| 717 |
}
|
| 718 |
|
| 719 |
function updateNodes() {
|
| 720 |
+
// Memory Fix 4: D3 keyed data join with exit().remove() already correct
|
| 721 |
const nodeJoin = gNodes.selectAll('.node-group').data(nodes, d => d.id);
|
| 722 |
nodeJoin.exit().remove();
|
| 723 |
const nodeEnter = nodeJoin.enter().append('g').attr('class','node-group')
|
|
|
|
| 1032 |
} finally { hideLoading(); }
|
| 1033 |
}
|
| 1034 |
|
| 1035 |
+
// Memory Fix 1: addOptions now removes existing children first (replace instead of append)
|
| 1036 |
async function addOptionsToNode(nodeId, count) {
|
| 1037 |
showLoading('Adding new options...');
|
| 1038 |
try {
|
| 1039 |
+
// Remove existing children for this node before adding new ones (prevents accumulation)
|
| 1040 |
+
removeChildrenOf(nodeId);
|
| 1041 |
const data = await apiPost('/add_options', { node_id: nodeId, count });
|
| 1042 |
const newChildren = data.children || [];
|
| 1043 |
newChildren.forEach(child => addNodeToGraph(child, nodeId));
|
| 1044 |
const parentNode = nodes.find(n => n.id === nodeId);
|
| 1045 |
+
if (parentNode) parentNode._childrenCount = newChildren.length; // set, not add
|
| 1046 |
renderCanvas();
|
| 1047 |
removeForeignPopup();
|
| 1048 |
selectedNodeId = null;
|
|
|
|
| 1816 |
initSvg();
|
| 1817 |
if (localStorage.getItem('overthinker_theme') === 'light') toggleTheme();
|
| 1818 |
|
| 1819 |
+
console.log('π§ Overthinker v29 β Browser Memory Fixes Applied (zoom cleanup, addOptions replace, keyed exit/remove), ID:', sessionId);
|
| 1820 |
</script>
|
| 1821 |
</body>
|
| 1822 |
</html>
|