diff --git a/generation_orchestrator.py b/generation_orchestrator.py index 61f299e..65ae688 100644 --- a/generation_orchestrator.py +++ b/generation_orchestrator.py @@ -263,6 +263,48 @@ def get_model_cache_key(conf): return f"{conf['model']}::{model_type}::{te_key}" +def _build_ltx_manifest_entry(conf, gen_result, output_filename, gen_index=None): + """Build a manifest entry for an LTX video. Mirrors image-gen entry shape + but with media_type='video' and LTX-specific fields.""" + return { + "id": gen_result.get("id"), # may be None - assigned downstream + "gen_index": gen_index, + "media_type": "video", + "image_path": None, + "video_path": gen_result["video_path"], + "preview_path": gen_result.get("preview_path"), + "width": gen_result["width"], + "height": gen_result["height"], + "duration_seconds": gen_result["duration_seconds"], + "frame_rate": gen_result["fps"], + "frames": gen_result["frames"], + "model_type": "ltx_video", + "model": conf["model"], + "clip_models": conf.get("clip_models", []), + "vae_video": conf.get("vae_video", ""), + "vae_audio": conf.get("vae_audio", ""), + "latent_upscaler": conf.get("latent_upscaler", ""), + "sampler_stage1": conf.get("sampler_stage1", ""), + "sigmas_stage1": conf.get("sigmas_stage1", ""), + "sampler_stage2": conf.get("sampler_stage2", ""), + "sigmas_stage2": conf.get("sigmas_stage2", ""), + "image_strength_stage1": conf.get("image_strength_stage1", 0.8), + "image_strength_stage2": conf.get("image_strength_stage2", 1.0), + "img_compression": conf.get("img_compression", 18), + "input_image": conf.get("input_image"), + "audio_mode": conf.get("audio_mode", "on"), + "cfg": conf.get("cfg", 1.0), + "seed": conf.get("seed"), + "positive": conf.get("positive", ""), + "negative": conf.get("negative", ""), + "lora": conf.get("lora", "None"), + "duration": gen_result.get("duration", 0), + "favorited": False, + "rejected": False, + "note": "", + } + + def load_model_by_type(conf, ckpt_name, use_remote_vae, optional_model, optional_clip, optional_vae, optional_positive, optional_negative, loaded_clip, loaded_vae, model_cache): """Dispatch to correct loader based on model_type in config.""" diff --git a/tests/test_ltx_cache_keys.py b/tests/test_ltx_cache_keys.py index 9589387..639bd6a 100644 --- a/tests/test_ltx_cache_keys.py +++ b/tests/test_ltx_cache_keys.py @@ -104,3 +104,48 @@ def test_ltx_sort_components_imports(): "latent_upscaler": "lup", } assert _ltx_sort_components(ltx) == (("c1", "c2"), "vv", "va", "lup") + + +def test_build_ltx_manifest_entry_imports(): + """Smoke test: _build_ltx_manifest_entry produces a valid manifest dict.""" + from generation_orchestrator import _build_ltx_manifest_entry + + conf = { + "model_type": "ltx_video", + "model": "ltx.safetensors", + "clip_models": ["c1.safetensors", "c2.safetensors"], + "vae_video": "vv.safetensors", + "vae_audio": "va.safetensors", + "latent_upscaler": "lup.safetensors", + "sampler_stage1": "euler_ancestral_cfg_pp", + "sigmas_stage1": "1.0, 0.5, 0.0", + "sampler_stage2": "euler_cfg_pp", + "sigmas_stage2": "0.85, 0.4, 0.0", + "cfg": 1.0, + "seed": 42, + "positive": "a video", + "negative": "ugly", + "lora": "None", + "audio_mode": "on", + } + gen_result = { + "video_path": "/tmp/gen.mp4", + "preview_path": "/tmp/gen.preview.png", + "frames": 126, + "fps": 25, + "duration_seconds": 5, + "width": 446, + "height": 576, + "duration": 47.3, + } + entry = _build_ltx_manifest_entry(conf, gen_result, "myfile_seed42") + assert entry["media_type"] == "video" + assert entry["video_path"] == "/tmp/gen.mp4" + assert entry["image_path"] is None + assert entry["preview_path"] == "/tmp/gen.preview.png" + assert entry["clip_models"] == ["c1.safetensors", "c2.safetensors"] + assert entry["sampler_stage2"] == "euler_cfg_pp" + assert entry["audio_mode"] == "on" + assert entry["favorited"] is False + assert entry["rejected"] is False + assert entry["note"] == ""