D2 Save Caption
The node that turns messy WD14 tag dumps into clean training captions
- text
- file_path
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.jpg→d:/images/aaa.txt. Feed it the image path fromD2 Folder Image Queue.text- the caption body (from a tagger orD2 Load Text).extension- output extension (defaulttxt).exclude_tags- tags to drop. Comma or newline separated. Prefix a line withregex/pattern/and it excludes anything matching that regex. Matching ignores bracket escaping, so you can excluderem_(re:zero)to killrem_\(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-wayword_separatoroption, 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.bakbefore 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-ComfyUIand 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.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| base_filename | STRING | — | |
| text | STRING | — | |
| extension | STRING | txt | — |
| exclude_tags | STRING | — | |
| prepend_tags | STRING | — | |
| word_separator | COMBO | underscore | 3 options: underscore, space, none |
| remove_escape | BOOLEAN | true | — |
| trailing_comma | BOOLEAN | false | — |
| ignore_case | BOOLEAN | true | — |
| backup | BOOLEAN | true | — |
| dry_run | BOOLEAN | false | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| text | STRING | — |
| file_path | STRING | — |