Offer isolated VoxCPM runtime installation from model setup

This commit is contained in:
Mikei386 committed 2026-10-02 11:55:25 +02:00
1 parent 1f0fc42344
commit aee31359b6
18 files changed
+168 -21

No files matched your search

+51
View File
@@ -0,0 +1,51 @@
"""Owned, GUI-installable VoxCPM runtime; never downloads or loads models."""
import json,os,shutil,sys,time
from pathlib import Path
from ltx_original_runtime import LTXOriginalRuntime
VERSION='2.0.3'
class VoxCPMRuntime(LTXOriginalRuntime):
name='VoxCPM'
def paths(self):
try:
ident=json.loads((self.root/'active.json').read_text())['id']
if len(ident)==32 and all(c in '0123456789abcdef' for c in ident):
base=self.root/ident
if (base/'ready').read_text().strip()==VERSION:return base/'python/bin/python',base
except (OSError,ValueError,KeyError):pass
return self.root/'missing-python',self.root/'missing-runtime'
def status(self):
python,base=self.paths();shared=self.image_runtime.paths()[0].is_file() if self.image_runtime else False
return dict(installed=python.is_file() and (base/'ready').is_file(),version=VERSION,job=dict(self.job) if self.job else None,required_disk_gib=8 if shared else 25,shared_cuda=shared,worker_available=False,origin='OpenBMB/VoxCPM · offizielles Python-Paket',message='Laufzeitinstallation lädt keine Gewichte. Für die Generierung fehlt noch der Deck-Worker.')
def start(self):
if not shutil.which('ffmpeg'):raise ValueError('FFmpeg fehlt. Systemvoraussetzungen über den Deck-Installer einrichten.')
return super().start()
def _run(self):
base=self.root/self.job['id'];state='failed';phase='VoxCPM-Einrichtung fehlgeschlagen.'
try:
base.mkdir(mode=0o700);tmp=base/'tmp';tmp.mkdir()
# A new environment may reference existing CUDA packages but never alters them.
env={k:v for k,v in os.environ.items() if not k.startswith(('HF_','DECK_','LLAMA_'))}
env.update(TMPDIR=str(tmp),PIP_NO_INPUT='1',PIP_DISABLE_PIP_VERSION_CHECK='1',HF_HUB_OFFLINE='1',OMP_NUM_THREADS='2')
shared=self.image_runtime.paths()[0] if self.image_runtime else Path('/missing')
bootstrap=shared if shared.is_file() else Path(sys.executable)
self._phase('Eigene VoxCPM-Python-Umgebung erstellen');self._command([bootstrap,'-m','venv',base/'python'],env)
python=base/'python/bin/python'
self._command([python,'-c','import sys; assert (3,10)<=sys.version_info[:2]<(3,13), "VoxCPM benötigt Python 3.10 bis 3.12"'],env)
if shared.is_file():
self._phase('Vorhandene CUDA-Pakete lesend wiederverwenden')
self._command([python,'-c','import json,site,subprocess,sys;from pathlib import Path;p=json.loads(subprocess.check_output([sys.argv[1],"-c","import json,site;print(json.dumps(site.getsitepackages()))"],text=True));Path(site.getsitepackages()[0],"deck-shared-cuda.pth").write_text("\\n".join(p)+"\\n")',shared],env)
self._phase('CUDA-PyTorch prüfen / installieren')
self._command([python,'-m','pip','install','--no-cache-dir','torch==2.11.0','torchaudio==2.11.0','--index-url','https://download.pytorch.org/whl/cu128'],env)
self._phase('VoxCPM '+VERSION+' und Abhängigkeiten installieren')
self._command([python,'-m','pip','install','--no-cache-dir','-c',Path(__file__).parent/'deploy/voxcpm-requirements.lock','voxcpm=='+VERSION],env)
self._phase('Paketkonsistenz und VoxCPM2-Unterstützung prüfen')
self._command([python,'-m','pip','check'],env)
self._command([python,'-c','import torch,soundfile;from voxcpm import VoxCPM;from voxcpm.model.voxcpm2 import VoxCPM2Model;assert torch.version.cuda;assert callable(VoxCPM.from_pretrained)'],env)
if self.cancel.is_set():raise InterruptedError()
(base/'ready').write_text(VERSION);marker=self.root/'active.tmp';marker.write_text(json.dumps(dict(id=base.name)));marker.replace(self.root/'active.json')
state='complete';phase='VoxCPM-Laufzeit installiert · noch kein Deck-Worker und kein Modell geladen'
except InterruptedError:state='cancelled';phase='VoxCPM-Einrichtung abgebrochen.'
except Exception as exc:phase=str(exc)
finally:
if state!='complete':shutil.rmtree(base,ignore_errors=True)
with self.lock:self.process=None;self.job.update(state=state,phase=phase,finished_at=time.time());self._save()