window.SeparatorUI=(()=>{
const e=v=>String(v??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
let section='discover';
async function api(path,data){const response=await fetch('/api/v1/'+path,data===undefined?{}:{method:'POST',headers:{'Content-Type':'application/json','X-Athena-Deck':'1'},body:JSON.stringify(data)});const value=await response.json();if(!response.ok)throw Error(value.error||'Anfrage fehlgeschlagen');return value;}
function sources(m){return `
Quelle: ${e(m.source?.publisher||'Nicht belegt')}
Originalquellen und Prüfsummen ${(m.source?.files||[]).map(f=>`${e(f.file)} ${f.urls.map(u=>`Downloadquelle `).join(' · ')}${e(f.sha256)}
`).join('')} `;}
function rows(models,library){const list=models.filter(m=>!library||m.installed);return list.length?`${list.map(m=>`
${e(m.name)} ${m.installed?'Bereit':'Nicht heruntergeladen'} ${m.source?.files?.length||0} Dateien ${e(m.id)}
${sources(m)}
Vollständiges Modellpaket · einschließlich Konfiguration und benötigter Teilmodelle. Die Laufzeit wird wiederverwendet.
${m.installed?'
In der Steuerung Audio-Trennung starten → ':`
Modellpaket herunterladen `}
`).join('')}
`:'Noch keine Modellpakete Unter Entdecken ein geprüftes Modellpaket herunterladen.
';}
function render(tool=false,force=false){if(!force&&document.querySelector('#separator-panel')?.dataset.tool===String(tool))return;
const tabs=[['discover','Entdecken'],['library','Bibliothek'],['downloads','Downloads'],['profiles','Profile'],['test','Testen']];
document.querySelector('#view').innerHTML=`${tool?'ATHENA / MODELLVERWALTUNG':'EINSTELLUNGEN / LAUFZEITEN'}
${tool?'Audio-Trennung':'Audio Separator'} ${tool?'Gesang, Schlagzeug, Bass, Gitarre, Klavier oder die übrige Begleitung aus einer Aufnahme herauslösen.':'Native CUDA-Laufzeit für BS-Roformer, MelBand und Demucs. Einmal installieren und für passende Modellpakete wiederverwenden.'}
${tool?`
${tabs.map(([id,label])=>`${label} `).join('')}
`:''}
`;
const root=document.querySelector('#separator-panel'),msg=root.querySelector('#sep-message'),content=root.querySelector('#sep-content');let pending=false,signature='';
async function action(path,data){pending=true;try{await api(path,data);msg.textContent=path==='separator-profiles/save'?'Profil gespeichert.':'Aktion gestartet.';}catch(error){msg.textContent=error.message;}finally{pending=false;signature='';poll();}}
function bind(s,t){
root.querySelectorAll('[data-sep-profile]').forEach(form=>{form.onsubmit=event=>{event.preventDefault();action('separator-profiles/save',{model:form.dataset.sepProfile,enabled:form.elements.enabled.checked,device:form.elements.device.value});};});
root.querySelectorAll('[data-sep-model]').forEach(b=>{b.disabled=pending||s.job?.state==='running'||!s.installed;b.onclick=()=>action('separator-runtime/download',{model:b.dataset.sepModel});});
const install=root.querySelector('#sep-install');if(install){install.disabled=pending||s.installed||s.job?.state==='running';install.onclick=()=>action('separator-runtime/install',{});}
const cancel=root.querySelector('#sep-cancel');if(cancel){cancel.disabled=s.job?.state!=='running';cancel.onclick=()=>action('separator-runtime/cancel',{});}
const stop=root.querySelector('#sep-test-cancel');if(stop){stop.disabled=t.job?.state!=='running';stop.onclick=()=>action('separator-tests/cancel',{});}
const form=root.querySelector('#sep-test');if(form){form.querySelector('button').disabled=pending||t.job?.state==='running'||!s.models.some(m=>m.installed);form.onsubmit=async event=>{event.preventDefault();pending=true;msg.textContent='Audio wird hochgeladen …';try{const response=await fetch('/api/v1/separator-tests/start',{method:'POST',headers:{'X-Athena-Deck':'1'},body:new FormData(form)}),value=await response.json();if(!response.ok)throw Error(value.error);msg.textContent='Trenntest gestartet.';}catch(error){msg.textContent=error.message;}finally{pending=false;signature='';poll();}};}
}
async function poll(){if(!root.isConnected)return;try{const [s,t]=await Promise.all([api('separator-runtime'),api('separator-tests')]);if(!root.isConnected)return;
const key=JSON.stringify([s,t,pending]);if(key!==signature&& (!root.querySelector('form')?.contains(document.activeElement)||t.job?.state==='running'||root.dataset.jobState!==String(t.job?.state))){signature=key;root.dataset.jobState=String(t.job?.state);
if(!tool){content.innerHTML=`Laufzeit ${s.installed?'Installiert':'Noch nicht installiert'} · Version ${e(s.version)}
Laufzeit installieren Einrichtung abbrechen Mindestens 15 GiB frei. Keine Änderung an Host-Treibern oder alten Diensten.
Audio-Trennung öffnen → ${e(s.job?.phase||'')}
${s.job?.state==='running'?' ':''}Installationsausgabe `;
const log=await api('separator-runtime/log');if(root.isConnected)root.querySelector('#sep-log').textContent=log.text;
}else if(section==='discover'||section==='library'){content.innerHTML=`${section==='discover'?'Geprüfte Pakete mit allen benötigten Zusatzdateien. Downloads prüfen die Originalquellen per SHA-256.
':''}${!s.installed?'Laufzeit fehlt. Audio Separator installieren →
':''}${rows(s.models,section==='library')}`;
}else if(section==='profiles'){content.innerHTML=`${t.hardware_error?`${e(t.hardware_error)}
`:''}Ein Profil pro Modellpaket. Aktivierte Profile sind für die Weboberfläche verfügbar. Gewichte laden bei Auftrag und werden danach entladen. Automatisch bevorzugt die RTX 5080, anschließend die RTX 3060; eine feste GPU wird niemals still gewechselt.
${s.models.map(m=>{const p=t.profiles[m.id];return `
${e(m.name)} ${p.enabled?'Aktiv':'Deaktiviert'} ${e(p.device==='auto'?'Automatisch · 5080 zuerst':t.devices.find(d=>d.uuid===p.device)?.name||'GPU nicht vorhanden')} `;}).join('')}
`;
}else if(section==='downloads'){content.innerHTML=s.job?`${e(s.job.state)} Einrichtungsauftrag ${e(s.job.phase)}
${s.job.state==='running'?'Abbrechen ':''}Abgeschlossene Modellpakete findest du in der Bibliothek.
`:'Keine Downloads Unter Entdecken ein Modellpaket auswählen.
';
}else{const j=t.job;content.innerHTML=`Audio-Trennung testen Kurzer PCM-WAV-Test: 16 Bit, Mono/Stereo, bis 30 Sekunden und 8 MiB. Für längere Dateien die Weboberfläche verwenden.
Audio-Trennoberfläche öffnen → · Audio-Trennung in der Steuerung starten →
Gewichte laden bei Auftrag und werden anschließend entladen. Fremde Dienste bleiben unberührt.
${j?`
${e(j.state)} · ${e(j.phase)} ${j.gpu?'· '+e(j.gpu):''} ${j.elapsed_seconds?e(j.elapsed_seconds)+' s':''}
${j.state==='running'?'
':''}`:''}
${j?.state==='complete'?j.files.map(f=>`${e(f.name)}
Spur herunterladen
`).join(''):''} `;}
}
bind(s,t);
}catch(error){if(root.isConnected)msg.textContent=error.message;}clearTimeout(root.pollTimer);if(root.isConnected)root.pollTimer=setTimeout(poll,3000);}
root.querySelectorAll('[data-sep-tab]').forEach(b=>b.onclick=()=>{section=b.dataset.sepTab;render(tool,true);});poll();
}
return {render};
})();