Files
llm-monitor/app/web/static/js/data-sync.worker.js
T
2026-04-25 15:57:37 +02:00

204 lines
5.5 KiB
JavaScript

/**
* LLM Monitor - Data Sync Worker
* Aggiorna i dati in background e notifica il main thread
*/
const API_BASE = "/api/v1";
const REFRESH_INTERVAL = 30000; // 30 secondi
let activeServerId = null;
let activeHost = null;
let nextSyncTimeout = null;
// Formattare bytes
function formatBytes(bytes) {
if (bytes === 0) return "0 B";
const k = 1024;
const sizes = ["B", "KB", "MB", "GB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return (bytes / Math.pow(k, i)).toFixed(2) + " " + sizes[i];
}
// Recuperare health
async function fetchHealth() {
if (!activeHost) {
return null;
}
try {
const response = await fetch(buildApiUrl(`${API_BASE}/health`));
if (response.ok) {
const data = await response.json();
return {
status: data.status,
ollama_status: data.ollama_status,
timestamp: new Date().toISOString(),
serverId: activeServerId
};
}
} catch (error) {
console.error("Health check error:", error);
}
return null;
}
// Recuperare modelli
async function fetchModels() {
if (!activeHost) {
return null;
}
try {
const response = await fetch(buildApiUrl(`${API_BASE}/models`));
if (!response.ok) throw new Error("Failed to load models");
const data = await response.json();
const models = data.models || [];
return {
models,
total: models.length,
totalSize: formatBytes(models.reduce((sum, m) => sum + m.size, 0)),
timestamp: new Date().toISOString(),
serverId: activeServerId
};
} catch (error) {
console.error("Error loading models:", error);
return null;
}
}
// Recuperare dettagli show per un modello
async function fetchModelShow(modelName) {
try {
const response = await fetch(buildApiUrl(`${API_BASE}/models/${encodeURIComponent(modelName)}/show`));
if (!response.ok) {
return null;
}
return await response.json();
} catch (error) {
console.error(`Error loading show data for model ${modelName}:`, error);
return null;
}
}
// Recuperare dettagli show per tutti i modelli
async function fetchAllModelsShow(models) {
const showByModel = {};
const results = await Promise.allSettled(
models.map(async (model) => {
const showData = await fetchModelShow(model.name);
return { name: model.name, showData };
})
);
results.forEach((result) => {
if (result.status === "fulfilled" && result.value.showData) {
showByModel[result.value.name] = result.value.showData;
}
});
return showByModel;
}
async function fetchRunningModels() {
if (!activeHost) {
return null;
}
try {
const response = await fetch(buildApiUrl(`${API_BASE}/models/running`));
if (!response.ok) {
throw new Error("Failed to load running models");
}
const data = await response.json();
return {
models: data.models || [],
total: data.total || (data.models || []).length,
timestamp: new Date().toISOString(),
serverId: activeServerId
};
} catch (error) {
console.error("Error loading running models:", error);
return null;
}
}
// Sincronizzare i dati
async function syncData() {
if (!activeHost) {
self.postMessage({
type: "DATA_UPDATED",
health: null,
modelsData: null,
serverId: activeServerId
});
return;
}
const health = await fetchHealth();
const modelsData = await fetchModels();
const runningData = await fetchRunningModels();
if (modelsData && modelsData.models.length > 0) {
modelsData.showByModel = await fetchAllModelsShow(modelsData.models);
} else if (modelsData) {
modelsData.showByModel = {};
}
// Notificare il main thread
// (il main thread gestisce localStorage)
self.postMessage({
type: "DATA_UPDATED",
health,
modelsData,
runningData,
serverId: activeServerId
});
}
function buildApiUrl(path) {
const url = new URL(path, self.location.origin);
url.searchParams.set("host", activeHost);
return `${url.pathname}${url.search}`;
}
function clearNextSync() {
if (nextSyncTimeout) {
clearTimeout(nextSyncTimeout);
nextSyncTimeout = null;
}
}
function scheduleNextSync(lastSyncTimestamp = 0) {
clearNextSync();
const ageMs = lastSyncTimestamp ? Math.max(0, Date.now() - lastSyncTimestamp) : REFRESH_INTERVAL;
const delayMs = Math.max(0, REFRESH_INTERVAL - ageMs);
nextSyncTimeout = setTimeout(async () => {
await syncData();
scheduleNextSync(Date.now());
}, delayMs);
}
// Gestire messaggi dal main thread
self.onmessage = (event) => {
if (event.data.type === "SET_SERVER") {
activeServerId = event.data.serverId || null;
activeHost = event.data.host || null;
const lastSyncTimestamp = Number(event.data.lastSyncTimestamp || 0);
if (event.data.syncImmediately) {
syncData().finally(() => scheduleNextSync(Date.now()));
return;
}
scheduleNextSync(lastSyncTimestamp);
}
if (event.data.type === "SYNC_NOW") {
syncData().finally(() => scheduleNextSync(Date.now()));
}
};