Spaces:
Running
Running
| from __future__ import annotations | |
| import importlib.util | |
| import sys | |
| import types | |
| from pathlib import Path | |
| import pytest | |
| import torch | |
| ROOT = Path(__file__).resolve().parents[1] | |
| SRC = ROOT / "src" | |
| def _load_module(name: str, path: Path): | |
| spec = importlib.util.spec_from_file_location(name, path) | |
| module = importlib.util.module_from_spec(spec) | |
| assert spec.loader is not None | |
| sys.modules[name] = module | |
| spec.loader.exec_module(module) | |
| return module | |
| def bootstrap_repo_modules(monkeypatch): | |
| for name, path in [ | |
| ("voxcpm", SRC / "voxcpm"), | |
| ("voxcpm.model", SRC / "voxcpm" / "model"), | |
| ("voxcpm.modules", SRC / "voxcpm" / "modules"), | |
| ]: | |
| pkg = types.ModuleType(name) | |
| pkg.__path__ = [str(path)] | |
| monkeypatch.setitem(sys.modules, name, pkg) | |
| hh = types.ModuleType("huggingface_hub") | |
| hh.snapshot_download = lambda *a, **k: "/tmp/fake" | |
| monkeypatch.setitem(sys.modules, "huggingface_hub", hh) | |
| pydantic = types.ModuleType("pydantic") | |
| class BaseModel: | |
| def model_rebuild(cls): | |
| return None | |
| def model_validate_json(cls, s): | |
| return cls() | |
| def model_dump(self): | |
| return {} | |
| pydantic.BaseModel = BaseModel | |
| monkeypatch.setitem(sys.modules, "pydantic", pydantic) | |
| torchaudio = types.ModuleType("torchaudio") | |
| monkeypatch.setitem(sys.modules, "torchaudio", torchaudio) | |
| librosa = types.ModuleType("librosa") | |
| librosa.effects = types.SimpleNamespace(trim=lambda *a, **k: (None, (0, 0))) | |
| monkeypatch.setitem(sys.modules, "librosa", librosa) | |
| einops = types.ModuleType("einops") | |
| einops.rearrange = lambda x, *a, **k: x | |
| monkeypatch.setitem(sys.modules, "einops", einops) | |
| tqdm_pkg = types.ModuleType("tqdm") | |
| tqdm_pkg.__path__ = ["/nonexistent"] | |
| tqdm_pkg.tqdm = lambda x, *a, **k: x | |
| monkeypatch.setitem(sys.modules, "tqdm", tqdm_pkg) | |
| tqdm_auto = types.ModuleType("tqdm.auto") | |
| tqdm_auto.tqdm = lambda x, *a, **k: x | |
| monkeypatch.setitem(sys.modules, "tqdm.auto", tqdm_auto) | |
| transformers = types.ModuleType("transformers") | |
| class LlamaTokenizerFast: | |
| pass | |
| class PreTrainedTokenizer: | |
| pass | |
| transformers.LlamaTokenizerFast = LlamaTokenizerFast | |
| transformers.PreTrainedTokenizer = PreTrainedTokenizer | |
| monkeypatch.setitem(sys.modules, "transformers", transformers) | |
| internal_mods = { | |
| "voxcpm.modules.audiovae": ["AudioVAE", "AudioVAEConfig", "AudioVAEV2", "AudioVAEConfigV2"], | |
| "voxcpm.modules.layers": ["ScalarQuantizationLayer"], | |
| "voxcpm.modules.locdit": ["CfmConfig", "UnifiedCFM", "VoxCPMLocDiT", "VoxCPMLocDiTV2"], | |
| "voxcpm.modules.locenc": ["VoxCPMLocEnc"], | |
| "voxcpm.modules.minicpm4": ["MiniCPM4Config", "MiniCPMModel"], | |
| "voxcpm.modules.layers.lora": ["apply_lora_to_named_linear_modules", "LoRALinear"], | |
| } | |
| for modname, names in internal_mods.items(): | |
| module = types.ModuleType(modname) | |
| for name in names: | |
| if name == "apply_lora_to_named_linear_modules": | |
| setattr(module, name, lambda *a, **k: None) | |
| else: | |
| setattr(module, name, type(name, (), {})) | |
| monkeypatch.setitem(sys.modules, modname, module) | |
| _load_module("voxcpm.model.utils", SRC / "voxcpm" / "model" / "utils.py") | |
| voxcpm = _load_module("voxcpm.model.voxcpm", SRC / "voxcpm" / "model" / "voxcpm.py") | |
| voxcpm2 = _load_module("voxcpm.model.voxcpm2", SRC / "voxcpm" / "model" / "voxcpm2.py") | |
| return voxcpm.VoxCPMModel, voxcpm2.VoxCPM2Model | |
| class DummyModel: | |
| device = "cpu" | |
| def named_parameters(self): | |
| return [] | |
| def test_load_lora_weights_accepts_tensor_only_legacy_checkpoints(monkeypatch, tmp_path, module_name): | |
| VoxCPMModel, VoxCPM2Model = bootstrap_repo_modules(monkeypatch) | |
| cls = VoxCPMModel if module_name == "v1" else VoxCPM2Model | |
| ckpt_path = tmp_path / "lora_weights.ckpt" | |
| torch.save({"state_dict": {"fake": torch.zeros(1)}}, ckpt_path) | |
| loaded, skipped = cls.load_lora_weights(DummyModel(), str(ckpt_path), device="cpu") | |
| assert loaded == [] | |
| assert skipped == ["fake"] | |
| def test_load_lora_weights_rejects_malicious_pickle_payloads(monkeypatch, tmp_path, module_name): | |
| VoxCPMModel, VoxCPM2Model = bootstrap_repo_modules(monkeypatch) | |
| cls = VoxCPMModel if module_name == "v1" else VoxCPM2Model | |
| ckpt_path = tmp_path / "lora_weights.ckpt" | |
| marker_path = tmp_path / f"{module_name}-marker.txt" | |
| class Exploit: | |
| def __reduce__(self): | |
| import pathlib | |
| return (pathlib.Path.write_text, (marker_path, f"{module_name} executed\n")) | |
| torch.save({"state_dict": {"fake": torch.zeros(1)}, "boom": Exploit()}, ckpt_path) | |
| with pytest.raises(Exception, match="Weights only load failed"): | |
| cls.load_lora_weights(DummyModel(), str(ckpt_path), device="cpu") | |
| assert not marker_path.exists() | |