From 6e0808032359a9cd95f508d2d965352fc0902504 Mon Sep 17 00:00:00 2001 From: Bane <34267409+Analaser@users.noreply.github.com> Date: Mon, 20 Oct 2025 01:53:16 +0300 Subject: [PATCH] Add files via upload --- README.md | 50 ++++++++++++++++++++++++-- __init__.py | 1 + random_tag_weights.py | 81 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 __init__.py create mode 100644 random_tag_weights.py diff --git a/README.md b/README.md index 0d9aafd..d061834 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,48 @@ -# ComfyUI-RandomTagWeights -ComfyUI node that randomizes tag weights +# 🧩 ComfyUI - Random Tag Weights Node + +A custom **ComfyUI** node that randomizes tag weights for text prompts. +Useful for dynamic prompt generation or creative experimentation in AI image workflows. + +--- + +## ✨ Features + +- Randomly generates weights for each tag (e.g., `(dog:1.2)`) +- Filters tags based on a minimum threshold +- Optionally shuffles the order of tags +- Allows reproducible randomness via a seed +- Supports both inline text input and external input connections + +--- + +## ⚙️ Parameters + +| Name | Type | Description | +|------|------|-------------| +| `text` | string | Base tag list (comma-separated) | +| `min_weight` | float | Minimum random weight | +| `max_weight` | float | Maximum random weight | +| `threshold` | float | Minimum weight to include tag | +| `max_tags` | int | Maximum number of tags to output | +| `seed` | int | Random seed for reproducibility | +| `shuffle_tags` | bool | Shuffle the order of selected tags | +| `input_text` | optional string | Alternative input text | + +--- + +## 🧠 How It Works + +1. The node parses the provided text for tags. +2. Each tag is assigned a random weight between `min_weight` and `max_weight`. +3. Tags with weights **above `threshold`** are kept. +4. The selected tags are shuffled (if enabled) and limited to `max_tags`. +5. The result is returned as a formatted string like: (dog:1.2), (cat:1.3), (bird:1.0) + + +--- + +## 📦 Installation + +1. Download or clone this repo into your `ComfyUI/custom_nodes` folder + +2. Restart ComfyUI — your new node will appear under the Text category! \ No newline at end of file diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..3534e74 --- /dev/null +++ b/__init__.py @@ -0,0 +1 @@ +from .random_tag_weights import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS diff --git a/random_tag_weights.py b/random_tag_weights.py new file mode 100644 index 0000000..246fc73 --- /dev/null +++ b/random_tag_weights.py @@ -0,0 +1,81 @@ +import random +import re + +class RandomTagWeights: + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "text": ("STRING", {"multiline": True, "default": "big cat, dog, small bird, red fox, blue sky, green tree, tall building, fast car, loud noise, bright light"}), + "min_weight": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 10.0, "step": 0.1}), + "max_weight": ("FLOAT", {"default": 1.3, "min": 0.0, "max": 10.0, "step": 0.1}), + "threshold": ("FLOAT", {"default": 1.2, "min": 0.0, "max": 10.0, "step": 0.1}), + "max_tags": ("INT", {"default": 3, "min": 1, "max": 10000, "step": 1}), + "seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}), + "shuffle_tags": ("BOOLEAN", {"default": True}), + }, + "optional": { + "input_text": ("STRING", {"multiline": True, "default": "", "forceInput": True}), + } + } + + RETURN_TYPES = ("STRING",) + RETURN_NAMES = ("modified_text",) + FUNCTION = "randomize_weights" + CATEGORY = "text" + + def randomize_weights(self, text, min_weight, max_weight, threshold, max_tags, seed, shuffle_tags, input_text=None): + if input_text and input_text.strip(): + source_text = input_text + else: + source_text = text + + if not isinstance(source_text, str): + source_text = str(source_text) + + random.seed(seed) + + weighted_pattern = r"\(([^:]+):([\d.]+)\)" + plain_tag_pattern = r"(^|,\s*)([^,]+?)(?=,|$|\s*$)" + + def get_random_weight(): + return round(random.uniform(min_weight, max_weight), 2) + + qualifying_tags = [] + + def replace_weight(match): + tag = match.group(1).strip() + new_weight = get_random_weight() + if new_weight >= threshold: + qualifying_tags.append((tag, new_weight)) + return "" + + text_with_weighted = re.sub(weighted_pattern, replace_weight, source_text) + + def wrap_plain_tag(match): + tag = match.group(2).strip() + if not re.search(rf"\({re.escape(tag)}:[\d.]+\)", text_with_weighted): + new_weight = get_random_weight() + if new_weight >= threshold: + qualifying_tags.append((tag, new_weight)) + return "" + + text_with_weighted = re.sub(plain_tag_pattern, wrap_plain_tag, text_with_weighted) + + if shuffle_tags: + random.shuffle(qualifying_tags) + + qualifying_tags = qualifying_tags[:max_tags] + + modified_text = ", ".join(f"({tag}:{weight})" for tag, weight in qualifying_tags).strip() + + return (modified_text,) + +NODE_CLASS_MAPPINGS = { + "RandomTagWeights": RandomTagWeights +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "RandomTagWeights": "Random Tag Weights" +} +