Files
hexxacubic 5d6c1c5aee Improve prompt handling and formatting features
Enhanced Prompt_Extender to support flexible separators and intelligent tag merging.
2026-05-09 20:21:35 +02:00

131 lines
4.7 KiB
Python

# Prompt_Extender.py
import re
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
def INPUT_TYPES(cls):
return {
"required": {
"prompt_additions": ("STRING", {
"multiline": True,
"default": "beautiful, high quality\n---\nblurry, low quality"
}),
"prepend_mode": ("BOOLEAN", {
"default": False,
"label_on": "Prepend",
"label_off": "Append"
}),
},
"optional": {
"double_prompt": ("STRING", {"forceInput": True}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("double_prompt",)
FUNCTION = "extend_prompts"
CATEGORY = "hexxacubic"
def extend_prompts(self, prompt_additions, prepend_mode, double_prompt=""):
# If no input connected, return additions as-is
if not double_prompt:
return (prompt_additions.strip(),)
# Parse both inputs
positive_prompt, negative_prompt = self._parse_double_prompt(double_prompt)
positive_addition, negative_addition = self._parse_double_prompt(prompt_additions)
# Combine based on mode
if prepend_mode:
combined_positive = self._combine_prompts(positive_addition, positive_prompt)
combined_negative = self._combine_prompts(negative_addition, negative_prompt)
else:
combined_positive = self._combine_prompts(positive_prompt, positive_addition)
combined_negative = self._combine_prompts(negative_prompt, negative_addition)
# Format output with clean separator
return (self._format_double_prompt(combined_positive, combined_negative),)
def _parse_double_prompt(self, text):
"""Parse double prompt: supports --- anywhere in text (mid-line or own line)"""
if not text or not text.strip():
return "", ""
# Match ---, ----, -----, ----- (with optional spaces/dashes)
pattern = r'\s*[-—]{3,}\s*' # includes en-dash, em-dash
match = re.search(pattern, text)
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 _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:
return addition
if not addition:
return base
base_tags = self._split_tags(base)
add_tags = self._split_tags(addition)
# 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(cls, prompt_additions, prepend_mode, double_prompt=""):
"""Cache busting based on all inputs"""
return hash(prompt_additions + str(prepend_mode) + double_prompt)