window.AutoTestUI=(()=>{ const e=x=>String(x??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); async function api(path,data){const r=await fetch('/api/v1/'+path,data===undefined?{}:{method:'POST',headers:{'Content-Type':'application/json','X-Athena-Deck':'1'},body:JSON.stringify(data)});const v=await r.json();if(!r.ok)throw Error(v.error||'Anfrage fehlgeschlagen');return v;} function html(){return `

Automatische Einpassung & Leistungstest

Priorität: RTX 5080 allein → möglichst kleiner Anteil auf RTX 3060 → erst zuletzt CPU-Auslagerung. Synthetische Tests belegen die Deck-Laufzeit exklusiv; API-Anfragen warten. Fremde GPU-Dienste werden nicht beendet.

Ein Slot, Batch 2048, Microbatch 128 / 64 / 256. Kontextstufen ab 2048; pro Kandidat werden 75 % des Kontextes tatsächlich gefüllt und 64 Token erzeugt. Höchstens 48 Kandidaten bzw. zwei Stunden zwischen Kandidaten. Kein absichtliches Übergehen der Speicherreserve.

Dies ist eine begrenzte Suche, kein Beweis des absoluten Optimums oder der Stabilität bei vollem Kontext und paralleler Last. Erfolgreiche Profile werden nur auf Wunsch gespeichert, nicht am Endpunkt freigegeben.

`;} function bind(){const root=document.querySelector('#auto-test'),el=x=>root.querySelector('#'+x);let job=null,last='';const msg=x=>{if(root.isConnected)el('auto-message').textContent=x;}; api('catalog').then(s=>{if(root.isConnected)el('auto-model').innerHTML=s.entries.filter(x=>x.kind==='chat'&&x.profile_eligible&&x.file.endsWith('.gguf')).map(x=>``).join('');}).catch(x=>msg(x.message)); async function refresh(){try{const s=await api('auto-tests');if(!root.isConnected)return;job=s.job;const running=job?.state==='running';el('auto-start').disabled=running;el('auto-stop').disabled=!running;el('auto-phase').textContent=job?`${job.state} · ${job.phase} · ${job.attempts} Kandidaten${job.error?' · '+job.error:''}`:'Noch kein Auto-Test.';const rows=job?.results||[],signature=JSON.stringify(rows);if(last!==signature){last=signature;const best=rows.reduce((a,r,i)=>r.success&&(!a||r.timings.predicted_per_second>a.speed)?{i,speed:r.timings.predicted_per_second}:a,null);el('auto-results').innerHTML=rows.map((r,i)=>`

${r.context.toLocaleString('de-DE')} Kontext · ${e(r.tier)} ${best?.i===i?'· schnellster gemessener Kandidat':''}

Verteilung ${e(r.parameters.tensor_split.join(':')||'nur 5080')} · Microbatch ${r.parameters.ubatch}

${r.success?`

Prefill ${Number(r.timings.prompt_per_second).toFixed(1)} Token/s · Ausgabe ${Number(r.timings.predicted_per_second).toFixed(1)} Token/s · ${r.timings.prompt_n} Eingabe-Token geprüft

GPU-Layerlimit: ${r.memory_plan.gpu_layers===999?'alle':r.memory_plan.gpu_layers}

`:`

${e(r.error)}

`}
`).join('');root.querySelectorAll('[data-save]').forEach(b=>b.onclick=async()=>{try{await api('auto-tests/save',{job_id:job.id,index:Number(b.dataset.save),name:el('auto-name').value});msg('Profil gespeichert.');}catch(x){msg(x.message);}});}}catch(x){msg(x.message);}finally{if(root.isConnected)setTimeout(refresh,2000);}} el('auto-form').onsubmit=async ev=>{ev.preventDefault();try{await api('auto-tests/start',{model_id:el('auto-model').value,max_context:Number(el('auto-context').value),mtp:el('auto-mtp').checked});msg('Auto-Test gestartet.');}catch(x){msg(x.message);}}; el('auto-stop').onclick=()=>api('auto-tests/cancel',{}).then(()=>msg('Abbruch angefordert.')).catch(x=>msg(x.message));refresh(); }return {html,bind}; })();