Nodes/D2 Nodes ComfyUI/D2 Save Caption
ComfyUI Node

D2 Save Caption

The node that turns messy WD14 tag dumps into clean training captions

By da2el-ai·Created 2 years ago·Updated 6 days ago· 66
D2 Save Caption
    • text
    • file_path
    base_filename
    text
    extensiontxt
    exclude_tags
    prepend_tags
    word_separatorunderscore
    remove_escapetrue
    trailing_commafalse
    ignore_casetrue
    backuptrue
    dry_runfalse

    If you've ever run a WD14 tagger over a folder of training images and looked at the raw output, you know the problem: duplicates, quality tags you don't want in your LoRA, escaped parentheses, inconsistent blue eyes vs blue_hair. D2 Save Caption is the cleanup + write step for exactly that pipeline. It formats a tag string, filters it, and writes it to a caption file next to your image.

    It's aimed at the dataset-prep workflow, and it pairs naturally with the rest of the D2 pack: D2 Folder Image Queue hands you image paths, D2 Load Text reads an existing caption, and this node writes the cleaned version back out. It's not a generation node - think of it as the "save as" step with opinions.

    The inputs that matter

    • base_filename - the source path your caption is named after. The node replaces the extension and saves there: d:/images/aaa.jpgd:/images/aaa.txt. Feed it the image path from D2 Folder Image Queue.
    • text - the caption body (from a tagger or D2 Load Text).
    • extension - output extension (default txt).
    • exclude_tags - tags to drop. Comma or newline separated. Prefix a line with regex/pattern/ and it excludes anything matching that regex. Matching ignores bracket escaping, so you can exclude rem_(re:zero) to kill rem_\(re:zero\) tags.
    • prepend_tags - tags to force onto the front. Already-present tags aren't duplicated.
    • replace_underscore - unifies the word separator in tags (the newer pack versions renamed this to a three-way word_separator option, so exact behavior depends on your version).
    • trailing_comma - add a trailing comma (some training setups want it).
    • ignore_case - case-insensitive matching for exclusion (on by default).
    • backup - if a file with the same name exists, rename the old one to .bak before writing (on by default). This has saved me more than once.
    • dry_run - preview mode: format and return the result without writing a file.

    Outputs: text (the formatted caption) and file_path (the full save path, or the planned path under dry_run).

    How it works

    The pipeline is deterministic and documented: split → trim → unify word separators → strip bracket escapes → exclude → dedupe → prepend → trailing comma. Dedup keeps the first occurrence. If base_filename is empty, it stops with an error rather than save somewhere unintended - which is annoying until you realize it just protected you from writing 500 captions into a wrong directory.

    Installing

    Part of the D2-nodes-ComfyUI pack - install the pack, not the node.

    • ComfyUI Manager → search "D2-nodes-ComfyUI" → Install → restart.
    • Or cd ComfyUI/custom_nodes && git clone https://github.com/da2el-ai/D2-nodes-ComfyUI and restart.

    Light dependencies (piexif, charset-normalizer), no model downloads. Pack gotcha: v32.0.0+ needs the ComfyUI V3 schema; older ComfyUI → pre-32.0.0 release.

    Where people get burned

    Run a dry_run before you let it touch real files - the text output shows you exactly what will be written, and it costs one queue. The exclude_tags regex syntax trips people up: it's regex/pattern/ (slash-wrapped), not bare. And remember backup only creates a .bak of the existing caption; if you've already got .bak files, they get overwritten. If you're captioning a few thousand images, build the exclude list with the pack's D2 Tag Report (which counts tag frequency in a folder) rather than guessing - it'll save you a full re-run.

    CategoryD2/Text

    Inputs (11)

    NameTypeDefaultDescription
    base_filenameSTRING
    textSTRING
    extensionSTRINGtxt
    exclude_tagsSTRING
    prepend_tagsSTRING
    word_separatorCOMBOunderscore3 options: underscore, space, none
    remove_escapeBOOLEANtrue
    trailing_commaBOOLEANfalse
    ignore_caseBOOLEANtrue
    backupBOOLEANtrue
    dry_runBOOLEANfalse

    Outputs (2)

    NameTypeDescription
    textSTRING
    file_pathSTRING