OverviewFilesCommitsIssuesDocsReleasesPeers

hypercore-kb / opencog-kb / language-learning / mvp / viz / index.html

649 lines · html ref:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Language Learning Visualization</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
      font-family: 'Monaco', 'Consolas', monospace;
      background: #0a0a0f;
      color: #e0e0e0;
      overflow: hidden;
    }
    #container {
      display: flex;
      height: 100vh;
    }
    #canvas-container {
      flex: 1;
      position: relative;
    }
    #sidebar {
      width: 300px;
      background: #12121a;
      padding: 20px;
      overflow-y: auto;
      border-left: 1px solid #333;
    }
    h1 { font-size: 14px; margin-bottom: 20px; color: #888; }
    h2 { font-size: 12px; margin: 15px 0 10px; color: #666; text-transform: uppercase; }
    details { margin-bottom: 4px; }
    details > summary {
      font-size: 12px;
      color: #666;
      text-transform: uppercase;
      cursor: pointer;
      padding: 6px 0;
      user-select: none;
      list-style: none;
    }
    details > summary::-webkit-details-marker { display: none; }
    details > summary::before {
      content: '\25b6';
      display: inline-block;
      width: 14px;
      font-size: 8px;
      transition: transform 0.15s;
      color: #555;
    }
    details[open] > summary::before {
      transform: rotate(90deg);
    }
    details > summary:hover { color: #999; }
    details[open] > summary { color: #4ecdc4; }
    details > .section-body { padding-left: 2px; }
    .stat {
      display: flex;
      justify-content: space-between;
      padding: 5px 0;
      font-size: 12px;
    }
    .stat-value { color: #4ecdc4; }
    .stat-label { color: #999; }
    .stat-separator {
      border-top: 1px solid #222;
      margin: 4px 0;
    }
    .legend {
      display: flex;
      flex-direction: column;
      gap: 5px;
      margin: 10px 0;
    }
    .legend-item {
      display: flex;
      align-items: center;
      gap: 10px;
      font-size: 11px;
    }
    .legend-color {
      width: 20px;
      height: 10px;
      border-radius: 2px;
    }
    .slider-container {
      margin: 15px 0;
    }
    .slider-container label {
      display: block;
      font-size: 11px;
      color: #666;
      margin-bottom: 5px;
    }
    input[type="range"] {
      width: 100%;
      background: #333;
    }
    .hint {
      font-size: 9px;
      color: #555;
      margin-top: 2px;
    }
    .cluster-list {
      max-height: 200px;
      overflow-y: auto;
      font-size: 11px;
    }
    .cluster-item {
      padding: 5px;
      margin: 2px 0;
      background: #1a1a25;
      border-radius: 3px;
      cursor: pointer;
    }
    .cluster-item:hover {
      background: #252535;
    }
    #tooltip {
      position: absolute;
      background: rgba(0,0,0,0.9);
      border: 1px solid #4ecdc4;
      padding: 10px;
      font-size: 11px;
      pointer-events: none;
      display: none;
      max-width: 250px;
      z-index: 100;
    }
    #loading {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      color: #4ecdc4;
    }
    canvas { display: block; }
    #labels-overlay {
      position: absolute;
      top: 0; left: 0; right: 0; bottom: 0;
      pointer-events: none;
      overflow: hidden;
    }
    .node-label {
      position: absolute;
      color: #e0e0e0;
      font-family: 'Monaco', 'Consolas', monospace;
      white-space: nowrap;
      text-shadow: 0 0 4px #000, 0 0 8px #000, 1px 1px 2px #000;
      pointer-events: none;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s;
    }
    /* Histogram panel */
    #histogram-panel {
      position: absolute;
      bottom: 40px;
      left: 10px;
      background: rgba(10, 10, 18, 0.92);
      border: 1px solid #333;
      border-radius: 6px;
      padding: 12px;
      z-index: 150;
      width: 520px;
    }
    #histogram-panel.collapsed {
      display: none;
    }
    #histogram-panel.fullscreen {
      top: calc(100% / 12);
      left: calc(100% / 12);
      right: calc(100% / 12);
      bottom: calc(100% / 12 + 30px);
      width: auto;
      display: flex;
      flex-direction: column;
    }
    #histogram-panel.fullscreen .histogram-canvas-wrap {
      flex: 1;
      min-height: 0;
    }
    .histogram-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 8px;
    }
    .histogram-header h3 {
      font-size: 11px;
      color: #888;
      text-transform: uppercase;
      letter-spacing: 1px;
    }
    .histogram-tabs {
      display: flex;
      gap: 4px;
    }
    .histogram-tab {
      padding: 3px 8px;
      font-size: 10px;
      font-family: inherit;
      background: #1a1a25;
      color: #666;
      border: 1px solid #333;
      border-radius: 3px;
      cursor: pointer;
    }
    .histogram-tab.active {
      color: #4ecdc4;
      border-color: #4ecdc4;
    }
    .histogram-canvas-wrap {
      position: relative;
    }
    #histogram-canvas {
      display: block;
      background: #0a0a12;
      border-radius: 3px;
    }
    .histogram-stats {
      display: flex;
      gap: 16px;
      margin-top: 6px;
      font-size: 10px;
      color: #666;
    }
    .histogram-stats span {
      color: #4ecdc4;
    }
    #histogram-toggle {
      position: absolute;
      bottom: 10px;
      left: 10px;
      background: rgba(0,0,0,0.7);
      color: #4ecdc4;
      padding: 4px 10px;
      border-radius: 4px;
      font-size: 10px;
      font-family: monospace;
      z-index: 200;
      cursor: pointer;
      border: 1px solid #333;
      user-select: none;
    }
    #histogram-toggle:hover {
      border-color: #4ecdc4;
    }
    /* Promotion progress bar */
    .prom-bar {
      background: #1a1a25;
      border-radius: 3px;
      height: 6px;
      margin: 4px 0 8px;
      overflow: hidden;
    }
    .prom-bar-fill {
      height: 100%;
      background: #4ecdc4;
      border-radius: 3px;
      transition: width 0.5s;
    }
    .prom-check {
      display: flex;
      justify-content: space-between;
      font-size: 10px;
      padding: 2px 0;
    }
    .prom-check .label { color: #888; }
    .prom-check .pass { color: #44cc88; }
    .prom-check .fail { color: #ff6666; }
    /* Benchmark stats */
    .bench-row {
      display: flex;
      justify-content: space-between;
      font-size: 11px;
      padding: 2px 0;
    }
    .bench-row .label { color: #888; }
    .bench-row .val { color: #4ecdc4; font-variant-numeric: tabular-nums; }
    .bench-group {
      border-left: 2px solid #222;
      padding-left: 8px;
      margin: 4px 0;
    }
    .bench-group-title {
      font-size: 10px;
      color: #555;
      text-transform: uppercase;
      margin-bottom: 2px;
    }
  </style>
</head>
<body>
  <div id="container">
    <div id="canvas-container">
      <canvas id="canvas"></canvas>
      <div id="labels-overlay"></div>
      <div id="tooltip"></div>
      <div id="loading">Loading visualization data...</div>

      <!-- Histogram panel -->
      <div id="histogram-panel" class="collapsed">
        <div class="histogram-header">
          <h3>Distribution</h3>
          <div class="histogram-tabs">
            <button class="histogram-tab active" data-hist="mi">MI</button>
            <button class="histogram-tab" data-hist="surprise">Per-Word</button>
            <button class="histogram-tab" id="hist-fullscreen" style="margin-left:8px;">FULL</button>
          </div>
        </div>
        <div class="histogram-canvas-wrap">
          <canvas id="histogram-canvas" width="496" height="180"></canvas>
        </div>
        <div class="histogram-stats" id="histogram-stats"></div>
      </div>
      <div id="histogram-toggle">HISTOGRAMS</div>
    </div>
    <div id="sidebar">
      <h1>LANGUAGE LEARNING VISUALIZER</h1>

      <details open>
        <summary>Learning Progress</summary>
        <div class="section-body">
          <div class="stat"><span>Sentences:</span><span class="stat-value" id="stat-sentences">0</span></div>
          <div class="stat"><span>Learn Rate:</span><span class="stat-value" id="stat-learn-rate">0%</span></div>
          <div class="stat"><span>Level:</span><span class="stat-value" id="stat-level">0</span></div>
          <div class="stat"><span>Epoch:</span><span class="stat-value" id="stat-epoch">0</span></div>
          <div class="stat"><span>Avg Surprise:</span><span class="stat-value" id="stat-surprise">0</span></div>
        </div>
      </details>

      <details open>
        <summary>Graph</summary>
        <div class="section-body">
          <div class="stat"><span>Words:</span><span class="stat-value" id="stat-words">0</span></div>
          <div class="stat"><span>Pairs:</span><span class="stat-value" id="stat-pairs">0</span></div>
          <div class="stat"><span>Clusters:</span><span class="stat-value" id="stat-clusters">0</span></div>
          <div class="stat"><span>Word Classes:</span><span class="stat-value" id="stat-classes">0</span></div>
        </div>
      </details>

      <details>
        <summary>MI Distribution</summary>
        <div class="section-body">
          <div class="stat"><span>Total MI Pairs:</span><span class="stat-value" id="stat-mi-total">0</span></div>
          <div class="stat"><span>MI Mean:</span><span class="stat-value" id="stat-mi-mean">-</span></div>
          <div class="stat"><span>MI Std:</span><span class="stat-value" id="stat-mi-std">-</span></div>
          <div class="stat"><span>MI Range:</span><span class="stat-value" id="stat-mi-range">-</span></div>
        </div>
      </details>

      <details open>
        <summary>Promotion to L1 (Senses)</summary>
        <div class="section-body">
          <div class="prom-bar"><div class="prom-bar-fill" id="prom-bar-fill" style="width:0%"></div></div>
          <div class="prom-check"><span class="label">Sentences > 2000</span><span id="prom-sent" class="fail">--</span></div>
          <div class="prom-check"><span class="label">Cluster iterations > 3</span><span id="prom-iter" class="fail">--</span></div>
          <div class="prom-check"><span class="label">Classes > 20</span><span id="prom-classes" class="fail">--</span></div>
          <div class="prom-check"><span class="label">Structure exhausted</span><span id="prom-exhausted" class="fail">--</span></div>
          <div class="stat-separator"></div>
          <div class="prom-check"><span class="label">Top-pair / floor</span><span id="prom-top-score" class="fail">--</span></div>
          <div class="prom-check"><span class="label">Marginal entropy</span><span id="prom-entropy" class="fail">--</span></div>
          <div class="stat-separator"></div>
          <div class="stat"><span>Word Senses:</span><span class="stat-value" id="stat-senses">0</span></div>
          <div class="stat"><span>Section Pairs:</span><span class="stat-value" id="stat-sections">0</span></div>
        </div>
      </details>

      <details open>
        <summary>Benchmark</summary>
        <div class="section-body">
          <div class="bench-row"><span class="label">Runtime</span><span class="val" id="bench-runtime">-</span></div>
          <div class="bench-row"><span class="label">Throughput</span><span class="val" id="bench-throughput">-</span></div>
          <div class="bench-group">
            <div class="bench-group-title">GPU MI</div>
            <div class="bench-row"><span class="label">Total / Calls</span><span class="val" id="bench-mi-summary">-</span></div>
            <div class="bench-row"><span class="label">Avg per call</span><span class="val" id="bench-mi-avg">-</span></div>
            <div class="bench-row"><span class="label">Pairs processed</span><span class="val" id="bench-mi-pairs">-</span></div>
          </div>
          <div class="bench-group">
            <div class="bench-group-title">Clustering</div>
            <div class="bench-row"><span class="label">Total / Calls</span><span class="val" id="bench-cluster-summary">-</span></div>
            <div class="bench-row"><span class="label">Avg per round</span><span class="val" id="bench-cluster-avg">-</span></div>
          </div>
          <div class="bench-group">
            <div class="bench-group-title">Eviction</div>
            <div class="bench-row"><span class="label">Total / Calls</span><span class="val" id="bench-evict-summary">-</span></div>
          </div>
          <div class="bench-group">
            <div class="bench-group-title">Export</div>
            <div class="bench-row"><span class="label">Total / Calls</span><span class="val" id="bench-export-summary">-</span></div>
            <div class="bench-row"><span class="label">Avg per export</span><span class="val" id="bench-export-avg">-</span></div>
          </div>
        </div>
      </details>

      <details>
        <summary>Layout Quality</summary>
        <div class="section-body">
          <div class="stat"><span>Layout Stress:</span><span class="stat-value" id="stat-stress">-</span></div>
          <div class="stat"><span>MI&harr;Dist Corr:</span><span class="stat-value" id="stat-corr">-</span></div>
          <div style="margin-top: 8px;">
            <button onclick="exportPositions()" style="width: 100%; padding: 6px; background: #1a1a25; color: #4ecdc4; border: 1px solid #333; border-radius: 4px; cursor: pointer; font-family: inherit; font-size: 11px;">Export Positions</button>
          </div>
        </div>
      </details>

      <details open>
        <summary>Layout</summary>
        <div class="section-body">
          <div class="slider-container">
            <select id="layout-mode" style="width: 100%; padding: 5px; background: #1a1a25; color: #e0e0e0; border: 1px solid #333;">
              <option value="unified">Unified (single cloud)</option>
              <option value="atomspaces">Mindmap (radial)</option>
              <option value="chapters">Chapters (radial rings)</option>
            </select>
            <div class="hint">Mindmap = radial by surprise. Chapters = rings per chapter.</div>
          </div>
          <div class="slider-container">
            <label>Detail Level: <span id="detail-level-value">3</span></label>
            <input type="range" id="detail-level-slider" min="1" max="4" step="1" value="3">
            <div class="hint">1=books 2=core 3=communities 4=full</div>
          </div>
          <div class="slider-container">
            <label>Grid Opacity: <span id="grid-opacity-value">0.4</span></label>
            <input type="range" id="grid-opacity-slider" min="0.05" max="1.0" step="0.05" value="0.4">
          </div>
          <div class="slider-container">
            <label>Cell Size: <span id="cell-size-value">8</span></label>
            <input type="range" id="cell-size-slider" min="4" max="20" step="1" value="8">
          </div>
          <div class="slider-container">
            <label>Cell Gap: <span id="cell-gap-value">0</span></label>
            <input type="range" id="cell-gap-slider" min="0" max="8" step="0.5" value="0">
          </div>
        </div>
      </details>

      <details open>
        <summary>Color Mode</summary>
        <div class="section-body">
          <div class="slider-container">
            <select id="color-mode" style="width: 100%; padding: 5px; background: #1a1a25; color: #e0e0e0; border: 1px solid #333;">
              <option value="density">Connection Density</option>
              <option value="cluster" selected>Cluster Membership</option>
              <option value="wordClass">Word Class</option>
              <option value="atomspace">Atomspace</option>
              <option value="vagueness">Vagueness/Surprise</option>
              <option value="mindmap">Mindmap (centrality)</option>
            </select>
            <div class="hint">How nodes are colored</div>
          </div>
        </div>
      </details>

      <details>
        <summary>Legend</summary>
        <div class="section-body">
          <div class="legend" id="density-legend">
            <div class="legend-item">
              <div class="legend-color" style="background: #ffeeaa;"></div>
              <span>Hub (many connections)</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: #e6b333;"></div>
              <span>High connectivity</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: #66cc99;"></div>
              <span>Medium connectivity</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: #3399cc;"></div>
              <span>Low connectivity</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: #334dcc;"></div>
              <span>Isolated (few connections)</span>
            </div>
          </div>
          <div class="legend" id="vagueness-legend" style="display: none;">
            <div class="legend-item">
              <div class="legend-color" style="background: #ff4444;"></div>
              <span>High surprise (unknown)</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: #ffcc44;"></div>
              <span>Learning</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: #44cc88;"></div>
              <span>Low surprise</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: #4488ff;"></div>
              <span>Well known</span>
            </div>
          </div>
          <div class="legend" id="cluster-legend" style="display: none;">
            <div class="legend-item">
              <span>Each cluster has a unique color</span>
            </div>
          </div>
          <div class="legend" id="wordclass-legend" style="display: none;">
            <div class="legend-item">
              <span>Each grammatical word class has a unique color</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: #666;"></div>
              <span>Unclassified words (gray)</span>
            </div>
          </div>
          <div class="legend" id="atomspace-legend" style="display: none;">
            <div class="legend-item">
              <div class="legend-color" style="background: rgb(255,235,153);"></div>
              <span>Common (shared knowledge)</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: rgb(102,204,255);"></div>
              <span>Alice in Wonderland</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: rgb(255,102,153);"></div>
              <span>Pride and Prejudice</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: rgb(102,255,153);"></div>
              <span>Sherlock Holmes</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: rgb(204,127,255);"></div>
              <span>Great Expectations</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: rgb(255,178,76);"></div>
              <span>Moby Dick</span>
            </div>
          </div>

          <div class="legend" id="mindmap-legend" style="display: none;">
            <div class="legend-item">
              <div class="legend-color" style="background: linear-gradient(to right, #ddd, #4ecdc4);"></div>
              <span>Center = vivid (certain)</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: linear-gradient(to right, #888, #334);"></div>
              <span>Edge = faded (vague)</span>
            </div>
            <div class="legend-item">
              <span>Hue = community, brightness = centrality</span>
            </div>
          </div>

          <h2 style="margin-top: 10px;">Edges (MI Strength)</h2>
          <div class="legend">
            <div class="legend-item">
              <div class="legend-color" style="background: #ffffff;"></div>
              <span>Very strong MI</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: #ffff33;"></div>
              <span>Strong MI</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: #33cccc;"></div>
              <span>Medium MI</span>
            </div>
            <div class="legend-item">
              <div class="legend-color" style="background: #1a3380;"></div>
              <span>Weak MI</span>
            </div>
          </div>
        </div>
      </details>

      <details>
        <summary>Filters</summary>
        <div class="section-body">
          <div class="slider-container">
            <label>Min Edge MI: <span id="mi-value">0.5</span></label>
            <input type="range" id="mi-slider" min="0" max="5" step="0.1" value="0.5">
            <div class="hint">Higher = fewer edges, only strong links</div>
          </div>
          <div class="slider-container">
            <label>Max Surprise: <span id="vague-value">10</span></label>
            <input type="range" id="vague-slider" min="0" max="10" step="0.5" value="10">
            <div class="hint">Lower = only well-known words</div>
          </div>
        </div>
      </details>

      <details>
        <summary>Display</summary>
        <div class="section-body">
          <div class="slider-container">
            <label>Point Size: <span id="point-size-value">1.0</span></label>
            <input type="range" id="point-size-slider" min="0.1" max="5" step="0.1" value="1.0">
          </div>
          <div class="slider-container">
            <label>Edge Opacity: <span id="line-width-value">0.4</span></label>
            <input type="range" id="line-width-slider" min="0.1" max="3" step="0.1" value="0.4">
          </div>
          <div class="slider-container">
            <label style="display: flex; align-items: center; gap: 8px;">
              <input type="checkbox" id="auto-rotate" checked> Auto Rotate
            </label>
          </div>
          <div class="slider-container">
            <label style="display: flex; align-items: center; gap: 8px;">
              <input type="checkbox" id="show-labels" checked> Show Labels
            </label>
          </div>
          <div class="slider-container">
            <label>Label Count: <span id="label-count-value">60</span></label>
            <input type="range" id="label-count-slider" min="10" max="200" step="10" value="60">
            <div class="hint">How many top words get labels</div>
          </div>
        </div>
      </details>

      <details open>
        <summary>Atomspaces</summary>
        <div class="section-body">
          <div class="cluster-list" id="atomspace-list">
            <div style="color:#555;font-size:10px;padding:4px;">No atomspace data — use (compartment-export)</div>
          </div>
        </div>
      </details>

      <details>
        <summary>Word Clusters</summary>
        <div class="section-body">
          <div class="cluster-list" id="cluster-list"></div>
        </div>
      </details>

      <details open>
        <summary>Word Classes</summary>
        <div class="section-body">
          <div class="cluster-list" id="class-list"></div>
        </div>
      </details>
    </div>
  </div>

  <script src="viz-3d.js?v=76"></script>
</body>
</html>