Files
2125_GCE/glyph_dashboard/index.html
T
2026-07-09 12:54:44 -04:00

1117 lines
47 KiB
HTML
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>