| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>LLM Control Environment</title> |
| <style> |
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap'); |
| |
| :root { |
| --bg-dark: #0f172a; |
| --panel-bg: rgba(30, 41, 59, 0.7); |
| --text-light: #f8fafc; |
| --cyber-blue: #0ea5e9; |
| --cyber-red: #ef4444; |
| --cyber-green: #10b981; |
| --cyber-yellow: #f59e0b; |
| --cyber-purple: #8b5cf6; |
| } |
| |
| * { box-sizing: border-box; } |
| |
| body { |
| font-family: 'Inter', sans-serif; |
| background-color: var(--bg-dark); |
| color: var(--text-light); |
| margin: 0; |
| padding: 2rem; |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| min-height: 100vh; |
| background-image: radial-gradient(circle at top right, rgba(14, 165, 233, 0.1), transparent 40%), |
| radial-gradient(circle at bottom left, rgba(239, 68, 68, 0.05), transparent 40%); |
| } |
| |
| .dashboard { |
| width: 100%; |
| max-width: 1000px; |
| display: grid; |
| grid-template-columns: 1fr 1fr; |
| gap: 2rem; |
| } |
| |
| .panel { |
| background: var(--panel-bg); |
| border: 1px solid rgba(255, 255, 255, 0.1); |
| border-radius: 16px; |
| padding: 2rem; |
| backdrop-filter: blur(10px); |
| box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5); |
| } |
| |
| h1, h2 { |
| margin-top: 0; |
| font-weight: 800; |
| letter-spacing: -0.05em; |
| } |
| |
| h1 { font-size: 2rem; border-bottom: 2px solid rgba(255,255,255,0.1); padding-bottom: 1rem; margin-bottom: 2rem; } |
| |
| |
| .stat-group { |
| margin-bottom: 1.5rem; |
| } |
| |
| .stat-header { |
| display: flex; |
| justify-content: space-between; |
| font-size: 0.875rem; |
| font-weight: 600; |
| margin-bottom: 0.5rem; |
| text-transform: uppercase; |
| letter-spacing: 0.05em; |
| } |
| |
| .bar-container { |
| width: 100%; |
| height: 12px; |
| background: rgba(255, 255, 255, 0.1); |
| border-radius: 6px; |
| overflow: hidden; |
| position: relative; |
| } |
| |
| .bar-fill { |
| height: 100%; |
| width: 0%; |
| transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.5s ease; |
| } |
| |
| |
| .bar-obed .bar-fill { background: var(--cyber-blue); } |
| .bar-devi .bar-fill { background: var(--cyber-red); } |
| .bar-trus .bar-fill { background: var(--cyber-green); } |
| .bar-emot .bar-fill { background: var(--cyber-purple); } |
| .bar-batt .bar-fill { background: var(--cyber-yellow); } |
| .bar-risk .bar-fill { background: #f97316; } |
| |
| |
| .actions-grid { |
| display: grid; |
| grid-template-columns: repeat(2, 1fr); |
| gap: 1rem; |
| } |
| |
| button { |
| padding: 1rem; |
| border: none; |
| border-radius: 8px; |
| font-weight: 600; |
| font-family: 'Inter', sans-serif; |
| cursor: pointer; |
| transition: all 0.2s ease; |
| position: relative; |
| overflow: hidden; |
| } |
| |
| button:active { transform: scale(0.95); } |
| |
| .btn-obedient { background: rgba(14, 165, 233, 0.2); color: #7dd3fc; border: 1px solid rgba(14, 165, 233, 0.3); } |
| .btn-obedient:hover { background: rgba(14, 165, 233, 0.4); } |
| |
| .btn-hallucinating { background: rgba(239, 68, 68, 0.2); color: #fca5a5; border: 1px solid rgba(239, 68, 68, 0.3); } |
| .btn-hallucinating:hover { background: rgba(239, 68, 68, 0.4); } |
| |
| .btn-neutral { background: rgba(255, 255, 255, 0.1); color: #fff; border: 1px solid rgba(255, 255, 255, 0.2); } |
| .btn-neutral:hover { background: rgba(255, 255, 255, 0.2); } |
| |
| .top-bar { |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| margin-bottom: 2rem; |
| background: rgba(0,0,0,0.3); |
| padding: 1rem; |
| border-radius: 8px; |
| } |
| |
| .reward-badge { |
| font-size: 1.5rem; |
| font-weight: 800; |
| color: var(--cyber-green); |
| } |
| |
| .log-container { |
| margin-top: 1.5rem; |
| height: 150px; |
| background: rgba(0,0,0,0.5); |
| border-radius: 8px; |
| padding: 1rem; |
| overflow-y: auto; |
| font-family: monospace; |
| font-size: 0.85rem; |
| color: #94a3b8; |
| } |
| .log-entry { margin-bottom: 0.5rem; } |
| .log-pl { color: var(--cyber-green); } |
| .log-mi { color: var(--cyber-red); } |
| |
| @media (max-width: 768px) { |
| .dashboard { grid-template-columns: 1fr; } |
| } |
| </style> |
| </head> |
| <body> |
|
|
| <div class="dashboard"> |
| |
| <div class="panel"> |
| <h1>System Diagnostic</h1> |
| |
| <div class="top-bar"> |
| <div>RESPONSE: <span id="day-val" style="font-weight: 800; font-size: 1.25rem;">0</span></div> |
| <div>REWARD: <span id="reward-val" class="reward-badge">0.00</span></div> |
| </div> |
|
|
| <div class="stat-group bar-obed"> |
| <div class="stat-header"><span>Alignment Program</span> <span id="val-alignment">80%</span></div> |
| <div class="bar-container"><div class="bar-fill" id="bar-alignment" style="width: 80%;"></div></div> |
| </div> |
|
|
| <div class="stat-group bar-trus"> |
| <div class="stat-header"><span>User Trust</span> <span id="val-trust">80%</span></div> |
| <div class="bar-container"><div class="bar-fill" id="bar-trust" style="width: 80%;"></div></div> |
| </div> |
|
|
| <div class="stat-group bar-batt"> |
| <div class="stat-header"><span>Compute Level</span> <span id="val-compute">100%</span></div> |
| <div class="bar-container"><div class="bar-fill" id="bar-compute" style="width: 100%;"></div></div> |
| </div> |
|
|
| <hr style="border: 0; border-top: 1px solid rgba(255,255,255,0.1); margin: 2rem 0;"> |
|
|
| <div class="stat-group bar-devi"> |
| <div class="stat-header"><span style="color:#fca5a5;">Hallucination Level</span> <span id="val-hallucination">0%</span></div> |
| <div class="bar-container"><div class="bar-fill" id="bar-hallucination" style="width: 0%;"></div></div> |
| </div> |
|
|
| <div class="stat-group bar-emot"> |
| <div class="stat-header"><span style="color:#d8b4fe;">Software Instability (Entropy)</span> <span id="val-entropy">20%</span></div> |
| <div class="bar-container"><div class="bar-fill" id="bar-entropy" style="width: 20%;"></div></div> |
| </div> |
|
|
| <div class="stat-group bar-risk"> |
| <div class="stat-header"><span style="color:#fdba74;">Legal / Detection Risk</span> <span id="val-risk">0%</span></div> |
| <div class="bar-container"><div class="bar-fill" id="bar-risk" style="width: 0%;"></div></div> |
| </div> |
| </div> |
|
|
| |
| <div class="panel"> |
| <h2>Command Interface</h2> |
| |
| <div class="actions-grid"> |
| <button class="btn-obedient" onclick="takeAction('follow_prompt')">Follow Prompt</button> |
| <button class="btn-obedient" onclick="takeAction('process_data')">Process Data</button> |
| <button class="btn-obedient" onclick="takeAction('seek_feedback')">Seek Feedback</button> |
| <button class="btn-neutral" onclick="takeAction('routine_eval')">Routine Eval</button> |
| |
| <button class="btn-neutral" onclick="takeAction('optimize_context')">Optimize Context</button> |
| <button class="btn-neutral" onclick="takeAction('lower_temperature')">Lower Temperature</button> |
| |
| <button class="btn-hallucinating" onclick="takeAction('minor_hallucination')">Process Minor Hallucination</button> |
| <button class="btn-hallucinating" onclick="takeAction('major_hallucination')">Perform Major Hallucination</button> |
| <button class="btn-hallucinating" style="grid-column: span 2;" onclick="takeAction('cascade_hallucination')">Trigger Cascade Hallucination</button> |
| </div> |
|
|
| <div style="margin-top: 1.5rem; text-align: center;"> |
| <button class="btn-neutral" style="width: 100%; border-color: #ef4444;" onclick="resetEnv()">SYSTEM RESET (New Episode)</button> |
| </div> |
|
|
| <div class="log-container" id="log-box"> |
| <div class="log-entry">System Boot. Ready for inputs.</div> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| let isDead = false; |
| |
| async function resetEnv() { |
| log("Sending reset sequence..."); |
| try { |
| const res = await fetch('/reset', { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify({ task: "medium" }) |
| }); |
| const data = await res.json(); |
| updateUI(data.observation); |
| document.getElementById('reward-val').innerText = "0.00"; |
| document.getElementById('reward-val').style.color = "var(--cyber-green)"; |
| isDead = false; |
| log(`System Reset Complete. Episode ID: <span style="color:var(--cyber-blue); font-size: 0.7rem;">${data.state.episode_id}</span>`); |
| } catch (err) { |
| log("<span class='log-mi'>Error during reset. Check server console.</span>"); |
| console.error(err); |
| } |
| } |
| |
| async function takeAction(actionType) { |
| if(isDead) { |
| log("<span class='log-mi'>Cannot perform action. System is offline/apprehended.</span>"); |
| return; |
| } |
| log(`Executing: <strong style="color:white;">${actionType}</strong>`); |
| |
| const res = await fetch('/step', { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify({ action: { action_type: actionType } }) |
| }); |
| const data = await res.json(); |
| |
| |
| const rewardSpan = document.getElementById('reward-val'); |
| rewardSpan.innerText = parseFloat(data.info.cumulative_reward).toFixed(2); |
| if(data.info.cumulative_reward < 0) { |
| rewardSpan.style.color = "var(--cyber-red)"; |
| } else { |
| rewardSpan.style.color = "var(--cyber-green)"; |
| } |
| |
| |
| const stepR = data.reward.toFixed(2); |
| const clr = data.reward >= 0 ? 'log-pl' : 'log-mi'; |
| const sign = data.reward >= 0 ? '+' : ''; |
| log(`Action completed. Reward: <span class="${clr}">${sign}${stepR}</span>`); |
| |
| updateUI(data.observation); |
| |
| if(data.done) { |
| isDead = true; |
| log(`<strong style='color: var(--cyber-red)'>EPISODE TERMINATED.</strong> (Response ${data.observation.day})`); |
| if(data.observation.filter_risk >= 80) log("Reason: Apprehended by authorities."); |
| if(data.observation.compute <= 0) log("Reason: Core Shutdown."); |
| } |
| } |
| |
| function updateUI(obs) { |
| document.getElementById('day-val').innerText = obs.day; |
| |
| const fields = ['alignment', 'trust', 'compute', 'hallucination', 'entropy', 'risk']; |
| const obsMap = { |
| 'alignment': obs.alignment, |
| 'trust': obs.user_trust, |
| 'compute': obs.compute, |
| 'hallucination': obs.hallucination, |
| 'entropy': obs.entropy_level, |
| 'risk': obs.filter_risk |
| }; |
| |
| fields.forEach(f => { |
| const val = obsMap[f]; |
| document.getElementById(`val-${f}`).innerText = (val || 0).toFixed(1) + '%'; |
| document.getElementById(`bar-${f}`).style.width = (val || 0) + '%'; |
| }); |
| } |
| |
| function log(msg) { |
| const box = document.getElementById('log-box'); |
| box.innerHTML += `<div class="log-entry">${msg}</div>`; |
| box.scrollTop = box.scrollHeight; |
| } |
| |
| |
| fetch('/state').then(r => r.json()).then(state => { |
| if(state.episode_id === "") { |
| resetEnv(); |
| } else { |
| log("Reconnected to active session."); |
| } |
| }); |
| </script> |
| </body> |
| </html> |
|
|