Restore readable vocals and instrumental ZIP filenames

This commit is contained in:
Mikei386 committed 2026-10-01 20:46:40 +02:00
1 parent 932284a831
commit 96c394cd6c
3 files changed
+10 -2

No files matched your search

+4
View File
@@ -27,3 +27,7 @@ Unterstützt Gesang (BS-Roformer), Schlagzeug/Bass (Demucs FT), Gitarre/Klavier/
Modellquellen einschließlich aller Ensemble-Dateien und SHA-256 stehen in separator_sources.json. Paket-Downloads und Restore prüfen alle Hashes. Quelle darf GitHub/UVR oder Meta sein; es wird keine Hugging-Face-Herkunft erfunden. Lokale Übernahme erhält IDs und wird separat als Übernahme dargestellt. Unbekannte lokale Dateien benötigen weiterhin einen belegten Herkunftsabgleich.
Backup speichert Paketrezepte, Quellen und Container-Konfiguration. Der Docker-Helfer kann das hier hinterlegte Image-Rezept auf einer leeren Installation wieder bauen; Gewichte werden von den geprüften Quellen erneut bezogen.
ZIP-Ausgaben heißen bei Gesang `Vocals.wav` und `Instrumental.wav`; andere Ziele
verwenden `Drums.wav`, `Bass.wav`, `Guitar.wav`, `Piano.wav` oder `Other.wav`
zusammen mit `Rest.wav`, ohne technische Modell- oder Eingabedateinamen.
+5 -1
View File
@@ -7,6 +7,10 @@ from email.parser import BytesParser
BASE='http://127.0.0.1:8108'
CONFIG=Path('/data/deck-connection.json')
TARGETS={'vocals':'model_bs_roformer_ep_317_sdr_12.9755.ckpt','drums':'htdemucs_ft.yaml','bass':'htdemucs_ft.yaml','guitar':'htdemucs_6s.yaml','piano':'htdemucs_6s.yaml','other':'htdemucs_6s.yaml'}
def archive_name(target,filename):
if target not in TARGETS:raise ValueError('Unbekannte Zielspur.')
if Path(filename).name=='rest.wav':return 'Instrumental.wav' if target=='vocals' else 'Rest.wav'
return {'vocals':'Vocals','drums':'Drums','bass':'Bass','guitar':'Guitar','piano':'Piano','other':'Other'}[target]+'.wav'
def request(path,body=None,ctype='application/json',token=None):
if token is None:token=json.loads(CONFIG.read_text())['token'] if CONFIG.exists() else ''
if not token:raise ValueError('Zuerst die Deck-Verbindung einrichten.')
@@ -71,7 +75,7 @@ class Handler(BaseHTTPRequestHandler):
if current['state']!='complete':raise ValueError(current['phase'])
result=io.BytesIO()
with zipfile.ZipFile(result,'w',zipfile.ZIP_STORED) as bundle:
for f in current['files']:bundle.writestr(Path(f['name']).name,request(f"/api/v1/separator-tests/audio?id={ident}&index={f['index']}"))
for f in current['files']:bundle.writestr(archive_name(target,f['name']),request(f"/api/v1/separator-tests/audio?id={ident}&index={f['index']}"))
return self.send(result.getvalue(),mime='application/zip')
raise ValueError('Trennauftrag hat das Zeitlimit überschritten.')
except Exception as exc:return self.send({'detail':str(exc) if isinstance(exc,ValueError) else 'Verarbeitung fehlgeschlagen; Verbindung und Audioformat prüfen.'},400)
+1 -1
View File
@@ -15,5 +15,5 @@
</div>
<label class="drop" id="drop">Audio auswählen oder hier ablegen<input id="file" type="file" accept="audio/*"><div class="file" id="name">Noch keine Datei gewählt</div></label><button id="start" disabled>Ausgewählte Spur und Rest erzeugen</button><div class="status" id="status">Bereit.</div><div class="bar" id="bar"><div class="fill"></div></div><small>Verarbeitung durch Athena Deck. Bis 20 Minuten und 256 MiB; Ausgabe als WAV-ZIP. Modell wird nach dem Auftrag entladen. Synthesizer, Streicher sowie elektrische und akustische Gitarre separat benötigen zusätzliche Spezialmodelle.</small></main><script>
const file=document.querySelector('#file'),drop=document.querySelector('#drop'),name=document.querySelector('#name'),start=document.querySelector('#start'),status=document.querySelector('#status'),bar=document.querySelector('#bar');let selected;async function packages(){let r=await fetch('/api/status'),s=await r.json();document.querySelector('#packages').textContent=r.ok?s.models.map(m=>`${m.name}: ${m.installed?'bereit':'fehlt – in Deck herunterladen'}`).join(' · '):s.detail}document.querySelector('#connect').onclick=async()=>{let token=document.querySelector('#token');let r=await fetch('/api/connection',{method:'POST',headers:{'Content-Type':'application/json','X-Athena-UI':'1'},body:JSON.stringify({token:token.value})});let s=await r.json();token.value='';status.textContent=r.ok?'Deck verbunden.':s.detail;packages()};packages();const names={vocals:'gesang',drums:'schlagzeug',bass:'bass',guitar:'gitarre',piano:'piano',other:'sonstiges',speech:'sprache-und-hintergrund'};function choose(f){selected=f;name.textContent=f?`${f.name} · ${(f.size/1048576).toFixed(1)} MiB`:'Noch keine Datei gewählt';start.disabled=!f}file.onchange=()=>choose(file.files[0]);drop.ondragover=e=>{e.preventDefault();drop.classList.add('drag')};drop.ondragleave=()=>drop.classList.remove('drag');drop.ondrop=e=>{e.preventDefault();drop.classList.remove('drag');choose(e.dataTransfer.files[0])};start.onclick=async()=>{const target=document.querySelector('input[name=target]:checked').value;start.disabled=true;bar.classList.add('run');status.textContent=target==='speech'?'MossFormer2 trennt Sprache und Hintergrund – das kann einige Minuten dauern …':'Modell löst die gewählte Spur heraus – das kann einige Minuten dauern …';let body=new FormData();body.append('file',selected);body.append('target',target);try{let r=await fetch('/v1/separate',{method:'POST',headers:{'X-Athena-UI':'1'},body});if(!r.ok)throw Error((await r.json()).detail||`HTTP ${r.status}`);let blob=await r.blob(),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=`athena-${names[target]}-und-rest.zip`;a.click();setTimeout(()=>URL.revokeObjectURL(a.href),5000);status.textContent='Fertig – ZIP mit der ausgewählten Spur und dem Rest wurde geladen.'}catch(e){status.textContent=`Fehler: ${e.message}`}finally{bar.classList.remove('run');start.disabled=false}};
const file=document.querySelector('#file'),drop=document.querySelector('#drop'),name=document.querySelector('#name'),start=document.querySelector('#start'),status=document.querySelector('#status'),bar=document.querySelector('#bar');let selected;async function packages(){let r=await fetch('/api/status'),s=await r.json();document.querySelector('#packages').textContent=r.ok?s.models.map(m=>`${m.name}: ${m.installed?'bereit':'fehlt – in Deck herunterladen'}`).join(' · '):s.detail}document.querySelector('#connect').onclick=async()=>{let token=document.querySelector('#token');let r=await fetch('/api/connection',{method:'POST',headers:{'Content-Type':'application/json','X-Athena-UI':'1'},body:JSON.stringify({token:token.value})});let s=await r.json();token.value='';status.textContent=r.ok?'Deck verbunden.':s.detail;packages()};packages();const names={vocals:'gesang',drums:'schlagzeug',bass:'bass',guitar:'gitarre',piano:'piano',other:'sonstiges',speech:'sprache-und-hintergrund'};function choose(f){selected=f;name.textContent=f?`${f.name} · ${(f.size/1048576).toFixed(1)} MiB`:'Noch keine Datei gewählt';start.disabled=!f}file.onchange=()=>choose(file.files[0]);drop.ondragover=e=>{e.preventDefault();drop.classList.add('drag')};drop.ondragleave=()=>drop.classList.remove('drag');drop.ondrop=e=>{e.preventDefault();drop.classList.remove('drag');choose(e.dataTransfer.files[0])};start.onclick=async()=>{const target=document.querySelector('input[name=target]:checked').value;start.disabled=true;bar.classList.add('run');status.textContent=target==='speech'?'MossFormer2 trennt Sprache und Hintergrund – das kann einige Minuten dauern …':'Modell löst die gewählte Spur heraus – das kann einige Minuten dauern …';let body=new FormData();body.append('file',selected);body.append('target',target);try{let r=await fetch('/v1/separate',{method:'POST',headers:{'X-Athena-UI':'1'},body});if(!r.ok)throw Error((await r.json()).detail||`HTTP ${r.status}`);let blob=await r.blob(),a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=target==='vocals'?'athena-vocals-instrumental.zip':`athena-${names[target]}-und-rest.zip`;a.click();setTimeout(()=>URL.revokeObjectURL(a.href),5000);status.textContent='Fertig – ZIP mit der ausgewählten Spur und dem Rest wurde geladen.'}catch(e){status.textContent=`Fehler: ${e.message}`}finally{bar.classList.remove('run');start.disabled=false}};
</script></body></html>