"""Pure functions over LTX 2.3 mode API-format workflow templates. Templates in `workflows/.json` are saved from ComfyUI's editor via "Save (API Format)". Shape: `{node_id_str: {"class_type": str, "inputs": dict}}`. This is what ComfyUI's `PromptExecutor.execute(prompt=...)` expects directly. """ from __future__ import annotations import copy import json import pathlib from typing import Any WORKFLOWS_DIR = pathlib.Path(__file__).parent / "workflows" VALID_MODES: tuple[str, ...] = ("t2v", "a2v", "i2v", "lipsync", "keyframe", "style") def load_template(mode: str) -> dict[str, Any]: """Load a fresh, independent copy of the named mode's API workflow template.""" if mode not in VALID_MODES: raise ValueError(f"unknown mode {mode!r}; expected one of {VALID_MODES}") path = WORKFLOWS_DIR / f"{mode}.json" return copy.deepcopy(json.loads(path.read_text())) def set_input(workflow: dict[str, Any], node_id: int | str, field: str, value: Any) -> None: """Patch a node's input field in place. For API-format workflows, each node has an `inputs` dict keyed by field name. `node_id` is the dict key (string for top-level, ":" for subgraph-internal). `field` is an entry name in `inputs`. Args: workflow: API-format workflow dict (mapping id → {class_type, inputs}). node_id: Dict key of the target node. field: Name of the input field to set. value: New value (literal, or `[src_id, src_slot]` link form). Raises: KeyError: If the node doesn't exist in the workflow. """ nid = str(node_id) if nid not in workflow: raise KeyError(f"node id {nid!r} not found in workflow") inputs = workflow[nid].setdefault("inputs", {}) inputs[field] = value