Improve live preview VAE picker and Models wiring.
Show node class in the picker, allow manual wire to Chain Sampler live preview from Models, and keep wires synced with the View menu config. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
2761d6d3ac
commit
3fd08dcd13
@@ -81,6 +81,7 @@ OPEN_PORTS: list[tuple[str, str, str, bool]] = [ # (core_id, input, type, requ
|
||||
("studio", "source_image", "IMAGE", False),
|
||||
("studio", "latent", "LATENT", False),
|
||||
("sampler", "vae", "VAE", True),
|
||||
("sampler", "preview_vae", "VAE", False),
|
||||
("concat", "audio_latent", "LATENT", True),
|
||||
("audiodec", "audio_vae", "VAE", True),
|
||||
]
|
||||
@@ -207,6 +208,9 @@ def _wire_live_preview_vae(
|
||||
return
|
||||
if "sampler" not in graph:
|
||||
return
|
||||
existing = graph["sampler"].get("inputs", {}).get("preview_vae")
|
||||
if isinstance(existing, list):
|
||||
return
|
||||
sid = lp.get("slot_id")
|
||||
if not sid:
|
||||
report["unsatisfied"].append(
|
||||
@@ -591,13 +595,14 @@ def core_graph(object_info: dict, models_config: dict | None = None) -> list[dic
|
||||
|
||||
def _port_index(object_info: dict) -> dict[str, tuple[str, str]]:
|
||||
"""Map pipeline-port id ('Class.input' / 'FunPackStudio.input') -> (core_id, input)."""
|
||||
cls_to_core = {v: k for k, v in CORE.items()}
|
||||
idx: dict[str, tuple[str, str]] = {}
|
||||
for cid, cls in CORE.items():
|
||||
nd = object_info.get(cls)
|
||||
for ci in connection_inputs(nd or {}):
|
||||
idx[f"{cls}.{ci['name']}"] = (cid, ci["name"])
|
||||
# FunPack ports use the class name directly too (already covered above).
|
||||
# Authoritative open-core ports (includes optional sockets like preview_vae).
|
||||
for port_id, (cid, inp) in pipeline_wiring.PORT_TO_OPEN_CORE.items():
|
||||
idx[port_id] = (cid, inp)
|
||||
return idx
|
||||
|
||||
|
||||
@@ -661,6 +666,9 @@ def _autowire(graph, slots, slot_node_id, slot_def, object_info, producers, repo
|
||||
L = lambda nid: label.get(nid, nid)
|
||||
|
||||
targets = list(OPEN_PORTS) # (core_id, input, type, required)
|
||||
# Live preview VAE is explicit-only (Models wire or live_preview picker), never auto-wired.
|
||||
targets = [(nid, inp, t, req) for (nid, inp, t, req) in targets
|
||||
if not (nid == "sampler" and inp == "preview_vae")]
|
||||
for s in slots: # slot connection inputs (e.g. image-proc vae/image/length)
|
||||
if active_slots is not None and s["id"] not in active_slots:
|
||||
continue # inert slot (feeds nothing) — don't auto-wire or block on its inputs
|
||||
|
||||
@@ -72,8 +72,41 @@ def parse_config(raw: Any) -> dict[str, Any]:
|
||||
return {}
|
||||
|
||||
|
||||
PREVIEW_VAE_PORT = "FunPackLTXAVSceneChainSampler.preview_vae"
|
||||
PREVIEW_VAE_WIRE = f"port:{PREVIEW_VAE_PORT}"
|
||||
|
||||
|
||||
def _wire_targets(raw: Any) -> list[str]:
|
||||
if not raw:
|
||||
return []
|
||||
if isinstance(raw, list):
|
||||
return [str(t) for t in raw if t]
|
||||
return [str(raw)]
|
||||
|
||||
|
||||
def preview_vae_wire(models: Any) -> tuple[Optional[str], Optional[str]]:
|
||||
"""Return (slot_id, vae_output) wired to Chain Sampler live preview, if any."""
|
||||
if not isinstance(models, dict):
|
||||
return None, None
|
||||
for slot in models.get("slots") or []:
|
||||
sid = slot.get("id")
|
||||
if not sid:
|
||||
continue
|
||||
for out_name, raw in (slot.get("wires") or {}).items():
|
||||
if PREVIEW_VAE_WIRE in _wire_targets(raw):
|
||||
return str(sid), str(out_name or "VAE")
|
||||
lp = models.get("live_preview") or {}
|
||||
sid = lp.get("slot_id")
|
||||
if sid:
|
||||
return str(sid), str(lp.get("vae_output") or "VAE")
|
||||
return None, None
|
||||
|
||||
|
||||
def models_enabled(models: Any) -> bool:
|
||||
if not isinstance(models, dict):
|
||||
return False
|
||||
sid, _ = preview_vae_wire(models)
|
||||
if sid:
|
||||
return True
|
||||
lp = models.get("live_preview") or {}
|
||||
return bool(lp.get("enabled") and lp.get("slot_id"))
|
||||
|
||||
@@ -12,6 +12,7 @@ from __future__ import annotations
|
||||
import json
|
||||
|
||||
from . import config
|
||||
from . import pipeline_wiring
|
||||
|
||||
# Types that are graph CONNECTIONS (wired automatically), not user widgets.
|
||||
LINK_TYPES = {
|
||||
@@ -80,6 +81,7 @@ ROLES: dict[str, dict] = {
|
||||
"unet": {"label": "Unet / Diffusion Model", "category": "Loaders", "output": "MODEL"},
|
||||
"lora": {"label": "LoRA", "category": "Loaders", "output": "MODEL", "input": "MODEL"},
|
||||
"video_vae": {"label": "Video VAE", "category": "Loaders", "output": "VAE"},
|
||||
"preview_vae": {"label": "Live Preview VAE", "category": "Loaders", "output": "VAE"},
|
||||
"audio_vae": {"label": "Audio VAE", "category": "Loaders", "output": "VAE"},
|
||||
"clip": {"label": "CLIP / Text Encoder", "category": "Loaders", "output": "CLIP"},
|
||||
"clip_vision": {"label": "CLIP Vision", "category": "Loaders", "output": "CLIP_VISION"},
|
||||
@@ -357,6 +359,8 @@ def pipeline_ports(object_info: dict | None = None) -> list[dict]:
|
||||
if object_info:
|
||||
for cls, label in CORE_PORT_NODES:
|
||||
ports += ports_from_object_info(object_info, cls, label)
|
||||
for p in ports:
|
||||
p["label"] = pipeline_wiring.port_label(p["id"])
|
||||
return ports
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ ROLE_WIRE_TARGETS: dict[str, list[tuple[str, Optional[str], str]]] = {
|
||||
"clip": [("CLIP", None, "FunPackStudio.clip")],
|
||||
"lora": [("MODEL", None, "FunPackStudio.model"), ("CLIP", None, "FunPackStudio.clip")],
|
||||
"video_vae": [("VAE", None, "FunPackLTXAVSceneChainSampler.vae")],
|
||||
"preview_vae": [("VAE", None, "FunPackLTXAVSceneChainSampler.preview_vae")],
|
||||
"audio_vae": [("VAE", None, "LTXVAudioVAEDecode.audio_vae")],
|
||||
"audio_encoder": [("LATENT", None, "LTXVConcatAVLatent.audio_latent")],
|
||||
"empty_latent": [("LATENT", None, "FunPackStudio.latent")],
|
||||
@@ -45,6 +46,7 @@ DEFAULT_WIRES_BY_ROLE: dict[str, dict[str, str]] = {
|
||||
"unet": {"MODEL": "port:FunPackStudio.model"},
|
||||
"clip": {"CLIP": "port:FunPackStudio.clip"},
|
||||
"video_vae": {"VAE": "port:FunPackLTXAVSceneChainSampler.vae"},
|
||||
"preview_vae": {"VAE": "port:FunPackLTXAVSceneChainSampler.preview_vae"},
|
||||
"audio_vae": {"VAE": "port:LTXVAudioVAEDecode.audio_vae"},
|
||||
"audio_encoder": {"LATENT": "port:LTXVConcatAVLatent.audio_latent"},
|
||||
"empty_latent": {"LATENT": "port:FunPackStudio.latent"},
|
||||
@@ -63,6 +65,7 @@ PORT_LABELS: dict[str, str] = {
|
||||
"FunPackStudio.latent": "Studio · latent (forwards to Concat AV · video_latent)",
|
||||
"FunPackStudio.source_image": "Studio · source_image (Img2Video anchor)",
|
||||
"FunPackLTXAVSceneChainSampler.vae": "Chain Sampler · vae",
|
||||
"FunPackLTXAVSceneChainSampler.preview_vae": "Chain Sampler · live preview",
|
||||
"LTXVConcatAVLatent.audio_latent": "Concat AV Latent · audio_latent",
|
||||
"LTXVAudioVAEDecode.audio_vae": "Audio VAE Decode · audio_vae",
|
||||
}
|
||||
@@ -75,6 +78,7 @@ OPEN_CORE_INPUTS: frozenset[tuple[str, str]] = frozenset({
|
||||
("studio", "source_image"),
|
||||
("studio", "latent"),
|
||||
("sampler", "vae"),
|
||||
("sampler", "preview_vae"),
|
||||
("concat", "audio_latent"),
|
||||
("audiodec", "audio_vae"),
|
||||
})
|
||||
@@ -85,6 +89,7 @@ PORT_TO_OPEN_CORE: dict[str, tuple[str, str]] = {
|
||||
"FunPackStudio.source_image": ("studio", "source_image"),
|
||||
"FunPackStudio.latent": ("studio", "latent"),
|
||||
"FunPackLTXAVSceneChainSampler.vae": ("sampler", "vae"),
|
||||
"FunPackLTXAVSceneChainSampler.preview_vae": ("sampler", "preview_vae"),
|
||||
"LTXVConcatAVLatent.audio_latent": ("concat", "audio_latent"),
|
||||
"LTXVAudioVAEDecode.audio_vae": ("audiodec", "audio_vae"),
|
||||
}
|
||||
|
||||
@@ -166,10 +166,14 @@
|
||||
const vaeOuts = (spec.outputs || []).filter((o) => o.type === "VAE");
|
||||
if (!vaeOuts.length) continue;
|
||||
const outName = vaeOuts.find((o) => o.name === "VAE")?.name || vaeOuts[0].name;
|
||||
const cls = s.node_class || "?";
|
||||
const name = (s.label || "").trim();
|
||||
const label = name && name !== cls ? `${name} — ${cls}` : cls;
|
||||
const role = s.role_label || s.role;
|
||||
options.push({
|
||||
value: `${s.id}\x1f${outName}`,
|
||||
label: s.label || s.node_class || s.id,
|
||||
hint: `${outName} · ${s.node_class}`,
|
||||
label,
|
||||
hint: [role, `${outName} output`].filter(Boolean).join(" · "),
|
||||
});
|
||||
}
|
||||
if (!options.length) {
|
||||
|
||||
@@ -19,6 +19,74 @@
|
||||
const expanded = new Set(); // slot ids currently expanded (collapsed by default)
|
||||
let linkMode = false; // selecting inputs to bind into one shared control
|
||||
let linkSel = []; // [{slotId, input, kind, choices, label}]
|
||||
const LIVE_PREVIEW_PORT = "port:FunPackLTXAVSceneChainSampler.preview_vae";
|
||||
|
||||
function _clearLivePreviewWires(exceptSlotId, exceptOut) {
|
||||
for (const s of config.slots) {
|
||||
s.wires = s.wires || {};
|
||||
for (const outName of Object.keys(s.wires)) {
|
||||
if (s.id === exceptSlotId && outName === exceptOut) continue;
|
||||
const kept = wireTargets(s.wires[outName]).filter((t) => t !== LIVE_PREVIEW_PORT);
|
||||
if (kept.length) s.wires[outName] = kept;
|
||||
else delete s.wires[outName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _syncLivePreviewConfig(slotId, outName, wired) {
|
||||
config.live_preview = {
|
||||
enabled: false,
|
||||
slot_id: null,
|
||||
vae_output: "VAE",
|
||||
...(config.live_preview || {}),
|
||||
};
|
||||
if (wired && slotId && outName) {
|
||||
config.live_preview.enabled = true;
|
||||
config.live_preview.slot_id = slotId;
|
||||
config.live_preview.vae_output = outName;
|
||||
} else if (!wired && config.live_preview.slot_id === slotId
|
||||
&& (config.live_preview.vae_output || "VAE") === outName) {
|
||||
config.live_preview.enabled = false;
|
||||
config.live_preview.slot_id = null;
|
||||
}
|
||||
}
|
||||
|
||||
function _findLivePreviewWire() {
|
||||
for (const s of config.slots) {
|
||||
for (const [outName, raw] of Object.entries(s.wires || {})) {
|
||||
if (wireTargets(raw).includes(LIVE_PREVIEW_PORT)) {
|
||||
return { slotId: s.id, outName };
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function _scanLivePreviewFromWires() {
|
||||
const hit = _findLivePreviewWire();
|
||||
if (hit) _syncLivePreviewConfig(hit.slotId, hit.outName, true);
|
||||
}
|
||||
|
||||
function _afterLivePreviewWireChange(slot, outName) {
|
||||
const targets = wireTargets(slot.wires?.[outName]);
|
||||
if (targets.includes(LIVE_PREVIEW_PORT)) {
|
||||
_clearLivePreviewWires(slot.id, outName);
|
||||
if (!wireTargets(slot.wires[outName]).includes(LIVE_PREVIEW_PORT)) {
|
||||
_addWire(slot.id, outName, LIVE_PREVIEW_PORT);
|
||||
}
|
||||
_syncLivePreviewConfig(slot.id, outName, true);
|
||||
} else if (config.live_preview?.slot_id === slot.id
|
||||
&& (config.live_preview?.vae_output || "VAE") === outName) {
|
||||
_syncLivePreviewConfig(slot.id, outName, false);
|
||||
}
|
||||
}
|
||||
|
||||
function slotDisplayLabel(slot) {
|
||||
const cls = slot.node_class || "?";
|
||||
const name = (slot.label || "").trim();
|
||||
if (name && name !== cls) return `${name} — ${cls}`;
|
||||
return cls;
|
||||
}
|
||||
|
||||
function roleLabel(key) { const r = roles.find((x) => x.key === key); return r ? r.label : (key === "custom" ? "Node" : (key || "?")); }
|
||||
function slotName(slot) { return slot.label || slot.node_class; }
|
||||
@@ -112,6 +180,7 @@
|
||||
_clearPortWires(portId, parsed.slotId, parsed.out);
|
||||
_addWire(parsed.slotId, parsed.out, "port:" + portId);
|
||||
}
|
||||
_scanLivePreviewFromWires();
|
||||
}
|
||||
|
||||
function clearInternalCoreOverrides() {
|
||||
@@ -325,7 +394,7 @@
|
||||
const roleSpan = el("span", "slot-role", roleText);
|
||||
roleSpan.title = "Click ✎ to rename this label";
|
||||
head.append(roleSpan);
|
||||
head.append(el("span", "slot-node", slotName(slot)));
|
||||
head.append(el("span", "slot-node", slotDisplayLabel(slot)));
|
||||
const ren = el("button", "ic-btn", "✎"); ren.title = "Rename role label";
|
||||
ren.onclick = async (e) => {
|
||||
e.stopPropagation();
|
||||
@@ -533,10 +602,26 @@
|
||||
const sel = el("select", "wire-select");
|
||||
dests.forEach((d) => { const o = el("option", null, d.label); o.value = d.value; if (d.value === t) o.selected = true; sel.append(o); });
|
||||
if (t && !dests.some((d) => d.value === t)) { const o = el("option", null, t + " (not allowed)"); o.value = t; o.selected = true; sel.append(o); }
|
||||
sel.onchange = async () => { _setWireTarget(slot, out.name, targets[i], sel.value); targets[i] = sel.value; reconcileOpenPortWiring(); await persist(); render(); };
|
||||
sel.onchange = async () => {
|
||||
_setWireTarget(slot, out.name, targets[i], sel.value);
|
||||
targets[i] = sel.value;
|
||||
slot.wires[out.name] = targets;
|
||||
_afterLivePreviewWireChange(slot, out.name);
|
||||
reconcileOpenPortWiring();
|
||||
await persist();
|
||||
render();
|
||||
};
|
||||
const rm = el("button", "btn ghost tiny wire-rm", "×");
|
||||
rm.title = "Remove this wire";
|
||||
rm.onclick = async () => { _setWireTarget(slot, out.name, targets[i], ""); targets.splice(i, 1); reconcileOpenPortWiring(); await persist(); render(); };
|
||||
rm.onclick = async () => {
|
||||
_setWireTarget(slot, out.name, targets[i], "");
|
||||
targets.splice(i, 1);
|
||||
slot.wires[out.name] = targets;
|
||||
_afterLivePreviewWireChange(slot, out.name);
|
||||
reconcileOpenPortWiring();
|
||||
await persist();
|
||||
render();
|
||||
};
|
||||
row.append(sel, rm);
|
||||
wrap.append(row);
|
||||
});
|
||||
@@ -859,6 +944,10 @@
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cid === "sampler" && inp === "preview_vae") {
|
||||
_clearLivePreviewWires(parsed.slotId, parsed.out);
|
||||
_syncLivePreviewConfig(parsed.slotId, parsed.out, true);
|
||||
}
|
||||
} else if (prev) {
|
||||
const old = _parseOutSource(prev);
|
||||
if (old) {
|
||||
@@ -869,6 +958,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cid === "sampler" && inp === "preview_vae") {
|
||||
_clearLivePreviewWires(null, null);
|
||||
config.live_preview = { ...(config.live_preview || {}), enabled: false, slot_id: null };
|
||||
}
|
||||
}
|
||||
}
|
||||
function coreCard(n) {
|
||||
@@ -953,6 +1046,7 @@
|
||||
? "Fixed FunPack path (Studio → Conditioning → Chain Sampler → decode). "
|
||||
+ "Wire video LATENT to Studio · latent (not Concat · video_latent — that link is internal). "
|
||||
+ "Wire IMAGE via Input Image Processing → Studio · source_image (Timeline default). "
|
||||
+ "Wire a fast VAE (e.g. taehv) to Chain Sampler · live preview for per-scene previews. "
|
||||
+ "MODEL/CLIP may chain through patchers. Enable Full control to override core links."
|
||||
: "The fixed FunPack nodes and their wiring. Each input defaults to its built-in source — pick another to re-wire it.";
|
||||
sec.append(el("div", "links-hint", hint));
|
||||
|
||||
@@ -1131,7 +1131,16 @@
|
||||
}
|
||||
canvas.append(ro);
|
||||
}
|
||||
if (["queuing", "running", "pending"].includes(gen.state) && S.get().models?.live_preview?.enabled) {
|
||||
if (["queuing", "running", "pending"].includes(gen.state)) {
|
||||
const lp = S.get().models?.live_preview || {};
|
||||
const lpPort = "port:FunPackLTXAVSceneChainSampler.preview_vae";
|
||||
const lpWired = (S.get().models?.slots || []).some((s) =>
|
||||
Object.values(s.wires || {}).some((raw) => {
|
||||
const arr = Array.isArray(raw) ? raw : raw ? [raw] : [];
|
||||
return arr.includes(lpPort);
|
||||
}));
|
||||
const showLp = lp.enabled || lp.slot_id || lpWired;
|
||||
if (showLp) {
|
||||
const lpLayer = el("div", "pm-live-preview");
|
||||
_livePreviewEl = el("img", "pm-live-preview-img");
|
||||
_livePreviewEl.alt = "Live preview";
|
||||
@@ -1147,6 +1156,7 @@
|
||||
lpLayer.append(_livePreviewEl, _livePreviewBadgeEl);
|
||||
canvas.append(lpLayer);
|
||||
}
|
||||
}
|
||||
if (previewAsset?.kind === "image") {
|
||||
const layer = el("div", "pm-media-preview");
|
||||
const label = el("div", "pm-media-preview-label", previewAsset.name || "Media preview");
|
||||
|
||||
@@ -37,6 +37,42 @@
|
||||
const listeners = new Set();
|
||||
const SAVE_DEBOUNCE_MS = 5000; // discrete edits (dropdowns, toggles)
|
||||
const SAVE_SILENT_DEBOUNCE_MS = 20000; // typing in fields — flushed on blur / generate
|
||||
const LIVE_PREVIEW_PORT = "port:FunPackLTXAVSceneChainSampler.preview_vae";
|
||||
|
||||
function _modelWireTargets(raw) {
|
||||
if (!raw) return [];
|
||||
return Array.isArray(raw) ? raw.slice() : [raw];
|
||||
}
|
||||
|
||||
function _clearLivePreviewWiresInModels(models, exceptSlotId, exceptOut) {
|
||||
for (const s of models.slots || []) {
|
||||
s.wires = s.wires || {};
|
||||
for (const outName of Object.keys(s.wires)) {
|
||||
if (s.id === exceptSlotId && outName === exceptOut) continue;
|
||||
const kept = _modelWireTargets(s.wires[outName]).filter((t) => t !== LIVE_PREVIEW_PORT);
|
||||
if (kept.length) s.wires[outName] = kept;
|
||||
else delete s.wires[outName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _applyLivePreviewWire(models, slotId, vaeOutput) {
|
||||
_clearLivePreviewWiresInModels(models, slotId, vaeOutput);
|
||||
const slot = (models.slots || []).find((s) => s.id === slotId);
|
||||
if (!slot) return;
|
||||
slot.wires = slot.wires || {};
|
||||
const out = vaeOutput || "VAE";
|
||||
const targets = _modelWireTargets(slot.wires[out]);
|
||||
if (!targets.includes(LIVE_PREVIEW_PORT)) targets.push(LIVE_PREVIEW_PORT);
|
||||
slot.wires[out] = targets;
|
||||
}
|
||||
|
||||
function _livePreviewConfigured() {
|
||||
const lp = state.models?.live_preview || {};
|
||||
if (lp.slot_id) return true;
|
||||
return (state.models?.slots || []).some((s) =>
|
||||
Object.values(s.wires || {}).some((raw) => _modelWireTargets(raw).includes(LIVE_PREVIEW_PORT)));
|
||||
}
|
||||
let saveTimer = null;
|
||||
let _localDirty = false; // local edits newer than the in-flight save snapshot
|
||||
let _commitPromise = null; // avoid overlapping saves stomping newer anchor edits
|
||||
@@ -2689,7 +2725,7 @@
|
||||
});
|
||||
}
|
||||
} catch (_) {}
|
||||
if (state.models?.live_preview?.enabled) {
|
||||
if (_livePreviewConfigured()) {
|
||||
try {
|
||||
const lp = await API.livePreview();
|
||||
if (lp?.ready && lp.url) {
|
||||
@@ -3330,6 +3366,16 @@
|
||||
...(state.models.live_preview || {}),
|
||||
enabled: !!enabled,
|
||||
};
|
||||
if (!enabled) {
|
||||
_clearLivePreviewWiresInModels(state.models, null, null);
|
||||
state.models.live_preview.slot_id = null;
|
||||
} else if (state.models.live_preview.slot_id) {
|
||||
_applyLivePreviewWire(
|
||||
state.models,
|
||||
state.models.live_preview.slot_id,
|
||||
state.models.live_preview.vae_output,
|
||||
);
|
||||
}
|
||||
if (state.project) {
|
||||
state.project.models = JSON.parse(JSON.stringify(state.models));
|
||||
}
|
||||
@@ -3350,6 +3396,7 @@
|
||||
vae_output: vaeOutput || "VAE",
|
||||
enabled: true,
|
||||
};
|
||||
_applyLivePreviewWire(state.models, slotId, vaeOutput);
|
||||
if (state.project) {
|
||||
state.project.models = JSON.parse(JSON.stringify(state.models));
|
||||
}
|
||||
|
||||
@@ -237,3 +237,28 @@ def test_live_preview_wires_preview_vae_separately():
|
||||
assert graph["sampler"]["inputs"]["preview_vae"] == ["slot_pv", 0]
|
||||
assert any("preview_vae" in w for w in report["wired"])
|
||||
assert report["blocking"] == []
|
||||
|
||||
|
||||
def test_live_preview_port_wire_from_models_slot():
|
||||
models = {
|
||||
"full_control": True,
|
||||
"slots": [
|
||||
{"id": "u", "node_class": "UnetLoader", "inputs": {}, "wires": {"MODEL": "port:FunPackStudio.model"}},
|
||||
{"id": "c", "node_class": "ClipLoader", "inputs": {}, "wires": {"CLIP": "port:FunPackStudio.clip"}},
|
||||
{"id": "v", "node_class": "VaeLoader", "inputs": {}, "wires": {
|
||||
"VAE": ["port:FunPackLTXAVSceneChainSampler.vae", "port:LTXVAudioVAEDecode.audio_vae"],
|
||||
}},
|
||||
{"id": "pv", "node_class": "VaeLoader", "inputs": {}, "wires": {
|
||||
"VAE": "port:FunPackLTXAVSceneChainSampler.preview_vae",
|
||||
}},
|
||||
{"id": "ip", "node_class": "ImgProc", "inputs": {},
|
||||
"wires": {"latent": "port:FunPackStudio.latent",
|
||||
"Latent": "port:LTXVConcatAVLatent.audio_latent",
|
||||
"output_image": "port:FunPackStudio.source_image"},
|
||||
"input_sources": {"vae": "out:v:VAE"}},
|
||||
{"id": "li", "node_class": "LoadImage", "inputs": {}, "wires": {"IMAGE": "node:ip:image"}},
|
||||
],
|
||||
}
|
||||
graph, report = builder.build(OI, models, PARAMS)
|
||||
assert graph["sampler"]["inputs"]["preview_vae"] == ["slot_pv", 0]
|
||||
assert report["blocking"] == []
|
||||
|
||||
Reference in New Issue
Block a user