Files

408 lines
12 KiB
Python

import random
DIRECTIONS = (
"front view",
"front-right quarter view",
"right side view",
"back-right quarter view",
"back view",
"back-left quarter view",
"left side view",
"front-left quarter view",
)
VERTICAL_ANGLES = ("low-angle", "eye-level", "elevated", "high-angle")
SHOT_SIZES = ("close-up", "medium shot", "wide shot")
EXPRESSIONS = (
"neutral", "smile", "big smile", "laughing", "smirk", "frown", "sad", "crying",
"angry", "surprised", "shocked", "scared", "disgusted", "confused", "winking", "pouting",
)
POSES = (
"standing", "sitting", "kneeling", "crouching", "lying down", "walking", "running", "jumping",
"arms crossed", "hands on hips", "arms raised", "leaning forward", "leaning back",
"looking over shoulder", "T-pose", "contrapposto",
)
LIGHTING = (
"soft natural light", "harsh sunlight", "golden hour", "blue hour", "overcast daylight",
"studio lighting", "rim lighting", "backlight", "side lighting", "top-down lighting",
"low-key lighting", "high-key lighting", "neon lighting", "candlelight", "moonlight",
"dramatic chiaroscuro",
)
CAMERA_TYPES = (
# vintage film & early imaging
"Kodak Brownie box camera",
"pinhole camera",
"Bolex 16mm film camera",
"Super 8 film camera",
"VHS camcorder",
"Sony Mavica floppy disk camera",
"Sony Handycam camcorder",
# instant
"Polaroid SX-70 instant camera",
"Polaroid 600 instant camera",
"disposable film camera",
# classic 35mm SLRs
"Canon AE-1 35mm SLR",
"Nikon F3 35mm SLR",
"Pentax K1000 35mm SLR",
"Olympus OM-1 35mm SLR",
# rangefinder & toy
"Leica M6 rangefinder",
"Lomography LC-A",
"Holga toy medium format camera",
# medium / large format film
"Hasselblad 500C/M medium format",
"large format view camera",
# modern digital stills
"Canon EOS 5D Mark IV DSLR",
"Nikon D850 DSLR",
"Sony Alpha A7 III mirrorless",
"Fujifilm X100V mirrorless",
"Leica Q2",
"Hasselblad X1D medium format digital",
# mobile
"iPhone 15 Pro smartphone",
"Samsung Galaxy smartphone camera",
# action / aerial
"GoPro Hero action camera",
"DJI Mavic drone camera",
# cinema
"Arri Alexa cinema camera",
"RED Komodo cinema camera",
"Panavision Panaflex 35mm cinema camera",
"IMAX 70mm camera",
"anamorphic lens",
# specialty / surveillance
"security CCTV camera",
"webcam",
"dashcam",
"thermal imaging camera",
"night vision camera",
)
BACKGROUNDS = (
# residential interiors
"living room",
"messy living room",
"bedroom",
"messy bedroom",
"modern kitchen",
"rustic kitchen",
"bathroom",
"home office",
"attic",
"basement",
"garage",
"dining room",
"nursery",
"walk-in closet",
"cozy reading nook",
# public / commercial interiors
"coffee shop",
"fine dining restaurant",
"dive bar",
"nightclub",
"public library",
"bookstore",
"art gallery",
"museum hall",
"hotel lobby",
"open-plan office",
"classroom",
"gym",
"hospital room",
"subway station platform",
"airport terminal",
# outdoor urban
"busy city street at night",
"narrow alleyway",
"rooftop at sunset",
"multi-level parking garage",
"suburban street",
"neon-lit Tokyo street",
# outdoor nature
"dense forest",
"tropical beach",
"desert dunes",
"snowy mountain peak",
"flower meadow",
"lakeside dock",
"waterfall clearing",
"jungle",
"autumn park",
# studio
"white seamless backdrop",
"black studio backdrop",
"gray studio backdrop",
"green screen",
)
CLOTHES = (
# formal / business
"business suit",
"three-piece suit",
"tuxedo",
"cocktail dress",
"evening gown",
"ball gown",
# casual everyday
"white t-shirt and jeans",
"hoodie and joggers",
"summer dress",
"sundress",
"cargo shorts and tank top",
# outerwear-led looks
"leather biker jacket outfit",
"noir trenchcoat look",
"denim jacket and jeans",
"peacoat ensemble",
# workwear / uniforms
"chef whites",
"doctor's scrubs",
"lab coat",
"hospital gown",
"military fatigues",
"police uniform",
"firefighter turnout gear",
"construction hi-vis",
# athletic / outdoor
"athletic tracksuit",
"yoga outfit",
"ski jumpsuit",
"hiking gear",
"swimwear",
"wetsuit",
# traditional / cultural
"kimono",
"hanbok",
"sari",
"cheongsam",
"dashiki",
"lederhosen",
"Scottish kilt outfit",
# historical eras
"medieval peasant garb",
"Victorian gown",
"1920s flapper dress",
"1950s rockabilly",
"1970s disco outfit",
"1980s power suit",
"1990s grunge",
# subculture / genre
"cyberpunk streetwear",
"gothic lolita",
"punk rock",
"steampunk attire",
"hip-hop streetwear",
"preppy",
# fantasy / costume
"wizard robes",
"knight's armor",
"superhero costume",
"vampire attire",
"pirate outfit",
"space suit",
# loungewear / sleepwear
"pajamas",
"silk robe",
"bathrobe",
)
_SEED = ("INT", {"default": 0, "min": 0, "max": 0xFFFFFFFFFFFFFFFF})
_PREVIOUS = ("STRING", {"default": "", "forceInput": True})
def _build_prompt(prefix: str, body: str, previous: str, separator: str) -> str:
own = f"{prefix}{body}"
return f"{previous}{separator}{own}" if previous else own
def _resolve(rng: random.Random, value: str, choices: tuple) -> str:
return rng.choice(choices) if value == "random" else value
class CameraAngleSelector:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"direction": (("random", *DIRECTIONS), {"default": "front view"}),
"vertical_angle": (("random", *VERTICAL_ANGLES), {"default": "eye-level"}),
"shot_size": (("random", *SHOT_SIZES), {"default": "medium shot"}),
"prefix": ("STRING", {"default": "Change camera angle to ", "multiline": False}),
"separator": ("STRING", {"default": ", ", "multiline": False}),
"seed": _SEED,
},
"optional": {"previous_prompt": _PREVIOUS},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("prompt",)
FUNCTION = "build"
CATEGORY = "prompt/camera"
def build(self, direction, vertical_angle, shot_size, prefix, separator, seed, previous_prompt=""):
rng = random.Random(seed)
direction = _resolve(rng, direction, DIRECTIONS)
vertical_angle = _resolve(rng, vertical_angle, VERTICAL_ANGLES)
shot_size = _resolve(rng, shot_size, SHOT_SIZES)
body = f"{direction} {vertical_angle} shot {shot_size}"
return (_build_prompt(prefix, body, previous_prompt, separator),)
class FacialExpressionSelector:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"expression": (("random", *EXPRESSIONS), {"default": "neutral"}),
"prefix": ("STRING", {"default": "Change facial expression to ", "multiline": False}),
"separator": ("STRING", {"default": ", ", "multiline": False}),
"seed": _SEED,
},
"optional": {"previous_prompt": _PREVIOUS},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("prompt",)
FUNCTION = "build"
CATEGORY = "prompt/character"
def build(self, expression, prefix, separator, seed, previous_prompt=""):
rng = random.Random(seed)
expression = _resolve(rng, expression, EXPRESSIONS)
return (_build_prompt(prefix, expression, previous_prompt, separator),)
class PoseSelector:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"pose": (("random", *POSES), {"default": "standing"}),
"prefix": ("STRING", {"default": "Change pose to ", "multiline": False}),
"separator": ("STRING", {"default": ", ", "multiline": False}),
"seed": _SEED,
},
"optional": {"previous_prompt": _PREVIOUS},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("prompt",)
FUNCTION = "build"
CATEGORY = "prompt/character"
def build(self, pose, prefix, separator, seed, previous_prompt=""):
rng = random.Random(seed)
pose = _resolve(rng, pose, POSES)
return (_build_prompt(prefix, pose, previous_prompt, separator),)
class LightingSelector:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"lighting": (("random", *LIGHTING), {"default": "soft natural light"}),
"prefix": ("STRING", {"default": "Change lighting to ", "multiline": False}),
"separator": ("STRING", {"default": ", ", "multiline": False}),
"seed": _SEED,
},
"optional": {"previous_prompt": _PREVIOUS},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("prompt",)
FUNCTION = "build"
CATEGORY = "prompt/scene"
def build(self, lighting, prefix, separator, seed, previous_prompt=""):
rng = random.Random(seed)
lighting = _resolve(rng, lighting, LIGHTING)
return (_build_prompt(prefix, lighting, previous_prompt, separator),)
class CameraTypeSelector:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"camera_type": (("random", *CAMERA_TYPES), {"default": "Canon EOS 5D Mark IV DSLR"}),
"prefix": ("STRING", {"default": "Change camera type to ", "multiline": False}),
"separator": ("STRING", {"default": ", ", "multiline": False}),
"seed": _SEED,
},
"optional": {"previous_prompt": _PREVIOUS},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("prompt",)
FUNCTION = "build"
CATEGORY = "prompt/camera"
def build(self, camera_type, prefix, separator, seed, previous_prompt=""):
rng = random.Random(seed)
camera_type = _resolve(rng, camera_type, CAMERA_TYPES)
return (_build_prompt(prefix, camera_type, previous_prompt, separator),)
class BackgroundChangerSelector:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"background": (("random", *BACKGROUNDS), {"default": "living room"}),
"custom_background": ("STRING", {"default": "", "multiline": True}),
"prefix": ("STRING", {"default": "Change background to ", "multiline": False}),
"separator": ("STRING", {"default": ", ", "multiline": False}),
"seed": _SEED,
},
"optional": {"previous_prompt": _PREVIOUS},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("prompt",)
FUNCTION = "build"
CATEGORY = "prompt/scene"
def build(self, background, custom_background, prefix, separator, seed, previous_prompt=""):
custom = custom_background.strip()
if custom:
body = custom
else:
rng = random.Random(seed)
body = _resolve(rng, background, BACKGROUNDS)
return (_build_prompt(prefix, body, previous_prompt, separator),)
class ClothesChangerSelector:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"clothes": (("random", *CLOTHES), {"default": "business suit"}),
"custom_clothes": ("STRING", {"default": "", "multiline": True}),
"prefix": ("STRING", {"default": "Change clothes to ", "multiline": False}),
"separator": ("STRING", {"default": ", ", "multiline": False}),
"seed": _SEED,
},
"optional": {"previous_prompt": _PREVIOUS},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("prompt",)
FUNCTION = "build"
CATEGORY = "prompt/character"
def build(self, clothes, custom_clothes, prefix, separator, seed, previous_prompt=""):
custom = custom_clothes.strip()
if custom:
body = custom
else:
rng = random.Random(seed)
body = _resolve(rng, clothes, CLOTHES)
return (_build_prompt(prefix, body, previous_prompt, separator),)