Files
Athena-Deck/audio_cpp_runtime.py

74 lines
4.4 KiB
Python

"""Pinned audio.cpp build, isolated from model execution and existing runtimes."""
import json
import os
from pathlib import Path
import shutil
import sys
import time
from ltx_original_runtime import LTXOriginalRuntime
REVISION='f2b4937306daa25f5c78520f3c626ed31495a37a'
VERSION='v0.8.1'
class AudioCppRuntime(LTXOriginalRuntime):
name="audio.cpp"
def __init__(self,root):
super().__init__(root,None)
request=self.root/'resume-request'
if request.is_file():
request.unlink()
self.start()
def paths(self):
p=self.root/'active.json'
if p.is_file():
ident=json.loads(p.read_text()).get('id','')
if len(ident)==32 and all(c in '0123456789abcdef' for c in ident):
base=self.root/ident
if (base/'ready').is_file():return base/'build/bin/audiocpp_cli',base/'source'
return self.root/'missing-cli',self.root/'missing-source'
def status(self):
cli,source=self.paths()
return dict(installed=cli.is_file() and (source/'model_specs/yue2.json').is_file(),revision=REVISION,version=VERSION,job=dict(self.job) if self.job else None,required_disk_gib=6,adapter_ready=True,origin='0xShug0/audio.cpp',message='Gemeinsame Laufzeit. Ein Build startet kein Modell; Der YuE2-Musikworker ist angebunden; Profil und Komponenten werden benötigt. Andere Familien brauchen eigene geprüfte Anbindungen.')
def start(self):
if sys.platform!='linux':raise ValueError('audio.cpp wird auf dem Debian-Server gebaut.')
missing=[name for name in ('git','cmake','g++','nvcc','nvidia-smi') if not shutil.which(name)]
if missing:raise ValueError('Build-Werkzeuge fehlen: '+', '.join(missing)+'. Keine automatische Host-Paket- oder Treiberänderung.')
self.resume_id=(self.job or {}).get('id')
return super().start()
def _run(self):
base=self.root/self.job['id'];state='failed';phase='audio.cpp-Build fehlgeschlagen.'
try:
previous=self.root/getattr(self,'resume_id','missing') if getattr(self,'resume_id',None) else None
if previous and (previous/'source/.git').is_dir() and not (previous/'ready').exists():
base=previous;self.job['id']=previous.name;self._save()
else:base.mkdir(mode=0o700)
tmp=base/'tmp';tmp.mkdir(exist_ok=True)
env=dict(os.environ,TMPDIR=str(tmp),GIT_TERMINAL_PROMPT='0',OMP_NUM_THREADS='2')
source=base/'source';build=base/'build'
self._phase('Offizielle audio.cpp-Quelle herunterladen')
if not (source/'.git').is_dir():
self._command(['git','init',source],env)
self._command(['git','-C',source,'fetch','--depth','1','https://github.com/0xShug0/audio.cpp.git',REVISION],env)
self._command(['git','-C',source,'checkout','--detach','FETCH_HEAD'],env)
else:self._command(['git','-C',source,'rev-parse','--verify',REVISION+'^{commit}'],env)
# Compile for the actual available GPUs; no weight allocation or inference.
import subprocess
raw=subprocess.check_output(['nvidia-smi','--query-gpu=compute_cap','--format=csv,noheader'],text=True)
arch=sorted({line.strip().replace('.','') for line in raw.splitlines() if line.strip()})
if not arch or any(not a.isdigit() for a in arch):raise ValueError('CUDA-Architekturen nicht ermittelbar.')
self._phase('CUDA-Build konfigurieren · GPU-Ziele '+', '.join(arch))
self._command(['cmake','-S',source,'-B',build,'-DCMAKE_BUILD_TYPE=Release','-DENGINE_ENABLE_CUDA=ON','-DCMAKE_CUDA_ARCHITECTURES='+';'.join(arch),'-DAUDIOCPP_DEPLOYMENT_BUILD=ON','-DAUDIOCPP_BUILD_SERVER_FRONTENDS=OFF','-DENGINE_BUILD_TESTS=OFF'],env)
self._phase('audio.cpp bauen · sechs parallele Build-Jobs')
self._command(['cmake','--build',build,'--target','audiocpp_cli','audiocpp_server','--parallel','6'],env)
self._phase('Programmstart ohne Modell prüfen')
self._command([build/'bin/audiocpp_cli','--help'],env)
if not (source/'model_specs/yue2.json').is_file():raise ValueError('YuE2-Modellspezifikation fehlt.')
if self.cancel.is_set():raise InterruptedError()
(base/'ready').write_text(REVISION)
marker=self.root/'active.tmp';marker.write_text(json.dumps({'id':base.name}));marker.replace(self.root/'active.json')
state='complete';phase='audio.cpp installiert. Kein Modell gestartet; Deck-Worker noch erforderlich.'
except InterruptedError:state='cancelled';phase='Build abgebrochen.'
except Exception as exc:phase=str(exc)
finally:
# Keep unfinished compiler artifacts so retry resumes the same pinned build.
with self.lock:self.process=None;self.job.update(state=state,phase=phase,finished_at=time.time());self._save()