window.VideoUI=(()=>{ const e=v=>String(v??'').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)}:{}),s=await r.json();if(!r.ok)throw Error(s.error||'Anfrage fehlgeschlagen');return s;} function mode(root,s,profiles){ if(root.querySelector('#active-video')===document.activeElement||root.dataset.busy==='1')return; const html=`

GPU-Modus

Modus: ${e(s.mode.toUpperCase())} · ${e(s.state)} · ${e(s.error||'')}

${e(s.memory_policy)}

Video beendet laufende Deck-GPU-Aufträge und sperrt Chat, Bild und TTS (HTTP 503). CPU-STT bleibt verfügbar. Fremde Dienste werden nicht beendet.

Video-Laufzeit und Testauftrag →

`; if(root._html===html)return;root._html=html;root.innerHTML=html; async function act(path,data){root.dataset.busy='1';try{await api(path,data);root._html='';root.querySelector('.video-message').textContent='Übernommen; Status wird aktualisiert.';}catch(x){root.querySelector('.video-message').textContent=x.message;}finally{root.dataset.busy='0';}} root.querySelectorAll('[data-mode]').forEach(b=>b.onclick=()=>act('video/mode',{mode:b.dataset.mode})); root.querySelector('#active-video').onchange=ev=>{if(ev.target.value)act('video/profile',{id:ev.target.value});}; } function html(testing=false){return `
${testing?'

Video testen

Profil auswählen, Video-Modus aktivieren und einen kurzen Test starten.

':'

LTX-Video-Laufzeit

'}

Eigene Python-Umgebung, gepinnte LTX-Pipelines, CUDA 12.8. Installation verändert keine Host-Treiber. Erster Ausführungsweg: Text → Video mit dem Distilled-BF16-Rezept und Disk-Streaming auf der RTX 5080.

Modus und aktives Profil in der Übersicht auswählen →

Video-Test

Zuerst den Video-Modus aktivieren. Werte überschreiben die Profilstandards für diesen Auftrag. Distilled nutzt seine feste Schrittfolge. Noch kein Bild-/Audio-Upload.

${[['width','Breite',256],['height','Höhe',256],['frames','Bilder (8n+1)',9],['fps','FPS',24],['seed','Seed',42]].map(([n,l,v])=>``).join('')}

API: POST /v1/videos · GET /v1/videos/{id} · GET /v1/videos/{id}/content. Gleicher Port und API-Token wie Chat; eigenständige Deck-Video-API.

`;} async function runtime(){ const view=document.querySelector('#view');if(view.querySelector('#video-runtime-page'))return; view.innerHTML=html();bind(view.firstElementChild); } function bind(root=document.querySelector('#video-runtime-page')){ if(!root)return; const msg=root.querySelector('#video-message'); async function action(path,data){try{await api(path,data);msg.textContent='Auftrag angenommen.';}catch(x){msg.textContent=x.message;}} root.querySelector('#video-install').onclick=()=>action('video-runtime/install',{}); root.querySelector('#video-cancel').onclick=()=>action('video-runtime/cancel',{}); root.querySelector('#video-test button').disabled=true; root.querySelector('#video-test').onsubmit=ev=>{ev.preventDefault();const d=Object.fromEntries(new FormData(ev.target));for(const k of ['width','height','frames','fps','seed'])d[k]=Number(d[k]);action('video/generate',d);}; async function poll(){if(!root.isConnected)return;try{const s=await api('video');if(!root.isConnected)return;const panel=root.querySelector('#video-test-mode');if(panel){const p=await api('profiles');if(!root.isConnected)return;mode(panel,s,p.profiles);}root.querySelector('#video-status').textContent=s.runtime.installed?'Installiert · '+s.runtime.revision:(s.runtime.job?.phase||'Noch nicht installiert');root.querySelector('#video-install').disabled=s.runtime.installed||s.runtime.job?.state==='running';root.querySelector('#video-cancel').disabled=s.runtime.job?.state!=='running';root.querySelector('#video-test button').disabled=s.mode!=='video'||s.state!=='ready'||s.job?.state==='running';root.querySelector('#video-job').textContent=s.job?`${s.job.state} · ${s.job.phase||''} · ${s.job.id} · ${s.job.error||''}`:'Noch kein Video-Auftrag.';if(s.job?.state==='complete'&&root.querySelector('#video-result').dataset.id!==s.job.id){root.querySelector('#video-result').dataset.id=s.job.id;root.querySelector('#video-result').innerHTML=`Video herunterladen`;}}catch(x){msg.textContent=x.message;}if(root.isConnected)setTimeout(poll,2000);}poll(); } return {mode,runtime,html:()=>html(true),bind}; })();