From de4ac976650930a7f78b99a587dc3e724549137b Mon Sep 17 00:00:00 2001 From: Ethanfel Date: Thu, 25 Jun 2026 05:56:53 +0200 Subject: [PATCH] Connect accumulator preview by store key --- __init__.py | 1 + loop_nodes.py | 16 +++++++++++----- web/accumulator_preview.js | 9 ++++++++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/__init__.py b/__init__.py index 560ff49..741f569 100644 --- a/__init__.py +++ b/__init__.py @@ -110,6 +110,7 @@ COMMON_INPUT_TOOLTIPS = { "collection": "Existing accumulated value or batch.", "value": "Value to append, store, or pass through.", "store_key": "Accumulator memory key. Same key shares stored entries across executions.", + "store_key_input": "Connect SxCP Accumulator store_key here so preview/delete/save uses the same accumulator and graph dependency.", "action": "Accumulator operation: append, replace, clear, read, or append a variant.", "max_items": "Maximum stored entries kept in this accumulator.", "image_batch_mode": "How image entries are batched when dimensions differ.", diff --git a/loop_nodes.py b/loop_nodes.py index 570589e..1e5786a 100644 --- a/loop_nodes.py +++ b/loop_nodes.py @@ -646,13 +646,13 @@ class SxCPAccumulator: }, } - RETURN_TYPES = tuple([ANY_TYPE, "IMAGE", "IMAGE"] + ["IMAGE"] * ACCUMULATOR_IMAGE_GROUPS + ["INT", "STRING"]) + RETURN_TYPES = tuple([ANY_TYPE, "IMAGE", "IMAGE"] + ["IMAGE"] * ACCUMULATOR_IMAGE_GROUPS + ["INT", "STRING", "STRING"]) RETURN_NAMES = tuple( ["collection", "image_batch", "image_list"] + [f"image_batch_{index}" for index in range(1, ACCUMULATOR_IMAGE_GROUPS + 1)] - + ["count", "status"] + + ["count", "status", "store_key"] ) - OUTPUT_IS_LIST = tuple([False, False, True] + [False] * ACCUMULATOR_IMAGE_GROUPS + [False, False]) + OUTPUT_IS_LIST = tuple([False, False, True] + [False] * ACCUMULATOR_IMAGE_GROUPS + [False, False, False]) FUNCTION = "accumulate" CATEGORY = "prompt_builder/loop" @@ -771,7 +771,7 @@ class SxCPAccumulator: grouped_outputs = image_batches[:ACCUMULATOR_IMAGE_GROUPS] grouped_outputs += [None] * (ACCUMULATOR_IMAGE_GROUPS - len(grouped_outputs)) status = self._status(key, store, image_batch, image_batches) - return tuple([self._collection(store), image_batch, images] + grouped_outputs + [len(store), status]) + return tuple([self._collection(store), image_batch, images] + grouped_outputs + [len(store), status, key]) class SxCPAccumulatorPreview: @@ -792,6 +792,9 @@ class SxCPAccumulatorPreview: "filename_prefix": ("STRING", {"default": "sxcp_accum", "multiline": False}), "clear_after_save": ("BOOLEAN", {"default": False}), }, + "optional": { + "store_key_input": ("STRING", {"forceInput": True}), + }, "hidden": { "prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", @@ -838,11 +841,13 @@ class SxCPAccumulatorPreview: save_path, filename_prefix, clear_after_save, + store_key_input=None, prompt=None, extra_pnginfo=None, unique_id=None, ): - key = _accumulator_store_key(store_key, unique_id) + key_source = str(store_key_input or "").strip() or store_key + key = _accumulator_store_key(key_source, unique_id) store = _ACCUMULATOR_STORES.setdefault(key, []) removed = self._delete_from_inputs(key, delete_action, delete_entry_id, delete_index) images = [entry["image"] for entry in store if entry.get("image") is not None] @@ -870,6 +875,7 @@ class SxCPAccumulatorPreview: "entries": entries, "status": [status], "saved_paths": saved_paths, + "store_key": [key], }, "result": (len(store), status, saved_json), } diff --git a/web/accumulator_preview.js b/web/accumulator_preview.js index 1e74da8..83f2780 100644 --- a/web/accumulator_preview.js +++ b/web/accumulator_preview.js @@ -46,6 +46,12 @@ function outputStatus(output) { return status || ""; } +function outputStoreKey(output) { + const key = output?.store_key; + if (Array.isArray(key)) return key[0] || ""; + return key || ""; +} + function outputEntries(output) { const entries = output?.entries; if (!entries) return []; @@ -91,7 +97,7 @@ function selectedEntry(node) { } function storeKey(node) { - return String(widget(node, "store_key")?.value || "").trim(); + return String(widget(node, "store_key")?.value || node._sxcpResolvedStoreKey || "").trim(); } async function postJson(path, payload) { @@ -196,6 +202,7 @@ app.registerExtension({ const node = getNodeById(detail?.node); if (!isAccumulatorPreviewNode(node)) return; const output = detail?.output || {}; + node._sxcpResolvedStoreKey = outputStoreKey(output); setEntries(node, outputEntries(output), outputStatus(output)); }); },