Upload 2 files
Browse files- wildcard_2.py +708 -0
- wildcard_4.py +535 -0
wildcard_2.py
ADDED
|
@@ -0,0 +1,708 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import random
|
| 2 |
+
|
| 3 |
+
# ------------------------------------------------------------
|
| 4 |
+
# WildcardCharacterPrompt
|
| 5 |
+
#
|
| 6 |
+
# Generates two character prompts from the same "base"
|
| 7 |
+
# description:
|
| 8 |
+
# - 1girl variant
|
| 9 |
+
# - 1boy variant
|
| 10 |
+
#
|
| 11 |
+
# Structure of each prompt (comma-separated tokens):
|
| 12 |
+
#
|
| 13 |
+
# Category 1 : "1girl" or "1boy" (count + base gender, NEVER anything else)
|
| 14 |
+
# Category 2 : camera POV (8-ish logical directions, LEFTSIDE / RIGHTSIDE capitalized)
|
| 15 |
+
# Category 3 : "woman" / "man" / "girl" / "boy" / "grandma" / "grandpa" (age descriptor)
|
| 16 |
+
# Category 4 : two tokens: social type + inner personality
|
| 17 |
+
# both applied to Category 3 word:
|
| 18 |
+
# "<social> <age-word>, <inner> <age-word>"
|
| 19 |
+
# Skin tone : "<descriptor> skincolor"
|
| 20 |
+
# Category 5 : eyes:
|
| 21 |
+
# "<color> eyes, <style> eyes, <look direction> eyes"
|
| 22 |
+
# (no eyewear)
|
| 23 |
+
# Category 6 : hair:
|
| 24 |
+
# "<color> hair, <length> hair, <style> hair"
|
| 25 |
+
# Category 7 : top garment:
|
| 26 |
+
# "<color> <top>, <material> <top>, <adjective> <top>"
|
| 27 |
+
# Category 8 : skirt:
|
| 28 |
+
# "<color> skirt, <material> skirt, <adjective> skirt"
|
| 29 |
+
# Category 9 : bottom garment (pants/shorts/etc.):
|
| 30 |
+
# "<color> <bottom>, <material> <bottom>, <adjective> <bottom>"
|
| 31 |
+
# Category 10: footwear:
|
| 32 |
+
# "<color> <footwear>, <adjective> <footwear>, <adjective> <footwear>"
|
| 33 |
+
# Category 11: headwear:
|
| 34 |
+
# "<color> <headwear> headwear"
|
| 35 |
+
#
|
| 36 |
+
# Precision > token cost > political correctness, tuned for literal image generators.
|
| 37 |
+
# ------------------------------------------------------------
|
| 38 |
+
|
| 39 |
+
class Wildcard_2:
|
| 40 |
+
|
| 41 |
+
@classmethod
|
| 42 |
+
def INPUT_TYPES(cls):
|
| 43 |
+
return {
|
| 44 |
+
"required": {
|
| 45 |
+
"seed": ("INT", {
|
| 46 |
+
"default": 0,
|
| 47 |
+
"min": -1,
|
| 48 |
+
"max": 2**31 - 1,
|
| 49 |
+
"step": 1
|
| 50 |
+
}),
|
| 51 |
+
},
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
RETURN_TYPES = ("STRING", "STRING")
|
| 55 |
+
RETURN_NAMES = ("female_prompt", "male_prompt")
|
| 56 |
+
FUNCTION = "generate"
|
| 57 |
+
CATEGORY = "prompt/wildcards"
|
| 58 |
+
|
| 59 |
+
# -----------------------------
|
| 60 |
+
# Core public entry point
|
| 61 |
+
# -----------------------------
|
| 62 |
+
def generate(self, seed: int):
|
| 63 |
+
# Seed handling:
|
| 64 |
+
# seed >= 0 -> deterministic
|
| 65 |
+
# seed < 0 -> non-deterministic (system randomness)
|
| 66 |
+
if seed >= 0:
|
| 67 |
+
rng = random.Random(seed)
|
| 68 |
+
else:
|
| 69 |
+
rng = random.Random()
|
| 70 |
+
|
| 71 |
+
# Generate base traits once so male & female versions match
|
| 72 |
+
base_traits = self._generate_base_traits(rng)
|
| 73 |
+
|
| 74 |
+
female_prompt = self._build_prompt(base_traits, gender="female")
|
| 75 |
+
male_prompt = self._build_prompt(base_traits, gender="male")
|
| 76 |
+
|
| 77 |
+
return (female_prompt, male_prompt)
|
| 78 |
+
|
| 79 |
+
# -----------------------------
|
| 80 |
+
# Base trait randomization
|
| 81 |
+
# -----------------------------
|
| 82 |
+
def _generate_base_traits(self, rng: random.Random) -> dict:
|
| 83 |
+
# Camera POV (LEFTSIDE / RIGHTSIDE in caps where used)
|
| 84 |
+
camera_povs = [
|
| 85 |
+
"straight-on",
|
| 86 |
+
"Frontview",
|
| 87 |
+
"Diagonal LEFTSIDE",
|
| 88 |
+
"Three Quarter View LEFTSIDE",
|
| 89 |
+
"Sideview LEFTSIDE",
|
| 90 |
+
"frontview POV",
|
| 91 |
+
"Sideview RIGHTSIDE",
|
| 92 |
+
"Three Quarter View RIGHTSIDE",
|
| 93 |
+
]
|
| 94 |
+
camera_pov = rng.choice(camera_povs)
|
| 95 |
+
|
| 96 |
+
# Age bucket decides Category 3 word for each gender
|
| 97 |
+
age_buckets = ["young", "adult", "old"]
|
| 98 |
+
age_bucket = rng.choice(age_buckets)
|
| 99 |
+
|
| 100 |
+
# Social + inner personality traits (Category 4)
|
| 101 |
+
social_traits = [
|
| 102 |
+
"rich",
|
| 103 |
+
"high-class",
|
| 104 |
+
"middle-class",
|
| 105 |
+
"low-class",
|
| 106 |
+
"noble",
|
| 107 |
+
"royal",
|
| 108 |
+
"commoner",
|
| 109 |
+
"servant",
|
| 110 |
+
"outcast",
|
| 111 |
+
"scholar",
|
| 112 |
+
"warrior",
|
| 113 |
+
"mercenary",
|
| 114 |
+
"assassin",
|
| 115 |
+
"hunter",
|
| 116 |
+
"merchant",
|
| 117 |
+
"priestly",
|
| 118 |
+
"streetwise",
|
| 119 |
+
"criminal",
|
| 120 |
+
]
|
| 121 |
+
inner_traits = [
|
| 122 |
+
"sadistic",
|
| 123 |
+
"kind",
|
| 124 |
+
"shy",
|
| 125 |
+
"cheerful",
|
| 126 |
+
"cold",
|
| 127 |
+
"calculating",
|
| 128 |
+
"lonely",
|
| 129 |
+
"obsessive",
|
| 130 |
+
"playful",
|
| 131 |
+
"stoic",
|
| 132 |
+
"anxious",
|
| 133 |
+
"confident",
|
| 134 |
+
"sarcastic",
|
| 135 |
+
"gentle",
|
| 136 |
+
]
|
| 137 |
+
social_trait = rng.choice(social_traits)
|
| 138 |
+
inner_trait = rng.choice(inner_traits)
|
| 139 |
+
|
| 140 |
+
# Skin tones (avoid ambiguous 'colored' wording)
|
| 141 |
+
skin_tones = [
|
| 142 |
+
"very pale skincolor",
|
| 143 |
+
"fair skincolor",
|
| 144 |
+
"light tan skincolor",
|
| 145 |
+
"tan skincolor",
|
| 146 |
+
"olive skincolor",
|
| 147 |
+
"medium brown skincolor",
|
| 148 |
+
"dark brown skincolor",
|
| 149 |
+
"freckled skincolor",
|
| 150 |
+
]
|
| 151 |
+
skin_tone = rng.choice(skin_tones)
|
| 152 |
+
|
| 153 |
+
# Eyes
|
| 154 |
+
eye_colors = [
|
| 155 |
+
"blue eyes",
|
| 156 |
+
"green eyes",
|
| 157 |
+
"grey eyes",
|
| 158 |
+
"brown eyes",
|
| 159 |
+
"hazel eyes",
|
| 160 |
+
"amber eyes",
|
| 161 |
+
"dark brown eyes",
|
| 162 |
+
"pale blue eyes",
|
| 163 |
+
"violet eyes",
|
| 164 |
+
]
|
| 165 |
+
eye_styles = [
|
| 166 |
+
"sharp eyes",
|
| 167 |
+
"soft eyes",
|
| 168 |
+
"narrow eyes",
|
| 169 |
+
"wide eyes",
|
| 170 |
+
"sleepy eyes",
|
| 171 |
+
"intense eyes",
|
| 172 |
+
"cold eyes",
|
| 173 |
+
"warm eyes",
|
| 174 |
+
"round eyes",
|
| 175 |
+
]
|
| 176 |
+
eye_directions = [
|
| 177 |
+
"",
|
| 178 |
+
]
|
| 179 |
+
eye_color = rng.choice(eye_colors)
|
| 180 |
+
eye_style = rng.choice(eye_styles)
|
| 181 |
+
eye_direction = rng.choice(eye_directions)
|
| 182 |
+
|
| 183 |
+
# Hair (color, length, style)
|
| 184 |
+
hair_colors = [
|
| 185 |
+
"black hair",
|
| 186 |
+
"dark brown hair",
|
| 187 |
+
"brown hair",
|
| 188 |
+
"light brown hair",
|
| 189 |
+
"blonde hair",
|
| 190 |
+
"platinum blonde hair",
|
| 191 |
+
"ginger hair", # use 'ginger' instead of 'red hair'
|
| 192 |
+
"silver hair",
|
| 193 |
+
"white hair",
|
| 194 |
+
"blue hair",
|
| 195 |
+
"pink hair",
|
| 196 |
+
"purple hair",
|
| 197 |
+
]
|
| 198 |
+
hair_lengths = [
|
| 199 |
+
"very short hair",
|
| 200 |
+
"short hair",
|
| 201 |
+
"medium length hair",
|
| 202 |
+
"long hair",
|
| 203 |
+
"very long hair",
|
| 204 |
+
"waist-length hair",
|
| 205 |
+
]
|
| 206 |
+
hair_styles = [
|
| 207 |
+
"straight hair",
|
| 208 |
+
"wavy hair",
|
| 209 |
+
"curly hair",
|
| 210 |
+
"messy hair",
|
| 211 |
+
"braided hair",
|
| 212 |
+
"spiky hair",
|
| 213 |
+
"neatly combed hair",
|
| 214 |
+
]
|
| 215 |
+
hair_color = rng.choice(hair_colors)
|
| 216 |
+
hair_length = rng.choice(hair_lengths)
|
| 217 |
+
hair_style = rng.choice(hair_styles)
|
| 218 |
+
|
| 219 |
+
# Generic color palette for clothing and accessories
|
| 220 |
+
clothing_colors = [
|
| 221 |
+
"black",
|
| 222 |
+
"white",
|
| 223 |
+
"grey",
|
| 224 |
+
"brown",
|
| 225 |
+
"beige",
|
| 226 |
+
"red",
|
| 227 |
+
"blue",
|
| 228 |
+
"navy",
|
| 229 |
+
"green",
|
| 230 |
+
"yellow",
|
| 231 |
+
"purple",
|
| 232 |
+
"pink",
|
| 233 |
+
]
|
| 234 |
+
|
| 235 |
+
# Top garment
|
| 236 |
+
top_types = [
|
| 237 |
+
"shirt",
|
| 238 |
+
"blouse",
|
| 239 |
+
"jacket",
|
| 240 |
+
"coat",
|
| 241 |
+
"sweater",
|
| 242 |
+
"hoodie",
|
| 243 |
+
"turtleneck",
|
| 244 |
+
"robe",
|
| 245 |
+
"vest",
|
| 246 |
+
]
|
| 247 |
+
top_materials = [
|
| 248 |
+
"cotton",
|
| 249 |
+
"linen",
|
| 250 |
+
"silk",
|
| 251 |
+
"wool",
|
| 252 |
+
"leather",
|
| 253 |
+
"denim",
|
| 254 |
+
"canvas",
|
| 255 |
+
]
|
| 256 |
+
top_adjectives = [
|
| 257 |
+
"simple",
|
| 258 |
+
"elegant",
|
| 259 |
+
"torn",
|
| 260 |
+
"baggy",
|
| 261 |
+
"tight",
|
| 262 |
+
"oversized",
|
| 263 |
+
"patterned",
|
| 264 |
+
"striped",
|
| 265 |
+
"checkered",
|
| 266 |
+
"decorated",
|
| 267 |
+
"embroidered",
|
| 268 |
+
"formal",
|
| 269 |
+
"casual",
|
| 270 |
+
]
|
| 271 |
+
top_type = rng.choice(top_types)
|
| 272 |
+
top_color = rng.choice(clothing_colors)
|
| 273 |
+
top_material = rng.choice(top_materials)
|
| 274 |
+
top_adjective = rng.choice(top_adjectives)
|
| 275 |
+
|
| 276 |
+
# Skirt
|
| 277 |
+
skirt_colors = clothing_colors
|
| 278 |
+
skirt_materials = [
|
| 279 |
+
"cotton",
|
| 280 |
+
"linen",
|
| 281 |
+
"wool",
|
| 282 |
+
"silk",
|
| 283 |
+
"leather",
|
| 284 |
+
"denim",
|
| 285 |
+
"fur",
|
| 286 |
+
]
|
| 287 |
+
skirt_adjectives = [
|
| 288 |
+
"short",
|
| 289 |
+
"knee-length",
|
| 290 |
+
"long",
|
| 291 |
+
"pleated",
|
| 292 |
+
"frilled",
|
| 293 |
+
"flowing",
|
| 294 |
+
"tight",
|
| 295 |
+
"dotted",
|
| 296 |
+
"checkered",
|
| 297 |
+
"patterned",
|
| 298 |
+
]
|
| 299 |
+
skirt_color = rng.choice(skirt_colors)
|
| 300 |
+
skirt_material = rng.choice(skirt_materials)
|
| 301 |
+
skirt_adjective = rng.choice(skirt_adjectives)
|
| 302 |
+
|
| 303 |
+
# Bottom garment (pants / shorts / jeans / leggings, etc.)
|
| 304 |
+
bottom_types = [
|
| 305 |
+
"pants",
|
| 306 |
+
"trousers",
|
| 307 |
+
"jeans",
|
| 308 |
+
"shorts",
|
| 309 |
+
"leggings",
|
| 310 |
+
]
|
| 311 |
+
bottom_materials = [
|
| 312 |
+
"cotton",
|
| 313 |
+
"linen",
|
| 314 |
+
"wool",
|
| 315 |
+
"denim",
|
| 316 |
+
"leather",
|
| 317 |
+
"synthetic",
|
| 318 |
+
]
|
| 319 |
+
bottom_adjectives = [
|
| 320 |
+
"fluffy",
|
| 321 |
+
"baggy",
|
| 322 |
+
"tight",
|
| 323 |
+
"ripped",
|
| 324 |
+
"formal",
|
| 325 |
+
"casual",
|
| 326 |
+
"loose",
|
| 327 |
+
"high-waist",
|
| 328 |
+
"low-waist",
|
| 329 |
+
]
|
| 330 |
+
bottom_type = rng.choice(bottom_types)
|
| 331 |
+
bottom_color = rng.choice(clothing_colors)
|
| 332 |
+
bottom_material = rng.choice(bottom_materials)
|
| 333 |
+
bottom_adjective = rng.choice(bottom_adjectives)
|
| 334 |
+
|
| 335 |
+
# Footwear
|
| 336 |
+
footwear_types = [
|
| 337 |
+
"boots",
|
| 338 |
+
"shoes",
|
| 339 |
+
"sneakers",
|
| 340 |
+
"sandals",
|
| 341 |
+
"high heels",
|
| 342 |
+
"loafers",
|
| 343 |
+
]
|
| 344 |
+
footwear_adjectives = [
|
| 345 |
+
"long", # works for boots (long boots)
|
| 346 |
+
"ankle-high",
|
| 347 |
+
"knee-high",
|
| 348 |
+
"lace-up",
|
| 349 |
+
"high-heeled",
|
| 350 |
+
"elegant",
|
| 351 |
+
"sturdy",
|
| 352 |
+
"worn",
|
| 353 |
+
"dirty",
|
| 354 |
+
"polished",
|
| 355 |
+
]
|
| 356 |
+
footwear_type = rng.choice(footwear_types)
|
| 357 |
+
footwear_color = rng.choice(clothing_colors)
|
| 358 |
+
# ensure two different adjectives if possible
|
| 359 |
+
fw_adj1 = rng.choice(footwear_adjectives)
|
| 360 |
+
fw_adj2_options = [a for a in footwear_adjectives if a != fw_adj1]
|
| 361 |
+
fw_adj2 = rng.choice(fw_adj2_options) if fw_adj2_options else fw_adj1
|
| 362 |
+
|
| 363 |
+
# Headwear
|
| 364 |
+
headwear_types = [
|
| 365 |
+
"tiara",
|
| 366 |
+
"crown",
|
| 367 |
+
"hat",
|
| 368 |
+
"beret",
|
| 369 |
+
"beanie",
|
| 370 |
+
"headband",
|
| 371 |
+
"hood",
|
| 372 |
+
"helmet",
|
| 373 |
+
"cap",
|
| 374 |
+
"fedora",
|
| 375 |
+
"top hat",
|
| 376 |
+
"bowler hat",
|
| 377 |
+
"straw hat",
|
| 378 |
+
"sun hat",
|
| 379 |
+
"bucket hat",
|
| 380 |
+
"boater hat",
|
| 381 |
+
"panama hat",
|
| 382 |
+
"cloche hat",
|
| 383 |
+
"pillbox hat",
|
| 384 |
+
"fascinator",
|
| 385 |
+
"wide-brim hat",
|
| 386 |
+
"cowboy hat",
|
| 387 |
+
"sombrero",
|
| 388 |
+
"safari hat",
|
| 389 |
+
"pith helmet",
|
| 390 |
+
"trilby",
|
| 391 |
+
"newsboy cap",
|
| 392 |
+
"flat cap",
|
| 393 |
+
"ivy cap",
|
| 394 |
+
"driver cap",
|
| 395 |
+
"baseball cap",
|
| 396 |
+
"snapback cap",
|
| 397 |
+
"trucker cap",
|
| 398 |
+
"visor",
|
| 399 |
+
"sun visor",
|
| 400 |
+
"party cone hat",
|
| 401 |
+
"birthday hat",
|
| 402 |
+
"graduation cap",
|
| 403 |
+
"mortarboard",
|
| 404 |
+
"chef hat",
|
| 405 |
+
"toque",
|
| 406 |
+
"nurse cap",
|
| 407 |
+
"maid headband",
|
| 408 |
+
"sailor cap",
|
| 409 |
+
"military cap",
|
| 410 |
+
"officer cap",
|
| 411 |
+
"forage cap",
|
| 412 |
+
"garrison cap",
|
| 413 |
+
"tam o'shanter",
|
| 414 |
+
"deerstalker hat",
|
| 415 |
+
"ushanka",
|
| 416 |
+
"trapper hat",
|
| 417 |
+
"winter hat",
|
| 418 |
+
"knit cap",
|
| 419 |
+
"pom-pom beanie",
|
| 420 |
+
"ski cap",
|
| 421 |
+
"balaclava",
|
| 422 |
+
"hooded cloak",
|
| 423 |
+
"cowl hood",
|
| 424 |
+
"earmuffs",
|
| 425 |
+
"earflap hat",
|
| 426 |
+
"rain hat",
|
| 427 |
+
"oilskin hat",
|
| 428 |
+
"hard hat",
|
| 429 |
+
"construction helmet",
|
| 430 |
+
"miner helmet",
|
| 431 |
+
"bike helmet",
|
| 432 |
+
"motorcycle helmet",
|
| 433 |
+
"combat helmet",
|
| 434 |
+
"riot helmet",
|
| 435 |
+
"samurai helmet",
|
| 436 |
+
"horned helmet",
|
| 437 |
+
"viking helmet",
|
| 438 |
+
"roman helmet",
|
| 439 |
+
"spartan helmet",
|
| 440 |
+
"space helmet",
|
| 441 |
+
"astronaut helmet",
|
| 442 |
+
"pilot cap",
|
| 443 |
+
"flight helmet",
|
| 444 |
+
"aviator cap",
|
| 445 |
+
"swim cap",
|
| 446 |
+
"shower cap",
|
| 447 |
+
"sleeping cap",
|
| 448 |
+
"nightcap",
|
| 449 |
+
"veil",
|
| 450 |
+
"veiled hat",
|
| 451 |
+
"lace headscarf",
|
| 452 |
+
"headscarf",
|
| 453 |
+
"bandana",
|
| 454 |
+
"kerchief",
|
| 455 |
+
"turban",
|
| 456 |
+
"keffiyeh",
|
| 457 |
+
"wrapped headscarf",
|
| 458 |
+
"flower crown",
|
| 459 |
+
"floral wreath",
|
| 460 |
+
"leaf crown",
|
| 461 |
+
"laurel wreath",
|
| 462 |
+
"circlet",
|
| 463 |
+
"halo headband",
|
| 464 |
+
"sports headband",
|
| 465 |
+
"sweatband",
|
| 466 |
+
"visor cap",
|
| 467 |
+
"wizard hat",
|
| 468 |
+
"witch hat",
|
| 469 |
+
"magician hat",
|
| 470 |
+
"jester hat",
|
| 471 |
+
"animal-ear headband",
|
| 472 |
+
"horn headband",
|
| 473 |
+
"antenna headband",
|
| 474 |
+
"visor",
|
| 475 |
+
"sunhat",
|
| 476 |
+
"fedora",
|
| 477 |
+
"bowler hat",
|
| 478 |
+
"top hat",
|
| 479 |
+
"trilby",
|
| 480 |
+
"bucket hat",
|
| 481 |
+
"boater hat",
|
| 482 |
+
"newsboy cap",
|
| 483 |
+
"flat cap",
|
| 484 |
+
"snapback cap",
|
| 485 |
+
"baseball cap",
|
| 486 |
+
"cowboy hat",
|
| 487 |
+
"wide-brim hat",
|
| 488 |
+
"straw hat",
|
| 489 |
+
"panama hat",
|
| 490 |
+
"safari hat",
|
| 491 |
+
"rain hat",
|
| 492 |
+
"fur hat",
|
| 493 |
+
"ushanka hat",
|
| 494 |
+
"ski cap",
|
| 495 |
+
"earflap hat",
|
| 496 |
+
"turban",
|
| 497 |
+
"headscarf",
|
| 498 |
+
"bandana",
|
| 499 |
+
"kerchief",
|
| 500 |
+
"hooded cloak",
|
| 501 |
+
"wizard hat",
|
| 502 |
+
"witch hat",
|
| 503 |
+
"party hat",
|
| 504 |
+
"chef hat",
|
| 505 |
+
"nurse cap",
|
| 506 |
+
"military cap",
|
| 507 |
+
"officer cap",
|
| 508 |
+
"combat helmet",
|
| 509 |
+
"biker helmet",
|
| 510 |
+
"space helmet",
|
| 511 |
+
"pilot cap",
|
| 512 |
+
"aviator helmet",
|
| 513 |
+
"construction helmet",
|
| 514 |
+
"hard hat",
|
| 515 |
+
"diving helmet",
|
| 516 |
+
"knight helmet",
|
| 517 |
+
"samurai helmet",
|
| 518 |
+
"viking helmet",
|
| 519 |
+
"horned helmet",
|
| 520 |
+
"circlet",
|
| 521 |
+
"laurel wreath",
|
| 522 |
+
"flower crown",
|
| 523 |
+
"veil",
|
| 524 |
+
"bridal veil",
|
| 525 |
+
"fascinator",
|
| 526 |
+
"pillbox hat",
|
| 527 |
+
"cloche hat",
|
| 528 |
+
"mob cap",
|
| 529 |
+
"nightcap",
|
| 530 |
+
"sleeping cap",
|
| 531 |
+
"sailor cap",
|
| 532 |
+
"conductor cap",
|
| 533 |
+
"police cap",
|
| 534 |
+
"firefighter helmet",
|
| 535 |
+
"ranger hat",
|
| 536 |
+
"tactical helmet",
|
| 537 |
+
"bike helmet",
|
| 538 |
+
"sports visor",
|
| 539 |
+
"golf cap",
|
| 540 |
+
"hunting cap",
|
| 541 |
+
"trapper hat",
|
| 542 |
+
"tam o'shanter",
|
| 543 |
+
"deerstalker hat",
|
| 544 |
+
"santa hat",
|
| 545 |
+
"jester hat",
|
| 546 |
+
"carnival mask",
|
| 547 |
+
"masquerade mask",
|
| 548 |
+
"plague doctor mask",
|
| 549 |
+
"gas mask",
|
| 550 |
+
"earmuffs",
|
| 551 |
+
"cowl",
|
| 552 |
+
"balaclava",
|
| 553 |
+
"ski mask",
|
| 554 |
+
"hooded scarf",
|
| 555 |
+
"head wrap",
|
| 556 |
+
"shawl hood",
|
| 557 |
+
"animal hood",
|
| 558 |
+
"wolf hood",
|
| 559 |
+
"cat ear headband",
|
| 560 |
+
"bear ear headband",
|
| 561 |
+
"devil horn headband",
|
| 562 |
+
"bunny ear headband",
|
| 563 |
+
"antenna headband",
|
| 564 |
+
"spiked crown",
|
| 565 |
+
"metal halo",
|
| 566 |
+
"glowing halo",
|
| 567 |
+
"tiara crown",
|
| 568 |
+
"opera hat",
|
| 569 |
+
"feathered hat",
|
| 570 |
+
"fur hood",
|
| 571 |
+
"rain hood",
|
| 572 |
+
"straw bonnet",
|
| 573 |
+
"bonnet",
|
| 574 |
+
]
|
| 575 |
+
headwear_color = rng.choice(clothing_colors)
|
| 576 |
+
headwear_type = rng.choice(headwear_types)
|
| 577 |
+
|
| 578 |
+
return {
|
| 579 |
+
"camera_pov": camera_pov,
|
| 580 |
+
"age_bucket": age_bucket,
|
| 581 |
+
"social_trait": social_trait,
|
| 582 |
+
"inner_trait": inner_trait,
|
| 583 |
+
"skin_tone": skin_tone,
|
| 584 |
+
"eye_color": eye_color,
|
| 585 |
+
"eye_style": eye_style,
|
| 586 |
+
"eye_direction": eye_direction,
|
| 587 |
+
"hair_color": hair_color,
|
| 588 |
+
"hair_length": hair_length,
|
| 589 |
+
"hair_style": hair_style,
|
| 590 |
+
"top_color": top_color,
|
| 591 |
+
"top_material": top_material,
|
| 592 |
+
"top_adjective": top_adjective,
|
| 593 |
+
"top_type": top_type,
|
| 594 |
+
"skirt_color": skirt_color,
|
| 595 |
+
"skirt_material": skirt_material,
|
| 596 |
+
"skirt_adjective": skirt_adjective,
|
| 597 |
+
"bottom_color": bottom_color,
|
| 598 |
+
"bottom_material": bottom_material,
|
| 599 |
+
"bottom_adjective": bottom_adjective,
|
| 600 |
+
"bottom_type": bottom_type,
|
| 601 |
+
"footwear_color": footwear_color,
|
| 602 |
+
"footwear_type": footwear_type,
|
| 603 |
+
"footwear_adj1": fw_adj1,
|
| 604 |
+
"footwear_adj2": fw_adj2,
|
| 605 |
+
"headwear_color": headwear_color,
|
| 606 |
+
"headwear_type": headwear_type,
|
| 607 |
+
}
|
| 608 |
+
|
| 609 |
+
# -----------------------------
|
| 610 |
+
# Prompt assembly
|
| 611 |
+
# -----------------------------
|
| 612 |
+
def _build_prompt(self, base: dict, gender: str) -> str:
|
| 613 |
+
# gender: "female" or "male"
|
| 614 |
+
assert gender in ("female", "male")
|
| 615 |
+
|
| 616 |
+
# Category 1: "1girl" or "1boy"
|
| 617 |
+
if gender == "female":
|
| 618 |
+
cat1 = "1girl"
|
| 619 |
+
else:
|
| 620 |
+
cat1 = "1boy"
|
| 621 |
+
|
| 622 |
+
# Category 3: age word ("woman"/"man"/"girl"/"boy"/"grandma"/"grandpa")
|
| 623 |
+
age_bucket = base["age_bucket"]
|
| 624 |
+
if gender == "female":
|
| 625 |
+
if age_bucket == "young":
|
| 626 |
+
age_word = "girl"
|
| 627 |
+
elif age_bucket == "adult":
|
| 628 |
+
age_word = "woman"
|
| 629 |
+
else:
|
| 630 |
+
age_word = "loli"
|
| 631 |
+
else:
|
| 632 |
+
if age_bucket == "young":
|
| 633 |
+
age_word = "boy"
|
| 634 |
+
elif age_bucket == "adult":
|
| 635 |
+
age_word = "man"
|
| 636 |
+
else:
|
| 637 |
+
age_word = "shota"
|
| 638 |
+
|
| 639 |
+
# Category 4: social + inner personality descriptors that use the age_word
|
| 640 |
+
social_token = f"{base['social_trait']} {age_word}"
|
| 641 |
+
inner_token = f"{base['inner_trait']} {age_word}"
|
| 642 |
+
|
| 643 |
+
# Category 5: eyes (color, style, direction)
|
| 644 |
+
eye_color = base["eye_color"] # already contains "eyes"
|
| 645 |
+
eye_style = base["eye_style"] # already contains "eyes"
|
| 646 |
+
eye_direction = base["eye_direction"] # already contains "eyes"
|
| 647 |
+
|
| 648 |
+
# Category 6: hair
|
| 649 |
+
hair_color = base["hair_color"]
|
| 650 |
+
hair_length = base["hair_length"]
|
| 651 |
+
hair_style = base["hair_style"]
|
| 652 |
+
|
| 653 |
+
# Category 7: top garment
|
| 654 |
+
top_color = f"{base['top_color']} {base['top_type']}"
|
| 655 |
+
top_material = f"{base['top_material']} {base['top_type']}"
|
| 656 |
+
top_adjective = f"{base['top_adjective']} {base['top_type']}"
|
| 657 |
+
|
| 658 |
+
# Category 8: skirt
|
| 659 |
+
skirt_color = f"{base['skirt_color']} skirt"
|
| 660 |
+
skirt_material = f"{base['skirt_material']} skirt"
|
| 661 |
+
skirt_adjective = f"{base['skirt_adjective']} skirt"
|
| 662 |
+
|
| 663 |
+
# Category 9: bottom garment (pants etc.)
|
| 664 |
+
bottom_color = f"{base['bottom_color']} {base['bottom_type']}"
|
| 665 |
+
bottom_material = f"{base['bottom_material']} {base['bottom_type']}"
|
| 666 |
+
bottom_adjective = f"{base['bottom_adjective']} {base['bottom_type']}"
|
| 667 |
+
|
| 668 |
+
# Category 10: footwear
|
| 669 |
+
footwear_color = f"{base['footwear_color']} {base['footwear_type']}"
|
| 670 |
+
footwear_adj1 = f"{base['footwear_adj1']} {base['footwear_type']}"
|
| 671 |
+
footwear_adj2 = f"{base['footwear_adj2']} {base['footwear_type']}"
|
| 672 |
+
|
| 673 |
+
# Category 11: headwear
|
| 674 |
+
headwear = f"{base['headwear_color']} {base['headwear_type']} headwear"
|
| 675 |
+
|
| 676 |
+
# Assemble all tokens in the logical order of your template
|
| 677 |
+
tokens = [
|
| 678 |
+
cat1, # Category 1
|
| 679 |
+
base["camera_pov"], # Category 2
|
| 680 |
+
age_word, # Category 3
|
| 681 |
+
social_token, # Category 4 (social)
|
| 682 |
+
inner_token, # Category 4 (inner)
|
| 683 |
+
base["skin_tone"], # skincolor descriptor
|
| 684 |
+
eye_color, eye_style, eye_direction, # Category 5
|
| 685 |
+
hair_color, hair_length, hair_style, # Category 6
|
| 686 |
+
top_color, top_material, top_adjective, # Category 7
|
| 687 |
+
skirt_color, skirt_material, skirt_adjective, # Category 8
|
| 688 |
+
bottom_color, bottom_material, bottom_adjective, # Category 9
|
| 689 |
+
footwear_color, footwear_adj1, footwear_adj2, # Category 10
|
| 690 |
+
headwear, # Category 11
|
| 691 |
+
]
|
| 692 |
+
|
| 693 |
+
# Join tokens into a single prompt
|
| 694 |
+
prompt = ", ".join(tokens) + "."
|
| 695 |
+
return prompt
|
| 696 |
+
|
| 697 |
+
|
| 698 |
+
# ------------------------------------------------------------
|
| 699 |
+
# ComfyUI node registration
|
| 700 |
+
# ------------------------------------------------------------
|
| 701 |
+
|
| 702 |
+
NODE_CLASS_MAPPINGS = {
|
| 703 |
+
"Wildcard_2": Wildcard_2,
|
| 704 |
+
}
|
| 705 |
+
|
| 706 |
+
NODE_DISPLAY_NAME_MAPPINGS = {
|
| 707 |
+
"Wildcard_2": "Wildcard_2",
|
| 708 |
+
}
|
wildcard_4.py
ADDED
|
@@ -0,0 +1,535 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import random
|
| 2 |
+
|
| 3 |
+
class Wildcard_4:
|
| 4 |
+
"""
|
| 5 |
+
ComfyUI custom node:
|
| 6 |
+
Takes a seed and generates a pair of matching wildcard prompts:
|
| 7 |
+
- one female-focused ("1girl")
|
| 8 |
+
- one male-focused ("1boy")
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
@classmethod
|
| 12 |
+
def INPUT_TYPES(cls):
|
| 13 |
+
return {
|
| 14 |
+
"required": {
|
| 15 |
+
"seed": ("INT", {
|
| 16 |
+
"default": 0,
|
| 17 |
+
"min": 0,
|
| 18 |
+
"max": 0x7FFFFFFF,
|
| 19 |
+
"step": 1,
|
| 20 |
+
}),
|
| 21 |
+
},
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
RETURN_TYPES = ("STRING", "STRING",)
|
| 25 |
+
RETURN_NAMES = ("female_prompt", "male_prompt",)
|
| 26 |
+
FUNCTION = "generate"
|
| 27 |
+
CATEGORY = "wildcards/prompt"
|
| 28 |
+
|
| 29 |
+
# -------- core random building blocks --------
|
| 30 |
+
|
| 31 |
+
def _select_age_group(self, rng: random.Random):
|
| 32 |
+
# young / adult / elder - affects the noun in category 3
|
| 33 |
+
return rng.choice(["young", "adult", "kid"])
|
| 34 |
+
|
| 35 |
+
def _age_noun(self, variant: str, age_group: str) -> str:
|
| 36 |
+
# variant: "female" or "male"
|
| 37 |
+
if variant == "female":
|
| 38 |
+
if age_group == "young":
|
| 39 |
+
return "girl"
|
| 40 |
+
elif age_group == "kid":
|
| 41 |
+
return "loli"
|
| 42 |
+
else:
|
| 43 |
+
return "woman"
|
| 44 |
+
else:
|
| 45 |
+
if age_group == "young":
|
| 46 |
+
return "boy"
|
| 47 |
+
elif age_group == "kid":
|
| 48 |
+
return "shota"
|
| 49 |
+
else:
|
| 50 |
+
return "man"
|
| 51 |
+
|
| 52 |
+
def _camera_pov(self, rng: random.Random) -> str:
|
| 53 |
+
# Category 2: POV of camera – 8 directions, LEFTSIDE/RIGHTSIDE in caps
|
| 54 |
+
pov_options = [
|
| 55 |
+
"straight-on",
|
| 56 |
+
"diagonal LEFTSIDE",
|
| 57 |
+
"sideview LEFTSIDE",
|
| 58 |
+
"straight-on",
|
| 59 |
+
"sideview RIGHTSIDE",
|
| 60 |
+
"diagonal RIGHTSIDE",
|
| 61 |
+
"low-angle view from below",
|
| 62 |
+
]
|
| 63 |
+
return rng.choice(pov_options)
|
| 64 |
+
|
| 65 |
+
def _skincolor(self, rng: random.Random) -> str:
|
| 66 |
+
# No "colored skincolor" nonsense; purely descriptive
|
| 67 |
+
options = [
|
| 68 |
+
"porcelain skincolor",
|
| 69 |
+
"pale skincolor",
|
| 70 |
+
"fair skincolor",
|
| 71 |
+
"light brown skincolor",
|
| 72 |
+
"sun-kissed tan skincolor",
|
| 73 |
+
"olive skincolor",
|
| 74 |
+
"warm brown skincolor",
|
| 75 |
+
"deep brown skincolor",
|
| 76 |
+
"ashen grey skincolor",
|
| 77 |
+
"golden bronze skincolor",
|
| 78 |
+
]
|
| 79 |
+
return rng.choice(options)
|
| 80 |
+
|
| 81 |
+
def _eyes(self, rng: random.Random):
|
| 82 |
+
# Category 5: eyecolor, eye-style, look direction – always with "eyes"
|
| 83 |
+
eye_colors = [
|
| 84 |
+
"blue", "green", "hazel", "amber",
|
| 85 |
+
"grey", "violet", "golden", "turquoise",
|
| 86 |
+
]
|
| 87 |
+
eye_styles = [
|
| 88 |
+
"sharp gaze",
|
| 89 |
+
"cold gaze",
|
| 90 |
+
"soft gaze",
|
| 91 |
+
"tired gaze",
|
| 92 |
+
"glowing gaze",
|
| 93 |
+
"mysterious gaze",
|
| 94 |
+
"intense gaze",
|
| 95 |
+
"dreamy gaze",
|
| 96 |
+
]
|
| 97 |
+
eye_directions = [
|
| 98 |
+
"",
|
| 99 |
+
]
|
| 100 |
+
color = rng.choice(eye_colors)
|
| 101 |
+
style = rng.choice(eye_styles)
|
| 102 |
+
direction = rng.choice(eye_directions)
|
| 103 |
+
return [
|
| 104 |
+
f"{color} eyes",
|
| 105 |
+
f"{style} eyes",
|
| 106 |
+
f"{direction} eyes",
|
| 107 |
+
]
|
| 108 |
+
|
| 109 |
+
def _hair(self, rng: random.Random):
|
| 110 |
+
# Category 6: hair (color, length, hairstyle), note: no "red hair" – use "ginger"
|
| 111 |
+
hair_colors = [
|
| 112 |
+
"black",
|
| 113 |
+
"white",
|
| 114 |
+
"silver",
|
| 115 |
+
"ginger",
|
| 116 |
+
"copper",
|
| 117 |
+
"dark brown",
|
| 118 |
+
"chestnut",
|
| 119 |
+
"platinum blonde",
|
| 120 |
+
"strawberry blonde",
|
| 121 |
+
"midnight blue",
|
| 122 |
+
"lavender",
|
| 123 |
+
]
|
| 124 |
+
hair_lengths = [
|
| 125 |
+
"very short",
|
| 126 |
+
"short",
|
| 127 |
+
"shoulder-length",
|
| 128 |
+
"long",
|
| 129 |
+
"very long",
|
| 130 |
+
"waist-length",
|
| 131 |
+
"ankle-length",
|
| 132 |
+
]
|
| 133 |
+
hair_styles = [
|
| 134 |
+
"straight",
|
| 135 |
+
"wavy",
|
| 136 |
+
"curly",
|
| 137 |
+
"messy",
|
| 138 |
+
"braided",
|
| 139 |
+
"twin braids",
|
| 140 |
+
"high ponytail",
|
| 141 |
+
"low ponytail",
|
| 142 |
+
"intricate updo",
|
| 143 |
+
"windswept",
|
| 144 |
+
"spiky",
|
| 145 |
+
]
|
| 146 |
+
color = rng.choice(hair_colors)
|
| 147 |
+
length = rng.choice(hair_lengths)
|
| 148 |
+
style = rng.choice(hair_styles)
|
| 149 |
+
return [
|
| 150 |
+
f"{color} hair",
|
| 151 |
+
f"{length} hair",
|
| 152 |
+
f"{style} hair",
|
| 153 |
+
]
|
| 154 |
+
|
| 155 |
+
def _top_garment(self, rng: random.Random):
|
| 156 |
+
# Category 7: top garment – color, material, descriptive adjective; same noun
|
| 157 |
+
garment_nouns = [
|
| 158 |
+
# basic tops
|
| 159 |
+
"shirt",
|
| 160 |
+
"t-shirt",
|
| 161 |
+
"tank top",
|
| 162 |
+
"crop top",
|
| 163 |
+
"blouse",
|
| 164 |
+
"dress shirt",
|
| 165 |
+
"polo shirt",
|
| 166 |
+
"long-sleeve shirt",
|
| 167 |
+
# fitted / structured
|
| 168 |
+
"vest",
|
| 169 |
+
"waistcoat",
|
| 170 |
+
"bodice",
|
| 171 |
+
"corset",
|
| 172 |
+
# knitwear
|
| 173 |
+
"sweater",
|
| 174 |
+
"jumper",
|
| 175 |
+
"cardigan",
|
| 176 |
+
"pullover",
|
| 177 |
+
"sweatshirt",
|
| 178 |
+
"hoodie",
|
| 179 |
+
# loose / draped
|
| 180 |
+
"poncho",
|
| 181 |
+
"tunic",
|
| 182 |
+
"smock",
|
| 183 |
+
# robes & kimonos
|
| 184 |
+
"kimono",
|
| 185 |
+
"haori",
|
| 186 |
+
"robe",
|
| 187 |
+
"cloak",
|
| 188 |
+
"cape",
|
| 189 |
+
# jackets & coats
|
| 190 |
+
"jacket",
|
| 191 |
+
"denim jacket",
|
| 192 |
+
"leather jacket",
|
| 193 |
+
"bomber jacket",
|
| 194 |
+
"biker jacket",
|
| 195 |
+
"puffer jacket",
|
| 196 |
+
"parka",
|
| 197 |
+
"trench coat",
|
| 198 |
+
"overcoat",
|
| 199 |
+
"coat",
|
| 200 |
+
"pea coat",
|
| 201 |
+
# fantasy / historical
|
| 202 |
+
"doublet",
|
| 203 |
+
"tabard",
|
| 204 |
+
"jersey",
|
| 205 |
+
"sports jersey",
|
| 206 |
+
"armor vest",
|
| 207 |
+
"breastplate",
|
| 208 |
+
"armor top",
|
| 209 |
+
]
|
| 210 |
+
colors = [
|
| 211 |
+
"red", "crimson", "blue", "navy", "emerald",
|
| 212 |
+
"black", "white", "grey", "brown", "tan",
|
| 213 |
+
"purple", "royal purple", "teal",
|
| 214 |
+
]
|
| 215 |
+
materials = [
|
| 216 |
+
"linen", "silk", "velvet", "cotton",
|
| 217 |
+
"leather", "chainmail", "satin", "wool",
|
| 218 |
+
"dragon-scale", "enchanted silk",
|
| 219 |
+
]
|
| 220 |
+
descriptors = [
|
| 221 |
+
"torn", "ornate", "simple", "elegant",
|
| 222 |
+
"battle-worn", "embroidered", "loose",
|
| 223 |
+
"tight-fitting", "ceremonial", "casual",
|
| 224 |
+
"fancy", "royal",
|
| 225 |
+
]
|
| 226 |
+
noun = rng.choice(garment_nouns)
|
| 227 |
+
color = rng.choice(colors)
|
| 228 |
+
material = rng.choice(materials)
|
| 229 |
+
descriptor = rng.choice(descriptors)
|
| 230 |
+
return [
|
| 231 |
+
f"{color} {noun}",
|
| 232 |
+
f"{material} {noun}",
|
| 233 |
+
f"{descriptor} {noun}",
|
| 234 |
+
]
|
| 235 |
+
|
| 236 |
+
def _skirt(self, rng: random.Random):
|
| 237 |
+
# Category 8: skirt – always skirt, color + length + descriptor
|
| 238 |
+
colors = [
|
| 239 |
+
"black", "brown", "white", "grey", "navy",
|
| 240 |
+
"deep red", "forest green", "midnight blue",
|
| 241 |
+
"burgundy", "ivory",
|
| 242 |
+
]
|
| 243 |
+
lengths = [
|
| 244 |
+
"short", "knee-length", "mid-length",
|
| 245 |
+
"long", "floor-length",
|
| 246 |
+
]
|
| 247 |
+
descriptors = [
|
| 248 |
+
"pleated", "ruffled", "fur", "layered",
|
| 249 |
+
"dotted", "striped", "checkered",
|
| 250 |
+
"embroidered", "shimmering", "tattered",
|
| 251 |
+
]
|
| 252 |
+
color = rng.choice(colors)
|
| 253 |
+
length = rng.choice(lengths)
|
| 254 |
+
descriptor = rng.choice(descriptors)
|
| 255 |
+
return [
|
| 256 |
+
f"{color} skirt",
|
| 257 |
+
f"{length} skirt",
|
| 258 |
+
f"{descriptor} skirt",
|
| 259 |
+
]
|
| 260 |
+
|
| 261 |
+
def _bottoms(self, rng: random.Random):
|
| 262 |
+
# Category 9: any bottom garment – but consistent noun
|
| 263 |
+
garment_nouns = [
|
| 264 |
+
# pants & trousers
|
| 265 |
+
"pants",
|
| 266 |
+
"trousers",
|
| 267 |
+
"jeans",
|
| 268 |
+
"skinny jeans",
|
| 269 |
+
"cargo pants",
|
| 270 |
+
"sweatpants",
|
| 271 |
+
"track pants",
|
| 272 |
+
"yoga pants",
|
| 273 |
+
"chinos",
|
| 274 |
+
"slacks",
|
| 275 |
+
"dress pants",
|
| 276 |
+
"khaki pants",
|
| 277 |
+
"work pants",
|
| 278 |
+
# tight legwear
|
| 279 |
+
"leggings",
|
| 280 |
+
"tights",
|
| 281 |
+
"stockings",
|
| 282 |
+
# shorts
|
| 283 |
+
"shorts",
|
| 284 |
+
"denim shorts",
|
| 285 |
+
"bike shorts",
|
| 286 |
+
"running shorts",
|
| 287 |
+
# cropped / alternative cuts
|
| 288 |
+
"capris",
|
| 289 |
+
"breeches",
|
| 290 |
+
"riding pants",
|
| 291 |
+
"hakama",
|
| 292 |
+
"culottes",
|
| 293 |
+
"joggers",
|
| 294 |
+
# fantasy / armor
|
| 295 |
+
"battle greaves",
|
| 296 |
+
]
|
| 297 |
+
colors = [
|
| 298 |
+
"black", "dark brown", "grey", "charcoal",
|
| 299 |
+
"olive", "navy", "sand-colored",
|
| 300 |
+
]
|
| 301 |
+
materials = [
|
| 302 |
+
"leather", "denim", "wool", "linen",
|
| 303 |
+
"padded", "scale-plated",
|
| 304 |
+
]
|
| 305 |
+
descriptors = [
|
| 306 |
+
"tailored", "baggy", "fluffy", "fitted",
|
| 307 |
+
"torn", "patched", "armored",
|
| 308 |
+
]
|
| 309 |
+
noun = rng.choice(garment_nouns)
|
| 310 |
+
color = rng.choice(colors)
|
| 311 |
+
material = rng.choice(materials)
|
| 312 |
+
descriptor = rng.choice(descriptors)
|
| 313 |
+
return [
|
| 314 |
+
f"{color} {noun}",
|
| 315 |
+
f"{material} {noun}",
|
| 316 |
+
f"{descriptor} {noun}",
|
| 317 |
+
]
|
| 318 |
+
|
| 319 |
+
def _footwear(self, rng: random.Random):
|
| 320 |
+
# Category 10: any footwear – color + two styles, same base noun
|
| 321 |
+
shoe_nouns = [
|
| 322 |
+
"boots",
|
| 323 |
+
"shoes",
|
| 324 |
+
"sandals",
|
| 325 |
+
"riding boots",
|
| 326 |
+
"combat boots",
|
| 327 |
+
"high-heeled boots",
|
| 328 |
+
]
|
| 329 |
+
colors = [
|
| 330 |
+
"black", "dark brown", "grey", "white",
|
| 331 |
+
"red", "crimson", "navy", "forest green",
|
| 332 |
+
]
|
| 333 |
+
styles = [
|
| 334 |
+
"long", "knee-high", "ankle", "lace-up",
|
| 335 |
+
"fur-lined", "armored", "worn", "polished",
|
| 336 |
+
"buckled",
|
| 337 |
+
]
|
| 338 |
+
noun = rng.choice(shoe_nouns)
|
| 339 |
+
color = rng.choice(colors)
|
| 340 |
+
style1, style2 = rng.sample(styles, 2)
|
| 341 |
+
return [
|
| 342 |
+
f"{color} {noun}",
|
| 343 |
+
f"{style1} {noun}",
|
| 344 |
+
f"{style2} {noun}",
|
| 345 |
+
]
|
| 346 |
+
|
| 347 |
+
def _headwear(self, rng: random.Random):
|
| 348 |
+
# HEADWEAR: color + thing + literal word "headwear" at the end
|
| 349 |
+
headpieces = [
|
| 350 |
+
# caps & casual
|
| 351 |
+
"cap",
|
| 352 |
+
"baseball cap",
|
| 353 |
+
"beanie",
|
| 354 |
+
"knit cap",
|
| 355 |
+
"watch cap",
|
| 356 |
+
"newsboy cap",
|
| 357 |
+
"flat cap",
|
| 358 |
+
# hats
|
| 359 |
+
"bucket hat",
|
| 360 |
+
"sun hat",
|
| 361 |
+
"wide-brim hat",
|
| 362 |
+
"straw hat",
|
| 363 |
+
"boater hat",
|
| 364 |
+
"panama hat",
|
| 365 |
+
"fedora",
|
| 366 |
+
"trilby",
|
| 367 |
+
"top hat",
|
| 368 |
+
"bowler hat",
|
| 369 |
+
"cowboy hat",
|
| 370 |
+
"sombrero",
|
| 371 |
+
"fur hat",
|
| 372 |
+
"ushanka",
|
| 373 |
+
# sport / utility
|
| 374 |
+
"visor",
|
| 375 |
+
"headband",
|
| 376 |
+
"bandana",
|
| 377 |
+
"balaclava",
|
| 378 |
+
# hoods & helmets
|
| 379 |
+
"hood",
|
| 380 |
+
"cloak hood",
|
| 381 |
+
"helmet",
|
| 382 |
+
"combat helmet",
|
| 383 |
+
"riding helmet",
|
| 384 |
+
"steel helm",
|
| 385 |
+
"open-face helm",
|
| 386 |
+
"closed helm",
|
| 387 |
+
"coif",
|
| 388 |
+
# crowns etc
|
| 389 |
+
"circlet",
|
| 390 |
+
"tiara",
|
| 391 |
+
"crown",
|
| 392 |
+
"laurel wreath",
|
| 393 |
+
"flower crown",
|
| 394 |
+
# veils / scarves
|
| 395 |
+
"veil",
|
| 396 |
+
"headscarf",
|
| 397 |
+
"kerchief",
|
| 398 |
+
# fantasy
|
| 399 |
+
"witch hat",
|
| 400 |
+
"wizard hat",
|
| 401 |
+
"officer cap",
|
| 402 |
+
]
|
| 403 |
+
colors = [
|
| 404 |
+
"black", "silver", "gold", "dark-grey",
|
| 405 |
+
"white", "red", "purple", "green",
|
| 406 |
+
]
|
| 407 |
+
color = rng.choice(colors)
|
| 408 |
+
piece = rng.choice(headpieces)
|
| 409 |
+
return f"{color} {piece} headwear"
|
| 410 |
+
|
| 411 |
+
def _social_inner_traits(self, rng: random.Random):
|
| 412 |
+
# Category 4: outer/social & inner personality
|
| 413 |
+
social_traits = [
|
| 414 |
+
"rich",
|
| 415 |
+
"noble",
|
| 416 |
+
"royal",
|
| 417 |
+
"streetwise",
|
| 418 |
+
"mysterious",
|
| 419 |
+
"famous",
|
| 420 |
+
"feared",
|
| 421 |
+
"holy",
|
| 422 |
+
"cursed",
|
| 423 |
+
"arcane",
|
| 424 |
+
]
|
| 425 |
+
inner_traits = [
|
| 426 |
+
"kind",
|
| 427 |
+
"melancholic",
|
| 428 |
+
"sadistic",
|
| 429 |
+
"playful",
|
| 430 |
+
"arrogant",
|
| 431 |
+
"stoic",
|
| 432 |
+
"cold-blooded",
|
| 433 |
+
"gentle",
|
| 434 |
+
"obsessive",
|
| 435 |
+
"scheming",
|
| 436 |
+
]
|
| 437 |
+
social = rng.choice(social_traits)
|
| 438 |
+
inner = rng.choice(inner_traits)
|
| 439 |
+
if inner == social:
|
| 440 |
+
# ensure two distinct traits
|
| 441 |
+
inner = rng.choice([t for t in inner_traits if t != social])
|
| 442 |
+
return social, inner
|
| 443 |
+
|
| 444 |
+
def _build_shared_description(self, rng: random.Random):
|
| 445 |
+
"""
|
| 446 |
+
Use one RNG to build *shared* visual traits.
|
| 447 |
+
Gender-specific bits are applied later so male/female
|
| 448 |
+
prompts stay in sync.
|
| 449 |
+
"""
|
| 450 |
+
age_group = self._select_age_group(rng)
|
| 451 |
+
pov = self._camera_pov(rng)
|
| 452 |
+
social, inner = self._social_inner_traits(rng)
|
| 453 |
+
skin = self._skincolor(rng)
|
| 454 |
+
eyes = self._eyes(rng)
|
| 455 |
+
hair = self._hair(rng)
|
| 456 |
+
top = self._top_garment(rng)
|
| 457 |
+
skirt = self._skirt(rng)
|
| 458 |
+
bottoms = self._bottoms(rng)
|
| 459 |
+
footwear = self._footwear(rng)
|
| 460 |
+
headwear = self._headwear(rng)
|
| 461 |
+
|
| 462 |
+
return {
|
| 463 |
+
"age_group": age_group,
|
| 464 |
+
"pov": pov,
|
| 465 |
+
"social_trait": social,
|
| 466 |
+
"inner_trait": inner,
|
| 467 |
+
"skin": skin,
|
| 468 |
+
"eyes": eyes,
|
| 469 |
+
"hair": hair,
|
| 470 |
+
"top": top,
|
| 471 |
+
"skirt": skirt,
|
| 472 |
+
"bottoms": bottoms,
|
| 473 |
+
"footwear": footwear,
|
| 474 |
+
"headwear": headwear,
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
def _build_prompt_from_shared(self, shared: dict, variant: str) -> str:
|
| 478 |
+
assert variant in ("female", "male")
|
| 479 |
+
age_group = shared["age_group"]
|
| 480 |
+
pov = shared["pov"]
|
| 481 |
+
social_trait = shared["social_trait"]
|
| 482 |
+
inner_trait = shared["inner_trait"]
|
| 483 |
+
|
| 484 |
+
age_noun = self._age_noun(variant, age_group)
|
| 485 |
+
|
| 486 |
+
# Category 1: gender count (always 1girl / 1boy)
|
| 487 |
+
cat1 = "1girl" if variant == "female" else "1boy"
|
| 488 |
+
|
| 489 |
+
# Category 2: camera POV
|
| 490 |
+
cat2 = pov
|
| 491 |
+
|
| 492 |
+
# Category 3: age noun (woman / man / girl / boy / grandma / grandpa)
|
| 493 |
+
cat3 = age_noun
|
| 494 |
+
|
| 495 |
+
# Category 4: social + inner traits, both reuse age_noun as second word
|
| 496 |
+
cat4_1 = f"{social_trait} {age_noun}"
|
| 497 |
+
cat4_2 = f"{inner_trait} {age_noun}"
|
| 498 |
+
|
| 499 |
+
parts = []
|
| 500 |
+
parts.append(cat1)
|
| 501 |
+
parts.append(cat2)
|
| 502 |
+
parts.append(cat3)
|
| 503 |
+
parts.append(cat4_1)
|
| 504 |
+
parts.append(cat4_2)
|
| 505 |
+
parts.append(shared["skin"])
|
| 506 |
+
parts.extend(shared["eyes"])
|
| 507 |
+
parts.extend(shared["hair"])
|
| 508 |
+
parts.extend(shared["top"])
|
| 509 |
+
parts.extend(shared["skirt"])
|
| 510 |
+
parts.extend(shared["bottoms"])
|
| 511 |
+
parts.extend(shared["footwear"])
|
| 512 |
+
parts.append(shared["headwear"])
|
| 513 |
+
|
| 514 |
+
return ", ".join(parts)
|
| 515 |
+
|
| 516 |
+
# -------- main entrypoint --------
|
| 517 |
+
|
| 518 |
+
def generate(self, seed: int):
|
| 519 |
+
rng = random.Random(int(seed))
|
| 520 |
+
|
| 521 |
+
shared = self._build_shared_description(rng)
|
| 522 |
+
female_prompt = self._build_prompt_from_shared(shared, "female")
|
| 523 |
+
male_prompt = self._build_prompt_from_shared(shared, "male")
|
| 524 |
+
|
| 525 |
+
return (female_prompt, male_prompt,)
|
| 526 |
+
|
| 527 |
+
|
| 528 |
+
# ComfyUI registration
|
| 529 |
+
NODE_CLASS_MAPPINGS = {
|
| 530 |
+
"Wildcard_4": Wildcard_4,
|
| 531 |
+
}
|
| 532 |
+
|
| 533 |
+
NODE_DISPLAY_NAME_MAPPINGS = {
|
| 534 |
+
"Wildcard_4": "Wildcard_4",
|
| 535 |
+
}
|