83 lines
3.5 KiB
Python
83 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""V142 - Hub footer strip (aligned with WTP footer for consistency)
|
|
Shows: Docker N · Providers N · Qdrant N · L99 N/N · Tools N · Score X%
|
|
Live fetch /api/ecosystem-health.php
|
|
"""
|
|
import sys
|
|
src, dst = sys.argv[1], sys.argv[2]
|
|
with open(src, "r", encoding="utf-8") as f:
|
|
c = f.read()
|
|
|
|
if "V142-FOOTER-STRIP" in c:
|
|
print("ALREADY", file=sys.stderr)
|
|
sys.exit(0)
|
|
|
|
# Find a good place: at the END of the body, after all tabs but before closing </body> or </html>
|
|
# Simplest: before </body>
|
|
body_close_candidates = ['</body>', '</html>']
|
|
marker = None
|
|
for m in body_close_candidates:
|
|
if m in c:
|
|
marker = m
|
|
break
|
|
|
|
if not marker:
|
|
print("no </body> or </html>", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
footer_html = '''<!-- V142-FOOTER-STRIP: ecosystem health in footer (aligned with WTP) -->
|
|
<div id="v142-footer" style="position:fixed;bottom:0;left:0;right:0;background:rgba(0,0,0,0.75);border-top:1px solid var(--bd);padding:4px 12px;display:flex;gap:14px;align-items:center;font-size:9px;color:var(--mu);z-index:40;backdrop-filter:blur(8px);font-family:ui-monospace,monospace">
|
|
<span id="v142-score" style="font-weight:600"></span>
|
|
<span id="v142-l99"></span>
|
|
<span id="v142-tools"></span>
|
|
<span id="v142-docker"></span>
|
|
<span id="v142-providers"></span>
|
|
<span id="v142-qdrant"></span>
|
|
<span id="v142-ollama"></span>
|
|
<span style="margin-left:auto;color:#00d4b4;font-size:9px"><a href="/wevia-unified-hub.html" style="color:inherit;text-decoration:none" title="Truth Hub">Truth →</a></span>
|
|
</div>
|
|
''' + marker
|
|
|
|
c = c.replace(marker, footer_html, 1)
|
|
|
|
# Add JS fetcher (once, on load)
|
|
# Reuse same position as V139 truth loader
|
|
js_marker = 'async function __v139LoadTruthStrip('
|
|
js_add = '''/* V142-FOOTER-STRIP: load ecosystem health once */
|
|
async function __v142LoadFooter(){
|
|
try {
|
|
const r = await fetch('/api/ecosystem-health.php', {cache: 'no-store'});
|
|
if (!r.ok) return;
|
|
const d = await r.json();
|
|
const set = (id, content) => { const el = document.getElementById(id); if (el) el.innerHTML = content; };
|
|
const colorScore = d.percent >= 99 ? '#10b981' : d.percent >= 95 ? '#f59e0b' : '#ef4444';
|
|
set('v142-score', '<span style="color:' + colorScore + '">' + (d.score || '?') + ' ' + (d.percent ?? 0) + '%</span>');
|
|
if (d.l99) set('v142-l99', 'L99 <b>' + (d.l99.pass||0) + '/' + (d.l99.total||0) + '</b>');
|
|
set('v142-tools', 'Tools <b>' + (d.tools_wired ?? 0) + '</b>');
|
|
if (d.infra) set('v142-docker', 'Docker <b>' + (d.infra.docker ?? 0) + '</b>');
|
|
if (d.providers) set('v142-providers', 'Providers <b>' + (d.providers.free ?? 0) + '</b>');
|
|
if (d.providers?.qdrant) set('v142-qdrant', 'Qdrant <b>' + Number(d.providers.qdrant).toLocaleString('fr-FR') + '</b>');
|
|
if (d.infra?.ollama) set('v142-ollama', 'Ollama <b>' + d.infra.ollama + '</b>');
|
|
const footer = document.getElementById('v142-footer');
|
|
if (footer) footer.title = 'Ecosystem health live · source: /api/ecosystem-health.php · ts: ' + (d.ts || 'n/a') + ' · click Truth → for unified registry';
|
|
} catch(_) {}
|
|
}
|
|
__v142LoadFooter();
|
|
|
|
''' + js_marker
|
|
|
|
if js_marker in c:
|
|
c = c.replace(js_marker, js_add, 1)
|
|
|
|
# Also add padding-bottom to body so footer doesn't cover content
|
|
body_style_marker = '<body'
|
|
# safer: add CSS
|
|
style_close = '</style>'
|
|
style_add = '/* V142-FOOTER-STRIP: body padding to prevent footer overlap */\nbody{padding-bottom:26px}\n</style>'
|
|
if style_close in c:
|
|
c = c.replace(style_close, style_add, 1)
|
|
|
|
with open(dst, "w", encoding="utf-8") as f:
|
|
f.write(c)
|
|
print(f"OK size={len(c)}", file=sys.stderr)
|