window.VoiceUI=(()=>{
const e=v=>String(v??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
function html(){return `
Stimme ausprobieren · VoxCPM2
Text erzeugt Sprache. Mit optionaler WAV-Referenz übernimmt VoxCPM2 deren Stimme. Nur eingerichtete VoxCPM2-Profile stehen zur Auswahl.
Im LLM-Modus verfügbar. Deck entlädt sein LLM vor der Stimmgenerierung und lädt es bei der nächsten Chat-Anfrage wieder. VoxCPM2 wird nach dem Auftrag entladen. Referenzdatei wird nach dem Auftrag gelöscht; Text wird nicht gespeichert.
`;}
function bind(){const root=document.querySelector('#voice-panel');if(!root)return;const el=id=>root.querySelector('#'+id);let busy=false,lastResult='',ready=false;
async function api(path='',body){const r=await fetch('/api/v1/voice'+path,body===undefined?{}:{method:'POST',headers:body instanceof FormData?{'X-Athena-Deck':'1'}:{'X-Athena-Deck':'1','Content-Type':'application/json'},body:body instanceof FormData?body:JSON.stringify(body)});const d=await r.json();if(!r.ok)throw Error(d.error||'Stimmgenerierung fehlgeschlagen');return d;}
async function refresh(){try{const d=await api();if(!root.isConnected)return;const j=d.job;el('voice-status').textContent=(j?.phase||'Profil wählen und Text eingeben.')+(j?.gpu?' · '+j.gpu:'');el('voice-progress').hidden=j?.state!=='running';el('voice-start').disabled=busy||!ready||j?.state==='running';el('voice-cancel').disabled=j?.state!=='running';if(j?.state==='complete'&&j.id!==lastResult){lastResult=j.id;el('voice-result').innerHTML=`