Nodes/Comfyui-EzFlex-Presets/EzFlex-PromptHelper
ComfyUI Node

EzFlex-PromptHelper

Prompt Cards, Merged Output, and an Optional LLM Rewrite

By blackbossokok·Created about a month ago·Updated 8 days ago· 4
EzFlex-PromptHelper
  • media_in_1
  • media_in_2
  • media_in_3
  • media_in_4
  • media_in_5
  • media_in_6
  • media_in_7
  • media_in_8
  • media_in_9
  • media_in_10
  • media_in_11
  • media_in_12
  • media_in_13
  • media_in_14
  • media_in_15
  • media_in_16
  • Merged prompt
  • Card 1
  • Card 2
  • Card 3
  • Card 4
  • Card 5
  • Card 6
  • Card 7
  • Card 8
  • Card 9
  • Card 10
  • Card 11
  • Card 12
  • Card 13
  • Card 14
  • Card 15
  • Card 16
  • Card 17
  • Card 18
  • Card 19
  • Card 20
  • Card 21
  • Card 22
  • Card 23
  • Card 24
  • Card 25
  • Card 26
  • Card 27
  • Card 28
  • Card 29
  • Card 30
  • Card 31
  • Card 32
◄config{}►
◄card_in_1—►
◄card_in_2—►
◄card_in_3—►
◄card_in_4—►
◄card_in_5—►
◄card_in_6—►
◄card_in_7—►
◄card_in_8—►
◄card_in_9—►
◄card_in_10—►
◄card_in_11—►
◄card_in_12—►
◄card_in_13—►
◄card_in_14—►
◄card_in_15—►
◄card_in_16—►
◄card_in_17—►
◄card_in_18—►
◄card_in_19—►
◄card_in_20—►
◄card_in_21—►
◄card_in_22—►
◄card_in_23—►
◄card_in_24—►
◄card_in_25—►
◄card_in_26—►
◄card_in_27—►
◄card_in_28—►
◄card_in_29—►
◄card_in_30—►
◄card_in_31—►
◄card_in_32—►
◄index0►

A prompt in ComfyUI is a text box. Which is fine until you're maintaining four of them - a character block, a style block, a negative, a block of camera terms - and trying a second version of one means pasting over the good one.

EzFlex-PromptHelper turns the prompt into a stack of cards. Each card is a small rich-text editor with a Default and an Optimized tab, a merge switch, and its own output port. The node emits a Merged prompt plus one STRING per card. Compose, toggle, and nothing gets destroyed.

Inputs

Beyond the panel-written config (multiline STRING, default "{}"), this node has no CLIP input - deliberately. Instead it has two families of dynamic optional sockets:

  • media_in_1 … media_in_16 - any-type: images, video, audio, 3D models, with a new empty slot appearing when you connect one. These are reference media. The node reads the media ports of generator nodes on the canvas and numbers them, and you reference them in text as @图片1 / @视频1 / @音频1 - or pick them from the reference-media window, grouped by the node that produces them.
  • card_in_1 … card_in_32 - STRING, one per card. Connect external text and it overrides that card's panel content, and the card greys out. This is how you drive the stack from a wildcard processor or a generated prompt.

Outputs

Merged prompt first, then Card 1 … Card 32 - all STRING. Wire the merged output into your CLIP Text Encode; wire an individual card when one encoder wants only the character block.

The thing to internalize is that the card slider and the overall slider are separate layers with separate slots. A card's "Optimized" result lives in that card's slot and only affects that card's port; the overall result only affects the merged prompt. They never overwrite each other. Point a slider at an empty slot and you get an empty string - no fallback, no padding. Strict, and it has saved a few people from silently sampling an empty prompt.

Merge is a per-card switch: green means the card joins the merged prompt, gray means it only travels through its own port.

The optimize layer, where the opinion lives

There's a Tools dropdown offering three ways to have a model rewrite your prompt: API (a vendor endpoint), TextGenerate (a local CLIP/text-generation path you point at a model file in the settings), and llama (a llama.cpp/Ollama-style server, or llama-cpp-python running in process). Fire one manually, or flip a runtime auto-optimize switch. The three auto switches are mutually exclusive, and if a call fails it errors out rather than quietly using the unoptimized text. Good.

What gets sent to the model is your original text with the @图片1 markers intact - the system prompt asks it to leave them alone - and the vendor-specific syntax (<Picture 1>, @image1) is only compiled at the output ports. So if the model rewrites your marker into "the first image", the mapping is gone and no amount of spec compilation brings it back. If you lean on reference media, prefer a local model. The KB's LLM-in-ComfyUI notes make the same point from the other end: local, uncensored models are why this category exists, since API providers filter exactly the prompts people buy these tools to write. And a node holding your API key is a node to install deliberately, not because a workflow told you to.

The other stuff it does

The editor is Word-flavoured - bold, alignment, font size, colour, highlight, find & replace, a skill button that inserts a *.md file line by line at the caret, a tag panel with a bundled tag library and random-tag generator, card presets saved to user_data/prompts/<name>.json. Since v1.2.5, ModelsCombo can auto-read a loaded LoRA's trigger words and show them live here - the same "where did my trigger word go" problem rgthree's Power Lora Loader is famous for solving, from a different direction.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/blackbossokok/Comfyui-EzFlex-Presets
pip install -r requirements.txt   # mutagen

Manager: search EzFlex, restart. Optional extras are manual on purpose: pip install llama-cpp-python for in-process llama mode (kept out of requirements.txt so Manager doesn't try to compile it, which regularly fails on Windows) and pip install gguf onnx for metadata cards elsewhere in the pack. One thing you may have to add yourself: the local llama.cpp / Ollama server address is registered when you save settings rather than being open by default, so a node that can't reach your own localhost server just needs its address added. ComfyUI 0.3.13+ per pack metadata.

Common issues

Merged output is empty. Slider on Optimized with an empty optimized slot - strict by design. Flip to Default, or run the optimize.

A card is greyed out and ignores your edits. Something is connected to its card_in_N socket, and external text wins.

Auto-optimize errors the whole run. That's intended; failures are loud. Fix the API key, the TextGenerate model path or the llama server address, or turn the switch off. Also check only one of the three switches is on - the panel enforces it, but a hand-edited config gets a hard error.

Your @图片1 came out as prose. The optimize model rewrote the marker. Use a more literal model, or skip optimization on cards that carry references.

CategoryEzFlex

Inputs (50)

NameTypeDefaultDescription
configSTRING{}Config JSON generated by the Prompt Cards panel (card list).
media_in_1opt*Any media 1: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
media_in_2opt*Any media 2: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
media_in_3opt*Any media 3: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
media_in_4opt*Any media 4: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
media_in_5opt*Any media 5: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
media_in_6opt*Any media 6: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
media_in_7opt*Any media 7: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
media_in_8opt*Any media 8: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
media_in_9opt*Any media 9: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
media_in_10opt*Any media 10: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
media_in_11opt*Any media 11: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
media_in_12opt*Any media 12: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
media_in_13opt*Any media 13: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
media_in_14opt*Any media 14: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
media_in_15opt*Any media 15: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
media_in_16opt*Any media 16: images / video / audio / 3D models are accepted (a new empty slot is added when connected).
card_in_1optSTRINGText of prompt card 1 (when connected it overrides that card panel content).
card_in_2optSTRINGText of prompt card 2 (when connected it overrides that card panel content).
card_in_3optSTRINGText of prompt card 3 (when connected it overrides that card panel content).
card_in_4optSTRINGText of prompt card 4 (when connected it overrides that card panel content).
card_in_5optSTRINGText of prompt card 5 (when connected it overrides that card panel content).
card_in_6optSTRINGText of prompt card 6 (when connected it overrides that card panel content).
card_in_7optSTRINGText of prompt card 7 (when connected it overrides that card panel content).
card_in_8optSTRINGText of prompt card 8 (when connected it overrides that card panel content).
card_in_9optSTRINGText of prompt card 9 (when connected it overrides that card panel content).
card_in_10optSTRINGText of prompt card 10 (when connected it overrides that card panel content).
card_in_11optSTRINGText of prompt card 11 (when connected it overrides that card panel content).
card_in_12optSTRINGText of prompt card 12 (when connected it overrides that card panel content).
card_in_13optSTRINGText of prompt card 13 (when connected it overrides that card panel content).
card_in_14optSTRINGText of prompt card 14 (when connected it overrides that card panel content).
card_in_15optSTRINGText of prompt card 15 (when connected it overrides that card panel content).
card_in_16optSTRINGText of prompt card 16 (when connected it overrides that card panel content).
card_in_17optSTRINGText of prompt card 17 (when connected it overrides that card panel content).
card_in_18optSTRINGText of prompt card 18 (when connected it overrides that card panel content).
card_in_19optSTRINGText of prompt card 19 (when connected it overrides that card panel content).
card_in_20optSTRINGText of prompt card 20 (when connected it overrides that card panel content).
card_in_21optSTRINGText of prompt card 21 (when connected it overrides that card panel content).
card_in_22optSTRINGText of prompt card 22 (when connected it overrides that card panel content).
card_in_23optSTRINGText of prompt card 23 (when connected it overrides that card panel content).
card_in_24optSTRINGText of prompt card 24 (when connected it overrides that card panel content).
card_in_25optSTRINGText of prompt card 25 (when connected it overrides that card panel content).
card_in_26optSTRINGText of prompt card 26 (when connected it overrides that card panel content).
card_in_27optSTRINGText of prompt card 27 (when connected it overrides that card panel content).
card_in_28optSTRINGText of prompt card 28 (when connected it overrides that card panel content).
card_in_29optSTRINGText of prompt card 29 (when connected it overrides that card panel content).
card_in_30optSTRINGText of prompt card 30 (when connected it overrides that card panel content).
card_in_31optSTRINGText of prompt card 31 (when connected it overrides that card panel content).
card_in_32optSTRINGText of prompt card 32 (when connected it overrides that card panel content).
indexoptINT0Loop index: when wired, the Merged prompt outputs only card #index's text (one prompt per loop round).

Outputs (33)

NameTypeDescription
Merged promptSTRING—
Card 1STRING—
Card 2STRING—
Card 3STRING—
Card 4STRING—
Card 5STRING—
Card 6STRING—
Card 7STRING—
Card 8STRING—
Card 9STRING—
Card 10STRING—
Card 11STRING—
Card 12STRING—
Card 13STRING—
Card 14STRING—
Card 15STRING—
Card 16STRING—
Card 17STRING—
Card 18STRING—
Card 19STRING—
Card 20STRING—
Card 21STRING—
Card 22STRING—
Card 23STRING—
Card 24STRING—
Card 25STRING—
Card 26STRING—
Card 27STRING—
Card 28STRING—
Card 29STRING—
Card 30STRING—
Card 31STRING—
Card 32STRING—