Spaces:
Running on Zero
Running on Zero
| """Shared pytest fixtures and CLI flags.""" | |
| import json | |
| import os | |
| import pathlib | |
| from typing import Any | |
| import pytest | |
| REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent | |
| DEFAULT_MASTER_WORKFLOW = pathlib.Path( | |
| os.environ.get( | |
| "LTX23_MASTER_WORKFLOW", | |
| pathlib.Path.home() | |
| / "Projects/comfyui/user/default/workflows" | |
| / "1. LTX 2.3 All-In-One 260406-05.json", | |
| ) | |
| ) | |
| def pytest_addoption(parser: pytest.Parser) -> None: | |
| parser.addoption("--gpu", action="store_true", help="Run L4 GPU smoke tests.") | |
| parser.addoption( | |
| "--comfy-real", | |
| action="store_true", | |
| help="Use bundled ComfyUI for L2 graph validation (slower).", | |
| ) | |
| def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item]) -> None: | |
| if not config.getoption("--gpu"): | |
| skip_gpu = pytest.mark.skip(reason="GPU smoke tests skipped (use --gpu)") | |
| for item in items: | |
| if "gpu" in item.keywords: | |
| item.add_marker(skip_gpu) | |
| def master_workflow() -> dict[str, Any]: | |
| """The full LTX 2.3 All-In-One workflow JSON (loaded from user's ComfyUI).""" | |
| if not DEFAULT_MASTER_WORKFLOW.exists(): | |
| pytest.skip( | |
| f"Master workflow not found at {DEFAULT_MASTER_WORKFLOW}. " | |
| "Set LTX23_MASTER_WORKFLOW env var to its path." | |
| ) | |
| return json.loads(DEFAULT_MASTER_WORKFLOW.read_text()) | |
| def canonical_inputs() -> dict[str, dict[str, Any]]: | |
| """Known-good Gradio input dicts per mode (used by L1/L2 tests).""" | |
| return { | |
| "t2v": { | |
| "prompt": "a tiger walking through a misty forest at dawn, cinematic", | |
| "negative_prompt": "", | |
| "preset": "balanced", | |
| "width": 512, | |
| "height": 768, | |
| "frames": 81, | |
| "fps": 24, | |
| "seed": 42, | |
| "camera_lora": "none", | |
| "camera_strength": 0.8, | |
| "detailer_on": False, | |
| "detailer_strength": 0.5, | |
| }, | |
| "i2v": { | |
| "prompt": "the subject turns toward the camera and smiles", | |
| "image": "/tmp/portrait.png", | |
| "preset": "balanced", | |
| "width": 512, | |
| "height": 768, | |
| "frames": 81, | |
| "fps": 24, | |
| "seed": 42, | |
| "camera_lora": "none", | |
| "camera_strength": 0.8, | |
| "detailer_on": True, | |
| "detailer_strength": 0.5, | |
| "ic_lora": "union", | |
| "ic_strength": 0.5, | |
| "pose_on": False, | |
| }, | |
| "a2v": { | |
| "prompt": "a dancer moves to the beat in a neon-lit studio", | |
| "audio": "/tmp/track.wav", | |
| "preset": "balanced", | |
| "width": 512, | |
| "height": 768, | |
| "frames": 81, | |
| "fps": 24, | |
| "seed": 42, | |
| "audio_cfg": 7.0, | |
| }, | |
| "lipsync": { | |
| "prompt": "the person speaks the audio with natural mouth movement", | |
| "image": "/tmp/portrait.png", | |
| "audio": "/tmp/speech.wav", | |
| "preset": "balanced", | |
| "image_strength": 0.7, | |
| "frames": 81, | |
| "fps": 24, | |
| "seed": 42, | |
| }, | |
| "keyframe": { | |
| "prompt": "smooth transition between the two frames", | |
| "first_frame": "/tmp/start.png", | |
| "last_frame": "/tmp/end.png", | |
| "preset": "balanced", | |
| "frames": 81, | |
| "fps": 24, | |
| "seed": 42, | |
| }, | |
| "style": { | |
| "prompt": "in the style of a renaissance oil painting", | |
| "input_video": "/tmp/source.mp4", | |
| "preset": "balanced", | |
| "frames": 81, | |
| "fps": 24, | |
| "seed": 42, | |
| "ic_lora": "motion-track", | |
| "ic_strength": 0.5, | |
| }, | |
| } | |
| def fake_hf_cache(tmp_path: pathlib.Path) -> pathlib.Path: | |
| """A fake ~/.cache/huggingface/hub layout with placeholder files.""" | |
| hub = tmp_path / "huggingface" / "hub" | |
| layouts = { | |
| "models--Lightricks--LTX-2.3": [ | |
| "ltx-2.3-22b-distilled.safetensors", | |
| "ltx-2.3-spatial-upscaler-x2-1.0.safetensors", | |
| "ltx-2.3-22b-distilled-lora-384.safetensors", | |
| ], | |
| "models--google--gemma-3-12b-it-qat-q4_0-unquantized": [ | |
| "model-00001-of-00005.safetensors", | |
| "model-00002-of-00005.safetensors", | |
| "model-00003-of-00005.safetensors", | |
| "model-00004-of-00005.safetensors", | |
| "model-00005-of-00005.safetensors", | |
| "model.safetensors.index.json", | |
| "tokenizer.model", | |
| "preprocessor_config.json", | |
| ], | |
| "models--Kijai--LTX2.3_comfy": [ | |
| "LTX23_video_vae_bf16.safetensors", | |
| "LTX23_audio_vae_bf16.safetensors", | |
| ], | |
| } | |
| for repo, files in layouts.items(): | |
| snapshot_dir = hub / repo / "snapshots" / "deadbeef" | |
| snapshot_dir.mkdir(parents=True, exist_ok=True) | |
| for filename in files: | |
| (snapshot_dir / filename).write_text("") # placeholder | |
| return hub | |