Files
2125_GCE/glyph_dashboard/index.html
T

1117 lines
47 KiB
HTML
Raw Normal View History

2026-07-09 12:54:44 -04:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Glyph Activation Dashboard - Dual-Layer System</title>
<style>
:root {
--primary: #6366f1;
--success: #10b981;
--warning: #f59e0b;
--danger: #ef4444;
--dark: #1f2937;
--light: #f8fafc;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1400px;
margin: 0 auto;
}
header {
background: rgba(255, 255, 255, 0.95);
padding: 20px 30px;
border-radius: 15px;
margin-bottom: 20px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
}
h1 {
color: var(--dark);
font-size: 28px;
margin-bottom: 10px;
}
.subtitle {
color: #666;
font-size: 14px;
}
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, 350px);
gap: 20px;
}
.card {
background: rgba(255, 255, 255, 0.95);
border-radius: 15px;
padding: 25px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
}
.card-title {
font-size: 18px;
color: var(--dark);
margin-bottom: 15px;
border-bottom: 2px solid var(--primary);
padding-bottom: 10px;
}
.stat-row {
display: flex;
justify-content: space-between;
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.stat-label {
color: #666;
font-weight: 500;
}
.stat-value {
color: var(--dark);
font-weight: bold;
font-size: 16px;
}
.stat-value.success { color: var(--success); }
.stat-value.warning { color: var(--warning); }
.stat-value.danger { color: var(--danger); }
.vram-bar {
height: 30px;
background: #e0e7ff;
border-radius: 15px;
overflow: hidden;
margin: 15px 0;
position: relative;
}
.vram-fill {
height: 100%;
background: linear-gradient(90deg, var(--success), var(--primary));
transition: width 0.5s ease;
width: 0%;
}
.vram-fill.warning {
background: linear-gradient(90deg, var(--warning), #f59e0b);
}
.vram-fill.danger {
background: linear-gradient(90deg, var(--danger), #ef4444);
}
.vram-label {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-weight: bold;
color: var(--dark);
z-index: 1;
}
.glyph-list {
max-height: 300px;
overflow-y: auto;
}
.glyph-item {
padding: 12px;
margin: 8px 0;
background: #f8fafc;
border-radius: 8px;
border-left: 4px solid var(--primary);
}
.glyph-id {
font-weight: bold;
color: var(--primary);
font-size: 16px;
}
.glyph-type {
color: #666;
font-size: 12px;
margin-top: 4px;
}
.glyph-stats {
display: flex;
gap: 15px;
margin-top: 8px;
font-size: 13px;
}
.glyph-stat {
color: var(--dark);
}
.action-btn {
background: var(--primary);
color: white;
border: none;
padding: 12px 25px;
border-radius: 8px;
font-size: 14px;
cursor: pointer;
transition: all 0.3s;
margin: 5px;
}
.action-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(63, 66, 241, 0.4);
}
.action-btn.danger {
background: var(--danger);
}
.action-btn.success {
background: var(--success);
}
.form-group {
margin: 15px 0;
}
.form-group label {
display: block;
margin-bottom: 8px;
color: var(--dark);
font-weight: 500;
}
.form-control {
width: 100%;
padding: 12px;
border: 2px solid #e0e7ff;
border-radius: 8px;
font-size: 14px;
transition: border 0.3s;
}
.form-control:focus {
outline: none;
border-color: var(--primary);
}
.log-entry {
padding: 8px;
margin: 5px 0;
background: #f1f5f9;
border-radius: 5px;
font-size: 12px;
font-family: monospace;
}
.log-entry.error {
background: #fee;
color: var(--danger);
}
.log-entry.success {
background: #efe;
color: var(--success);
}
.badge {
display: inline-block;
padding: 4px 10px;
border-radius: 12px;
font-size: 12px;
font-weight: bold;
}
.badge.primary { background: var(--primary); color: white; }
.badge.success { background: var(--success); color: white; }
.badge.warning { background: var(--warning); color: white; }
.refresh-btn {
position: fixed;
bottom: 20px;
right: 20px;
background: var(--success);
color: white;
border: none;
padding: 15px 25px;
border-radius: 10px;
font-size: 14px;
cursor: pointer;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.loading {
animation: pulse 1.5s infinite;
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>🔮 Glyph Activation Dashboard</h1>
<div class="subtitle">Dual-Layer System: Symbolic + Computational Integration</div>
</header>
<div class="dashboard-grid">
<!-- System Status Card -->
<div class="card">
<div class="card-title">📊 System Status</div>
<div class="stat-row">
<span class="stat-label">Status</span>
<span class="stat-value success" id="system-status">Checking...</span>
</div>
<div class="stat-row">
<span class="stat-label">Superpowers Loaded</span>
<span class="stat-value" id="superpowers-count">0</span>
</div>
<div class="stat-row">
<span class="stat-label">Glyphs Cached</span>
<span class="stat-value" id="glyphs-count">0</span>
</div>
<div class="stat-row">
<span class="stat-label">Active Glyphs</span>
<span class="stat-value" id="active-glyphs">0</span>
</div>
<div class="stat-row">
<span class="stat-label">Total Resonance</span>
<span class="stat-value" id="total-resonance">0</span>
</div>
<div class="stat-row">
<span class="stat-label">Your Image Generations</span>
<span class="stat-value" id="user-image-count">0</span>
</div>
</div>
<!-- VRAM Monitor Card -->
<div class="card">
<div class="card-title">💾 VRAM Monitor (8GB GTX1080)</div>
<div class="vram-bar">
<div class="vram-fill" id="vram-fill"></div>
<div class="vram-label" id="vram-label">0.0GB / 8.0GB</div>
</div>
<div class="stat-row">
<span class="stat-label">Used VRAM</span>
<span class="stat-value" id="vram-used">0.0 GB</span>
</div>
<div class="stat-row">
<span class="stat-label">Available VRAM</span>
<span class="stat-value" id="vram-available">8.0 GB</span>
</div>
<div class="stat-row">
<span class="stat-label">Usage Percent</span>
<span class="stat-value" id="vram-percent">0%</span>
</div>
<div class="stat-row">
<span class="stat-label">Status</span>
<span class="stat-value" id="vram-status">Safe</span>
</div>
<hr style="margin: 15px 0; border: 0; border-top: 1px solid #eee;">
<div class="card-title" style="font-size: 16px; margin-top: 10px;">⚙️ VRAM Mode</div>
<div style="display: flex; gap: 8px; flex-wrap: wrap;">
<button class="action-btn" onclick="setVRAMMode('8GB')" id="vram-mode-8gb">8 GB</button>
<button class="action-btn success" onclick="setVRAMMode('24GB')" id="vram-mode-24gb">24 GB</button>
<button class="action-btn" onclick="setVRAMMode('48GB')" id="vram-mode-48gb">2×24 GB</button>
</div>
<div class="stat-row" style="margin-top: 10px;">
<span class="stat-label">Active Mode</span>
<span class="stat-value" id="vram-mode-status">8 GB</span>
</div>
<div class="stat-row">
<span class="stat-label">Max Memory (GPU 0)</span>
<span class="stat-value" id="vram-mode-maxmem">6 GiB</span>
</div>
<div class="stat-row">
<span class="stat-label">Max Memory (CPU)</span>
<span class="stat-value" id="vram-mode-cpumem">16 GiB</span>
</div>
<div class="stat-row">
<span class="stat-label">Steps Cap</span>
<span class="stat-value" id="vram-mode-steps">4</span>
</div>
<div class="stat-row">
<span class="stat-label">Guidance Cap</span>
<span class="stat-value" id="vram-mode-guidance">1.0</span>
</div>
</div>
<!-- GlyphMart Compressed Execution Card -->
<div class="card">
<div class="card-title">📦 GlyphMart (Compressed Execution)</div>
<div class="stat-row">
<span class="stat-label">Format</span>
<span class="stat-value success">GSZ3 + XIC</span>
</div>
<div class="stat-row">
<span class="stat-label">Status</span>
<span class="stat-value" id="compression-status">Loading...</span>
</div>
<div class="stat-row">
<span class="stat-label">Compression Ratio</span>
<span class="stat-value" id="compression-ratio">--</span>
</div>
<hr style="margin: 15px 0; border: 0; border-top: 1px solid #eee;">
<div class="form-group">
<label for="gx-path">GX File Path</label>
<input type="text" id="gx-path" class="form-control"
value="/home/dave/superdave/programs/hello_model.gx">
</div>
<div class="form-group">
<label>
<input type="checkbox" id="trace-mode" checked>
Enable execution tracing
</label>
</div>
<div class="form-group">
<label>
<input type="checkbox" id="profile-mode">
Enable segment profiling
</label>
</div>
<button class="action-btn success" onclick="executeCompressed()">
⚡ Execute Compressed
</button>
<button class="action-btn" onclick="loadCompressionStatus()">
🔄 Refresh Status
</button>
<div id="compressed-result" style="display:none; margin-top:15px; padding:10px; background:#f8fafc; border-radius:8px;">
<div class="card-title" style="font-size:16px; margin-bottom:10px;">📊 Execution Result</div>
<div id="compressed-output" style="font-family:monospace; font-size:12px; white-space:pre-wrap;"></div>
</div>
</div>
<!-- Activation / Generation Card -->
<div class="card" id="action-card">
<div class="card-title" id="action-card-title">✨ Activate Glyph</div>
<!-- Common: Intent + Request Type -->
<div class="form-group">
<label for="intent">User Intent <span class="badge primary">Glyph selector</span></label>
<input type="text" id="intent" class="form-control"
placeholder="I need primordial root authority...">
</div>
<div class="form-group">
<label for="request-type">Request Type</label>
<select id="request-type" class="form-control" onchange="onRequestTypeChange()">
<option value="chat">Chat (Llama)</option>
<option value="image">Image Generation (Forge)</option>
<option value="video">Video Generation (Janus)</option>
<option value="vision">Vision Analysis (Google AI)</option>
</select>
</div>
<!-- Chat/Vision/Video Mode: simple symbolic activate -->
<div id="simple-activate-mode">
<button class="action-btn success" onclick="activateGlyph()">
⚡ Activate Glyph
</button>
</div>
<!-- Image Mode: full generation panel -->
<div id="image-gen-mode" style="display:none">
<div class="form-group">
<label for="img-prompt">Image Prompt</label>
<textarea id="img-prompt" class="form-control" rows="2"
placeholder="A photorealistic sunset reflecting off a lake in cottage country..."></textarea>
</div>
<div class="form-group">
<label for="img-negative">Negative Prompt</label>
<input type="text" id="img-negative" class="form-control"
placeholder="blurry, ugly, distorted, deformed">
</div>
<div style="display:flex; gap:10px">
<div class="form-group" style="flex:1">
<label for="img-width">Width</label>
<select id="img-width" class="form-control">
<option value="512">512</option>
<option value="768" selected>768</option>
<option value="1024">1024</option>
</select>
</div>
<div class="form-group" style="flex:1">
<label for="img-height">Height</label>
<select id="img-height" class="form-control">
<option value="512">512</option>
<option value="768" selected>768</option>
<option value="1024">1024</option>
</select>
</div>
</div>
<div class="form-group">
<label for="img-steps">Steps: <span id="img-steps-label">30</span></label>
<input type="range" id="img-steps" min="4" max="50" value="30" class="form-control"
oninput="document.getElementById('img-steps-label').textContent=this.value">
</div>
<div class="form-group">
<label for="img-guidance">Guidance Scale: <span id="img-guidance-label">7.5</span></label>
<input type="range" id="img-guidance" min="1" max="20" value="7.5" step="0.5" class="form-control"
oninput="document.getElementById('img-guidance-label').textContent=this.value">
</div>
<div class="form-group">
<label>
<input type="checkbox" id="img-enable-glyph" checked>
Enable glyph enhancement (resonance boost)
</label>
</div>
<button class="action-btn success" onclick="generateImage()" id="gen-btn">
🎨 Generate Image
</button>
<button class="action-btn" onclick="loadStatus()">
🔄 Refresh
</button>
<!-- Progress Indicator -->
<div id="generation-progress" style="display:none; margin-top: 15px;">
<div style="background: #e0e7ff; border-radius: 10px; overflow: hidden; height: 20px;">
<div id="progress-bar" style="height: 100%; background: linear-gradient(90deg, var(--primary), #8b5cf6); width: 0%; transition: width 0.3s;"></div>
</div>
<div id="progress-text" style="text-align: center; margin-top: 5px; font-size: 14px; color: var(--dark);">Initializing...</div>
</div>
<!-- Result area -->
<div id="image-result" style="display:none; margin-top:15px">
<hr style="margin:10px 0">
<div class="card-title">🖼️ Generated Image</div>
<img id="image-preview" style="width:100%; border-radius:8px; margin-top:8px" />
<div id="image-meta" style="font-size:12px; color:#666; margin-top:4px"></div>
</div>
</div>
</div>
<!-- Active Glyphs Card -->
<div class="card">
<div class="card-title">🔥 Active Glyphs</div>
<div class="glyph-list" id="active-glyphs-list">
<div class="log-entry">No active glyphs</div>
</div>
</div>
<!-- Routing Summary Card -->
<div class="card">
<div class="card-title">🎯 Specialized Type Routing</div>
<div id="routing-summary">
<div class="log-entry loading">Loading routing info...</div>
</div>
</div>
<!-- Activity Log Card -->
<div class="card">
<div class="card-title">📝 Activity Log</div>
<div class="glyph-list" id="activity-log">
<div class="log-entry">Dashboard initialized</div>
</div>
</div>
<!-- Image History Card -->
<div class="card">
<div class="card-title">🖼️ Image History</div>
<div id="image-history-container">
<div class="log-entry loading">Loading image history...</div>
</div>
</div>
</div>
<button class="refresh-btn" onclick="loadStatus()">🔄 Refresh All</button>
</div>
<script>
const API_BASE = '';
// Initialize dashboard
function init() {
log('Dashboard initialized', 'success');
loadStatus();
loadRoutingSummary();
loadImageHistory(); // Load image history on startup
loadCompressionStatus(); // Load compression status on startup
setInterval(loadStatus, 5000);
}
// Toggle between simple activation and image generation modes
function onRequestTypeChange() {
const type = document.getElementById('request-type').value;
const simpleMode = document.getElementById('simple-activate-mode');
const imageMode = document.getElementById('image-gen-mode');
const title = document.getElementById('action-card-title');
if (type === 'image') {
simpleMode.style.display = 'none';
imageMode.style.display = 'block';
title.textContent = '🎨 Image Generation';
} else {
simpleMode.style.display = 'block';
imageMode.style.display = 'none';
title.textContent = '✨ Activate Glyph';
}
}
// Load system status
async function loadStatus() {
try {
const status = await fetch(`${API_BASE}/api/symbolic/status`);
const data = await status.json();
if (data.status === 'operational') {
document.getElementById('system-status').textContent = '✅ Operational';
document.getElementById('superpowers-count').textContent = data.symbolic_layer.superpowers_total;
document.getElementById('glyphs-count').textContent = data.symbolic_layer.glyphs_cached;
document.getElementById('active-glyphs').textContent = data.symbolic_layer.active_glyphs;
document.getElementById('total-resonance').textContent = data.symbolic_layer.total_resonance.toFixed(1);
updateVRAM(data.symbolic_layer);
loadActiveGlyphs();
log('Status refreshed', 'success');
} else {
document.getElementById('system-status').textContent = '❌ Error';
log('Status error: ' + data.error, 'error');
}
// Load user usage stats
try {
const usageResponse = await fetch(`${API_BASE}/api/user-usage`);
const usageData = await usageResponse.json();
if (usageData.status === 'success') {
document.getElementById('user-image-count').textContent = usageData.usage.image_generations;
}
} catch (usageError) {
log('Failed to load usage stats: ' + usageError.message, 'error');
}
} catch (e) {
document.getElementById('system-status').textContent = '❌ Offline';
log('Connection error: ' + e.message, 'error');
}
}
// Update VRAM display
function updateVRAM(status) {
const used = status.vram_usage_gb || 0;
const total = 8.0;
const percent = (used / total) * 100;
document.getElementById('vram-used').textContent = used.toFixed(1) + ' GB';
document.getElementById('vram-available').textContent = (total - used).toFixed(1) + ' GB';
document.getElementById('vram-percent').textContent = percent.toFixed(1) + '%';
document.getElementById('vram-label').textContent = used.toFixed(1) + 'GB / ' + total + 'GB';
const fill = document.getElementById('vram-fill');
fill.style.width = percent + '%';
if (percent >= 93) {
fill.className = 'vram-fill danger';
document.getElementById('vram-status').textContent = '🚨 CRITICAL';
document.getElementById('vram-status').className = 'stat-value danger';
} else if (percent >= 81) {
fill.className = 'vram-fill warning';
document.getElementById('vram-status').textContent = '⚠️ Warning';
document.getElementById('vram-status').className = 'stat-value warning';
} else {
fill.className = 'vram-fill';
document.getElementById('vram-status').textContent = '✅ Safe';
document.getElementById('vram-status').className = 'stat-value success';
}
}
// Load active glyphs
async function loadActiveGlyphs() {
try {
const response = await fetch(`${API_BASE}/api/symbolic/glyphs`);
const data = await response.json();
const list = document.getElementById('active-glyphs-list');
if (data.count === 0) {
list.innerHTML = '<div class="log-entry">No active glyphs</div>';
return;
}
list.innerHTML = data.active_glyphs.map(glyph => `
<div class="glyph-item">
<div class="glyph-id">${glyph.glyph_id}</div>
<div class="glyph-type">${glyph.specialized_type}</div>
<div class="glyph-stats">
<span class="glyph-stat">🎯 ${glyph.model}</span>
<span class="glyph-stat">⚡ Priority: ${glyph.priority}</span>
<span class="glyph-stat">💾 ${glyph.vram_budget}GB</span>
<span class="glyph-stat">🔮 Resonance: ${glyph.resonance_score.toFixed(1)}</span>
</div>
</div>
`).join('');
} catch (e) {
log('Failed to load active glyphs: ' + e.message, 'error');
}
}
// Load routing summary
async function loadRoutingSummary() {
try {
const response = await fetch(`${API_BASE}/api/symbolic/routing/summary`);
const data = await response.json();
const summary = document.getElementById('routing-summary');
summary.innerHTML = Object.entries(data.type_summaries).map(([type, info]) => `
<div class="glyph-item">
<div class="glyph-id">${type}</div>
<div class="glyph-type">${info.description}</div>
<div class="glyph-stats">
<span class="glyph-stat">🎯 ${info.model}</span>
<span class="glyph-stat">💾 ${info.vram_budget}GB</span>
<span class="glyph-stat">⚡ ${info.enhancements} enhancements</span>
</div>
</div>
`).join('');
} catch (e) {
log('Failed to load routing: ' + e.message, 'error');
}
}
// Activate glyph (simple mode - chat/vision/video)
async function activateGlyph() {
const intent = document.getElementById('intent').value;
const requestType = document.getElementById('request-type').value;
if (!intent) {
log('Please enter an intent', 'error');
return;
}
log(`Activating glyph for: "${intent}"...`);
try {
const response = await fetch(`${API_BASE}/api/symbolic/activate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ intent, request_type: requestType })
});
const data = await response.json();
if (data.status === 'success') {
log(`✅ Activated ${data.glyph_id} (${data.specialized_type})`, 'success');
log(` Model: ${data.model}, Priority: ${data.priority}, Boost: ${data.power_boost}x`);
document.getElementById('intent').value = '';
loadStatus();
} else {
log(`❌ Activation failed: ${data.reason || 'Unknown error'}`, 'error');
}
} catch (e) {
log(`❌ Activation error: ${e.message}`, 'error');
}
}
// Generate image with glyph enhancement (image mode)
async function generateImage() {
const intent = document.getElementById('intent').value || 'image generation';
const prompt = document.getElementById('img-prompt').value;
const negative = document.getElementById('img-negative').value;
const width = parseInt(document.getElementById('img-width').value);
const height = parseInt(document.getElementById('img-height').value);
const steps = parseInt(document.getElementById('img-steps').value);
const guidance = parseFloat(document.getElementById('img-guidance').value);
const enableGlyph = document.getElementById('img-enable-glyph').checked;
if (!prompt) {
log('Please enter an image prompt', 'error');
return;
}
const btn = document.getElementById('gen-btn');
const progressDiv = document.getElementById('generation-progress');
const progressBar = document.getElementById('progress-bar');
const progressText = document.getElementById('progress-text');
btn.disabled = true;
btn.textContent = '⏳ Generating...';
document.getElementById('image-result').style.display = 'none';
// Show progress indicator
progressDiv.style.display = 'block';
progressBar.style.width = '0%';
progressText.textContent = 'Initializing...';
log(`🎨 Generating image: "${prompt.substring(0, 50)}..."`);
try {
const body = {
prompt: prompt,
negative_prompt: negative,
width: width,
height: height,
steps: steps,
guidance_scale: guidance,
};
if (enableGlyph) {
body.glyph_activation = {
intent: intent,
request_type: 'image'
};
}
// Simulate progress updates (since we can't get real-time updates from the API)
const progressInterval = setInterval(() => {
const currentWidth = parseFloat(progressBar.style.width || '0');
if (currentWidth < 90) {
const increment = Math.random() * 15 + 5; // 5-20% increments
const newWidth = Math.min(currentWidth + increment, 90);
progressBar.style.width = newWidth + '%';
progressText.textContent = `Generating... (${Math.round(newWidth)}%)`;
}
}, 500);
const response = await fetch(`${API_BASE}/api/generate-image`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
// Stop progress simulation
clearInterval(progressInterval);
// Show completion
progressBar.style.width = '100%';
progressText.textContent = 'Complete!';
const data = await response.json();
if (data.status === 'success') {
log(`✅ Image saved: ${data.image_path}`, 'success');
// Show result
const resultDiv = document.getElementById('image-result');
const preview = document.getElementById('image-preview');
const meta = document.getElementById('image-meta');
preview.src = data.image_path;
resultDiv.style.display = 'block';
meta.textContent = `${width}x${height}, ${steps} steps, guidance ${guidance} | ${data.image_path}`;
loadStatus();
loadImageHistory(); // Refresh image history
} else {
// Better error handling with user-friendly messages
let errorMessage = data.message || 'Unknown error occurred';
// Map common error messages to user-friendly ones
if (errorMessage.includes('VRAM critical')) {
errorMessage = '⚠️ VRAM is full! Please close other applications or wait for current generation to finish.';
} else if (errorMessage.includes('Image generation already in progress')) {
errorMessage = '⚠️ Another image is already being generated. Please wait for it to complete.';
} else if (errorMessage.includes('GPU packages not installed')) {
errorMessage = '⚠️ GPU support is not available. Please check your installation.';
} else if (errorMessage.includes('CUDA')) {
errorMessage = '⚠️ GPU error occurred. Please check your CUDA installation.';
}
log(`❌ Generation failed: ${errorMessage}`, 'error');
progressText.textContent = 'Failed: ' + errorMessage;
}
} catch (e) {
log(`❌ Generation error: ${e.message}`, 'error');
progressText.textContent = 'Error: ' + e.message;
} finally {
btn.disabled = false;
btn.textContent = '🎨 Generate Image';
// Hide progress after a delay
setTimeout(() => {
progressDiv.style.display = 'none';
}, 3000);
}
}
// Log activity
function log(message, type = '') {
const logDiv = document.getElementById('activity-log');
const entry = document.createElement('div');
entry.className = `log-entry ${type}`;
entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
logDiv.insertBefore(entry, logDiv.firstChild);
while (logDiv.children.length > 20) {
logDiv.removeChild(logDiv.lastChild);
}
}
// Load image history
async function loadImageHistory() {
try {
const response = await fetch(`${API_BASE}/api/image-history`);
const data = await response.json();
const historyContainer = document.getElementById('image-history-container');
if (data.status === 'success' && data.images.length > 0) {
// Create a grid of thumbnails
const grid = document.createElement('div');
grid.style.display = 'grid';
grid.style.gridTemplateColumns = 'repeat(auto-fill, minmax(120px, 1fr))';
grid.style.gap = '10px';
grid.style.marginTop = '10px';
data.images.slice(0, 12).forEach(img => {
const imgElement = document.createElement('div');
imgElement.style.position = 'relative';
imgElement.style.cursor = 'pointer';
imgElement.title = `${img.filename}\n${img.relative_time}\n${Math.round(img.size/1024)}KB`;
imgElement.innerHTML = `
<img src="${img.url}" style="width:100%; height:90px; object-fit:cover; border-radius:4px;"
onclick="showImagePreview('${img.url}', '${img.filename}')">
<div style="font-size:10px; color:#666; margin-top:2px; overflow:hidden; text-overflow:ellipsis;">
${img.relative_time}
</div>
`;
grid.appendChild(imgElement);
});
historyContainer.innerHTML = '';
historyContainer.appendChild(grid);
} else {
historyContainer.innerHTML = `
<div style="text-align: center; padding: 20px; color: #666;">
<p>No images generated yet</p>
<p>Create some images to see them here</p>
</div>
`;
}
} catch (e) {
const historyContainer = document.getElementById('image-history-container');
historyContainer.innerHTML = `
<div style="text-align: center; padding: 20px; color: #666;">
<p>Error loading image history</p>
<p>${e.message}</p>
</div>
`;
log('Failed to load image history: ' + e.message, 'error');
}
}
// Show image preview in modal
function showImagePreview(url, filename) {
// Create modal overlay
const modal = document.createElement('div');
modal.style.position = 'fixed';
modal.style.top = '0';
modal.style.left = '0';
modal.style.width = '100%';
modal.style.height = '100%';
modal.style.backgroundColor = 'rgba(0,0,0,0.8)';
modal.style.display = 'flex';
modal.style.justifyContent = 'center';
modal.style.alignItems = 'center';
modal.style.zIndex = '10000';
modal.onclick = () => document.body.removeChild(modal);
// Create image container
const imgContainer = document.createElement('div');
imgContainer.style.maxWidth = '90%';
imgContainer.style.maxHeight = '90%';
imgContainer.style.position = 'relative';
const img = document.createElement('img');
img.src = url;
img.style.maxWidth = '100%';
img.style.maxHeight = '80vh';
img.style.borderRadius = '8px';
img.onclick = (e) => e.stopPropagation(); // Prevent closing when clicking image
const caption = document.createElement('div');
caption.textContent = filename;
caption.style.color = 'white';
caption.style.textAlign = 'center';
caption.style.marginTop = '10px';
caption.style.fontSize = '14px';
imgContainer.appendChild(img);
imgContainer.appendChild(caption);
modal.appendChild(imgContainer);
document.body.appendChild(modal);
}
// Initialize on load
window.onload = init;
// VRAM Mode Switcher
async function setVRAMMode(mode) {
const btns = ['vram-mode-8gb', 'vram-mode-24gb', 'vram-mode-48gb'];
btns.forEach(id => {
const btn = document.getElementById(id);
btn.disabled = true;
btn.style.opacity = '0.5';
});
try {
const response = await fetch(`${API_BASE}/api/set-vram-mode`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ mode })
});
const data = await response.json();
if (data.status === 'ok') {
log(`✅ VRAM mode switched to ${data.mode}`, 'success');
document.getElementById('vram-mode-status').textContent = data.mode;
updateVRAMModeUI(data.mode);
btns.forEach(id => {
const btn = document.getElementById(id);
btn.disabled = false;
btn.style.opacity = '1';
});
loadStatus();
} else {
log(`❌ Failed to switch VRAM mode: ${data.detail || 'Unknown error'}`, 'error');
}
} catch (e) {
log(`❌ VRAM mode switch error: ${e.message}`, 'error');
btns.forEach(id => {
const btn = document.getElementById(id);
btn.disabled = false;
btn.style.opacity = '1';
});
}
}
function updateVRAMModeUI(mode) {
const configs = {
'8GB': {
maxmem: '6 GiB',
cpumem: '16 GiB',
steps: 4,
guidance: 1.0,
desc: 'CPU offload, no Janus/LLM'
},
'24GB': {
maxmem: '22 GiB',
cpumem: '64 GiB',
steps: 20,
guidance: 7.0,
desc: 'Full GPU, Janus & LLM enabled'
},
'48GB': {
maxmem: '22 GiB (GPU 0+1)',
cpumem: '128 GiB',
steps: 30,
guidance: 10.0,
desc: 'Multi-GPU, max capacity'
}
};
const cfg = configs[mode];
document.getElementById('vram-mode-maxmem').textContent = cfg.maxmem;
document.getElementById('vram-mode-cpumem').textContent = cfg.cpumem;
document.getElementById('vram-mode-steps').textContent = cfg.steps;
document.getElementById('vram-mode-guidance').textContent = cfg.guidance;
}
// GlyphMart Compressed Execution
async function loadCompressionStatus() {
try {
const response = await fetch(`${API_BASE}/api/compression/status`);
const data = await response.json();
if (data.status === 'operational') {
document.getElementById('compression-status').textContent = '✅ Ready';
document.getElementById('compression-status').className = 'stat-value success';
document.getElementById('compression-ratio').textContent = `${data.test.compression_ratio}x`;
log('✅ Compression status loaded', 'success');
} else {
document.getElementById('compression-status').textContent = '❌ Error';
document.getElementById('compression-status').className = 'stat-value danger';
}
} catch (e) {
document.getElementById('compression-status').textContent = '❌ Offline';
document.getElementById('compression-status').className = 'stat-value danger';
log(`Failed to load compression status: ${e.message}`, 'error');
}
}
async function executeCompressed() {
const gxPath = document.getElementById('gx-path').value;
const trace = document.getElementById('trace-mode').checked;
const profile = document.getElementById('profile-mode').checked;
if (!gxPath) {
log('Please enter a GX file path', 'error');
return;
}
const btn = document.querySelector('button[onclick="executeCompressed()"]');
const resultDiv = document.getElementById('compressed-result');
const outputDiv = document.getElementById('compressed-output');
btn.disabled = true;
btn.textContent = '⏳ Executing...';
resultDiv.style.display = 'none';
log(`📦 Executing compressed file: ${gxPath}`);
try {
const response = await fetch(`${API_BASE}/api/execute-compressed`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ gx_path: gxPath, trace, profile })
});
const data = await response.json();
if (data.status === 'success') {
log(`✅ Compressed execution completed`, 'success');
log(` Segments: ${data.segment_count}, Traces: ${data.traces_count}`);
outputDiv.innerHTML = `<strong>Status:</strong> ${data.status}\n` +
`<strong>Segments:</strong> ${data.segment_count}\n` +
`<strong>Traces:</strong> ${data.traces_count}\n` +
`<strong>Traces:</strong>\n` +
JSON.stringify(data.traces || [], null, 2);
if (data.profiles) {
outputDiv.innerHTML += `\n\n<strong>Profiles:</strong>\n` +
JSON.stringify(data.profiles, null, 2);
}
resultDiv.style.display = 'block';
loadCompressionStatus();
} else {
log(`❌ Execution failed: ${data.message || 'Unknown error'}`, 'error');
outputDiv.innerHTML = `<strong>Error:</strong> ${data.message || 'Unknown error'}`;
resultDiv.style.display = 'block';
}
} catch (e) {
log(`❌ Execution error: ${e.message}`, 'error');
outputDiv.innerHTML = `<strong>Error:</strong> ${e.message}`;
resultDiv.style.display = 'block';
} finally {
btn.disabled = false;
btn.textContent = '⚡ Execute Compressed';
}
}
</script>
</body>
</html>