From a77266c7bd6d70b6ee7a372d4ebe19e00a126aa5 Mon Sep 17 00:00:00 2001
From: Mikei386 <44135113+Mikei386@users.noreply.github.com>
Date: Mon, 28 Sep 2026 21:29:48 +0200
Subject: [PATCH] Add bounded GPU-priority automatic model testing and profile
export
---
STUDIO.md | 10 ++++
auto-test-ui.js | 11 +++++
auto_test.py | 100 ++++++++++++++++++++++++++++++++++++++
deploy/Dockerfile | 4 +-
deploy/install.py | 2 +-
index.html | 2 +-
inference.py | 6 ++-
network/install_remote.py | 2 +-
server.py | 14 +++++-
studio.js | 5 +-
test_auto_test.py | 39 +++++++++++++++
test_server.py | 2 +-
12 files changed, 187 insertions(+), 10 deletions(-)
create mode 100644 auto-test-ui.js
create mode 100644 auto_test.py
create mode 100644 test_auto_test.py
diff --git a/STUDIO.md b/STUDIO.md
index fabea86..1cd5bd8 100644
--- a/STUDIO.md
+++ b/STUDIO.md
@@ -163,3 +163,13 @@ Sprachmodelle besitzen jetzt den Reiter **Testen**: interner Textchat mit Stream
Im Profileditor kann MTP aktiviert werden, mit 1–8 Draft-Token und Mindestwahrscheinlichkeit 0–1. Medium-Referenz: 2 und 0,05; Draft-KV ist f16. Bestehende Profile bleiben standardmäßig ohne MTP. Das Modell muss eingebettete MTP-Gewichte enthalten. Der CUDA-Build benötigt den Deck-MTP-Fit-Adapter; neue GUI-Builds installieren ihn automatisch. Die Prognose zählt die gemeinsamen Gewichte einmal sowie Haupt- und MTP-Kontext und deren Compute-Puffer. Ein inkompatibles Modell oder ein alter Build wird nicht still ohne MTP gestartet. MTP garantiert keinen Geschwindigkeitsgewinn.
GPU-Ausführung: „Automatisch“ darf bei Platzmangel Schichten auf die CPU verlagern. „Vollständig auf GPU“ verlangt alle Schichten einschließlich Ausgabe und bricht sonst vor dem Laden ab. Die Prognose lässt je GPU mindestens 512 MiB bzw. 2,5 % Gesamtspeicher frei (der größere Wert gilt); keine Garantie für beliebige Last. Die Chat-Diagnose kennzeichnet eine begrenzte Layerzahl.
+
+## Auto-Test für heruntergeladene Sprachmodelle
+
+Unter Sprachmodelle → Auto-Test ein GGUF und eine obere Kontextgrenze auswählen. Feste Gerätepriorität RTX 5080, dann RTX 3060; andere Hardware wird ausdrücklich abgelehnt. Kontextstufen: 2048, 4096, 8192, 16384, 32768, 65536, 131072, 160000, 192000, 262144 bis zur gewählten Grenze. Pro Kontext zuerst nur 5080, dann Layer-Splits 95:5, 90:10, 85:15, 75:25, 50:50. Nur wenn kein GPU-Kandidat besteht, wird automatische CPU-Auslagerung mit 85:15 getestet. Die erste erfolgreiche Gerätestufe hat Priorität; keine Behauptung eines globalen Geschwindigkeitsoptimums.
+
+Microbatch 128, 64 und 256, Batch 2048, ein Slot; optional MTP2/p-min0,05. Erst Speicherprognose, dann echter Start, Aufwärmrunde und synthetischer, per Modelltokenizer auf 75 Prozent des Kontexts gefüllter Prompt mit bis zu 64 Ausgabetoken. Speicherung nur von Parametern, Prognose, Messwerten und Fehlerstatus; keine Antworten. Keine absichtliche Überschreitung der Speicherreserve. Höchstens 48 Kandidaten bzw. zwei Stunden zwischen Kandidaten; laufende Einzeloperationen haben eigene Zeitlimits. Ein kurzer erfolgreicher Lauf ist kein Vollkontext-/Parallelitäts-Stabilitätsnachweis.
+
+Der gemeinsame Scheduler sperrt die Deck-Modelle während der Testreihe exklusiv. Bereits laufende Anfragen verhindern den Start; fremde GPU-Prozesse werden nicht beendet. Abbrechen schließt die eigene Anfrage, beendet nur die eigenen Testprozesse und gibt die Reservierung frei. Beim App-Neustart wird eine offene Reihe als unterbrochen markiert. Ergebnisse bleiben in auto-tests.json; ein neuer Test ersetzt diese Ergebnisliste. Erfolgreiche Kandidaten lassen sich explizit als neues Profil speichern, ohne Veröffentlichung am Endpunkt.
+
+Admin-API: GET /api/v1/auto-tests; POST /start mit model_id, max_context, mtp; POST /cancel mit {}; POST /save mit job_id, index, name (jeweils unter /api/v1/auto-tests). Session und CSRF-Schutz wie Profilverwaltung; API-Bearer gewährt keinen Zugriff.
diff --git a/auto-test-ui.js b/auto-test-ui.js
new file mode 100644
index 0000000..cce4095
--- /dev/null
+++ b/auto-test-ui.js
@@ -0,0 +1,11 @@
+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.
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)=>`