Commit e3b1fecc by PLN (Algolia)

fix(vibe): warm CLAP at server startup + honest UI feedback/timeout

The first /vibe hit cold-loaded CLAP (~16s) with the UI stuck on 'searching…',
reading as hung. Now serve.py warms the model in a daemon thread at startup (when
semantics_embeds.npz is present) so the first query is instant; the client shows
'first search loads the model, ~15s' on a cold start and aborts after 90s with a
retry hint instead of spinning forever.
parent 0e441195
...@@ -173,4 +173,16 @@ if __name__ == "__main__": ...@@ -173,4 +173,16 @@ if __name__ == "__main__":
print(f"serving {os.getcwd()}") print(f"serving {os.getcwd()}")
print(f" local : http://127.0.0.1:{a.port}/") print(f" local : http://127.0.0.1:{a.port}/")
print(f" LAN : http://{ip}:{a.port}/ ← open on phone (same wifi)") print(f" LAN : http://{ip}:{a.port}/ ← open on phone (same wifi)")
# Warm CLAP in the background so the FIRST /vibe query isn't a 15s cold-load.
if os.path.exists("semantics_embeds.npz"):
def _warm():
try:
print(" vibe : warming CLAP…", flush=True)
_vibe_load()
print(" vibe : ready (/vibe, /similar)", flush=True)
except Exception as e:
print(f" vibe : disabled — {e}", flush=True)
threading.Thread(target=_warm, daemon=True).start()
httpd.serve_forever() httpd.serve_forever()
...@@ -384,12 +384,19 @@ function vibeRamp(sim){const t=state.vibe?state.vibe.norm(sim):0.5; ...@@ -384,12 +384,19 @@ function vibeRamp(sim){const t=state.vibe?state.vibe.norm(sim):0.5;
// faint violet → brand magenta as similarity rises // faint violet → brand magenta as similarity rises
const r=Math.round(90+t*(217-90)),g=Math.round(58+t*(0-58)),b=Math.round(106+t*(255-106)); const r=Math.round(90+t*(217-90)),g=Math.round(58+t*(0-58)),b=Math.round(106+t*(255-106));
return `rgb(${r},${g},${b})`;} return `rgb(${r},${g},${b})`;}
let _vibeWarm=false;
async function runVibe(url,label){ async function runVibe(url,label){
const banner=$("#vibebanner");banner.innerHTML=`<span class="mono">searching…</span>`; const banner=$("#vibebanner");banner.classList.add("on");
banner.classList.add("on"); banner.innerHTML=`<span class="mono">searching…${_vibeWarm?"":" (first search loads the model, ~15s)"}</span>`;
let data; let data;
try{ data=await fetch(url).then(r=>r.json()); } const ac=new AbortController();const to=setTimeout(()=>ac.abort(),90000);
catch(_){ data={error:"no /vibe endpoint — start serve.py (python3 ../serve.py --dir .)"}; } try{ const r=await fetch(url,{signal:ac.signal});
if(!r.ok){data=await r.json().catch(()=>({error:`endpoint ${r.status}`}));}
else{data=await r.json();_vibeWarm=true;} }
catch(e){ data={error: e.name==="AbortError"
? "timed out (90s) — is CLAP still loading? retry in a moment"
: "no /vibe endpoint — run: python3 armada/serve.py --dir armada/tide-table --port 8731"}; }
finally{ clearTimeout(to); }
if(data.error){banner.innerHTML=`<span class="err">⚠ ${data.error}</span>` if(data.error){banner.innerHTML=`<span class="err">⚠ ${data.error}</span>`
+`<button class="x" id="vclr">clear</button>`;$("#vclr").onclick=clearVibe; +`<button class="x" id="vclr">clear</button>`;$("#vclr").onclick=clearVibe;
state.vibe=null;return;} state.vibe=null;return;}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment