From 5d6c1c5aeecf34d80db80e7742e56ced69f95e4e Mon Sep 17 00:00:00 2001 From: hexxacubic Date: Sat, 9 May 2026 20:21:35 +0200 Subject: [PATCH] Improve prompt handling and formatting features Enhanced Prompt_Extender to support flexible separators and intelligent tag merging. --- Prompt_Extender.py | 117 +++++++++++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 47 deletions(-) diff --git a/Prompt_Extender.py b/Prompt_Extender.py index 9fc87dd..70d59c5 100644 --- a/Prompt_Extender.py +++ b/Prompt_Extender.py @@ -1,3 +1,4 @@ +# Prompt_Extender.py import re class Prompt_Extender: @@ -5,6 +6,12 @@ class Prompt_Extender: A ComfyUI node for building double prompts from two text fields. Can also extend existing prompts when connected. Can prepend or append the additions based on the prepend_mode setting. + + Features: + - Supports separator (---, ----, -----) anywhere: own line or mid-text + - Output: always clean --- on its own line + - Intelligent tag merging: deduplication, comma-separated + - Preserves positive/negative separation """ @classmethod @@ -15,7 +22,11 @@ class Prompt_Extender: "multiline": True, "default": "beautiful, high quality\n---\nblurry, low quality" }), - "prepend_mode": ("BOOLEAN", {"default": False, "label_on": "Prepend", "label_off": "Append"}), + "prepend_mode": ("BOOLEAN", { + "default": False, + "label_on": "Prepend", + "label_off": "Append" + }), }, "optional": { "double_prompt": ("STRING", {"forceInput": True}), @@ -28,80 +39,92 @@ class Prompt_Extender: CATEGORY = "hexxacubic" def extend_prompts(self, prompt_additions, prepend_mode, double_prompt=""): - # If no input connected, prompt_additions becomes the main prompt + # If no input connected, return additions as-is if not double_prompt: - # Just return the additions as the output - return (prompt_additions,) + return (prompt_additions.strip(),) - # Parse input double prompt + # Parse both inputs positive_prompt, negative_prompt = self._parse_double_prompt(double_prompt) - - # Parse additions positive_addition, negative_addition = self._parse_double_prompt(prompt_additions) - # Combine the prompts based on prepend_mode + # Combine based on mode if prepend_mode: - # Prepend mode: additions come first combined_positive = self._combine_prompts(positive_addition, positive_prompt) combined_negative = self._combine_prompts(negative_addition, negative_prompt) else: - # Append mode (default): additions come last combined_positive = self._combine_prompts(positive_prompt, positive_addition) combined_negative = self._combine_prompts(negative_prompt, negative_addition) - # Return as double prompt format - if combined_positive and combined_negative: - return (f"{combined_positive}\n---\n{combined_negative}",) - elif combined_positive: - return (combined_positive,) - elif combined_negative: - return (f"\n---\n{combined_negative}",) - else: - return ("",) + # Format output with clean separator + return (self._format_double_prompt(combined_positive, combined_negative),) def _parse_double_prompt(self, text): - """Parse double prompt format into positive and negative parts""" - if not text.strip(): + """Parse double prompt: supports --- anywhere in text (mid-line or own line)""" + if not text or not text.strip(): return "", "" - - lines = text.split('\n') - # Find separator (---, ----, or -----) - separator_idx = -1 - for i, line in enumerate(lines): - if line.strip() in ["---", "----", "-----"]: - separator_idx = i - break + # Match ---, ----, -----, ----- (with optional spaces/dashes) + pattern = r'\s*[-—]{3,}\s*' # includes en-dash, em-dash + match = re.search(pattern, text) - if separator_idx != -1: - positive = "\n".join(lines[:separator_idx]).strip() - negative = "\n".join(lines[separator_idx+1:]).strip() + if match: + sep_start = match.start() + sep_end = match.end() + positive = text[:sep_start].strip() + negative = text[sep_end:].strip() else: positive = text.strip() negative = "" - + return positive, negative - def _combine_prompts(self, base_prompt, addition): - """Intelligently combines base prompt and addition""" - base_prompt = base_prompt.strip() + def _split_tags(self, text): + """Split prompt into clean list of tags (by comma, semicolon, or newline)""" + if not text: + return [] + # Split by comma, semicolon, or newline + parts = re.split(r'[,;\n]+', text) + tags = [p.strip() for p in parts if p.strip()] + return tags + + def _combine_prompts(self, base, addition): + """Combine two prompt parts: deduplicate, comma-separated""" + base = base.strip() addition = addition.strip() - if not base_prompt: + if not base: return addition if not addition: - return base_prompt + return base - # Add comma between prompts if none exists - if base_prompt and addition: - if not base_prompt.endswith(',') and not base_prompt.endswith('.'): - return f"{base_prompt}, {addition}" - else: - return f"{base_prompt} {addition}" + base_tags = self._split_tags(base) + add_tags = self._split_tags(addition) - return base_prompt + # Merge and deduplicate (preserve base order, then additions) + seen = set() + combined = [] + for tag in base_tags + add_tags: + if tag not in seen: + seen.add(tag) + combined.append(tag) + + return ", ".join(combined) + + def _format_double_prompt(self, positive, negative): + """Format positive and negative into clean double prompt with --- on own line""" + positive = positive.strip() + negative = negative.strip() + + if positive and negative: + return f"{positive}\n---\n{negative}" + elif positive: + return positive + elif negative: + return f"\n---\n{negative}" + else: + return "" @classmethod - def IS_CHANGED(s, prompt_additions, prepend_mode, double_prompt=""): - # Cache based on all inputs + def IS_CHANGED(cls, prompt_additions, prepend_mode, double_prompt=""): + """Cache busting based on all inputs""" return hash(prompt_additions + str(prepend_mode) + double_prompt)