# 📝 ComfyUI Prompt Formatting Nodes This repository contains custom nodes for ComfyUI designed to help structure, filter, and generate text prompts using categorized tag definitions stored in a YAML file. ## Nodes Included 1. **📝 Categorized Prompt Formatter:** Filters and restructures an *existing* input prompt based on categories and a template. Preserves tag details like weights. 2. **📝 Categorized Random Prompt Formatter:** *Generates* a new random prompt by sampling tags from categories defined in the YAML, using a template structure and a seed for reproducibility. --- ## Key Features (Overall) * **YAML-based Categorization:** Define tags belonging to specific categories (e.g., `eyes`, `style`, `quality`) in an easy-to-edit YAML file. * **Hierarchical Categories (`$include`):** Define broad categories that automatically inherit tags from more specific ones without manual repetition in the YAML. * **Template-Driven Output:** Control the structure of the output prompt using simple placeholders like `<|category_name|>`. * **Flexible Tag Handling:** Options for case sensitivity and matching tags regardless of underscores vs. spaces (e.g., `blue_eyes` vs `blue eyes`). --- ## Installation 1. **Clone the Repository:** Navigate to your ComfyUI `custom_nodes` directory and clone this repository: ```bash cd ComfyUI/custom_nodes/ git clone https://github.com/xLegende/ComfyUI-Prompt-Formatter.git ``` 2. **Install Dependencies:** This node requires the `PyYAML` library. Navigate into the cloned directory and run the installation script using the Python environment associated with your ComfyUI installation: ```bash cd ComfyUI-Prompt-Formatter # Example (adjust path to your Python executable if needed): # /path/to/your/ComfyUI/python_env/bin/python install.py # Or if your system python is the one used by ComfyUI: python install.py ``` 3. **Restart ComfyUI:** Ensure ComfyUI is completely restarted to recognize the new nodes. --- ## The YAML Definitions File (`prompt_categories.yaml`) Both nodes rely on a YAML file to define which tags belong to which categories. An example file (`prompt_categories.yaml`) is included in this repository. **Format:** * **Basic:** ```yaml category_name: - tag1 - tag2 - another tag ``` * **Hierarchical Inclusion (`$include`):** A category can include all tags from other categories using the `$include` directive. It can also have its own specific tags listed under the `tags:` key. ```yaml eyes: - blue eyes - red eyes person_details: $include: # Inherit from 'eyes' - eyes tags: # Add tags specific to 'person_details' - smiling - freckles # Using '<|person_details|>' will now consider tags from 'eyes' AND 'smiling', 'freckles'. ``` **File Location:** The nodes will search for the specified YAML file in this order: 1. Absolute path (if provided). 2. Relative to the `ComfyUI-Prompt-Formatter` node directory. 3. Relative to the main ComfyUI `input/` directory. **Example File:** See the included [prompt_categories.yaml](prompt_categories.yaml) for a comprehensive example. --- ## 1. 📝 Categorized Prompt Formatter This node takes an existing prompt string, analyzes its tags against your YAML definitions, and reconstructs a new prompt based on your template, applying various filtering options. ![Categorized Prompt Formatter Node UI](formatter_node.png) ### Inputs & Widgets * `prompt` (String): The input prompt string (e.g., "1girl, masterpiece, blue_eyes, smiling..."). * `category_definition_file` (String): Name or path to your category YAML file (e.g., "prompt_categories.yaml"). * `output_template` (String): Defines the output structure using placeholders. * `<|category_name|>`: Includes all matched tags for this category. * `<|category_name:N|>`: * If N > 0: Includes **at most** the **first N** matched tags. * If N < 0: Includes **at most** the **last `abs(N)`** matched tags. * If N = 0: Includes **no** tags for this category. * `input_delimiter` (String): Character(s) separating tags in the input `prompt` (Default: `,`). * `output_delimiter` (String): Character(s) used to join tags in the output `formatted_prompt` (Default: `, `). * `strip_whitespace` (Boolean): Remove whitespace around input tags before matching (Default: True). * `case_sensitive_matching` (Boolean): Match tags case-sensitively against YAML (Default: False). * `handle_weights` (Boolean): Parse and preserve weights like `(tag:1.2)` or `[tag]` (Default: True). * `match_underscores_spaces` (Boolean): Treat `tag_one` and `tag one` as equivalent during matching (Default: True). Output preserves original format. * `disable_duplicates` (Boolean): Prevent the same tag string from appearing multiple times in the output (first occurrence wins) (Default: False). * `unmatched_tag_handling` (Dropdown): What to do with input tags not used by the template: * `discard`: Ignore them (Default). * `append_end`: Add them all to the end of the formatted prompt. * `output_separately`: Output them in the `rejected_prompt` slot. ### Outputs * `formatted_prompt` (String): The restructured prompt based on the template. * `rejected_prompt` (String): Tags not included in `formatted_prompt` (content depends on `unmatched_tag_handling`). ### Example Usage * **Input Prompt:** `"masterpiece, 1girl, blue eyes, red eyes, smiling, detailed background, anime style, illustration"` * **YAML:** (Assumes `quality`, `character_num`, `eyes`, `person_details`, `style` categories exist) * **Template:** `<|quality:1|>, <|character_num|>, <|eyes:-1|>, <|style:1|>` * **Unmatched Handling:** `output_separately` * **Disable Duplicates:** `False` * **Result (`formatted_prompt`):** `"masterpiece, 1girl, red eyes, anime style"` * **Result (`rejected_prompt`):** `"blue eyes, smiling, detailed background, illustration"` (Assuming 'smiling', 'detailed background' weren't matched or used; 'blue eyes' was dropped by the limit `-1`; 'illustration' dropped by limit `1`) --- ## 2. 📝 Categorized Random Prompt Formatter This node generates completely new, random prompts by selecting tags from your YAML categories based on a template structure and a seed. ![Categorized Random Prompt Formatter Node UI](random_node.png) ### Inputs & Widgets * `category_definition_file` (String): Name or path to your category YAML file. * `output_template` (String): Defines the structure and *how many* random tags to pick per category. * `<|category_name|>`: Picks **1** random tag from the category. * `<|category_name:N|>`: Picks **N** unique random tags from the category (N >= 0). If fewer than N tags exist, picks all available. N=0 picks none. * `seed` (Int): Seed for the random number generator. 0 generates a new random seed each run; any other value provides reproducible results. * `output_delimiter` (String): Character(s) used to join the selected random tags (Default: `, `). ### Outputs * `random_prompt` (String): The generated random prompt string. * `used_seed` (Int): The actual seed used for generation (useful if input `seed` was 0). ### Example Usage * **YAML:** (Assumes standard categories exist) * **Template:** `<|quality:1|>, <|character_num:1|>, <|hair_style:2|>, <|setting:1|>` * **Seed:** `42` * **Possible Result (`random_prompt`):** `"best quality, 1girl, long hair, twintails, outdoors"` (Specific tags depend on seed 42 and YAML content) * **Result (`used_seed`):** `42` * **If Seed = -1:** * **Possible Result (`random_prompt`):** `"masterpiece, 2boys, short hair, ponytail, indoors"` (Different random result) * **Result (`used_seed`):** (A large random integer) --- ## Notes & Troubleshooting * **YAML Not Found:** If the node prints a warning about not finding the YAML file, double-check the filename/path and ensure it's accessible (in the node folder, `ComfyUI/input/`, or an absolute path). * **Restart Required:** Always restart ComfyUI after installing or updating custom nodes. * **`$include` Cycles:** The code has basic protection against circular `$include` directives in the YAML (e.g., A includes B, B includes A). If detected, a warning is printed, and the cycle is broken. * **Tag Order (Formatter):** When using limits (`<|cat:N|>`) or duplicate prevention in the Formatter node, the order of tags *in the input prompt* determines which ones are selected first or last. * **Tag Format Preservation (Formatter):** The Formatter node preserves the exact format (including weights, underscores/spaces) of the *input tags* when placing them in the output, even if matching used variants (lowercase, space/underscore swap).