saliacoel commited on
Commit
271947b
·
verified ·
1 Parent(s): 142752f

Upload wildcard_3.py

Browse files
Files changed (1) hide show
  1. wildcard_3.py +471 -0
wildcard_3.py ADDED
@@ -0,0 +1,471 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+
3
+ class Wildcard_3:
4
+ """
5
+ ComfyUI custom node that generates two deterministic wildcard-style prompts
6
+ (female and male variation) from a given seed.
7
+
8
+ Each prompt roughly follows:
9
+
10
+ 1girl, straight-on, woman,
11
+ rich woman, sadistic woman,
12
+ fair skincolor, blue eyes, sharp eyes, looking at viewer eyes,
13
+ silver hair, very long hair, wavy hair,
14
+ red blouse, linen blouse, checkered blouse,
15
+ brown skirt, knee-length skirt, pleated skirt,
16
+ black pants, denim pants, baggy pants,
17
+ grey boots, ankle-high boots, lace-up boots,
18
+ black tiara headwear.
19
+
20
+ Male variant mirrors it with male age / gender words:
21
+
22
+ 1boy, straight-on, man,
23
+ rich man, sadistic man,
24
+ ...
25
+
26
+ The same seed always gives the same pair of prompts.
27
+ """
28
+
29
+ CATEGORY = "prompt/wildcard"
30
+ FUNCTION = "generate"
31
+ RETURN_TYPES = ("STRING", "STRING")
32
+ RETURN_NAMES = ("female_prompt", "male_prompt")
33
+ OUTPUT_NODE = False
34
+
35
+ @classmethod
36
+ def INPUT_TYPES(cls):
37
+ return {
38
+ "required": {
39
+ # Concept seed. Same seed => same pair of prompts.
40
+ "seed": ("INT", {
41
+ "default": 0,
42
+ "min": 0,
43
+ "max": 2**31 - 1,
44
+ "step": 1,
45
+ }),
46
+ },
47
+ }
48
+
49
+ # ---- Helper methods -------------------------------------------------
50
+
51
+ @staticmethod
52
+ def _rng(seed: int) -> random.Random:
53
+ """Deterministic RNG helper."""
54
+ return random.Random(int(seed))
55
+
56
+ @staticmethod
57
+ def _choose(rng: random.Random, items):
58
+ return items[rng.randrange(len(items))]
59
+
60
+ @classmethod
61
+ def _build_common_concept(cls, rng: random.Random):
62
+ """
63
+ Build the gender-neutral part of the character concept:
64
+ camera POV, age stage, skin, eyes, hair, clothes, etc.
65
+ """
66
+ # --- Camera POV (Category 2) --------------------------------------
67
+ # LEFTSIDE / RIGHTSIDE stay in ALL CAPS
68
+ pov_options = [
69
+ # each entry is a list of 1–2 tokens
70
+ ["straight-on"],
71
+ ["straight-on", "frontview"],
72
+ ["diagonal LEFTSIDE", "three-quarter view LEFTSIDE"],
73
+ ["sideview LEFTSIDE", "from LEFTSIDE side"],
74
+ ["from front POV", "frontview POV"],
75
+ ["sideview RIGHTSIDE", "from RIGHTSIDE side"],
76
+ ["diagonal RIGHTSIDE", "three-quarter view RIGHTSIDE"],
77
+ ["slight high-angle", "from above POV"],
78
+ ["low-angle", "from below POV"],
79
+ ]
80
+ pov_tokens = cls._choose(rng, pov_options)
81
+
82
+ # --- Age stage / category 3 base ---------------------------------
83
+ stage = cls._choose(rng, ["teen", "adult", "elder"])
84
+
85
+ if stage == "teen":
86
+ cat3_female = "girl"
87
+ cat3_male = "boy"
88
+ elif stage == "adult":
89
+ cat3_female = "woman"
90
+ cat3_male = "man"
91
+ else:
92
+ cat3_female = "loli"
93
+ cat3_male = "shota"
94
+
95
+ # --- Social and inner personality (Category 4 style) -------------
96
+ # Two tokens, second word identical within each prompt:
97
+ # e.g. "rich woman, sadistic woman"
98
+ outer_traits = [
99
+ "rich",
100
+ "well-dressed",
101
+ "casual",
102
+ "elegant",
103
+ "gothic",
104
+ "punk",
105
+ "corporate",
106
+ "sporty",
107
+ "nerdy",
108
+ "streetwise",
109
+ ]
110
+ inner_traits = [
111
+ "sadistic",
112
+ "kind",
113
+ "cold",
114
+ "gentle",
115
+ "playful",
116
+ "serious",
117
+ "melancholic",
118
+ "anxious",
119
+ "confident",
120
+ "calm",
121
+ ]
122
+
123
+ outer_trait = cls._choose(rng, outer_traits)
124
+ # ensure inner != outer for a bit of contrast
125
+ possible_inner = [t for t in inner_traits if t != outer_trait]
126
+ inner_trait = cls._choose(rng, possible_inner)
127
+
128
+ # --- Skin colour (no "colored") ----------------------------------
129
+ skin_tones = [
130
+ "pale skincolor",
131
+ "fair skincolor",
132
+ "light tan skincolor",
133
+ "olive skincolor",
134
+ "golden brown skincolor",
135
+ "medium brown skincolor",
136
+ "dark brown skincolor",
137
+ "deep brown skincolor",
138
+ ]
139
+ skin_token = cls._choose(rng, skin_tones)
140
+
141
+ # --- Eyes (Category 5) -------------------------------------------
142
+ eye_colors = [
143
+ "blue eyes",
144
+ "green eyes",
145
+ "light brown eyes",
146
+ "dark brown eyes",
147
+ "hazel eyes",
148
+ "grey eyes",
149
+ "amber eyes",
150
+ ]
151
+ eye_styles = [
152
+ "sharp eyes",
153
+ "narrow eyes",
154
+ "round eyes",
155
+ "large eyes",
156
+ "tired eyes",
157
+ "bright eyes",
158
+ "soft eyes",
159
+ ]
160
+ eye_directions = [
161
+ "",
162
+ ]
163
+
164
+ eye_color = cls._choose(rng, eye_colors)
165
+ eye_style = cls._choose(rng, eye_styles)
166
+ eye_direction = cls._choose(rng, eye_directions)
167
+
168
+ # --- Hair (Category 6: color -> length -> style) -----------------
169
+ # Haircolor never uses "red hair"; we use "ginger hair" instead.
170
+ hair_colors = [
171
+ "black hair",
172
+ "dark brown hair",
173
+ "light brown hair",
174
+ "blonde hair",
175
+ "platinum blonde hair",
176
+ "ginger hair",
177
+ "white hair",
178
+ "silver hair",
179
+ "ash brown hair",
180
+ ]
181
+ hair_lengths = [
182
+ "short hair",
183
+ "medium length hair",
184
+ "shoulder length hair",
185
+ "long hair",
186
+ "very long hair",
187
+ ]
188
+ hair_styles = [
189
+ "straight hair",
190
+ "wavy hair",
191
+ "curly hair",
192
+ "messy hair",
193
+ "neatly combed hair",
194
+ "braided hair",
195
+ "ponytail hair",
196
+ "bun hair",
197
+ ]
198
+
199
+ hair_color = cls._choose(rng, hair_colors)
200
+ hair_length = cls._choose(rng, hair_lengths)
201
+ hair_style = cls._choose(rng, hair_styles)
202
+
203
+ # --- Top garment (Category 7) ------------------------------------
204
+ # color + material + adjective, but same garment word
205
+ top_items = [
206
+ "shirt",
207
+ "blouse",
208
+ "turtleneck",
209
+ "hoodie",
210
+ "sweater",
211
+ "jacket",
212
+ "coat",
213
+ ]
214
+ top_colors = [
215
+ "red",
216
+ "blue",
217
+ "green",
218
+ "yellow",
219
+ "black",
220
+ "white",
221
+ "grey",
222
+ "brown",
223
+ "beige",
224
+ "navy",
225
+ "burgundy",
226
+ ]
227
+ top_materials = [
228
+ "cotton",
229
+ "linen",
230
+ "silk",
231
+ "wool",
232
+ "denim",
233
+ "leather",
234
+ "polyester",
235
+ ]
236
+ top_styles = [
237
+ "plain",
238
+ "striped",
239
+ "checkered",
240
+ "printed",
241
+ "torn",
242
+ "fitted",
243
+ "oversized",
244
+ ]
245
+
246
+ top_item = cls._choose(rng, top_items)
247
+ top_color = cls._choose(rng, top_colors)
248
+ top_material = cls._choose(rng, top_materials)
249
+ top_style = cls._choose(rng, top_styles)
250
+
251
+ top_tokens = [
252
+ f"{top_color} {top_item}",
253
+ f"{top_material} {top_item}",
254
+ f"{top_style} {top_item}",
255
+ ]
256
+
257
+ # --- Skirt (Category 8) ------------------------------------------
258
+ skirt_colors = top_colors # reuse palette
259
+ skirt_lengths = [
260
+ "short skirt",
261
+ "knee-length skirt",
262
+ "midi skirt",
263
+ "ankle-length skirt",
264
+ ]
265
+ skirt_styles = [
266
+ "pleated skirt",
267
+ "denim skirt",
268
+ "wool skirt",
269
+ "cotton skirt",
270
+ "pencil skirt",
271
+ "A-line skirt",
272
+ ]
273
+
274
+ skirt_color = cls._choose(rng, skirt_colors)
275
+ skirt_length = cls._choose(rng, skirt_lengths)
276
+ skirt_style = cls._choose(rng, skirt_styles)
277
+
278
+ skirt_tokens = [
279
+ f"{skirt_color} skirt",
280
+ skirt_length,
281
+ skirt_style,
282
+ ]
283
+
284
+ # --- Bottom garment (Category 9) ---------------------------------
285
+ # color + material + adjective, same garment word
286
+ bottom_items = [
287
+ "pants",
288
+ "jeans",
289
+ "trousers",
290
+ "shorts",
291
+ "leggings",
292
+ "sweatpants",
293
+ ]
294
+ bottom_colors = top_colors
295
+ bottom_materials = [
296
+ "cotton",
297
+ "linen",
298
+ "wool",
299
+ "denim",
300
+ "leather",
301
+ "corduroy",
302
+ ]
303
+ bottom_styles = [
304
+ "fluffy",
305
+ "slim-fit",
306
+ "baggy",
307
+ "wrinkled",
308
+ "ripped",
309
+ "distressed",
310
+ "cuffed",
311
+ ]
312
+
313
+ bottom_item = cls._choose(rng, bottom_items)
314
+ bottom_color = cls._choose(rng, bottom_colors)
315
+ bottom_material = cls._choose(rng, bottom_materials)
316
+ bottom_style = cls._choose(rng, bottom_styles)
317
+
318
+ bottom_tokens = [
319
+ f"{bottom_color} {bottom_item}",
320
+ f"{bottom_material} {bottom_item}",
321
+ f"{bottom_style} {bottom_item}",
322
+ ]
323
+
324
+ # --- Footwear (Category 10) --------------------------------------
325
+ # color + adjective + adjective
326
+ footwear_items = [
327
+ "boots",
328
+ "sneakers",
329
+ "shoes",
330
+ "sandals",
331
+ "loafers",
332
+ "ankle boots",
333
+ ]
334
+ footwear_colors = top_colors
335
+ footwear_styles = [
336
+ "ankle-high",
337
+ "knee-high",
338
+ "lace-up",
339
+ "slip-on",
340
+ "chunky sole",
341
+ "thin-heeled",
342
+ "low-top",
343
+ "high-top",
344
+ ]
345
+
346
+ footwear_item = cls._choose(rng, footwear_items)
347
+ footwear_color = cls._choose(rng, footwear_colors)
348
+ style1 = cls._choose(rng, footwear_styles)
349
+ remaining_styles = [s for s in footwear_styles if s != style1]
350
+ style2 = cls._choose(rng, remaining_styles)
351
+
352
+ footwear_tokens = [
353
+ f"{footwear_color} {footwear_item}",
354
+ f"{style1} {footwear_item}",
355
+ f"{style2} {footwear_item}",
356
+ ]
357
+
358
+ # --- Headwear (Category 11) --------------------------------------
359
+ # color + headwear + "headwear"
360
+ headwear_items = [
361
+ "baseball cap",
362
+ "knit beanie",
363
+ "beret",
364
+ "fedora",
365
+ "wide-brim hat",
366
+ "headband",
367
+ "hairband",
368
+ "tiara",
369
+ "hood",
370
+ "bandana",
371
+ ]
372
+ headwear_colors = top_colors
373
+
374
+ headwear_item = cls._choose(rng, headwear_items)
375
+ headwear_color = cls._choose(rng, headwear_colors)
376
+ headwear_token = f"{headwear_color} {headwear_item} headwear"
377
+
378
+ return {
379
+ "pov_tokens": pov_tokens,
380
+ "stage": stage,
381
+ "cat3_female": cat3_female,
382
+ "cat3_male": cat3_male,
383
+ "outer_trait": outer_trait,
384
+ "inner_trait": inner_trait,
385
+ "skin_token": skin_token,
386
+ "eye_color": eye_color,
387
+ "eye_style": eye_style,
388
+ "eye_direction": eye_direction,
389
+ "hair_color": hair_color,
390
+ "hair_length": hair_length,
391
+ "hair_style": hair_style,
392
+ "top_tokens": top_tokens,
393
+ "skirt_tokens": skirt_tokens,
394
+ "bottom_tokens": bottom_tokens,
395
+ "footwear_tokens": footwear_tokens,
396
+ "headwear_token": headwear_token,
397
+ }
398
+
399
+ # ---- Main generation -----------------------------------------------
400
+
401
+ def generate(self, seed: int):
402
+ rng = self._rng(seed)
403
+ concept = self._build_common_concept(rng)
404
+
405
+ # Category 1: fixed gender token (never anything else)
406
+ cat1_female = "1girl"
407
+ cat1_male = "1boy"
408
+
409
+ # Category 3: age / gender word
410
+ cat3_female = concept["cat3_female"]
411
+ cat3_male = concept["cat3_male"]
412
+
413
+ # Category 4: two tokens, second word identical within each prompt
414
+ # e.g. "rich woman, sadistic woman"
415
+ outer = concept["outer_trait"]
416
+ inner = concept["inner_trait"]
417
+
418
+ cat4_female = [
419
+ f"{outer} {cat3_female}",
420
+ f"{inner} {cat3_female}",
421
+ ]
422
+ cat4_male = [
423
+ f"{outer} {cat3_male}",
424
+ f"{inner} {cat3_male}",
425
+ ]
426
+
427
+ # Common tokens shared across both prompts
428
+ common_sequence = [
429
+ concept["skin_token"],
430
+ concept["eye_color"],
431
+ concept["eye_style"],
432
+ concept["eye_direction"],
433
+ concept["hair_color"],
434
+ concept["hair_length"],
435
+ concept["hair_style"],
436
+ ]
437
+ common_sequence.extend(concept["top_tokens"])
438
+ common_sequence.extend(concept["skirt_tokens"])
439
+ common_sequence.extend(concept["bottom_tokens"])
440
+ common_sequence.extend(concept["footwear_tokens"])
441
+ common_sequence.append(concept["headwear_token"])
442
+
443
+ # Build female token list
444
+ female_tokens = []
445
+ female_tokens.append(cat1_female)
446
+ female_tokens.extend(concept["pov_tokens"])
447
+ female_tokens.append(cat3_female)
448
+ female_tokens.extend(cat4_female)
449
+ female_tokens.extend(common_sequence)
450
+
451
+ # Build male token list
452
+ male_tokens = []
453
+ male_tokens.append(cat1_male)
454
+ male_tokens.extend(concept["pov_tokens"])
455
+ male_tokens.append(cat3_male)
456
+ male_tokens.extend(cat4_male)
457
+ male_tokens.extend(common_sequence)
458
+
459
+ female_prompt = ", ".join(female_tokens) + "."
460
+ male_prompt = ", ".join(male_tokens) + "."
461
+
462
+ return (female_prompt, male_prompt)
463
+
464
+
465
+ NODE_CLASS_MAPPINGS = {
466
+ "Wildcard_3": Wildcard_3,
467
+ }
468
+
469
+ NODE_DISPLAY_NAME_MAPPINGS = {
470
+ "Wildcard_3": "Wildcard_3",
471
+ }