Nodes/ComfyUI-NeuralMedia/πŸ–ŒοΈ Save Captions & Images
ComfyUI Node

πŸ–ŒοΈ Save Captions & Images

Build a training dataset folder without leaving the graph

By YarvixPAΒ·Created 2 years agoΒ·Updated about a year agoΒ· 5
πŸ–ŒοΈ Save Captions & Images
  • images
    β—„captionsβ€”β–Ί
    β—„save_pathβ€”β–Ί
    β—„prefix_fileβ€”β–Ί
    β—„delimiter_file_β–Ί
    β—„caption_extensiontxtβ–Ί
    β—„image_extensionβ–Ύβ–Ί
    β—„image_quality100β–Ί
    β—„lossless_webpβ–Ύβ–Ί
    β—„overwritefalseβ–Ί

    If you've ever assembled a LoRA or fine-tune dataset by hand, you know the drill: a folder of images, each with a matching .txt file of the same name, captions living next to their pictures. It's the boring, fiddly part of training that everybody does with scripts and file explorers. Save Captions & Images is that exact job done inside ComfyUI - give it images and their captions, and it writes both to a folder with matching filenames, ready for kohya, AI Toolkit, or whatever trainer you use.

    This is a training-prep node, not a save-image node. The SaveImageNode from this pack is for outputs you want to look at; this one is for outputs you want to train on.

    How it works

    Under the hood it's a zip: captions and images are paired position by position, and for each pair it writes prefix_file_delimiter_number with the chosen extension. So with prefix_file set to dataset and delimiter_file left at _, you get:

    dataset_001.png   dataset_001.txt
    dataset_002.png   dataset_002.txt
    ...
    

    The numbering is smart about existing files - it scans the folder and starts after the highest number already there, so you can append runs without clobbering. Two behaviors worth knowing: empty captions are skipped with a warning (the pair isn't saved), and the whole batch is zipped together - if you feed 50 images but 40 captions, you get 40 pairs and the last 10 images vanish silently. Count your inputs.

    The inputs you'll actually set

    • captions - the text, one per image. Wire from whatever generated them: a captioning model, a text node, a prompt list.
    • images - the images, same count as the captions.
    • save_path - a real filesystem path (like /home/you/dataset). The node creates it if it doesn't exist.
    • prefix_file / delimiter_file - the filename stem and separator.
    • image_extension - png, jpg, jpeg, gif, tiff, webp, or bmp.
    • image_quality - JPEG/WebP quality, 1–100, default 100.
    • lossless_webp - set true to save WebP losslessly.
    • overwrite - default off, which is the safe setting.
    • caption_extension - default txt; leave it.

    Install

    ComfyUI Manager β†’ search ComfyUI-NeuralMedia, or:

    cd ComfyUI/custom_nodes
    git clone https://github.com/YarvixPA/ComfyUI-NeuralMedia
    cd ComfyUI-NeuralMedia
    pip install -r requirements.txt
    

    Restart ComfyUI. If the manual clone 404s - the repo's been renamed around a couple of times - use Manager's registry entry instead. It's YarvixPA's personal pack, small footprint, and this is one of its genuinely useful odd corners.

    Gotchas

    • Count mismatch is silent. Zip truncates; always feed matched lists.
    • The folder is real filesystem. A ComfyUI input path won't work.
    • Captions should be plain text, not JSON. Most trainers expect the bare caption in the .txt. If your upstream emits structured text, strip it before this node.

    One honest caveat: for a one-off save, core ComfyUI's SaveImage plus a text writer does this job with less setup. This node pays off when you're generating many caption/image pairs and want the exact training-folder layout without a detour through a script. That's a narrow lane, but it's the right tool in it.

    CategoryComfyUI-NeuralMedia

    Inputs (10)

    NameTypeDefaultDescription
    captionsSTRINGβ€”
    imagesIMAGEβ€”
    save_pathSTRINGβ€”
    prefix_fileSTRINGβ€”
    delimiter_fileSTRING_β€”
    caption_extensionSTRINGtxtβ€”
    image_extensionCOMBO7 options: png, jpg, jpeg, gif, tiff, webp, +1
    image_qualityINT1001–100β€”
    lossless_webpCOMBO2 options: false, true
    overwriteBOOLEANfalseβ€”

    Outputs (0)

    No outputs