| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"/> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"/> |
| <title>⚡ CodeDebug</title> |
| <link rel="preconnect" href="https://fonts.googleapis.com"> |
| <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;700&family=Syne:wght@600;700;800&display=swap" rel="stylesheet"> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css"> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/9.1.6/marked.min.js"></script> |
| <style> |
| /* ════════════════════════════════════════ |
| BASE - PROFESSIONAL MONOCHROME |
| ════════════════════════════════════════ */ |
| *,*::before,*::after{box-sizing:border-box;margin:0;padding:0} |
|
|
| :root{ |
| /* Professional grayscale palette */ |
| --bg: #ffffff; |
| --bg2: #f8f9fa; |
| --bg3: #f1f3f4; |
| --bg4: #e8eaed; |
| --bg5: #dadce0; |
| --line: #dadce0; |
| --line2: #c6c9ce; |
|
|
| --ink: #202124; |
| --ink2: #5f6368; |
| --ink3: #80868b; |
|
|
| /* Single accent: Deep Navy */ |
| --accent: #1a73e8; |
| --accent-light: rgba(26,115,232,0.08); |
| --accent-glow: rgba(26,115,232,0.15); |
|
|
| /* Status colors - muted */ |
| --green: #137333; |
| --red: #d93025; |
| --amber: #f9ab00; |
|
|
| --mono:'JetBrains Mono',monospace; |
| --sans:'Syne',sans-serif; |
| --r:4px; |
| } |
|
|
| html,body{height:100%;overflow:hidden} |
| body{ |
| background:var(--bg);color:var(--ink); |
| font-family:var(--mono);font-size:13px; |
| display:flex;flex-direction:column; |
| } |
|
|
| /* Subtle grid pattern instead of scanlines */ |
| body::after{ |
| content:'';position:fixed;inset:0;pointer-events:none;z-index:9999; |
| background-image: |
| linear-gradient(var(--bg5) 1px, transparent 1px), |
| linear-gradient(90deg, var(--bg5) 1px, transparent 1px); |
| background-size: 50px 50px; |
| opacity: 0.3; |
| } |
|
|
| /* ════════════════════════════════════════ |
| HEADER BAR |
| ════════════════════════════════════════ */ |
| .hdr{ |
| flex-shrink:0;height:48px; |
| background:var(--bg);border-bottom:1px solid var(--line); |
| display:flex;align-items:center;padding:0 20px;gap:16px; |
| box-shadow: 0 1px 2px rgba(60,64,67,0.1); |
| } |
| .logo{display:flex;align-items:center;gap:10px} |
| .logo-gem{ |
| width:28px;height:28px;border-radius:6px; |
| background:var(--accent); |
| display:flex;align-items:center;justify-content:center;font-size:14px; |
| color: white; |
| } |
| .logo-txt{font-family:var(--sans);font-size:16px;font-weight:700;letter-spacing:-0.3px;color:var(--ink)} |
| .logo-txt b{color:var(--accent);font-weight:800} |
| .hdr-sep{width:1px;height:20px;background:var(--line)} |
| .hdr-pills{display:flex;gap:8px} |
| .hp{padding:4px 12px;border-radius:4px;font-size:11px;border:1px solid var(--line);white-space:nowrap;background:var(--bg2);color:var(--ink2);font-weight:500} |
| .hp1{color:var(--accent);border-color:var(--accent);background:var(--accent-light)} |
| .hdr-right{margin-left:auto;font-size:11px;color:var(--ink2)} |
| .hdr-right b{color:var(--accent);font-weight:600} |
|
|
| /* ════════════════════════════════════════ |
| STATUS STRIP |
| ════════════════════════════════════════ */ |
| .sbar{ |
| flex-shrink:0;height:32px; |
| background:var(--bg2);border-bottom:1px solid var(--line); |
| display:flex;align-items:center;padding:0 20px;gap:12px; |
| font-size:12px;color:var(--ink2); |
| } |
| .sdot{width:6px;height:6px;border-radius:50%;background:var(--ink3);flex-shrink:0;transition:background .3s} |
| .sdot.idle {background:var(--ink3)} |
| .sdot.run {background:var(--accent);animation:pulse 1.5s ease-in-out infinite} |
| .sdot.done {background:var(--green)} |
| .sdot.err {background:var(--red)} |
| @keyframes pulse{0%,100%{opacity:1}50%{opacity:.5}} |
| #sMsg{flex:1;font-weight:500} |
| #sTime{color:var(--accent);font-weight:600} |
|
|
| /* ════════════════════════════════════════ |
| 3-COLUMN BODY 25 | 50 | 25 |
| ════════════════════════════════════════ */ |
| .body{ |
| flex:1;display:grid; |
| grid-template-columns:25% 50% 25%; |
| overflow:hidden;min-height:0; |
| } |
|
|
| /* shared column chrome */ |
| .col{display:flex;flex-direction:column;overflow:hidden;min-height:0} |
| .col+.col{border-left:1px solid var(--line)} |
|
|
| .col-hdr{ |
| flex-shrink:0;padding:10px 16px; |
| background:var(--bg);border-bottom:1px solid var(--line); |
| font-size:11px;text-transform:uppercase;letter-spacing:1px; |
| color:var(--ink2);display:flex;align-items:center;gap:8px; |
| font-weight:600; |
| } |
| .chd{width:6px;height:6px;border-radius:50%;flex-shrink:0;background:var(--accent)} |
| .col-body{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px} |
|
|
| /* ════════════════════════════════════════ |
| LEFT 25% — INPUT |
| ════════════════════════════════════════ */ |
| .query-wrap{position:relative} |
| .q-prompt{ |
| position:absolute;left:12px;top:12px; |
| color:var(--accent);font-size:14px;font-weight:700;pointer-events:none;z-index:1 |
| } |
| #qInput{ |
| width:100%;min-height:140px;max-height:360px; |
| padding:12px 12px 12px 28px; |
| background:var(--bg);border:1px solid var(--line2);border-radius:var(--r); |
| color:var(--ink);font-family:var(--mono);font-size:13px; |
| resize:vertical;outline:none;line-height:1.6; |
| transition:border-color .2s,box-shadow .2s; |
| } |
| #qInput:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-glow)} |
| #qInput::placeholder{color:var(--ink3)} |
|
|
| .field-lbl{font-size:11px;color:var(--ink2);margin-bottom:6px;text-transform:uppercase;letter-spacing:0.5px;font-weight:600} |
| .temp-row{display:flex;align-items:center;gap:12px;font-size:12px;color:var(--ink2)} |
| .temp-row input[type=range]{flex:1;accent-color:var(--accent);cursor:pointer;height:4px;border-radius:2px} |
| #tVal{color:var(--accent);min-width:32px;text-align:right;font-weight:600} |
|
|
| .btn-run{ |
| width:100%;padding:12px; |
| background:var(--accent); |
| color:#fff;border:none;border-radius:var(--r); |
| font-family:var(--sans);font-size:13px;font-weight:700; |
| letter-spacing:0.5px;text-transform:uppercase;cursor:pointer; |
| transition:all .2s;box-shadow:0 1px 3px rgba(26,115,232,0.3); |
| } |
| .btn-run:hover{background:#1557b0;transform:translateY(-1px);box-shadow:0 4px 8px rgba(26,115,232,0.25)} |
| .btn-run:active{transform:translateY(0)} |
| .btn-run:disabled{background:var(--bg5);color:var(--ink3);cursor:not-allowed;box-shadow:none;transform:none} |
|
|
| .hint-txt{font-size:11px;color:var(--ink3);text-align:center} |
| kbd{background:var(--bg3);border:1px solid var(--line2);border-radius:3px;padding:2px 6px;font-size:10px;color:var(--ink2);font-family:var(--mono)} |
|
|
| /* divider line in left col */ |
| .field-sep{height:1px;background:var(--line);margin:8px 0} |
|
|
| /* previous queries list */ |
| .q-history{display:flex;flex-direction:column;gap:8px} |
| .q-hist-item{ |
| padding:10px 12px;background:var(--bg);border:1px solid var(--line); |
| border-radius:var(--r);font-size:12px;color:var(--ink2); |
| cursor:pointer;line-height:1.5;transition:all .15s; |
| overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical; |
| } |
| .q-hist-item:hover{border-color:var(--accent);color:var(--ink);background:var(--bg2);box-shadow:0 1px 2px rgba(0,0,0,0.05)} |
|
|
| /* ════════════════════════════════════════ |
| MIDDLE 50% — JUDGE OUTPUT |
| ════════════════════════════════════════ */ |
| .judge-panel{ |
| background:var(--bg);border:1px solid var(--line); |
| border-radius:var(--r);display:flex;flex-direction:column; |
| flex:1;min-height:0;overflow:hidden;transition:border-color .3s; |
| box-shadow: 0 1px 3px rgba(60,64,67,0.08); |
| } |
| .judge-panel.done{border-color:var(--green);background:var(--bg)} |
|
|
| .jp-head{ |
| flex-shrink:0;display:flex;align-items:center;gap:12px; |
| padding:12px 16px; |
| background:var(--bg2);border-bottom:1px solid var(--line); |
| } |
| .jp-icon{ |
| width:28px;height:28px;border-radius:6px;flex-shrink:0; |
| background:var(--accent); |
| display:flex;align-items:center;justify-content:center;font-size:14px; |
| color: white; |
| } |
| .jp-title{font-family:var(--sans);font-size:14px;font-weight:700;color:var(--ink)} |
| .jp-sub {font-size:11px;color:var(--ink2);margin-top:2px} |
| .jp-lat { |
| margin-left:auto;font-size:11px;color:var(--accent); |
| padding:4px 10px;background:var(--accent-light); |
| border:1px solid var(--accent-glow);border-radius:12px; |
| font-weight:600; |
| } |
|
|
| /* error analysis box */ |
| .err-box{ |
| flex-shrink:0;margin:16px 16px 0; |
| background:var(--bg2);border:1px solid var(--line2); |
| border-radius:var(--r);overflow:hidden; |
| } |
| .err-box-hdr{ |
| padding:10px 14px;background:var(--bg3); |
| font-size:11px;text-transform:uppercase;letter-spacing:0.5px; |
| color:var(--red);border-bottom:1px solid var(--line); |
| display:flex;align-items:center;gap:8px;font-weight:600; |
| } |
| .err-box-body{padding:14px;font-size:13px;line-height:1.7;color:var(--ink)} |
|
|
| /* corrected code box */ |
| .code-box{ |
| flex:1;display:flex;flex-direction:column; |
| margin:12px 16px 16px;min-height:0; |
| background:var(--bg);border:1px solid var(--line2);border-radius:var(--r); |
| overflow:hidden; |
| } |
| .code-box-hdr{ |
| flex-shrink:0;padding:10px 14px;background:var(--bg2); |
| font-size:11px;text-transform:uppercase;letter-spacing:0.5px; |
| color:var(--green);border-bottom:1px solid var(--line); |
| display:flex;align-items:center;gap:8px;font-weight:600; |
| } |
| .copy-code-btn{ |
| margin-left:auto;padding:4px 12px;background:var(--bg); |
| border:1px solid var(--line2);border-radius:3px; |
| color:var(--ink2);font-size:10px;font-family:var(--mono);cursor:pointer;transition:all .15s;font-weight:500; |
| } |
| .copy-code-btn:hover{color:var(--accent);border-color:var(--accent);background:var(--bg3)} |
| .code-box-body{flex:1;overflow-y:auto;padding:0} |
| .code-box-body pre{margin:0;border-radius:0;border:none !important;height:100%;background:var(--bg3) !important} |
| .code-box-body pre code{font-size:13px;line-height:1.6} |
|
|
| /* judge placeholder / skeleton */ |
| .jp-placeholder{ |
| flex:1;display:flex;flex-direction:column; |
| align-items:center;justify-content:center; |
| gap:16px;color:var(--ink3);text-align:center;padding:60px 24px; |
| } |
| .jp-ph-icon{font-size:48px;opacity:0.2} |
| .jp-ph-txt{font-size:13px;line-height:1.7;max-width:320px} |
|
|
| .jp-skel{padding:20px 16px;display:flex;flex-direction:column;gap:12px} |
| .jsk{ |
| height:12px;border-radius:3px; |
| background:linear-gradient(90deg,var(--bg3) 25%,var(--bg4) 50%,var(--bg3) 75%); |
| background-size:200% 100%;animation:shim 2s infinite; |
| } |
| @keyframes shim{0%{background-position:200% 0}100%{background-position:-200% 0}} |
|
|
| /* ════════════════════════════════════════ |
| RIGHT 25% — PANEL MODELS |
| ════════════════════════════════════════ */ |
| .model-card{ |
| background:var(--bg);border:1px solid var(--line); |
| border-radius:var(--r);overflow:hidden;transition:all .3s; |
| box-shadow: 0 1px 2px rgba(60,64,67,0.05); |
| } |
| .model-card[data-s="d1"]{border-color:var(--accent);box-shadow:0 2px 8px var(--accent-glow)} |
| .model-card[data-s="d2"]{border-color:var(--ink2)} |
| .model-card[data-s="er"]{border-color:var(--red)} |
|
|
| .mc-hdr{ |
| display:flex;align-items:center;gap:12px;padding:12px 14px; |
| background:var(--bg2);border-bottom:1px solid var(--line); |
| cursor:pointer;user-select:none; |
| } |
| .mc-hdr:hover{background:var(--bg3)} |
|
|
| .mc-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0;transition:all .3s} |
| .mcd1{background:var(--accent)} .mcd2{background:var(--ink2)} |
| .model-card[data-s="d1"] .mcd1{box-shadow:0 0 0 3px var(--accent-glow)} |
| .model-card[data-s="d2"] .mcd2{box-shadow:0 0 0 3px rgba(95,99,104,0.15)} |
|
|
| .mc-info{flex:1} |
| .mc-name{font-family:var(--sans);font-size:12px;font-weight:700;color:var(--ink)} |
| .mc-id{font-size:10px;color:var(--ink2);margin-top:2px} |
|
|
| .mc-lat{font-size:11px;padding:4px 10px;border-radius:12px;background:var(--bg3);min-width:42px;text-align:center;font-weight:600;color:var(--ink2)} |
| .model-card[data-s="d1"] .mc-lat{color:var(--accent);background:var(--accent-light)} |
|
|
| .mc-chev{color:var(--ink2);font-size:10px;transition:transform .2s;flex-shrink:0} |
| .model-card.coll .mc-chev{transform:rotate(-90deg)} |
|
|
| .mc-body{overflow:hidden;transition:max-height .3s ease;max-height:480px} |
| .model-card.coll .mc-body{max-height:0!important} |
| .mc-inner{padding:14px;max-height:430px;overflow-y:auto} |
|
|
| /* skeleton */ |
| .skel{display:flex;flex-direction:column;gap:8px;padding:14px} |
| .sk{ |
| height:10px;border-radius:2px; |
| background:linear-gradient(90deg,var(--bg3) 25%,var(--bg4) 50%,var(--bg3) 75%); |
| background-size:200% 100%;animation:shim 1.6s infinite; |
| } |
| .sk:nth-child(2){width:78%;animation-delay:.15s} |
| .sk:nth-child(3){width:62%;animation-delay:.3s} |
| .sk:nth-child(4){width:85%;animation-delay:.45s} |
|
|
| .mc-empty{padding:28px 14px;text-align:center;color:var(--ink2);font-size:12px} |
| .mc-eicon{font-size:24px;margin-bottom:8px;opacity:0.3} |
| .mc-err{color:var(--red);font-size:12px;padding:14px;font-style:italic;background:var(--bg2);border-radius:var(--r)} |
|
|
| /* ════════════════════════════════════════ |
| MARKDOWN RENDERER |
| ════════════════════════════════════════ */ |
| .md p{margin-bottom:10px;line-height:1.7} |
| .md ul,.md ol{padding-left:20px;margin-bottom:10px} |
| .md li{margin-bottom:4px} |
| .md h1,.md h2,.md h3{font-family:var(--sans);font-weight:700;margin:16px 0 8px;color:var(--ink)} |
| .md h1{font-size:16px;border-bottom:1px solid var(--line);padding-bottom:8px} |
| .md h2{font-size:14px;color:var(--accent)} |
| .md h3{font-size:13px;color:var(--ink2)} |
| .md code{ |
| font-family:var(--mono);font-size:12px; |
| background:var(--bg3);border:1px solid var(--line2); |
| padding:2px 6px;border-radius:3px;color:var(--accent); |
| } |
| .md pre{ |
| background:var(--bg3)!important;border:1px solid var(--line2); |
| border-radius:var(--r);padding:14px;overflow-x:auto;margin:12px 0; |
| } |
| .md pre code{background:none!important;border:none!important;padding:0!important;color:inherit!important} |
| .md blockquote{border-left:3px solid var(--accent);padding-left:14px;color:var(--ink2);font-style:italic;margin:12px 0;background:var(--bg2);padding:12px 14px;border-radius:0 var(--r) var(--r) 0} |
| .md strong{color:var(--ink);font-weight:700} |
| .md em{color:var(--ink2)} |
| .md hr{border:none;border-top:1px solid var(--line);margin:16px 0} |
| .md a{color:var(--accent);text-decoration:none;font-weight:500} |
| .md a:hover{text-decoration:underline} |
| .md table{width:100%;border-collapse:collapse;margin:12px 0;font-size:12px;border:1px solid var(--line)} |
| .md th{background:var(--bg2);color:var(--ink);padding:10px 12px;text-align:left;border:1px solid var(--line);font-weight:600} |
| .md td{padding:8px 12px;border:1px solid var(--line)} |
|
|
| /* ════════════════════════════════════════ |
| SCROLLBARS |
| ════════════════════════════════════════ */ |
| ::-webkit-scrollbar{width:6px;height:6px} |
| ::-webkit-scrollbar-track{background:var(--bg2)} |
| ::-webkit-scrollbar-thumb{background:var(--line2);border-radius:3px} |
| ::-webkit-scrollbar-thumb:hover{background:var(--ink3)} |
|
|
| /* ════════════════════════════════════════ |
| UTILS |
| ════════════════════════════════════════ */ |
| @keyframes fadeUp{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:translateY(0)}} |
| .fu{animation:fadeUp .3s ease forwards} |
|
|
| @media(max-width:800px){ |
| .body{grid-template-columns:1fr;grid-template-rows:auto auto auto;overflow-y:auto} |
| html,body{overflow-y:auto;height:auto} |
| .col{overflow:visible;min-height:auto} |
| .col-body{overflow:visible} |
| .judge-panel{min-height:300px} |
| } |
| </style> |
| </head> |
| <body> |
|
|
| |
| <div class="hdr"> |
| <div class="logo"> |
| <div class="logo-gem">⚡</div> |
| <div class="logo-txt"><b>Code</b>Debug</div> |
| </div> |
| <div class="hdr-sep"></div> |
| <div class="hdr-pills"> |
| <span class="hp hp1">Trinity Large</span> |
| <span class="hp">Nemotron Nano</span> |
| <span class="hp">StepFun Judge</span> |
| </div> |
| <div class="hdr-right">Queries: <b id="qCnt">0</b></div> |
| </div> |
|
|
| |
| <div class="sbar"> |
| <div class="sdot idle" id="sDot"></div> |
| <span id="sMsg">Ready — enter your code or describe the bug</span> |
| <span id="sTime"></span> |
| </div> |
|
|
| |
| <div class="body"> |
|
|
| |
| <div class="col"> |
| <div class="col-hdr"><div class="chd"></div>Input</div> |
| <div class="col-body"> |
|
|
| <div> |
| <div class="field-lbl">Your code / question</div> |
| <div class="query-wrap"> |
| <div class="q-prompt">></div> |
| <textarea id="qInput" rows="5" |
| placeholder="Paste buggy code or describe the issue… e.g. def divide(a,b): return a/b divide(10,0)"></textarea> |
| </div> |
| </div> |
|
|
| <div> |
| <div class="field-lbl">Temperature</div> |
| <div class="temp-row"> |
| <input type="range" id="tSlider" min="0" max="1" step="0.05" value="0.3" |
| oninput="document.getElementById('tVal').textContent=this.value"> |
| <span id="tVal">0.3</span> |
| </div> |
| </div> |
|
|
| <button class="btn-run" id="runBtn" onclick="runDebug()">▶ Run Debug</button> |
| <div class="hint-txt"><kbd>Ctrl</kbd>+<kbd>Enter</kbd> to submit</div> |
|
|
| <div class="field-sep"></div> |
|
|
| |
| <div id="histWrap" style="display:none"> |
| <div class="field-lbl" style="margin-bottom:7px">Recent</div> |
| <div class="q-history" id="histList"></div> |
| </div> |
|
|
| </div> |
| </div> |
|
|
| |
| <div class="col"> |
| <div class="col-hdr"> |
| <div class="chd" style="background:var(--green)"></div> |
| Judge Output — StepFun Flash |
| </div> |
| <div class="col-body"> |
|
|
| <div class="judge-panel" id="jPanel"> |
| <div class="jp-head"> |
| <div class="jp-icon">⚖</div> |
| <div> |
| <div class="jp-title">StepFun Flash Judge</div> |
| <div class="jp-sub">stepfun/step-3.5-flash:free · synthesized verdict</div> |
| </div> |
| <div class="jp-lat" id="jLat">—</div> |
| </div> |
|
|
| <div id="jBody" style="display:flex;flex-direction:column;flex:1;min-height:0;overflow:hidden"> |
| <div class="jp-placeholder" id="jPlaceholder"> |
| <div class="jp-ph-icon">⚖️</div> |
| <div class="jp-ph-txt"> |
| The judge analyzes both model responses<br> |
| and returns the exact bug + corrected code. |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| </div> |
| </div> |
|
|
| |
| <div class="col"> |
| <div class="col-hdr"><div class="chd" style="background:var(--ink2)"></div>Debugger Models</div> |
| <div class="col-body"> |
|
|
| |
| <div class="model-card" id="c0" data-s="idle"> |
| <div class="mc-hdr" onclick="toggleCard(0)"> |
| <div class="mc-dot mcd1"></div> |
| <div class="mc-info"> |
| <div class="mc-name">Trinity Large</div> |
| <div class="mc-id">arcee-ai/trinity-large-preview</div> |
| </div> |
| <div class="mc-lat" id="l0">—</div> |
| <div class="mc-chev">▾</div> |
| </div> |
| <div class="mc-body"> |
| <div class="mc-empty"><div class="mc-eicon">🔵</div>Awaiting query…</div> |
| </div> |
| </div> |
|
|
| |
| <div class="model-card" id="c1" data-s="idle"> |
| <div class="mc-hdr" onclick="toggleCard(1)"> |
| <div class="mc-dot mcd2"></div> |
| <div class="mc-info"> |
| <div class="mc-name">Nemotron Nano</div> |
| <div class="mc-id">nvidia/nemotron-3-nano-30b-a3b</div> |
| </div> |
| <div class="mc-lat" id="l1">—</div> |
| <div class="mc-chev">▾</div> |
| </div> |
| <div class="mc-body"> |
| <div class="mc-empty"><div class="mc-eicon">🟡</div>Awaiting query…</div> |
| </div> |
| </div> |
|
|
| </div> |
| </div> |
|
|
| </div> |
|
|
| <script> |
| |
| const API = ''; |
| marked.setOptions({breaks:true,gfm:true}); |
| |
| |
| let running = false; |
| let qCount = 0; |
| const coll = [false, false]; |
| const hist = []; |
| |
| |
| function esc(s){ return String(s??'').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') } |
| |
| function md(text){ |
| if(!text) return '<em style="color:var(--ink3)">—</em>'; |
| return `<div class="md">${marked.parse(text)}</div>`; |
| } |
| |
| function hlCode(el){ |
| el.querySelectorAll('pre code').forEach(b => hljs.highlightElement(b)); |
| } |
| |
| function setStatus(state, msg, time=''){ |
| document.getElementById('sDot').className = `sdot ${state}`; |
| document.getElementById('sMsg').textContent = msg; |
| document.getElementById('sTime').textContent = time; |
| } |
| |
| function toggleCard(i){ |
| coll[i] = !coll[i]; |
| document.getElementById(`c${i}`).classList.toggle('coll', coll[i]); |
| } |
| |
| |
| function panelSkel(i){ |
| document.getElementById(`c${i}`).dataset.s = 'loading'; |
| document.getElementById(`l${i}`).textContent = '…'; |
| document.querySelector(`#c${i} .mc-body`).innerHTML = |
| '<div class="skel"><div class="sk"></div><div class="sk"></div><div class="sk"></div><div class="sk"></div></div>'; |
| } |
| |
| function panelResult(i, r){ |
| const card = document.getElementById(`c${i}`); |
| const body = document.querySelector(`#c${i} .mc-body`); |
| document.getElementById(`l${i}`).textContent = `${r.latency_ms}ms`; |
| if(r.error){ |
| card.dataset.s = 'er'; |
| body.innerHTML = `<div class="mc-err">⚠ ${esc(r.error)}</div>`; |
| return; |
| } |
| card.dataset.s = `d${i+1}`; |
| body.innerHTML = `<div class="mc-inner fu">${md(r.response)}</div>`; |
| hlCode(body); |
| } |
| |
| |
| function judgeSkel(){ |
| document.getElementById('jLat').textContent = '…'; |
| document.getElementById('jPanel').className = 'judge-panel'; |
| document.getElementById('jBody').innerHTML = ` |
| <div class="jp-skel"> |
| <div class="jsk" style="width:55%"></div><div class="jsk"></div> |
| <div class="jsk" style="width:78%"></div><div class="jsk" style="width:40%"></div> |
| <div class="jsk"></div><div class="jsk" style="width:68%"></div> |
| </div>`; |
| } |
| |
| function judgeResult(r){ |
| const jb = document.getElementById('jBody'); |
| const jp = document.getElementById('jPanel'); |
| document.getElementById('jLat').textContent = `${r.latency_ms}ms`; |
| |
| if(r.error){ |
| jp.className = 'judge-panel'; |
| jb.innerHTML = `<div style="padding:16px 14px"><div class="mc-err">⚠ ${esc(r.error)}</div></div>`; |
| return; |
| } |
| |
| jp.className = 'judge-panel done'; |
| |
| |
| let rawCode = r.corrected_code || ''; |
| let lang = 'python'; |
| const fenceMatch = rawCode.match(/^```(\w+)?\n?([\s\S]*?)```$/s); |
| if(fenceMatch){ lang = fenceMatch[1] || 'python'; rawCode = fenceMatch[2].trim(); } |
| |
| const errHtml = r.error_analysis |
| ? `<div class="err-box"> |
| <div class="err-box-hdr">🐛 Error Analysis</div> |
| <div class="err-box-body fu">${md(r.error_analysis)}</div> |
| </div>` |
| : ''; |
| |
| const codeHtml = rawCode |
| ? `<div class="code-box"> |
| <div class="code-box-hdr"> |
| ✅ Corrected Code |
| <button class="copy-code-btn" id="copyCodeBtn" onclick="copyCode()">Copy</button> |
| </div> |
| <div class="code-box-body"> |
| <pre><code id="correctedCode" class="language-${esc(lang)}">${esc(rawCode)}</code></pre> |
| </div> |
| </div>` |
| : `<div style="padding:14px;color:var(--ink2)">No corrected code returned.</div>`; |
| |
| jb.innerHTML = errHtml + codeHtml; |
| |
| |
| const codeEl = document.getElementById('correctedCode'); |
| if(codeEl) hljs.highlightElement(codeEl); |
| |
| |
| if(r.error_analysis) hlCode(jb); |
| } |
| |
| function copyCode(){ |
| const el = document.getElementById('correctedCode'); |
| if(!el) return; |
| navigator.clipboard.writeText(el.textContent); |
| const btn = document.getElementById('copyCodeBtn'); |
| if(btn){ btn.textContent = 'Copied ✓'; setTimeout(()=>btn.textContent='Copy', 1800); } |
| } |
| |
| |
| function addHistory(q){ |
| if(hist.includes(q)) return; |
| hist.unshift(q); |
| if(hist.length > 6) hist.pop(); |
| renderHistory(); |
| } |
| |
| function renderHistory(){ |
| const list = document.getElementById('histList'); |
| const wrap = document.getElementById('histWrap'); |
| if(!hist.length){ wrap.style.display='none'; return; } |
| wrap.style.display = ''; |
| list.innerHTML = hist.map(q => |
| `<div class="q-hist-item" onclick="fillQuery(this)" title="${esc(q)}">${esc(q)}</div>` |
| ).join(''); |
| } |
| |
| function fillQuery(el){ |
| const ta = document.getElementById('qInput'); |
| ta.value = el.title; |
| ta.style.height='auto'; |
| ta.style.height = Math.min(ta.scrollHeight,340)+'px'; |
| ta.focus(); |
| } |
| |
| |
| async function runDebug(){ |
| if(running) return; |
| const q = document.getElementById('qInput').value.trim(); |
| const temp = parseFloat(document.getElementById('tSlider').value); |
| if(!q){ document.getElementById('qInput').focus(); return; } |
| |
| running = true; |
| document.getElementById('runBtn').disabled = true; |
| const t0 = Date.now(); |
| |
| setStatus('run','Querying Trinity Large + Nemotron Nano in parallel…'); |
| panelSkel(0); panelSkel(1); |
| judgeSkel(); |
| |
| try{ |
| const res = await fetch(`${API}/api/v1/debug`,{ |
| method:'POST', |
| headers:{'Content-Type':'application/json'}, |
| body:JSON.stringify({question:q, temperature:temp}) |
| }); |
| |
| if(!res.ok){ |
| const e = await res.json().catch(()=>({})); |
| throw new Error(e.detail || e.error || `HTTP ${res.status}`); |
| } |
| |
| const data = await res.json(); |
| const ms = Date.now()-t0; |
| |
| data.panel.forEach((r,i)=>panelResult(i,r)); |
| await new Promise(r=>setTimeout(r,150)); |
| judgeResult(data.judge); |
| |
| const ok = data.panel.filter(p=>!p.error).length; |
| setStatus('done',`Done — ${ok}/2 models + judge completed`, `${ms}ms`); |
| |
| qCount++; |
| document.getElementById('qCnt').textContent = qCount; |
| addHistory(q); |
| |
| }catch(err){ |
| setStatus('err',`Error: ${err.message}`); |
| document.getElementById('jBody').innerHTML = |
| `<div style="padding:16px 14px"><div class="mc-err">⚠ ${esc(err.message)}</div></div>`; |
| [0,1].forEach(i=>{ |
| document.getElementById(`c${i}`).dataset.s='er'; |
| document.querySelector(`#c${i} .mc-body`).innerHTML='<div class="mc-err">Request failed</div>'; |
| }); |
| } |
| |
| running=false; |
| document.getElementById('runBtn').disabled=false; |
| } |
| |
| |
| const ta = document.getElementById('qInput'); |
| ta.addEventListener('input',()=>{ |
| ta.style.height='auto'; |
| ta.style.height=Math.min(ta.scrollHeight,340)+'px'; |
| }); |
| |
| |
| ta.addEventListener('keydown',e=>{ |
| if((e.ctrlKey||e.metaKey)&&e.key==='Enter'){e.preventDefault();runDebug();} |
| }); |
| </script> |
| </body> |
| </html> |