Architecture firm marketing aide - Expansion

#5
Files changed (6) hide show
  1. README.md +1 -1
  2. models.py +1 -3
  3. tests/conftest.py +1 -1
  4. tests/test_models.py +0 -17
  5. tests/test_workflow.py +0 -19
  6. workflow.py +1 -26
README.md CHANGED
@@ -16,7 +16,7 @@ preload_from_hub:
16
  - Lightricks/LTX-2-19b-LoRA-Camera-Control-Jib-Down ltx-2-19b-lora-camera-control-jib-down.safetensors
17
  - Lightricks/LTX-2-19b-LoRA-Camera-Control-Jib-Up ltx-2-19b-lora-camera-control-jib-up.safetensors
18
  - Lightricks/LTX-2-19b-LoRA-Camera-Control-Static ltx-2-19b-lora-camera-control-static.safetensors
19
- - Lightricks/LTX-2.3 ltx-2.3-22b-distilled-lora-384.safetensors,ltx-2.3-spatial-upscaler-x2-1.1.safetensors
20
  - Lightricks/LTX-2.3-22b-IC-LoRA-Union-Control ltx-2.3-22b-ic-lora-union-control-ref0.5.safetensors
21
  - google/gemma-3-12b-it-qat-q4_0-unquantized gemma-3-12b-it/model-00001-of-00005.safetensors,gemma-3-12b-it/model-00002-of-00005.safetensors,gemma-3-12b-it/model-00003-of-00005.safetensors,gemma-3-12b-it/model-00004-of-00005.safetensors,gemma-3-12b-it/model-00005-of-00005.safetensors,gemma-3-12b-it/model.safetensors.index.json,gemma-3-12b-it/preprocessor_config.json,gemma-3-12b-it/tokenizer.model
22
  ---
 
16
  - Lightricks/LTX-2-19b-LoRA-Camera-Control-Jib-Down ltx-2-19b-lora-camera-control-jib-down.safetensors
17
  - Lightricks/LTX-2-19b-LoRA-Camera-Control-Jib-Up ltx-2-19b-lora-camera-control-jib-up.safetensors
18
  - Lightricks/LTX-2-19b-LoRA-Camera-Control-Static ltx-2-19b-lora-camera-control-static.safetensors
19
+ - Lightricks/LTX-2.3 ltx-2.3-22b-distilled-lora-384.safetensors,ltx-2.3-spatial-upscaler-x2-1.0.safetensors
20
  - Lightricks/LTX-2.3-22b-IC-LoRA-Union-Control ltx-2.3-22b-ic-lora-union-control-ref0.5.safetensors
21
  - google/gemma-3-12b-it-qat-q4_0-unquantized gemma-3-12b-it/model-00001-of-00005.safetensors,gemma-3-12b-it/model-00002-of-00005.safetensors,gemma-3-12b-it/model-00003-of-00005.safetensors,gemma-3-12b-it/model-00004-of-00005.safetensors,gemma-3-12b-it/model-00005-of-00005.safetensors,gemma-3-12b-it/model.safetensors.index.json,gemma-3-12b-it/preprocessor_config.json,gemma-3-12b-it/tokenizer.model
22
  ---
models.py CHANGED
@@ -34,9 +34,7 @@ MODEL_REGISTRY: dict[str, ModelEntry] = {
34
  # Main LTX 2.3 transformer + LoRAs + upscalers
35
  "ltx-2.3-22b-distilled.safetensors": ModelEntry("Lightricks/LTX-2.3", comfy_type="checkpoints"),
36
  "ltx-2.3-22b-dev.safetensors": ModelEntry("Lightricks/LTX-2.3", comfy_type="checkpoints"),
37
- # v1.0 was deleted upstream on 2026-08-10; workflow.RETIRED_MODEL_RENAMES
38
- # rewrites the templates' references to this name.
39
- "ltx-2.3-spatial-upscaler-x2-1.1.safetensors": ModelEntry(
40
  "Lightricks/LTX-2.3", comfy_type="latent_upscale_models"
41
  ),
42
  "ltx-2.3-22b-distilled-lora-384.safetensors": ModelEntry(
 
34
  # Main LTX 2.3 transformer + LoRAs + upscalers
35
  "ltx-2.3-22b-distilled.safetensors": ModelEntry("Lightricks/LTX-2.3", comfy_type="checkpoints"),
36
  "ltx-2.3-22b-dev.safetensors": ModelEntry("Lightricks/LTX-2.3", comfy_type="checkpoints"),
37
+ "ltx-2.3-spatial-upscaler-x2-1.0.safetensors": ModelEntry(
 
 
38
  "Lightricks/LTX-2.3", comfy_type="latent_upscale_models"
39
  ),
40
  "ltx-2.3-22b-distilled-lora-384.safetensors": ModelEntry(
tests/conftest.py CHANGED
@@ -132,7 +132,7 @@ def fake_hf_cache(tmp_path: pathlib.Path) -> pathlib.Path:
132
  layouts = {
133
  "models--Lightricks--LTX-2.3": [
134
  "ltx-2.3-22b-distilled.safetensors",
135
- "ltx-2.3-spatial-upscaler-x2-1.1.safetensors",
136
  "ltx-2.3-22b-distilled-lora-384.safetensors",
137
  ],
138
  "models--google--gemma-3-12b-it-qat-q4_0-unquantized": [
 
132
  layouts = {
133
  "models--Lightricks--LTX-2.3": [
134
  "ltx-2.3-22b-distilled.safetensors",
135
+ "ltx-2.3-spatial-upscaler-x2-1.0.safetensors",
136
  "ltx-2.3-22b-distilled-lora-384.safetensors",
137
  ],
138
  "models--google--gemma-3-12b-it-qat-q4_0-unquantized": [
tests/test_models.py CHANGED
@@ -29,23 +29,6 @@ def test_walk_workflow_for_models_finds_t2v_loaders():
29
  assert any("gemma" in name.lower() for name in needed)
30
 
31
 
32
- def test_model_registry_has_no_retired_filenames():
33
- """A registry key that 404s on the Hub makes every generation abort mid-graph."""
34
- assert "ltx-2.3-spatial-upscaler-x2-1.0.safetensors" not in models.MODEL_REGISTRY
35
- assert "ltx-2.3-spatial-upscaler-x2-1.1.safetensors" in models.MODEL_REGISTRY
36
- entry = models.MODEL_REGISTRY["ltx-2.3-spatial-upscaler-x2-1.1.safetensors"]
37
- assert entry.repo_id == "Lightricks/LTX-2.3"
38
- assert entry.comfy_type == "latent_upscale_models"
39
-
40
-
41
- def test_walk_workflow_for_models_requests_current_upscaler_for_every_mode():
42
- """The download pass must fetch the upscaler the workflow actually loads."""
43
- for mode in workflow.VALID_MODES:
44
- needed = models.walk_workflow_for_models(workflow.load_template(mode))
45
- assert "ltx-2.3-spatial-upscaler-x2-1.1.safetensors" in needed
46
- assert "ltx-2.3-spatial-upscaler-x2-1.0.safetensors" not in needed
47
-
48
-
49
  def test_ensure_models_creates_symlinks_local(tmp_path, monkeypatch, fake_hf_cache):
50
  """In local mode, ensure_models creates symlinks from comfy/models -> HF cache."""
51
  monkeypatch.setenv("HF_HUB_CACHE", str(fake_hf_cache))
 
29
  assert any("gemma" in name.lower() for name in needed)
30
 
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  def test_ensure_models_creates_symlinks_local(tmp_path, monkeypatch, fake_hf_cache):
33
  """In local mode, ensure_models creates symlinks from comfy/models -> HF cache."""
34
  monkeypatch.setenv("HF_HUB_CACHE", str(fake_hf_cache))
tests/test_workflow.py CHANGED
@@ -1,7 +1,5 @@
1
  """Unit tests for workflow.py — pure functions over JSON dicts."""
2
 
3
- import json
4
-
5
  import pytest
6
 
7
  import workflow
@@ -59,23 +57,6 @@ def test_validate_rejects_orphan_link():
59
  workflow.validate(wf)
60
 
61
 
62
- def test_load_template_remaps_retired_upscaler_filename():
63
- """Lightricks deleted the x2 spatial upscaler v1.0; templates still name it."""
64
- for mode in workflow.VALID_MODES:
65
- wf = workflow.load_template(mode)
66
- assert wf["101"]["inputs"]["model_name"] == "ltx-2.3-spatial-upscaler-x2-1.1.safetensors", (
67
- f"{mode} still loads a retired upscaler"
68
- )
69
-
70
-
71
- def test_load_template_leaves_no_retired_filenames_in_any_mode():
72
- """No retired model filename may reach the workflow handed to PromptExecutor."""
73
- for mode in workflow.VALID_MODES:
74
- serialized = json.dumps(workflow.load_template(mode))
75
- for retired in ("ltx-2.3-spatial-upscaler-x2-1.0.safetensors",):
76
- assert retired not in serialized, f"{mode} references retired {retired}"
77
-
78
-
79
  def test_set_input_handles_dict_widgets_values():
80
  """VHS_* nodes carry dict-style widgets_values; set_input must support str keys."""
81
  wf = workflow.load_template("a2v")
 
1
  """Unit tests for workflow.py — pure functions over JSON dicts."""
2
 
 
 
3
  import pytest
4
 
5
  import workflow
 
57
  workflow.validate(wf)
58
 
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  def test_set_input_handles_dict_widgets_values():
61
  """VHS_* nodes carry dict-style widgets_values; set_input must support str keys."""
62
  wf = workflow.load_template("a2v")
workflow.py CHANGED
@@ -16,38 +16,13 @@ WORKFLOWS_DIR = pathlib.Path(__file__).parent / "workflows"
16
 
17
  VALID_MODES: tuple[str, ...] = ("t2v", "a2v", "i2v", "lipsync", "keyframe", "style")
18
 
19
- # Model files the upstream HF repos have deleted, mapped to their replacements.
20
- # The templates are machine-generated by tools/extract_modes.py from the user's
21
- # master ComfyUI export, so patching the JSON would be undone on the next
22
- # re-export — the remap has to live in code. load_template is the only reader of
23
- # workflows/*.json, which puts it upstream of both consumers: the dict handed to
24
- # PromptExecutor and models.walk_workflow_for_models' download pass.
25
- RETIRED_MODEL_RENAMES: dict[str, str] = {
26
- # Lightricks deleted x2 spatial upscaler v1.0 on 2026-08-10 (v1.1 is the
27
- # long-video hotfix). Loading the retired name 404s and aborts the graph
28
- # right after sampling, leaving the user with an empty output.
29
- "ltx-2.3-spatial-upscaler-x2-1.0.safetensors": "ltx-2.3-spatial-upscaler-x2-1.1.safetensors",
30
- }
31
-
32
-
33
- def _rename_retired_models(value: Any) -> Any:
34
- """Return *value* with every retired model filename swapped for its successor."""
35
- if isinstance(value, str):
36
- return RETIRED_MODEL_RENAMES.get(value, value)
37
- if isinstance(value, dict):
38
- return {k: _rename_retired_models(v) for k, v in value.items()}
39
- if isinstance(value, list):
40
- return [_rename_retired_models(v) for v in value]
41
- return value
42
-
43
 
44
  def load_template(mode: str) -> dict[str, Any]:
45
  """Load a fresh, independent copy of the named mode's API workflow template."""
46
  if mode not in VALID_MODES:
47
  raise ValueError(f"unknown mode {mode!r}; expected one of {VALID_MODES}")
48
  path = WORKFLOWS_DIR / f"{mode}.json"
49
- template = copy.deepcopy(json.loads(path.read_text()))
50
- return _rename_retired_models(template)
51
 
52
 
53
  def set_input(workflow: dict[str, Any], node_id: int | str, field: str, value: Any) -> None:
 
16
 
17
  VALID_MODES: tuple[str, ...] = ("t2v", "a2v", "i2v", "lipsync", "keyframe", "style")
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  def load_template(mode: str) -> dict[str, Any]:
21
  """Load a fresh, independent copy of the named mode's API workflow template."""
22
  if mode not in VALID_MODES:
23
  raise ValueError(f"unknown mode {mode!r}; expected one of {VALID_MODES}")
24
  path = WORKFLOWS_DIR / f"{mode}.json"
25
+ return copy.deepcopy(json.loads(path.read_text()))
 
26
 
27
 
28
  def set_input(workflow: dict[str, Any], node_id: int | str, field: str, value: Any) -> None: