Download tests/test_pipeline.py from supermind/OGG-Comfy: direct link, hf CLI and curl.
- Browser
- Download file 5.79 kB
-
https://huggingface.co/supermind/OGG-Comfy/resolve/main/tests/test_pipeline.py
- Command line
-
hf download hf://supermind/OGG-Comfy/tests/test_pipeline.py
-
curl -L -o test_pipeline.py https://huggingface.co/supermind/OGG-Comfy/resolve/main/tests/test_pipeline.py
5.79 kB
| import os as _os | |
| HERE = _os.path.dirname(_os.path.abspath(__file__)) | |
| ROOT = _os.path.dirname(HERE) | |
| import sys, os, json, types, math, shutil; sys.path.insert(0, HERE) | |
| import harness, torch | |
| from safetensors.torch import save_file | |
| pack, nodes = harness.load_pack() | |
| shutil.rmtree(harness.OUT, ignore_errors=True); os.makedirs(harness.OUT + "/temp") | |
| # ---- 1. the workflows match the schemas of the nodes (names, order, widget or socket) | |
| import asyncio | |
| async def _nodes(): | |
| return await (await pack.comfy_entrypoint()).get_node_list() | |
| ext = asyncio.run(_nodes()) | |
| by_type = {c.__name__: c for c in ext} | |
| node_ids = {} | |
| for c in ext: | |
| sch = c.define_schema(); node_ids[sch.k["node_id"]] = (c, sch) | |
| print("node ids:", sorted(node_ids)) | |
| WIDGET = {"COMBO", "INT", "FLOAT", "STRING", "BOOLEAN"} | |
| for name in ("ogg_text_to_speech", "ogg_voice_clone", "ogg_dialogue", "ogg_voice_design"): | |
| w = json.load(open(f"{ROOT}/example_workflows/{name}.json")) | |
| for n in w["nodes"]: | |
| if n["type"] in ("MarkdownNote", "SaveAudio", "LoadAudio"): continue | |
| cls, sch = node_ids[n["type"]] | |
| want = [(i.a[0], i.kind in WIDGET) for i in sch.k["inputs"]] | |
| have = [(i["name"], "widget" in i) for i in n["inputs"]] | |
| assert want == have, (n["type"], want, have) | |
| nw = sum(1 for _, wd in want if wd) + sum(1 for i in sch.k["inputs"] if i.k.get("control_after_generate")) | |
| if n["type"] != "OggEditor": assert len(n["widgets_values"]) == nw, (n["type"], len(n["widgets_values"]), nw) | |
| print("workflow OK:", name) | |
| # ---- 2. load_ogg path on a tiny checkpoint (tokenizer files are not available offline: from_config_dir is replaced) | |
| sys.path.insert(0, HERE) | |
| import runpy | |
| ns = runpy.run_path(HERE + "/smoke_core.py") | |
| tiny, tok = ns["model"], ns["tok"] | |
| tmp = harness.OUT + "/tiny_ogg.safetensors" | |
| save_file({k: v.contiguous() for k, v in tiny.state_dict().items()}, tmp) | |
| nodes.ensure_omnivoice_files = lambda: None | |
| seen = {} | |
| def fake_from_config_dir(path, dtype=torch.float32, attn="sdpa", prompt_x=False): | |
| seen["prompt_x"], seen["path"] = prompt_x, path | |
| from transformers import AutoModel | |
| m = nodes.of.OmniFish(AutoModel.from_config(tiny.llm.config), prompt_x=prompt_x).to(dtype) | |
| t = ns["StubTok"](); m.configure_languages(t); return m, t | |
| nodes.of.OmniFish.from_config_dir = staticmethod(fake_from_config_dir) | |
| ogg = nodes.load_ogg(tmp, torch.float32) | |
| print("load_ogg ok; prompt_x:", seen["prompt_x"], "tokenizer wrapped:", type(ogg.tok).__name__, "| omnivoice dir:", nodes.OMNIVOICE_DIR) | |
| try: | |
| save_file({"x": torch.zeros(1)}, harness.OUT + "/bad.safetensors"); nodes.load_ogg(harness.OUT + "/bad.safetensors", torch.float32) | |
| except ValueError as e: print("rejects a foreign file:", e) | |
| # ---- 3. a stand-in codec with the real interface: Encode Voice, Generate, Decode, Editor, save/load | |
| class FakeCodecModel: | |
| def encode(self, wav): | |
| T = math.ceil(wav.shape[-1] / 2048); torch.manual_seed(1) | |
| c = torch.randint(0, 1024, (1, 10, T)); c[:, 0] %= 4096; return c | |
| def decode(self, codes, dtype): | |
| n = codes.shape[-1] * 2048; t = torch.arange(n) / 44100 | |
| return (0.2 * torch.sin(2 * math.pi * 300 * t) * (torch.arange(n) % 20000 < 15000))[None] | |
| codec = types.SimpleNamespace(model=FakeCodecModel(), patcher=harness.ModelPatcher(None, torch.device("cpu"), torch.device("cpu"))) | |
| audio = {"waveform": torch.randn(1, 1, 48000) * 0.1, "sample_rate": 48000} | |
| voice = nodes.OggEncodeVoice.execute(codec, audio, "<|speaker:0|> hello there").args[0] | |
| print("encoded voice codes:", tuple(voice["codes"].shape)) | |
| nodes.OggSaveVoice.execute(voice, "ogg/voice") | |
| vf = [f for f in os.listdir(harness.OUT + "/ogg_voices/ogg")][0] | |
| loaded = nodes.OggLoadVoice.execute("ogg/" + vf) if False else None | |
| nodes.folder_paths.get_full_path_or_raise = lambda n, f: os.path.join(harness.OUT, n, f) | |
| loaded = nodes.OggLoadVoice.execute("ogg/" + vf).args[0] | |
| assert torch.equal(loaded["codes"], voice["codes"]) and loaded["transcript"] == voice["transcript"]; print("voice save/load round-trip ok") | |
| r = nodes.OggGenerate.execute(ogg, "[sad] one\ntwo\nthree", "en", 3, 2, 1.5, 0.8, True, 24, "", "", 0.0, 0, 4, loaded).args[0] | |
| print("generate: codes", tuple(r["codes"].shape), "takes", r["takes"], "lines", [(l["start"], l["end"]) for l in r["lines"]]) | |
| nodes.OggSaveCodes.execute(r, "ogg/take") | |
| cf = os.listdir(harness.OUT + "/ogg_codes/ogg")[0] | |
| r2 = nodes.OggLoadCodes.execute("ogg/" + cf).args[0] | |
| assert torch.equal(r2["codes"], r["codes"]) and r2["takes"] == r["takes"] and r2["lines"] == r["lines"]; print("codes save/load round-trip ok") | |
| a = nodes.OggDecode.execute(codec, r2, False).args[0] | |
| expect = sum(r["takes"]) * 2048 + 2 * round(0.3 * 44100) | |
| print("decode:", tuple(a["waveform"].shape), a["sample_rate"], "expected samples", expect); assert a["waveform"].shape[-1] == expect | |
| a2 = nodes.OggDecode.execute(codec, r2, True).args[0]; print("decode with shorten_long_pauses:", tuple(a2["waveform"].shape)) | |
| e = nodes.OggEditor.execute(codec, r2, None, "") | |
| print("editor audio:", tuple(e.args[0]["waveform"].shape), "ui:", e.ui["ogg_editor"][0]) | |
| assert os.path.exists(os.path.join(harness.OUT, "temp", "ogg_editor", e.ui["ogg_editor"][0]["audio"])) | |
| a_ = json.load(open(os.path.join(harness.OUT, "temp", "ogg_editor", e.ui["ogg_editor"][0]["analysis"]))) | |
| print("editor analysis: lines", len(a_["lines"]), "speakers", a_["speakers"], "duration", round(a_["duration"], 2)) | |
| # ---- 4. the editor's server route logic | |
| from ogg_pack.ogg.editor import DEFAULTS, plan | |
| p = plan(a_, dict(DEFAULTS)); print("plan pieces:", len(p["pieces"])) | |
| # ---- 5. error path of the omnivoice fetch (no network here) | |
| import importlib; importlib.reload(sys.modules["ogg_pack.nodes"]) if False else None | |
| src = open(ROOT + "/nodes.py").read() | |
| ns2 = {} | |
| print("ALL OK") | |