diff --git a/cast_character.manifest.json b/cast_character.manifest.json index e497aae..f0d9a7a 100644 --- a/cast_character.manifest.json +++ b/cast_character.manifest.json @@ -8,7 +8,7 @@ { "key": "character", "type": "form_builder", - "template": "{shot_type}. A {androgyny} {origin} {gender}, {age}, {build_type} build, {height}. {skin_tone} complexion {skin_details}, {skin_realism}, {skin_pores}, {freckles}, {moles}, {dimples}, {skin_imperfections}. {face_shape} face, {facial_asymmetry}, {lip_color} {lip_shape} lips, {makeup}, {expression}. {beard}. {eye_color} {eye_shape} eyes, {eye_details}. {hair_color} hair, {hair_style}, {hair_length}, {dishevelment}. Wardrobe: {wardrobe}. {pose}. Shot on {camera_type}, {focal_length} lens at {aperture}. Neutral pale grey seamless studio backdrop, soft even key light. Photoreal, natural unretouched skin texture, subtle facial asymmetry, lifelike detailed eyes, natural color, authentic, unfiltered.", + "template": "{shot_type}.\n\nA {androgyny} {origin} {gender}, {age}, {build_type} build, {height}.\n\n{skin_tone} complexion {skin_details}, {skin_realism}, {skin_pores}, {freckles}, {moles}, {dimples}, {skin_imperfections}.\n\n{face_shape} face, {facial_asymmetry}, {lip_color} {lip_shape} lips, {makeup}, {expression}. {beard}.\n\n{eye_color} {eye_shape} eyes, {eye_details}.\n\n{hair_color} hair, {hair_style}, {hair_length}, {dishevelment}.\n\nWardrobe: {wardrobe}.\n\n{pose}.\n\nShot on {camera_type}, {focal_length} lens at {aperture}, {camera_angle}.\n\n{backdrop_color} {backdrop}, {lighting}.\n\nPhotoreal, natural unretouched skin texture, subtle facial asymmetry, lifelike detailed eyes, natural color, authentic, unfiltered.", "seed_default": 0, "default_engine": "fast", "fields": [ @@ -501,19 +501,43 @@ "label": "Expressie", "group": "Gezicht", "allow_custom": true, - "default": "relaxed natural smile", + "default": "neutral", "options": [ - "relaxed natural smile", + "amused", + "angry", + "anxious", + "aroused", + "blissful", + "bored", + "concentrated", + "confused", + "contemptuous", + "crying", + "disgusted", + "ecstatic", + "embarrassed", + "excited", + "fearful", + "focused", + "frowning", + "happy", + "intense", + "laughing", + "lustful", "neutral", - "soft smile", - "serious", - "confident", - "playful", - "pensive", - "serene", - "joyful", - "horny", - "intense gaze" + "overwhelmed", + "passionate", + "proud", + "relaxed", + "sad", + "satisfied", + "sensual", + "shocked", + "skeptical", + "smiling", + "surprised", + "tired", + "yearning" ] }, { @@ -639,22 +663,152 @@ "label": "Haarstijl", "group": "Haar", "allow_custom": true, - "default": "loose beach waves, centre part", + "default": "beach waves", "options": [ - "loose beach waves", - "straight and sleek", - "soft waves", + "1970s long cut", + "angled bob", + "balayage", + "bangs", + "bantu knots", + "beach waves", + "blunt chin bob", + "bob", + "boho waves", + "box braids", + "braided ballerina bun", + "braided bun", + "braided chignon", + "braided cornrows", + "braided headband", + "braided low ponytail", + "braided ponytail", + "braided side bun", + "braided side sweep", + "braided sock bun", + "braided top knot", + "braided twist-out", + "braided updo", + "braided wrap-around ponytail", + "bubble ponytail", + "bun", + "buzz cut", + "cascading curls", + "center part", + "chignon", + "comb over", + "cornrow updo", + "cornrows", + "crew cut", + "curled ends", + "curls with bangs", "curly", - "tight curls", - "afro", - "blunt bob", - "pixie cut", - "long straight", + "curly bangs", + "curly faux hawk", + "curly half-up", + "curly ponytail", + "curly side sweep", + "curly undercut", + "curtain bangs", + "curtain fringe", + "double bun", + "double French braids", + "fade", + "faux hawk", + "faux locs", + "finger coils", + "finger waves", + "fishtail braid", + "fishtail updo", + "flamboyage", + "flat twist", + "French braid", + "French twist", + "frohawk", + "goddess braids", + "half-down", + "half-up", "high ponytail", + "highlights", + "honeycomb locs", + "layered", + "lob", + "low bun", + "low fade", + "low ponytail", + "low ponytail with twist", "messy bun", - "braided", + "messy pixie", + "messy side braid", + "milkmaid braids", + "mullet", + "pigtails", + "pinned back", + "pinned curls", + "pixie cut", + "pompadour", + "pompadour fade", + "ponytail", + "puff", + "quiff", + "rolled bangs", + "rope braid", + "scissor fade", + "sculpted curls", + "shag", + "sharp shoulder cut", + "shaved designs", + "side bun", + "side part", + "side shave", + "side-swept", + "side-swept curls", + "sleek and straight", + "sleek bob", + "sleek fishtail", + "sleek low bun", + "sleek top knot", "slicked back", - "shoulder-length layers" + "slicked back undercut", + "slicked ponytail", + "slicked side part", + "slicked-back bun", + "slicked-back quiff", + "soft waves", + "sombre", + "space buns", + "spiky", + "spiral curls", + "straight", + "swoop bangs", + "tapered cut", + "textured bob", + "textured messy bun", + "textured pixie", + "textured side sweep", + "top knot", + "tucked updo", + "twist braids", + "twist out", + "twisted bangs", + "twisted chignon", + "twisted half-up", + "twisted ponytail", + "twisted side updo", + "twisted top knot", + "twisted updo", + "undercut", + "updo", + "v-shaped layers", + "victory rolls", + "vintage curls", + "voluminous curls", + "voluminous high ponytail", + "voluminous side-swept bangs", + "voluminous updo", + "waterfall braid", + "waterfall twist", + "wavy", + "wet look" ] }, { @@ -716,17 +870,88 @@ "label": "Pose", "group": "Uitvoer", "allow_custom": true, - "default": "relaxed natural standing pose", + "default": "Standing straight with hands at sides", "options": [ - "relaxed natural standing pose", - "hand on hip", - "contrapposto stance", - "walking mid-stride", - "seated relaxed", - "dynamic action pose", - "arms crossed", - "candid over-the-shoulder glance", - "high-fashion editorial pose" + "Sitting cross-legged", + "Standing with hands on hips", + "Leaning against a wall", + "Jumping with arms raised", + "Lying on the stomach, propped up on elbows", + "Sitting with one leg folded", + "Posing with arms folded", + "Running with hands extended", + "Leaning forward with hands on knees", + "Standing on tiptoes", + "Spinning with arms outstretched", + "Crouching with hands on the ground", + "Arching the back", + "Bending over with hands touching toes", + "Kneeling with one hand on the thigh", + "Standing straight with hands clasped behind", + "Dancing with arms in the air", + "Twirling hair with fingers", + "Sitting with legs extended", + "Reaching high with both hands", + "Sitting, leaning on one hand", + "Kneeling with head bowed", + "Lying on the side, propped up on one elbow", + "Leaping with legs extended", + "Stretching both arms overhead", + "Balancing on one foot", + "Squatting with hands on ankles", + "Sitting with hands clasping the knee", + "Standing with one hand on the hip", + "Walking with hands swinging by sides", + "Sitting with legs crossed at ankles", + "Leaning back with hands stretched out", + "Standing with one leg bent", + "Bending sideways with one hand reaching down", + "Lying flat on the back with arms at sides", + "Dancing with one hand on the hip", + "Standing with arms behind the head", + "Kneeling with both hands on thighs", + "Running with arms pumping at sides", + "Sitting with back hunched", + "Leaping with one hand reaching up", + "Standing with one foot in front of the other", + "Lounging with one hand behind the head", + "Sitting with one knee up, hand on knee", + "Standing straight with hands at sides", + "Standing with arms crossed over chest", + "Sitting with legs tucked under", + "Dancing with one arm raised", + "Lying flat with hands under the head", + "Balancing with arms outstretched", + "Leaning forward with one hand on the knee", + "Jumping with legs apart", + "Sitting with one hand on the cheek", + "Standing with arms hanging loosely", + "Kneeling with one knee up", + "Lying on the side with knees bent", + "Standing with one hand on the waist", + "Walking with one hand in the pocket", + "Crouching with both hands on the ground", + "Sitting, hugging knees to chest", + "Standing with one hand waving", + "Lying on the back with knees up", + "Kneeling, hands folded in lap", + "Sitting with legs outstretched", + "Standing with one foot on tiptoe", + "Walking with an exaggerated stride", + "Leaning forward with hands on thighs", + "Sitting, leaning forward with elbows on knees", + "Walking with hands in pockets", + "Leaning back, arms folded", + "Sitting cross-legged with hands on knees", + "Kneeling with hands on the floor", + "Standing with one hand over the heart", + "Lying on the side, one hand propping up head", + "Standing with hands behind the back", + "Sitting with hands in the lap", + "Walking with arms swinging in rhythm", + "Standing with hands in pockets", + "Kneeling with one hand reaching out", + "Standing with arms stretched out" ] }, { @@ -780,6 +1005,162 @@ "f/11", "f/16" ] + }, + { + "key": "camera_angle", + "type": "enum", + "label": "Camera-hoek", + "group": "Camera & lens", + "allow_custom": true, + "default": "eye level", + "options": [ + "bird's eye view", + "boom shot", + "close-up", + "crane shot", + "dolly shot", + "dutch angle", + "eye level", + "fish-eye lens", + "handheld shot", + "high angle", + "jib shot", + "long shot", + "low angle", + "oblique angle", + "overhead shot", + "point-of-view shot", + "pov from above", + "pov from behind", + "pov from below", + "steadicam shot", + "tilt shot", + "tracking shot", + "wide shot", + "worm's eye view", + "zoom shot" + ] + }, + { + "key": "lighting", + "type": "enum", + "label": "Belichting", + "group": "Belichting", + "allow_custom": true, + "default": "soft even key light", + "options": [ + "soft even key light", + "key light from the left, soft fill", + "key light from the right, soft fill", + "key light from above, soft fill", + "45-degree key light", + "rim light from top left", + "rim light from top right", + "rim light from behind", + "backlight from behind", + "top-down light from above", + "underlight from below", + "window light from the left", + "window light from the right", + "side light from the left", + "side light from the right", + "accent lighting", + "ambient lighting", + "backlight", + "bright neon lighting", + "broad lighting", + "candlelight", + "chiaroscuro", + "clamshell lighting", + "color temperature lighting", + "contre-jour lighting", + "direct flash photography", + "fluorescent lighting", + "fresnel lighting", + "gelled lighting", + "glowy luminescence", + "glowy translucency", + "hard shadows", + "high-key lighting", + "hmi lighting", + "iridescent light", + "led panel lighting", + "light painting", + "loop lighting", + "low-key lighting", + "luminescence", + "moody low-light", + "motivated lighting", + "paramount lighting", + "practical lighting", + "radiant god rays", + "rembrandt lighting", + "rim lighting", + "short lighting", + "silhouetted against the bright window", + "soft bounced lighting", + "soft diffused lighting", + "soft fill lighting", + "soft natural lighting", + "specular lighting", + "split lighting", + "strobe lighting", + "strong side key lights", + "three-point lighting", + "translucency", + "tungsten lighting", + "warm golden hour lighting" + ] + }, + { + "key": "backdrop_color", + "type": "enum", + "label": "Achtergrond-kleur", + "group": "Achtergrond", + "allow_custom": true, + "default": "neutral pale grey", + "options": [ + "neutral pale grey", + "white", + "off-white", + "light grey", + "mid grey", + "charcoal", + "black", + "deep blue", + "teal", + "warm amber", + "muted green", + "dusty pink", + "burgundy", + "cool blue-grey" + ] + }, + { + "key": "backdrop", + "type": "enum", + "label": "Achtergrond", + "group": "Achtergrond", + "allow_custom": true, + "default": "seamless studio backdrop", + "options": [ + "seamless studio backdrop", + "seamless paper backdrop", + "gradient studio backdrop", + "plain painted wall", + "textured concrete wall", + "exposed brick wall", + "wooden panel wall", + "soft fabric curtain", + "blurred city street", + "blurred urban night scene", + "blurred park greenery", + "blurred café interior", + "cozy indoor interior", + "minimalist interior", + "blurred forest", + "blurred beach" + ] } ], "engines": [ @@ -806,17 +1187,72 @@ }, "default_format": "land", "formats": [ - {"key": "uw_21_9", "label": "Ultrawide 21:9 · 1440×608", "w": 1440, "h": 608}, - {"key": "land", "label": "Liggend 16:9 · 1440×800", "w": 1440, "h": 800}, - {"key": "land_3_2", "label": "Liggend 3:2 · 1440×960", "w": 1440, "h": 960}, - {"key": "land_4_3", "label": "Liggend 4:3 · 1440×1088", "w": 1440, "h": 1088}, - {"key": "land_5_4", "label": "Liggend 5:4 · 1440×1152", "w": 1440, "h": 1152}, - {"key": "square", "label": "Vierkant 1:1 · 1440×1440", "w": 1440, "h": 1440}, - {"key": "port_4_5", "label": "Staand 4:5 · 1152×1440", "w": 1152, "h": 1440}, - {"key": "port_3_4", "label": "Staand 3:4 · 1088×1440", "w": 1088, "h": 1440}, - {"key": "port_2_3", "label": "Staand 2:3 · 960×1440", "w": 960, "h": 1440}, - {"key": "port", "label": "Staand 9:16 · 800×1440", "w": 800, "h": 1440}, - {"key": "port_9_21", "label": "Staand 9:21 · 608×1440", "w": 608, "h": 1440} + { + "key": "uw_21_9", + "label": "Ultrawide 21:9 · 1440×608", + "w": 1440, + "h": 608 + }, + { + "key": "land", + "label": "Liggend 16:9 · 1440×800", + "w": 1440, + "h": 800 + }, + { + "key": "land_3_2", + "label": "Liggend 3:2 · 1440×960", + "w": 1440, + "h": 960 + }, + { + "key": "land_4_3", + "label": "Liggend 4:3 · 1440×1088", + "w": 1440, + "h": 1088 + }, + { + "key": "land_5_4", + "label": "Liggend 5:4 · 1440×1152", + "w": 1440, + "h": 1152 + }, + { + "key": "square", + "label": "Vierkant 1:1 · 1440×1440", + "w": 1440, + "h": 1440 + }, + { + "key": "port_4_5", + "label": "Staand 4:5 · 1152×1440", + "w": 1152, + "h": 1440 + }, + { + "key": "port_3_4", + "label": "Staand 3:4 · 1088×1440", + "w": 1088, + "h": 1440 + }, + { + "key": "port_2_3", + "label": "Staand 2:3 · 960×1440", + "w": 960, + "h": 1440 + }, + { + "key": "port", + "label": "Staand 9:16 · 800×1440", + "w": 800, + "h": 1440 + }, + { + "key": "port_9_21", + "label": "Staand 9:21 · 608×1440", + "w": 608, + "h": 1440 + } ] }, { diff --git a/compose_logic.py b/compose_logic.py index 1efd0e8..83f4d23 100644 --- a/compose_logic.py +++ b/compose_logic.py @@ -23,11 +23,18 @@ def compose_wardrobe(value: dict | None) -> str: def _cleanup(text: str) -> str: - text = re.sub(r"\s+", " ", text) - text = re.sub(r"\s+([,.])", r"\1", text) - text = re.sub(r",\s*,", ",", text) - text = re.sub(r"\(\s*\)", "", text) - return text.strip() + # Behoud alinea-breaks (witregels) tussen blokken; schoon binnen elk blok op. + blocks = re.split(r"\n\s*\n", text) + cleaned = [] + for b in blocks: + b = re.sub(r"\s+", " ", b) + b = re.sub(r"\s+([,.])", r"\1", b) + b = re.sub(r",\s*,", ",", b) + b = re.sub(r"\(\s*\)", "", b) + b = b.strip() + if b: + cleaned.append(b) + return "\n\n".join(cleaned) def compose_form(cb_param: dict, value: dict) -> str: diff --git a/tests/test_prompt_node.py b/tests/test_prompt_node.py index d75a9b4..5296466 100644 --- a/tests/test_prompt_node.py +++ b/tests/test_prompt_node.py @@ -61,6 +61,15 @@ def test_wardrobe_default_fallback_and_override(): assert node_compose.compose_form(cb, {"fields": {}, "wardrobe": {"mode": "free", "text": "a red gown"}}) == "Wardrobe: a red gown." +def test_compose_preserves_paragraph_breaks(): + cb = {"template": "{a}\n\n{b}\n\n{c}", + "fields": [{"key": "a", "type": "text", "default": "first block"}, + {"key": "b", "type": "text", "default": ""}, + {"key": "c", "type": "text", "default": "third block"}]} + # witregels blijven tussen blokken; een leeg blok wordt weggelaten + assert node_compose.compose_form(cb, {"fields": {}, "wardrobe": None}) == "first block\n\nthird block" + + @pytest.mark.skipif(app_compose is None, reason="orchestrator/compose.py niet beschikbaar (standalone repo)") def test_parity_with_app_compose(): # De geporte kopie moet exact hetzelfde produceren als orchestrator/compose.py.