Skip to content

Commit 997da34

Browse files
v1.4.2: Hash Vault Label Builder node
New node: HashVaultLabelBuilder (🏷️ Hash Vault Label Builder). Concatenates up to 4 any-type inputs with a configurable separator into one STRING for Hash Vault Save's label input. Wire once per workflow (e.g. style + variant + intensity from Gemini Style Transfer Settings) and never type a label manually again. Empty strings, None, and whitespace-only inputs are skipped so partial wiring produces clean output. Non-string inputs are stringified at join time. Solves the repeated-typing pain exposed by running the 77-entry photographer QA pass. Labels follow the canonical "Photographer / Variant / intensity" convention automatically.
1 parent 4048b9a commit 997da34

3 files changed

Lines changed: 67 additions & 1 deletion

File tree

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,24 @@ ComfyUI's native caching often breaks with external API nodes (dynamic timestamp
4444

4545
The Save Result node has an optional `label` input (v1.3.0+). Wire a human-readable string like `"Alec Soth / Songbook / full"` and the Hash Vault Browser will surface it when you need to find a specific past run. The label is stored in the sidecar JSON only, so changing it never breaks existing cache hits.
4646

47+
### Auto-labeling with the Label Builder node (v1.4.2)
48+
49+
Typing labels by hand gets old fast. The `🏷️ Hash Vault Label Builder` node concatenates up to four any-type inputs into one STRING, ready to wire into `Save Result`'s label input. Wire it once per workflow and never type a label again.
50+
51+
For the Gemini Style Transfer pattern:
52+
- `in_1` ← Settings node's `style` output (e.g. `"Alec Soth"`)
53+
- `in_2` ← Settings node's `variant` output (e.g. `"Niagara"`)
54+
- `in_3` ← Settings node's `intensity` output (e.g. `"full"`)
55+
- `separator` = `" / "`
56+
- → outputs `"Alec Soth / Niagara / full"`
57+
58+
For a Prompt Studio → Gemini Image Generate pattern:
59+
- `in_1` ← Prompt Studio's `style` output
60+
- `in_2` ← the assembled prompt (first line, or a short identifier)
61+
- → outputs `"Sebastião Salgado / Serra Pelada gold mine workers"`
62+
63+
Empty or None inputs are skipped, so partial wiring stays clean. Non-string inputs are stringified at join time.
64+
4765
### Migrating pre-v1.3.0 entries
4866

4967
Existing `.pt` files have no sidecar. To backfill:

api_optimizer_nodes.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,52 @@ def switch(self, is_cached, cached_data=None, api_data=None):
509509
print("🔀 [Lazy Switch] Cache Miss routed! API was executed.")
510510
return (api_data,)
511511

512+
# ------------------------------------------------------------------------
513+
# NODE 5: Hash Vault Label Builder (v1.4.2)
514+
# ------------------------------------------------------------------------
515+
class HashVaultLabelBuilder:
516+
"""Concatenate up to 4 any-type inputs into one STRING for Hash Vault Save's label.
517+
518+
Wire style/variant/intensity (or prompt/model/params) once per workflow and never
519+
manually type a label again. Empty or None inputs are skipped so the output stays
520+
clean when only some slots are wired.
521+
"""
522+
523+
@classmethod
524+
def INPUT_TYPES(s):
525+
return {
526+
"required": {
527+
"separator": ("STRING", {
528+
"default": " / ",
529+
"multiline": False,
530+
"tooltip": "Separator placed between each non-empty input. Defaults to ' / '."
531+
}),
532+
},
533+
"optional": {
534+
"in_1": (any_type, {"tooltip": "First input. Any type — stringified at join time. None or empty strings are skipped."}),
535+
"in_2": (any_type, {"tooltip": "Second input."}),
536+
"in_3": (any_type, {"tooltip": "Third input."}),
537+
"in_4": (any_type, {"tooltip": "Fourth input."}),
538+
}
539+
}
540+
541+
RETURN_TYPES = ("STRING",)
542+
RETURN_NAMES = ("label",)
543+
FUNCTION = "build"
544+
CATEGORY = "API Optimization"
545+
546+
def build(self, separator, in_1=None, in_2=None, in_3=None, in_4=None):
547+
parts = []
548+
for value in (in_1, in_2, in_3, in_4):
549+
if value is None:
550+
continue
551+
text = str(value).strip()
552+
if not text:
553+
continue
554+
parts.append(text)
555+
return (separator.join(parts),)
556+
557+
512558
# ------------------------------------------------------------------------
513559
# MAPPINGS: Registering the nodes with ComfyUI
514560
# ------------------------------------------------------------------------
@@ -517,11 +563,13 @@ def switch(self, is_cached, cached_data=None, api_data=None):
517563
"DeterministicHashVault": DeterministicHashVault,
518564
"HashVaultSave": HashVaultSave,
519565
"LazyAPISwitch": LazyAPISwitch,
566+
"HashVaultLabelBuilder": HashVaultLabelBuilder,
520567
}
521568

522569
NODE_DISPLAY_NAME_MAPPINGS = {
523570
"APICostTracker": "💰 API Cost & Quota Tracker",
524571
"DeterministicHashVault": "🔍 Hash Vault (Check Cache)",
525572
"HashVaultSave": "💾 Hash Vault (Save API Result)",
526573
"LazyAPISwitch": "🔀 Lazy API Switch (Bypass)",
574+
"HashVaultLabelBuilder": "🏷️ Hash Vault Label Builder",
527575
}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "comfyui-api-optimizer"
33
description = "API cost tracking, deterministic hash caching, and lazy execution bypass for cloud API workflows"
4-
version = "1.4.1"
4+
version = "1.4.2"
55
license = { file = "LICENSE" }
66

77
[project.urls]

0 commit comments

Comments
 (0)