Nodes/PerfectLab Studio/πŸ§ͺ PerfectLab - Prompt Assistant
ComfyUI Node

πŸ§ͺ PerfectLab - Prompt Assistant

A prompt builder that lives on the canvas

By perfectmodelslabΒ·Created 8 months agoΒ·Updated a day agoΒ· 23
πŸ§ͺ PerfectLab - Prompt Assistant
    • PROMPT
    • NEGATIVE
    β—„node_data{}β–Ί
    β—„main_promptscore_9, rating_explicit,β–Ί
    β—„modeβ–Ύβ–Ί
    β—„seed0β–Ί
    β—„variations1β–Ί

    Most of ComfyUI's prompt problem is that a prompt is a text box. You type a paragraph, hit queue, and the only thing you can vary is the seed - so "give me some options" means hand-editing the text twelve times. πŸ§ͺ PerfectLab - Prompt Assistant hands the text box back to you as a visual panel: a lighting dial, a camera rig, a palette and a stack of your own randomizable lists, assembled into the string that actually reaches the sampler.

    You reach for it when you're shooting a set, not an image. If you're generating one picture of one cat, this is overkill. If you're trying to get ten framings of the same person under the same light, it replaces you doing it by hand.

    What it actually does

    The node is a builder with a preview. Everything you configure in the panel - a time of day, a camera line, palette swatches, and your categories with their lock/random/cycle modes - gets stored as JSON in a hidden widget called node_data, and the Python side turns that JSON plus your base prompt into the final string.

    The assembly order is fixed and worth knowing, because it explains why your prompt reads the way it does: main_prompt first, then the lighting paragraph for the hour you dialed, then the camera line, then color palette: …, then your categories as separate paragraphs joined by blank lines. Dial 6am and your text trails off into "soft warm glow, morning light, diffuse illumination, long shadows…" - one of eight named lighting phases baked into the node.

    The categories are the interesting part. LCK always uses the item you selected, CYC advances one item every N seeds so a seed range walks a list in order, and RND picks from a per-variation RNG seeded with seed + i - deterministic, same seed same pick. The node also rewrites {a|b|c} choices, resolves __wildcard__ files from its own wildcards/ folder, and fills {{placeholders}} from the form fields the panel grows.

    The inputs that matter

    Five required inputs; you touch three of them.

    • main_prompt - your base text. Everything else is appended after it.
    • mode - the target model family, and it does real work. SDXL keeps tag and weight syntax at a 75-token scale; Flux, Flux/Z-Image, Z-Image Turbo, Qwen-Image and Wan (video) get natural-language cleanup that strips (word:1.2) weights and stray brackets, with much larger token budgets. It's the encoder-split made into a dropdown, and it's why naming a physical camera and film stock in your text pays off - those are the terms 2026 encoders were trained on.
    • seed and variations - variations is the one people miss. It's a list output: ask for 8 and ComfyUI iterates the whole graph downstream, one queue item per prompt, no scripting. Variation i uses seed + i with its own isolated RNG, so global random state is never disturbed.

    node_data is the hidden JSON widget the panel writes. You never type in it.

    Two outputs: PROMPT (a list - wire it into your CLIP text encode) and NEGATIVE (a list, its own base text and categories, edited under the NEG tab). Leave NEGATIVE unconnected on anything that runs at CFG 1.

    Install

    The pack has no third-party Python dependencies at all - requirements.txt is deliberately empty (comments only), and pyproject.toml declares dependencies = []. That's rare here and it means installation can't really break your environment.

    Manager β†’ Custom Nodes Manager β†’ Install via Git URL β†’ paste the repo. Or:

    cd ComfyUI/custom_nodes
    git clone https://github.com/perfectmodelslab/ComfyUI-PerfectLab PerfectLab
    

    Then restart and hard-refresh with Ctrl+F5. The folder name doesn't matter. Python 3.10+.

    Where people get burned

    The node doesn't appear in the Add Node menu. A running server only scans custom_nodes at startup, so a restart is mandatory, not optional. If it's still missing, look for IMPORT FAILED or a message naming PerfectLabAssistant in the console. Broken/unstyled panel means a cached stylesheet - Ctrl+F5.

    The default main_prompt is Pony/Illustrious tag syntax (score_9, rating_explicit,). Switch mode to a Flux/Z-Image profile and the cleanup strips weights and brackets - it does not strip quality tags. Dead tokens, still billed. Change the base text when you change the profile.

    Two seeds, one confusion. The node's seed drives RND picks and variations; your KSampler's seed drives the noise. They are unrelated, and the KSampler's default randomize-after-generate behavior is the usual reason a "reproducible" run wasn't. Set the KSampler to fixed while you're tuning.

    __wildcard__ does nothing. It resolves from wildcards/<name>.txt inside the node folder - the pack ships exactly one file, outfit.txt. Drop your own .txt there, and if the file is missing the token is left in the prompt untouched rather than erroring.

    Dragging a PNG onto the node restores the config - the workflow chunk is embedded in the image, so a shared PNG can carry your prompt and settings.

    CategoryPerfectLab

    Inputs (5)

    NameTypeDefaultDescription
    node_dataSTRING{}β€”
    main_promptSTRINGscore_9, rating_explicit,Base prompt. Categories, lighting, camera and palette from the visual UI are appended after it. Supports {a|b|c} choices and __wildcard__ files.
    modeCOMBOTarget model family: sets the token limit and natural-language cleanup. SDXL keeps tag/weight syntax; the other modes strip weights and brackets.
    seedINT00–18446744073709550000Base seed for RND category picks and {a|b|c} choices. Variation i uses seed+i. CYC categories advance every N seeds.
    variationsINT11–100How many prompt variations to produce per run. The output is a list -- ComfyUI iterates it downstream automatically (batch of prompts).

    Outputs (2)

    NameTypeDescription
    PROMPTSTRINGβ€”
    NEGATIVESTRINGβ€”