llm-semantic-visualizer / src /ui /panels /ProgressPanel.js
hbauzan's picture
Release v4.17.7 — sync from GitHub main
819a47f
Raw
History Blame Contribute Delete
7.64 kB
export function initProgressPanel(ctx) {
const sseUrl = '/api/telemetry/stream';
let eventSource = null;
function connect() {
if (eventSource) return;
eventSource = new EventSource(sseUrl);
eventSource.onmessage = (event) => {
try {
const payload = JSON.parse(event.data);
const { event: eventName, data } = payload;
if (eventName === 'ingest_progress') {
handleIngestProgress(data);
} else if (eventName === 'sae_progress') {
handleSaeProgress(data);
}
} catch (err) {
console.error("Error parsing telemetry SSE event:", err);
}
};
eventSource.onerror = (err) => {
console.warn("SSE connection error, closing EventSource:", err);
if (eventSource) {
eventSource.close();
eventSource = null;
}
// Auto reconnect after 3 seconds
setTimeout(connect, 3000);
};
}
function handleIngestProgress(data) {
const container = document.getElementById('relief-ingest-progress');
const phaseLabel = document.getElementById('relief-ingest-phase');
const fillBar = document.getElementById('relief-ingest-fill');
const subLabel = document.getElementById('relief-ingest-sublabel');
const pctLabel = document.getElementById('relief-ingest-pct');
const resultLabel = document.getElementById('relief-ingest-result');
const shield = document.getElementById('relief-ingest-shield');
if (!container) return;
if (data.status === 'processing') {
container.style.display = 'flex';
container.classList.add('active');
if (shield) shield.style.display = 'block';
if (fillBar) fillBar.style.width = `${data.progress}%`;
if (pctLabel) pctLabel.textContent = `${data.progress}%`;
let stageMsg = "Processing...";
if (data.stage === 'extract_text') {
stageMsg = "Extracting text from PDF...";
if (subLabel && data.current && data.total) {
subLabel.textContent = `Page ${data.current} / ${data.total}`;
}
} else if (data.stage === 'cleaning') {
stageMsg = "Normalizing text...";
if (subLabel) subLabel.textContent = "";
} else if (data.stage === 'chunking') {
stageMsg = "Splitting text into chunks...";
if (subLabel) subLabel.textContent = "";
} else if (data.stage === 'embeddings') {
stageMsg = "Generating semantic embeddings...";
if (subLabel && data.current && data.total) {
subLabel.textContent = `Chunk ${data.current} / ${data.total}`;
}
} else if (data.stage === 'storing') {
stageMsg = "Storing in database...";
if (subLabel) subLabel.textContent = "";
}
if (phaseLabel) phaseLabel.textContent = stageMsg;
if (resultLabel) resultLabel.textContent = "";
} else if (data.status === 'complete') {
if (fillBar) fillBar.style.width = '100%';
if (pctLabel) pctLabel.textContent = '100%';
if (phaseLabel) phaseLabel.textContent = "Ingestion complete!";
if (subLabel) subLabel.textContent = `${data.chunks} chunks generated`;
if (resultLabel) {
resultLabel.style.color = 'var(--color-semantic-success)';
resultLabel.textContent = `✅ Successfully indexed ${data.chunks} chunks.`;
}
setTimeout(() => {
if (shield) shield.style.display = 'none';
container.style.display = 'none';
container.classList.remove('active');
if (resultLabel) resultLabel.textContent = "";
}, 3000);
// Reload file selector list!
if (ctx && ctx.refresh && typeof ctx.refresh.reliefFiles === 'function') {
ctx.refresh.reliefFiles(data.filename);
}
} else if (data.status === 'error') {
if (phaseLabel) phaseLabel.textContent = "Error";
if (resultLabel) {
resultLabel.style.color = 'var(--color-semantic-error)';
resultLabel.textContent = `❌ ${data.message || 'Unknown error'}`;
}
if (shield) shield.style.display = 'none';
setTimeout(() => {
container.style.display = 'none';
container.classList.remove('active');
}, 6000);
}
}
function handleSaeProgress(data) {
const progressContainer = document.getElementById('sae-training-progress');
const fill = document.getElementById('sae-training-fill');
const label = document.getElementById('sae-training-label');
const saeStatusHint = document.getElementById('sae-status-hint');
const saeToggle = document.getElementById('sae-space-toggle');
const btnTrainSae = document.getElementById('btn-train-sae');
if (!progressContainer) return;
if (data.status === 'loading_vectors') {
progressContainer.style.display = 'flex';
if (fill) fill.style.width = '0%';
if (label) label.textContent = "Loading vectors from database...";
if (saeStatusHint) saeStatusHint.textContent = "Preparing data...";
if (saeToggle) saeToggle.setAttribute('disabled', 'true');
if (btnTrainSae) {
btnTrainSae.setAttribute('disabled', 'true');
btnTrainSae.textContent = '⏳ Preparing...';
}
} else if (data.status === 'training') {
progressContainer.style.display = 'flex';
if (fill) fill.style.width = `${data.progress}%`;
if (label) {
label.textContent = `Epoch ${data.current_epoch}/${data.total_epochs} (Loss: ${data.loss.toFixed(6)})`;
}
if (saeStatusHint) {
saeStatusHint.textContent = "⏳ Training SAE on server...";
saeStatusHint.style.color = 'var(--color-brand-secondary)';
}
if (btnTrainSae) {
btnTrainSae.textContent = `⏳ Training (${data.progress}%)`;
btnTrainSae.setAttribute('disabled', 'true');
}
} else if (data.status === 'success') {
if (fill) fill.style.width = '100%';
if (label) label.textContent = "Training complete.";
setTimeout(() => {
progressContainer.style.display = 'none';
}, 3000);
// Trigger saeStatus UI refresh
if (ctx && ctx.refresh && typeof ctx.refresh.saeStatus === 'function') {
ctx.refresh.saeStatus();
}
} else if (data.status === 'failed') {
if (label) label.textContent = `Failed: ${data.error_message}`;
if (saeStatusHint) {
saeStatusHint.textContent = `❌ Failed: ${data.error_message}`;
saeStatusHint.style.color = 'var(--color-semantic-error)';
}
setTimeout(() => {
progressContainer.style.display = 'none';
}, 5000);
if (ctx && ctx.refresh && typeof ctx.refresh.saeStatus === 'function') {
ctx.refresh.saeStatus();
}
}
}
connect();
}