614 lines
27 KiB
Python
614 lines
27 KiB
Python
import random
|
|
from typing import List, Dict, Any
|
|
|
|
|
|
class FactoryPromptsNegativeGenerator:
|
|
"""
|
|
Comprehensive negative prompt generator for all checkpoint types
|
|
Provides categorized negative prompts for quality control and style management
|
|
"""
|
|
|
|
def __init__(self):
|
|
# Base quality negatives - always included
|
|
self.base_quality = [
|
|
"lowres", "bad_anatomy", "bad_hands", "text", "error",
|
|
"missing_fingers", "extra_digit", "fewer_digits", "cropped",
|
|
"worst_quality", "low_quality", "normal_quality",
|
|
"jpeg_artifacts", "signature", "watermark", "username", "blurry"
|
|
]
|
|
|
|
# Enhanced quality negatives for higher standards
|
|
self.enhanced_quality = [
|
|
"bad_proportions", "bad_perspective", "bad_shading",
|
|
"bad_composition", "bad_lighting", "overexposed", "underexposed",
|
|
"noise", "grainy", "pixelated", "compression_artifacts",
|
|
"aliasing", "distorted", "deformed", "malformed"
|
|
]
|
|
|
|
# Anatomy and body negatives
|
|
self.anatomy_negatives = [
|
|
"bad_anatomy", "bad_hands", "bad_feet", "bad_face",
|
|
"missing_fingers", "extra_digit", "fewer_digits", "extra_fingers",
|
|
"mutated_hands", "poorly_drawn_hands", "poorly_drawn_face",
|
|
"mutation", "deformed", "ugly", "blurry_face", "disfigured",
|
|
"extra_limbs", "missing_limbs", "extra_arms", "missing_arms",
|
|
"extra_legs", "missing_legs", "fused_fingers", "too_many_fingers",
|
|
"long_neck", "duplicate", "morbid", "mutilated", "extra_head",
|
|
"poorly_drawn_eyes", "bad_eyes", "crossed_eyes", "extra_tongue",
|
|
"multiple_tongues", "deformed_tongue", "elongated_tongue"
|
|
]
|
|
|
|
# Non-realistic style control negatives
|
|
self.non_realistic_style_control = [
|
|
"source_cartoon", "source_furry", "source_pony", "western_comic",
|
|
"cartoon", "disney", "pixar", "anime_style", "manga_style",
|
|
"chibi", "cel_shading", "flat_colors", "simplified_art"
|
|
]
|
|
|
|
# Realistic style control negatives
|
|
self.realistic_style_control = [
|
|
"3d", "realistic", "photorealistic", "photo", "photography",
|
|
"real_person", "live_action", "cgi", "render", "blender",
|
|
"unreal_engine", "ray_tracing", "hyperrealistic", "lifelike"
|
|
]
|
|
|
|
# Art medium negatives
|
|
self.unwanted_mediums = [
|
|
"sketch", "pencil_sketch", "rough_sketch", "draft",
|
|
"unfinished", "incomplete", "work_in_progress", "wip",
|
|
"traditional_media", "pencil_drawing", "charcoal",
|
|
"crayon", "chalk", "pastel", "watercolor_paper",
|
|
"canvas_texture", "paper_texture", "scan_artifacts"
|
|
]
|
|
|
|
# Color and saturation control
|
|
self.color_negatives = [
|
|
"monochrome", "grayscale", "greyscale", "black_and_white",
|
|
"sepia", "desaturated", "oversaturated", "color_bleeding",
|
|
"bad_colors", "ugly_colors", "neon_colors", "garish",
|
|
"overexposed_colors", "washed_out", "faded_colors"
|
|
]
|
|
|
|
# Composition and framing negatives
|
|
self.composition_negatives = [
|
|
"bad_composition", "bad_framing", "cut_off", "cropped_head",
|
|
"cropped_body", "out_of_frame", "off_center", "unbalanced",
|
|
"awkward_pose", "stiff_pose", "unnatural_pose", "forced_smile",
|
|
"bad_perspective", "wrong_perspective", "floating"
|
|
]
|
|
|
|
# Background and environment negatives
|
|
self.background_negatives = [
|
|
"cluttered_background", "busy_background", "distracting_background",
|
|
"bad_background", "messy_background", "noisy_background",
|
|
"artifacts_in_background", "floating_objects", "inconsistent_lighting",
|
|
"multiple_light_sources", "confusing_background"
|
|
]
|
|
|
|
# Text and UI element negatives
|
|
self.text_negatives = [
|
|
"text", "words", "letters", "numbers", "symbols",
|
|
"watermark", "signature", "artist_name", "copyright",
|
|
"logo", "brand", "website", "url", "username",
|
|
"speech_bubble", "thought_bubble", "text_bubble",
|
|
"caption", "subtitle", "overlay_text", "ui_elements"
|
|
]
|
|
|
|
# Clothing and fashion negatives
|
|
self.clothing_negatives = [
|
|
"bad_clothing", "poorly_drawn_clothes", "floating_clothes",
|
|
"clipping_clothes", "transparent_clothes", "see_through_clothes",
|
|
"torn_clothes", "damaged_clothes", "wrinkled_clothes",
|
|
"ill_fitting_clothes", "oversized_clothes", "undersized_clothes"
|
|
]
|
|
|
|
# Expression and emotion negatives
|
|
self.expression_negatives = [
|
|
"dead_eyes", "empty_eyes", "soulless_eyes", "scary_eyes",
|
|
"angry_expression", "sad_expression", "depressed_expression",
|
|
"forced_expression", "unnatural_expression", "blank_expression",
|
|
"emotionless", "creepy_smile", "evil_smile"
|
|
]
|
|
|
|
# Hair negatives
|
|
self.hair_negatives = [
|
|
"bad_hair", "poorly_drawn_hair", "floating_hair", "messy_hair",
|
|
"tangled_hair", "unrealistic_hair", "bad_hair_physics",
|
|
"clipping_hair", "hair_artifacts", "inconsistent_hair_color"
|
|
]
|
|
|
|
# NSFW content filters (for SFW generations)
|
|
self.nsfw_filters = [
|
|
"nsfw", "explicit", "nude", "naked", "topless", "bottomless",
|
|
"underwear", "lingerie", "bikini", "swimsuit", "revealing_clothes",
|
|
"cleavage", "exposed_skin", "suggestive", "provocative",
|
|
"sexual", "erotic", "adult_content", "mature_content"
|
|
]
|
|
|
|
# Violence and disturbing content filters
|
|
self.violence_filters = [
|
|
"violence", "blood", "gore", "death", "killing", "murder",
|
|
"torture", "pain", "suffering", "injury", "wound", "scar",
|
|
"bruise", "cut", "bleeding", "dark_themes", "disturbing",
|
|
"nightmare", "horror", "scary", "frightening"
|
|
]
|
|
|
|
# Technical artifact negatives
|
|
self.technical_negatives = [
|
|
"compression_artifacts", "jpeg_artifacts", "aliasing", "moire",
|
|
"banding", "posterization", "color_banding", "pixelation",
|
|
"blur_artifacts", "sharpening_artifacts", "noise_artifacts",
|
|
"upscaling_artifacts", "interpolation_artifacts"
|
|
]
|
|
|
|
def get_base_negatives(self) -> List[str]:
|
|
"""Always included base negative prompts"""
|
|
return self.base_quality.copy()
|
|
|
|
def get_category_negatives(self, categories: List[str]) -> List[str]:
|
|
"""Get negatives from specific categories"""
|
|
negatives = []
|
|
|
|
category_map = {
|
|
"enhanced_quality": self.enhanced_quality,
|
|
"anatomy": self.anatomy_negatives,
|
|
"non_realistic_style_control": self.non_realistic_style_control,
|
|
"realistic_style_control": self.realistic_style_control,
|
|
"unwanted_mediums": self.unwanted_mediums,
|
|
"color_control": self.color_negatives,
|
|
"composition": self.composition_negatives,
|
|
"background": self.background_negatives,
|
|
"text_elements": self.text_negatives,
|
|
"clothing": self.clothing_negatives,
|
|
"expressions": self.expression_negatives,
|
|
"hair": self.hair_negatives,
|
|
"nsfw_filters": self.nsfw_filters,
|
|
"violence_filters": self.violence_filters,
|
|
"technical": self.technical_negatives
|
|
}
|
|
|
|
for category in categories:
|
|
if category in category_map:
|
|
negatives.extend(category_map[category])
|
|
|
|
return negatives
|
|
|
|
def build_negative_prompt(self,
|
|
preset: str = "standard",
|
|
custom_categories: List[str] = None,
|
|
include_style_control: bool = True,
|
|
include_nsfw_filters: bool = False,
|
|
include_violence_filters: bool = False,
|
|
custom_negatives: str = "",
|
|
strength_boost: bool = False) -> str:
|
|
"""
|
|
Build comprehensive negative prompt based on settings
|
|
|
|
Args:
|
|
preset: Predefined negative prompt preset
|
|
custom_categories: List of specific categories to include
|
|
include_style_control: Add style control negatives
|
|
include_nsfw_filters: Add NSFW content filters
|
|
include_violence_filters: Add violence/disturbing content filters
|
|
custom_negatives: Additional custom negative terms
|
|
strength_boost: Add emphasis to critical negatives
|
|
"""
|
|
|
|
negatives = self.get_base_negatives()
|
|
|
|
# Apply presets
|
|
if preset == "minimal":
|
|
# Just base quality negatives
|
|
pass
|
|
elif preset == "standard":
|
|
negatives.extend(self.get_category_negatives([
|
|
"enhanced_quality", "anatomy", "composition", "text_elements"
|
|
]))
|
|
elif preset == "comprehensive":
|
|
negatives.extend(self.get_category_negatives([
|
|
"enhanced_quality", "anatomy", "composition", "background",
|
|
"text_elements", "clothing", "hair", "technical"
|
|
]))
|
|
elif preset == "professional":
|
|
negatives.extend(self.get_category_negatives([
|
|
"enhanced_quality", "anatomy", "composition", "background",
|
|
"text_elements", "clothing", "expressions", "hair",
|
|
"unwanted_mediums", "technical"
|
|
]))
|
|
elif preset == "anime_focused":
|
|
negatives.extend(self.get_category_negatives([
|
|
"enhanced_quality", "anatomy", "non_realistic_style_control", "composition",
|
|
"text_elements", "unwanted_mediums"
|
|
]))
|
|
|
|
# Add custom categories
|
|
if custom_categories:
|
|
negatives.extend(self.get_category_negatives(custom_categories))
|
|
|
|
# Add optional filters
|
|
if include_style_control:
|
|
negatives.extend(self.non_realistic_style_control)
|
|
negatives.extend(self.realistic_style_control)
|
|
|
|
if include_nsfw_filters:
|
|
negatives.extend(self.nsfw_filters)
|
|
|
|
if include_violence_filters:
|
|
negatives.extend(self.violence_filters)
|
|
|
|
# Add custom negatives
|
|
if custom_negatives.strip():
|
|
custom_terms = [term.strip() for term in custom_negatives.split(",") if term.strip()]
|
|
negatives.extend(custom_terms)
|
|
|
|
# Remove duplicates while preserving order
|
|
seen = set()
|
|
unique_negatives = []
|
|
for negative in negatives:
|
|
if negative not in seen:
|
|
unique_negatives.append(negative)
|
|
seen.add(negative)
|
|
|
|
# Apply strength boost to critical terms
|
|
if strength_boost:
|
|
critical_terms = ["bad_anatomy", "bad_hands", "bad_face", "worst_quality", "low_quality"]
|
|
boosted_negatives = []
|
|
for negative in unique_negatives:
|
|
if negative in critical_terms:
|
|
boosted_negatives.append(f"({negative}:1.2)")
|
|
else:
|
|
boosted_negatives.append(negative)
|
|
unique_negatives = boosted_negatives
|
|
|
|
return ", ".join(unique_negatives)
|
|
|
|
def get_preset_description(self, preset: str) -> str:
|
|
"""Get description of what each preset includes"""
|
|
descriptions = {
|
|
"minimal": "Basic quality control only - fastest generation",
|
|
"standard": "Quality + anatomy + composition + text removal",
|
|
"comprehensive": "Standard + background + clothing + hair + technical",
|
|
"professional": "Comprehensive + expressions + unwanted mediums",
|
|
"anime_focused": "Optimized for anime style with strong style control"
|
|
}
|
|
return descriptions.get(preset, "Unknown preset")
|
|
|
|
|
|
class PonyNegativeNode:
|
|
"""ComfyUI Node for Pony Negative Prompt Generation"""
|
|
|
|
CATEGORY = "Prompt Factory"
|
|
RETURN_TYPES = ("STRING",)
|
|
RETURN_NAMES = ("negative_prompt",)
|
|
FUNCTION = "generate_negative"
|
|
|
|
def __init__(self):
|
|
self.generator = FactoryPromptsNegativeGenerator()
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"preset": (["minimal", "standard", "comprehensive", "professional", "anime_focused"], {"default": "standard"}),
|
|
"include_style_control": ("BOOLEAN", {"default": True}),
|
|
"include_nsfw_filters": ("BOOLEAN", {"default": False}),
|
|
"include_violence_filters": ("BOOLEAN", {"default": False}),
|
|
"strength_boost": ("BOOLEAN", {"default": False}),
|
|
},
|
|
"optional": {
|
|
"custom_negatives": ("STRING", {"multiline": True, "default": ""}),
|
|
"extra_categories": (["none", "enhanced_quality", "anatomy", "unwanted_mediums",
|
|
"color_control", "composition", "background", "text_elements",
|
|
"clothing", "expressions", "hair", "technical"], {"default": "none"}),
|
|
}
|
|
}
|
|
|
|
def generate_negative(self, preset, include_style_control, include_nsfw_filters,
|
|
include_violence_filters, strength_boost, custom_negatives="",
|
|
extra_categories="none"):
|
|
|
|
# Convert extra_categories to list
|
|
extra_cats = [extra_categories] if extra_categories != "none" else []
|
|
|
|
# Generate negative prompt
|
|
negative = self.generator.build_negative_prompt(
|
|
preset=preset,
|
|
custom_categories=extra_cats,
|
|
include_style_control=include_style_control,
|
|
include_nsfw_filters=include_nsfw_filters,
|
|
include_violence_filters=include_violence_filters,
|
|
custom_negatives=custom_negatives,
|
|
strength_boost=strength_boost
|
|
)
|
|
|
|
return (negative,)
|
|
|
|
|
|
class PonyNegativeCategorizedNode:
|
|
"""Advanced ComfyUI Node for Categorized Negative Prompt Control"""
|
|
|
|
CATEGORY = "Prompt Factory"
|
|
RETURN_TYPES = ("STRING",)
|
|
RETURN_NAMES = ("negative_prompt",)
|
|
FUNCTION = "generate_categorized_negative"
|
|
|
|
def __init__(self):
|
|
self.generator = FactoryPromptsNegativeGenerator()
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"base_quality": ("BOOLEAN", {"default": True}),
|
|
"enhanced_quality": ("BOOLEAN", {"default": True}),
|
|
"anatomy_control": ("BOOLEAN", {"default": True}),
|
|
"non_realistic_style_control": ("BOOLEAN", {"default": True}),
|
|
"realistic_style_control": ("BOOLEAN", {"default": False}),
|
|
"composition": ("BOOLEAN", {"default": True}),
|
|
"text_removal": ("BOOLEAN", {"default": True}),
|
|
},
|
|
"optional": {
|
|
"unwanted_mediums": ("BOOLEAN", {"default": False}),
|
|
"color_control": ("BOOLEAN", {"default": False}),
|
|
"background_control": ("BOOLEAN", {"default": False}),
|
|
"clothing_control": ("BOOLEAN", {"default": False}),
|
|
"expression_control": ("BOOLEAN", {"default": False}),
|
|
"hair_control": ("BOOLEAN", {"default": False}),
|
|
"nsfw_filters": ("BOOLEAN", {"default": False}),
|
|
"violence_filters": ("BOOLEAN", {"default": False}),
|
|
"technical_artifacts": ("BOOLEAN", {"default": False}),
|
|
"strength_boost": ("BOOLEAN", {"default": False}),
|
|
"custom_negatives": ("STRING", {"multiline": True, "default": ""}),
|
|
}
|
|
}
|
|
|
|
def generate_categorized_negative(self, base_quality, enhanced_quality, anatomy_control,
|
|
non_realistic_style_control, realistic_style_control, composition, text_removal, unwanted_mediums=False,
|
|
color_control=False, background_control=False, clothing_control=False,
|
|
expression_control=False, hair_control=False, nsfw_filters=False,
|
|
violence_filters=False, technical_artifacts=False, strength_boost=False,
|
|
custom_negatives=""):
|
|
|
|
negatives = []
|
|
|
|
# Add base categories based on selections
|
|
if base_quality:
|
|
negatives.extend(self.generator.get_base_negatives())
|
|
|
|
# Build category list
|
|
categories = []
|
|
if enhanced_quality:
|
|
categories.append("enhanced_quality")
|
|
if anatomy_control:
|
|
categories.append("anatomy")
|
|
if unwanted_mediums:
|
|
categories.append("unwanted_mediums")
|
|
if color_control:
|
|
categories.append("color_control")
|
|
if composition:
|
|
categories.append("composition")
|
|
if background_control:
|
|
categories.append("background")
|
|
if text_removal:
|
|
categories.append("text_elements")
|
|
if clothing_control:
|
|
categories.append("clothing")
|
|
if expression_control:
|
|
categories.append("expressions")
|
|
if hair_control:
|
|
categories.append("hair")
|
|
if technical_artifacts:
|
|
categories.append("technical")
|
|
|
|
# Add category negatives
|
|
negatives.extend(self.generator.get_category_negatives(categories))
|
|
|
|
# Add optional style control filters
|
|
if non_realistic_style_control:
|
|
negatives.extend(self.generator.non_realistic_style_control)
|
|
if realistic_style_control:
|
|
negatives.extend(self.generator.realistic_style_control)
|
|
if nsfw_filters:
|
|
negatives.extend(self.generator.nsfw_filters)
|
|
if violence_filters:
|
|
negatives.extend(self.generator.violence_filters)
|
|
|
|
# Add custom negatives
|
|
if custom_negatives.strip():
|
|
custom_terms = [term.strip() for term in custom_negatives.split(",") if term.strip()]
|
|
negatives.extend(custom_terms)
|
|
|
|
# Remove duplicates
|
|
seen = set()
|
|
unique_negatives = []
|
|
for negative in negatives:
|
|
if negative not in seen:
|
|
unique_negatives.append(negative)
|
|
seen.add(negative)
|
|
|
|
# Apply strength boost
|
|
if strength_boost:
|
|
critical_terms = ["bad_anatomy", "bad_hands", "bad_face", "worst_quality", "low_quality"]
|
|
boosted_negatives = []
|
|
for negative in unique_negatives:
|
|
if negative in critical_terms:
|
|
boosted_negatives.append(f"({negative}:1.2)")
|
|
else:
|
|
boosted_negatives.append(negative)
|
|
unique_negatives = boosted_negatives
|
|
|
|
return (", ".join(unique_negatives),)
|
|
|
|
|
|
class PonyNegativeToggleNode:
|
|
"""Comprehensive ComfyUI Node for Negative Prompt Control with Individual Toggles"""
|
|
|
|
CATEGORY = "Prompt Factory"
|
|
RETURN_TYPES = ("STRING", "STRING")
|
|
RETURN_NAMES = ("negative_prompt", "selected_categories")
|
|
FUNCTION = "generate_negative_toggles"
|
|
|
|
def __init__(self):
|
|
self.generator = FactoryPromptsNegativeGenerator()
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
|
},
|
|
"optional": {
|
|
# Quality Control Toggles
|
|
"base_quality": ("BOOLEAN", {"default": True}),
|
|
"enhanced_quality": ("BOOLEAN", {"default": False}),
|
|
"technical_artifacts": ("BOOLEAN", {"default": False}),
|
|
|
|
# Anatomy Control Toggles
|
|
"anatomy_control": ("BOOLEAN", {"default": True}),
|
|
"expression_control": ("BOOLEAN", {"default": False}),
|
|
"hair_control": ("BOOLEAN", {"default": False}),
|
|
|
|
# Style Control Toggles
|
|
"non_realistic_style_control": ("BOOLEAN", {"default": True}),
|
|
"realistic_style_control": ("BOOLEAN", {"default": False}),
|
|
"unwanted_mediums": ("BOOLEAN", {"default": False}),
|
|
"color_control": ("BOOLEAN", {"default": False}),
|
|
|
|
# Composition Toggles
|
|
"composition": ("BOOLEAN", {"default": True}),
|
|
"background_control": ("BOOLEAN", {"default": False}),
|
|
"text_removal": ("BOOLEAN", {"default": True}),
|
|
|
|
# Content Toggles
|
|
"clothing_control": ("BOOLEAN", {"default": False}),
|
|
"nsfw_filters": ("BOOLEAN", {"default": False}),
|
|
"violence_filters": ("BOOLEAN", {"default": False}),
|
|
|
|
# Enhancement Options
|
|
"strength_boost": ("BOOLEAN", {"default": False}),
|
|
"custom_negatives": ("STRING", {"multiline": True, "default": ""}),
|
|
}
|
|
}
|
|
|
|
def generate_negative_toggles(self, seed, base_quality=True, enhanced_quality=False,
|
|
technical_artifacts=False, anatomy_control=True,
|
|
expression_control=False, hair_control=False,
|
|
non_realistic_style_control=True, realistic_style_control=False, unwanted_mediums=False,
|
|
color_control=False, composition=True,
|
|
background_control=False, text_removal=True,
|
|
clothing_control=False, nsfw_filters=False,
|
|
violence_filters=False, strength_boost=False,
|
|
custom_negatives=""):
|
|
|
|
# Set random seed for reproducible results
|
|
if seed != 0:
|
|
random.seed(seed)
|
|
|
|
negatives = []
|
|
enabled_categories = []
|
|
|
|
# Add base categories based on toggles
|
|
if base_quality:
|
|
negatives.extend(self.generator.get_base_negatives())
|
|
enabled_categories.append("Base Quality")
|
|
|
|
# Build category list based on toggles
|
|
categories = []
|
|
if enhanced_quality:
|
|
categories.append("enhanced_quality")
|
|
enabled_categories.append("Enhanced Quality")
|
|
if technical_artifacts:
|
|
categories.append("technical")
|
|
enabled_categories.append("Technical Artifacts")
|
|
if anatomy_control:
|
|
categories.append("anatomy")
|
|
enabled_categories.append("Anatomy Control")
|
|
if expression_control:
|
|
categories.append("expressions")
|
|
enabled_categories.append("Expression Control")
|
|
if hair_control:
|
|
categories.append("hair")
|
|
enabled_categories.append("Hair Control")
|
|
if non_realistic_style_control:
|
|
categories.append("non_realistic_style_control")
|
|
enabled_categories.append("Non-Realistic Style Control")
|
|
if realistic_style_control:
|
|
categories.append("realistic_style_control")
|
|
enabled_categories.append("Realistic Style Control")
|
|
if unwanted_mediums:
|
|
categories.append("unwanted_mediums")
|
|
enabled_categories.append("Unwanted Mediums")
|
|
if color_control:
|
|
categories.append("color_control")
|
|
enabled_categories.append("Color Control")
|
|
if composition:
|
|
categories.append("composition")
|
|
enabled_categories.append("Composition")
|
|
if background_control:
|
|
categories.append("background")
|
|
enabled_categories.append("Background Control")
|
|
if text_removal:
|
|
categories.append("text_elements")
|
|
enabled_categories.append("Text Removal")
|
|
if clothing_control:
|
|
categories.append("clothing")
|
|
enabled_categories.append("Clothing Control")
|
|
|
|
# Add category negatives
|
|
if categories:
|
|
negatives.extend(self.generator.get_category_negatives(categories))
|
|
|
|
# Add optional filters
|
|
if nsfw_filters:
|
|
negatives.extend(self.generator.get_category_negatives(["nsfw_filters"]))
|
|
enabled_categories.append("NSFW Filters")
|
|
|
|
if violence_filters:
|
|
negatives.extend(self.generator.get_category_negatives(["violence_filters"]))
|
|
enabled_categories.append("Violence Filters")
|
|
|
|
# Add custom negatives
|
|
if custom_negatives.strip():
|
|
custom_terms = [term.strip() for term in custom_negatives.split(",") if term.strip()]
|
|
negatives.extend(custom_terms)
|
|
enabled_categories.append(f"Custom ({len(custom_terms)} terms)")
|
|
|
|
# Remove duplicates while preserving order
|
|
seen = set()
|
|
unique_negatives = []
|
|
for negative in negatives:
|
|
if negative not in seen:
|
|
unique_negatives.append(negative)
|
|
seen.add(negative)
|
|
|
|
# Apply strength boost to critical terms
|
|
if strength_boost:
|
|
critical_terms = ["bad_anatomy", "bad_hands", "bad_face", "worst_quality", "low_quality"]
|
|
boosted_negatives = []
|
|
for negative in unique_negatives:
|
|
if negative in critical_terms:
|
|
boosted_negatives.append(f"({negative}:1.2)")
|
|
else:
|
|
boosted_negatives.append(negative)
|
|
unique_negatives = boosted_negatives
|
|
enabled_categories.append("Strength Boost")
|
|
|
|
# Create category summary
|
|
category_summary = ", ".join(enabled_categories) if enabled_categories else "No categories enabled"
|
|
|
|
return (", ".join(unique_negatives), category_summary)
|
|
|
|
|
|
# Node registration
|
|
NODE_CLASS_MAPPINGS = {
|
|
"FactoryPromptsNegative": PonyNegativeNode,
|
|
"FactoryPromptsNegativeCategorized": PonyNegativeCategorizedNode,
|
|
"FactoryPromptsNegativeToggle": PonyNegativeToggleNode
|
|
}
|
|
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
"FactoryPromptsNegative": "Factory Prompts Negative Generator",
|
|
"FactoryPromptsNegativeCategorized": "Factory Prompts Negative (Categorized)",
|
|
"FactoryPromptsNegativeToggle": "Factory Prompts Negative Generator (Toggles)"
|
|
}
|