diff --git a/static/sport2.html b/static/sport2.html index 2216e7c..abcceb7 100644 --- a/static/sport2.html +++ b/static/sport2.html @@ -224,8 +224,8 @@ a.tag:hover,.tag[onclick]:hover{transform:translateY(-1px);filter:brightness(1.1 .pp-stats{grid-template-columns:repeat(3,1fr)} } - - + + @@ -743,6 +743,7 @@ async function loadAudit(){ +
${rows ? `
πŸ“œ Audit zapisi
@@ -755,6 +756,108 @@ async function loadAudit(){
` : '
Nema audit zapisa.
'} `; + loadEnrichWorker(); +} + + +// ─── 24/7 enrichment worker dashboard ─────────────────────────────── +let _enrichWorkerTimer = null; +async function loadEnrichWorker(){ + const card = document.getElementById('enrich-worker-card'); + if(!card) return; + let s; + try{ + const resp = await fetch(API+'/v2/enrich/worker/status'); + if(!resp.ok) throw new Error('HTTP '+resp.status); + s = await resp.json(); + }catch(e){ + card.innerHTML = '
πŸ€– Enrichment Worker
Status nedostupan: '+esc(e.message||String(e))+'
'; + return; + } + const conf = s.confidence_threshold != null ? s.confidence_threshold : 0.7; + const hbAge = s.heartbeat_age_s; + const hbBadge = hbAge == null + ? '⏳ PokreΔ‡e se…' + : (hbAge < 120 ? '🟒 AKTIVAN' : 'πŸ”΄ ZAUSTAVLJEN'); + const pauseBtn = s.paused + ? '' + : ''; + const lc = s.last_cycle || {}; + const recent = (s.recent || []).slice(0, 8); + const recentRows = recent.map(r => ` + + ${esc((r.created_at||'').replace('T',' ').slice(0,19))} + ${esc(r.kind||'')} #${r.target_id} + ${esc((r.fields_set||[]).join(', '))} + ${esc(r.source||'')} + `).join(''); + card.innerHTML = ` +
+
+
πŸ€– Enrichment Worker
+ ${hbBadge} + ${s.paused ? 'PAUZIRAN' : ''} + ${hbAge != null ? 'Zadnji heartbeat: '+hbAge+'s' : ''} + + + ${pauseBtn} + +
+
+
Zadnji ciklus
${lc.fields_total != null ? lc.fields_total + ' polja' : 'β€”'} +
${lc.elapsed_s ? lc.elapsed_s + ' s' : ''}
+
Sportasi / Klubovi / Savezi
${(lc.sportas||0)+' / '+(lc.klub||0)+' / '+(lc.savez||0)}
+
Polja zadnjih 24h
${s.fields_24h||0}
+
+
Confidence prag: ${(conf).toFixed(2)}
+ +
+
+ ${recentRows ? ` +
+
πŸ“‹ Posljednji enrich-write zapisi
+
+ + ${recentRows} +
VrijemeCiljPoljaIzvor
+
` : ''} +
+ `; + // Auto-refresh every 10s while audit page is open + if(_enrichWorkerTimer) clearTimeout(_enrichWorkerTimer); + _enrichWorkerTimer = setTimeout(()=>{ + if(_state.section === 'audit') loadEnrichWorker(); + }, 10000); +} + +async function setWorkerPause(paused){ + try{ + const r = await fetch(API+'/v2/enrich/worker/pause', {method:'POST', + headers:{'Content-Type':'application/json'}, body: JSON.stringify({paused})}); + if(!r.ok) throw new Error('HTTP '+r.status); + toast(paused ? '⏸ Worker pauziran' : '▢️ Worker nastavlja', 'info', 2500); + loadEnrichWorker(); + }catch(e){ toast('❌ '+(e.message||String(e)), 'error'); } +} + +async function runWorkerNow(){ + try{ + const r = await fetch(API+'/v2/enrich/worker/run-now', {method:'POST'}); + if(!r.ok) throw new Error('HTTP '+r.status); + toast('β–Ά Worker Δ‡e pokrenuti novi ciklus odmah', 'info', 2500); + setTimeout(loadEnrichWorker, 2000); + }catch(e){ toast('❌ '+(e.message||String(e)), 'error'); } +} + +async function setWorkerConfidence(value){ + try{ + const r = await fetch(API+'/v2/enrich/worker/confidence', {method:'POST', + headers:{'Content-Type':'application/json'}, body: JSON.stringify({value})}); + if(!r.ok) throw new Error('HTTP '+r.status); + toast('🎚 Confidence prag: '+value.toFixed(2), 'info', 2000); + }catch(e){ toast('❌ '+(e.message||String(e)), 'error'); } } //=========== DASHBOARD =========== @@ -1121,6 +1224,7 @@ function renderKluboviShell(){ +
@@ -1320,6 +1424,7 @@ function renderSportasiShell(){ +