Add Krea2 formatting and scalable scene pools

This commit is contained in:
2026-06-24 10:23:24 +02:00
parent 00ac8be640
commit 89af926a5a
9 changed files with 1191 additions and 23 deletions
+70
View File
@@ -9,6 +9,7 @@ The node is registered as:
- `prompt_builder / SxCP Seed Control` - `prompt_builder / SxCP Seed Control`
- `prompt_builder / SxCP Camera Control` - `prompt_builder / SxCP Camera Control`
- `prompt_builder / SxCP Caption Naturalizer` - `prompt_builder / SxCP Caption Naturalizer`
- `prompt_builder / SxCP Krea2 Formatter`
- `prompt_builder / SxCP Insta/OF Options` - `prompt_builder / SxCP Insta/OF Options`
- `prompt_builder / SxCP Insta/OF Prompt Pair` - `prompt_builder / SxCP Insta/OF Prompt Pair`
@@ -65,6 +66,35 @@ It outputs:
- `natural_caption` - `natural_caption`
- `method` - `method`
`SxCP Krea2 Formatter` rewrites an existing prompt or `metadata_json` into a
Krea2-oriented natural-language paragraph. It is a formatter, not a safety or
content downgrade pass: hardcore items, role graphs, sexual pose wording, and
camera controls are preserved. Negative prompts stay separate.
Important behavior:
- Age wording is preserved deliberately. Phrases like `21-year-old adult`,
`late 20s adult woman`, and `all participants 21+ and visibly adult` are kept
because they help avoid unwanted young-looking outputs.
- Trigger words are removed by default because Krea2 prompting generally reads
better as natural language. Enable `preserve_trigger` if you still need a LoRA
trigger in the positive prompt.
- `style_mode`: `preserve` keeps the current generated style text,
`photographic` converts the style tail toward creator-photo language, and
`minimal` omits most style text.
- For Insta/OF paired metadata, the node returns both `krea_softcore_prompt` and
`krea_hardcore_prompt`, with separate softcore and hardcore negatives.
It outputs:
- `krea_prompt`
- `negative_prompt`
- `krea_softcore_prompt`
- `krea_hardcore_prompt`
- `softcore_negative_prompt`
- `hardcore_negative_prompt`
- `method`
`SxCP Insta/OF Prompt Pair` is a special paired-output mode. It creates one `SxCP Insta/OF Prompt Pair` is a special paired-output mode. It creates one
shared primary creator descriptor, then returns both a softcore prompt and a shared primary creator descriptor, then returns both a softcore prompt and a
hardcore prompt from that same descriptor. This is useful when you want the same hardcore prompt from that same descriptor. This is useful when you want the same
@@ -180,6 +210,46 @@ provided, the node uses a generic composer that selects subject appearance,
scene, pose, expression, composition, and a random item from the selected scene, pose, expression, composition, and a random item from the selected
subcategory. subcategory.
Reusable location banks can be defined with top-level `scene_pools` in any
`categories/*.json` file. Categories, subcategories, and items can reference
them with `scene_pools`; referenced pools are merged with any local `scenes`.
This keeps location expansion scalable without duplicating the same bedroom,
selfie, mirror, creator, or group-sex locations across every subcategory.
Set `"inherit_scenes": false` on a subcategory or item when it should use only
its own `scenes` and `scene_pools` instead of also inheriting parent category
locations. This is useful for narrow subcategories such as group scenes, vehicle
sets, outdoor-only sets, or any category where a generic parent room would be a
bad match.
Example:
```json
{
"scene_pools": {
"creator_selfie_rooms": [
{
"slug": "bedroom_phone_tripod",
"prompt": "private creator bedroom with a phone tripod, rumpled bedding, and warm lamps"
}
]
},
"categories": [
{
"name": "Example",
"subcategories": [
{
"name": "Selfie set",
"inherit_scenes": false,
"scene_pools": ["creator_selfie_rooms"],
"items": ["simple outfit prompt"]
}
]
}
]
}
```
For large categories, prefer `item_templates` plus `item_axes` instead of writing For large categories, prefer `item_templates` plus `item_axes` instead of writing
every final item by hand: every final item by hand:
+73
View File
@@ -21,6 +21,7 @@ try:
subcategory_choices, subcategory_choices,
) )
from .caption_naturalizer import naturalize_caption from .caption_naturalizer import naturalize_caption
from .krea_formatter import format_krea2_prompt
except ImportError: except ImportError:
from prompt_builder import ( from prompt_builder import (
build_camera_config_json, build_camera_config_json,
@@ -40,6 +41,7 @@ except ImportError:
subcategory_choices, subcategory_choices,
) )
from caption_naturalizer import naturalize_caption from caption_naturalizer import naturalize_caption
from krea_formatter import format_krea2_prompt
class SxCPPromptBuilder: class SxCPPromptBuilder:
@@ -277,6 +279,75 @@ class SxCPCaptionNaturalizer:
) )
class SxCPKrea2Formatter:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"source_text": ("STRING", {"default": "", "multiline": True}),
"input_hint": (["auto", "metadata_json", "prompt"], {"default": "auto"}),
"target": (["auto", "single", "softcore", "hardcore"], {"default": "auto"}),
"detail_level": (["balanced", "concise", "dense"], {"default": "balanced"}),
"style_mode": (["preserve", "photographic", "minimal"], {"default": "preserve"}),
"preserve_trigger": ("BOOLEAN", {"default": False}),
},
"optional": {
"metadata_json": ("STRING", {"default": "", "multiline": True}),
"negative_prompt": ("STRING", {"default": "", "multiline": True}),
"extra_positive": ("STRING", {"default": "", "multiline": True}),
"extra_negative": ("STRING", {"default": "", "multiline": True}),
},
}
RETURN_TYPES = ("STRING", "STRING", "STRING", "STRING", "STRING", "STRING", "STRING")
RETURN_NAMES = (
"krea_prompt",
"negative_prompt",
"krea_softcore_prompt",
"krea_hardcore_prompt",
"softcore_negative_prompt",
"hardcore_negative_prompt",
"method",
)
FUNCTION = "build"
CATEGORY = "prompt_builder"
def build(
self,
source_text,
input_hint,
target,
detail_level,
style_mode,
preserve_trigger,
metadata_json="",
negative_prompt="",
extra_positive="",
extra_negative="",
):
row = format_krea2_prompt(
source_text=source_text or "",
metadata_json=metadata_json or "",
negative_prompt=negative_prompt or "",
input_hint=input_hint,
target=target,
detail_level=detail_level,
style_mode=style_mode,
preserve_trigger=preserve_trigger,
extra_positive=extra_positive or "",
extra_negative=extra_negative or "",
)
return (
row["krea_prompt"],
row["negative_prompt"],
row["krea_softcore_prompt"],
row["krea_hardcore_prompt"],
row["softcore_negative_prompt"],
row["hardcore_negative_prompt"],
row["method"],
)
class SxCPInstaOFOptions: class SxCPInstaOFOptions:
@classmethod @classmethod
def INPUT_TYPES(cls): def INPUT_TYPES(cls):
@@ -417,6 +488,7 @@ NODE_CLASS_MAPPINGS = {
"SxCPSeedControl": SxCPSeedControl, "SxCPSeedControl": SxCPSeedControl,
"SxCPCameraControl": SxCPCameraControl, "SxCPCameraControl": SxCPCameraControl,
"SxCPCaptionNaturalizer": SxCPCaptionNaturalizer, "SxCPCaptionNaturalizer": SxCPCaptionNaturalizer,
"SxCPKrea2Formatter": SxCPKrea2Formatter,
"SxCPInstaOFOptions": SxCPInstaOFOptions, "SxCPInstaOFOptions": SxCPInstaOFOptions,
"SxCPInstaOFPromptPair": SxCPInstaOFPromptPair, "SxCPInstaOFPromptPair": SxCPInstaOFPromptPair,
} }
@@ -426,6 +498,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"SxCPSeedControl": "SxCP Seed Control", "SxCPSeedControl": "SxCP Seed Control",
"SxCPCameraControl": "SxCP Camera Control", "SxCPCameraControl": "SxCP Camera Control",
"SxCPCaptionNaturalizer": "SxCP Caption Naturalizer", "SxCPCaptionNaturalizer": "SxCP Caption Naturalizer",
"SxCPKrea2Formatter": "SxCP Krea2 Formatter",
"SxCPInstaOFOptions": "SxCP Insta/OF Options", "SxCPInstaOFOptions": "SxCP Insta/OF Options",
"SxCPInstaOFPromptPair": "SxCP Insta/OF Prompt Pair", "SxCPInstaOFPromptPair": "SxCP Insta/OF Prompt Pair",
} }
+423 -21
View File
@@ -14,13 +14,136 @@
"name": "Streetwear", "name": "Streetwear",
"slug": "streetwear", "slug": "streetwear",
"weight": 1.0, "weight": 1.0,
"items": [ "scene_pools": ["casual_urban_scenes"],
"oversized hoodie with slim jeans and clean sneakers", "items": ["streetwear outfit generator"],
"cropped bomber jacket with cargo pants and chunky trainers", "item_templates": [
"graphic tee under an open flannel with fitted denim", "{outerwear} layered over {top}, with {bottom}, {footwear}, and {accessory}",
"sleek track jacket with joggers and minimal sneakers", "{top} with {bottom}, {outerwear}, {footwear}, and {detail}",
"denim-on-denim outfit with a fitted white tee" "{set_piece} styled with {footwear}, {accessory}, and {color_mood}",
"{outerwear} with {bottom}, {bag}, {footwear}, and {texture_detail}",
"{top} tucked into {bottom}, paired with {footwear}, {jewelry}, and {detail}",
"{outerwear} half-zipped over {top}, with {bottom}, {bag}, and {color_mood}",
"{set_piece} with {outerwear}, {footwear}, {jewelry}, and {texture_detail}",
"{top} under {outerwear}, with {bottom}, {accessory}, {bag}, and {footwear}"
], ],
"item_axes": {
"accessory": [
"a ribbed beanie",
"thin sunglasses",
"a baseball cap",
"wire-frame glasses",
"a silk neck scarf",
"fingerless gloves",
"a chunky belt",
"a low-profile headphones detail"
],
"bag": [
"a small crossbody bag",
"a canvas tote",
"a compact shoulder bag",
"a mini backpack",
"a waist pack worn crossbody",
"a structured leather satchel",
"a nylon sling bag",
"a glossy phone pouch"
],
"bottom": [
"relaxed cargo pants",
"straight-leg jeans",
"wide-leg denim",
"pleated utility trousers",
"fitted black jeans",
"soft joggers",
"a denim mini skirt with tights",
"tailored track pants",
"high-waist cropped trousers",
"washed grey jeans"
],
"color_mood": [
"muted city neutrals",
"black and cream contrast",
"soft grey-blue tones",
"washed denim colors",
"olive and charcoal accents",
"clean monochrome styling",
"warm brick-red accents",
"navy, white, and graphite layers"
],
"detail": [
"rolled cuffs",
"visible layered hems",
"a sharp cropped silhouette",
"clean oversized proportions",
"a relaxed off-duty fit",
"asymmetric tucked fabric",
"subtle graphic print details",
"a neat high-waist line"
],
"footwear": [
"clean white sneakers",
"chunky trainers",
"platform sneakers",
"minimal leather sneakers",
"black ankle boots",
"retro running shoes",
"canvas high-tops",
"sleek street boots"
],
"jewelry": [
"small hoop earrings",
"layered chain necklaces",
"a simple watch",
"stacked rings",
"a thin choker",
"minimal silver earrings",
"a pendant necklace",
"a narrow bracelet"
],
"outerwear": [
"oversized hoodie",
"cropped bomber jacket",
"open flannel shirt",
"sleek track jacket",
"denim jacket",
"boxy leather jacket",
"lightweight varsity jacket",
"oversized zip hoodie",
"short trench jacket",
"quilted street jacket"
],
"set_piece": [
"denim-on-denim outfit",
"matching track set",
"monochrome hoodie-and-jogger set",
"oversized shirt-and-cargo outfit",
"cropped jacket and wide denim outfit",
"clean athleisure set",
"utility vest and trouser outfit",
"layered tee and open-shirt outfit"
],
"texture_detail": [
"washed cotton texture",
"soft fleece texture",
"matte nylon fabric",
"structured denim seams",
"subtle ribbed knit trim",
"smooth leather accents",
"canvas strap details",
"creased everyday fabric"
],
"top": [
"fitted white tee",
"cropped tank top",
"graphic tee",
"ribbed long-sleeve top",
"simple black tee",
"slim turtleneck",
"soft henley shirt",
"cropped sweatshirt",
"mesh-layered tee",
"clean sleeveless top"
]
},
"scenes": [ "scenes": [
{ {
"slug": "city_crosswalk", "slug": "city_crosswalk",
@@ -34,20 +157,166 @@
"poses": [ "poses": [
"standing with one hand in a pocket", "standing with one hand in a pocket",
"leaning against a wall with relaxed confidence", "leaning against a wall with relaxed confidence",
"walking forward with a casual runway stride" "walking forward with a casual runway stride",
"looking over one shoulder while stepping off a curb",
"sitting on a low concrete wall with one knee raised",
"adjusting sunglasses with a relaxed half-smile",
"hands in jacket pockets with a slight hip shift",
"turning mid-step as fabric layers move naturally"
] ]
}, },
{ {
"name": "Summer casual", "name": "Summer casual",
"slug": "summer_casual", "slug": "summer_casual",
"weight": 1.0, "weight": 1.0,
"items": [ "scene_pools": ["casual_summer_scenes"],
"light cotton sundress with simple sandals", "items": ["summer casual outfit generator"],
"linen shorts with a tucked-in sleeveless blouse", "item_templates": [
"soft camp-collar shirt with relaxed trousers", "{dress} with {footwear}, {accessory}, and {fabric_detail}",
"ribbed tank top with a flowing midi skirt", "{top} with {bottom}, {footwear}, {bag}, and {color_mood}",
"breathable linen two-piece in pale summer colors" "{layer} over {top}, with {bottom}, {accessory}, and {texture_detail}",
"{two_piece} with {footwear}, {jewelry}, and {fabric_detail}",
"{top} tucked into {bottom}, paired with {bag}, {footwear}, and {detail}",
"{dress} under {layer}, with {accessory}, {jewelry}, and {color_mood}",
"{two_piece} styled with {bag}, {footwear}, {texture_detail}, and {detail}",
"{top} with {bottom}, {layer}, {accessory}, and {fabric_detail}"
], ],
"item_axes": {
"accessory": [
"wide sunglasses",
"a straw sunhat",
"a silk hair scarf",
"a woven belt",
"thin oval sunglasses",
"a cotton bandana",
"a simple sun visor",
"a lightweight shawl"
],
"bag": [
"a woven tote",
"a small raffia bag",
"a canvas beach bag",
"a soft shoulder bag",
"a compact basket purse",
"a linen drawstring bag",
"a minimal crossbody pouch",
"a straw clutch"
],
"bottom": [
"linen shorts",
"relaxed cropped trousers",
"a flowing midi skirt",
"high-waist cotton shorts",
"a breezy wrap skirt",
"wide-leg linen pants",
"a soft pleated skirt",
"light denim shorts",
"paperbag-waist trousers",
"a calf-length summer skirt"
],
"color_mood": [
"pale summer colors",
"sun-washed white and blue",
"coral and cream accents",
"sage green and ivory tones",
"soft yellow and denim blue",
"warm terracotta details",
"fresh white and citrus accents",
"muted sea-glass colors"
],
"detail": [
"rolled hems",
"a loose tucked waist",
"wind-lifted fabric edges",
"open collar styling",
"a relaxed vacation fit",
"thin shoulder straps",
"a clean high-waist line",
"softly draped fabric"
],
"dress": [
"light cotton sundress",
"button-front linen dress",
"soft wrap dress",
"ribbed tank dress",
"flowing midi sundress",
"simple slip dress",
"tiered cotton dress",
"halter summer dress"
],
"fabric_detail": [
"breathable linen texture",
"soft cotton folds",
"light gauze fabric",
"fine ribbed cotton",
"sunlit woven texture",
"thin summer knit texture",
"crisp poplin folds",
"airy voile fabric"
],
"footwear": [
"simple sandals",
"flat leather sandals",
"white canvas sneakers",
"espadrilles",
"strappy sandals",
"woven slides",
"minimal mule sandals",
"low platform sandals"
],
"jewelry": [
"small gold hoops",
"a shell necklace",
"a delicate anklet",
"thin stacked bracelets",
"a small pendant necklace",
"pearl stud earrings",
"a beaded bracelet",
"a fine waist chain over fabric"
],
"layer": [
"soft camp-collar shirt",
"open linen shirt",
"light cotton overshirt",
"cropped denim jacket",
"sheer beach shirt",
"loose short-sleeve cardigan",
"thin knit wrap",
"unbuttoned chambray shirt"
],
"texture_detail": [
"natural linen slubs",
"matte cotton finish",
"subtle woven stripes",
"soft wrinkled fabric",
"delicate eyelet texture",
"smooth summer poplin",
"sunlit thread texture",
"lightweight ribbing"
],
"top": [
"tucked-in sleeveless blouse",
"ribbed tank top",
"cropped cotton tee",
"linen camisole",
"halter knit top",
"soft bandeau under a shirt",
"square-neck tank",
"thin-strapped summer top",
"buttoned linen vest",
"loose cotton blouse"
],
"two_piece": [
"breathable linen two-piece",
"matching crop top and skirt set",
"soft resort shirt-and-short set",
"ribbed tank and midi skirt set",
"cotton co-ord set",
"linen vest and trouser set",
"open shirt and wrap-skirt set",
"minimal summer knit set"
]
},
"scenes": [ "scenes": [
{ {
"slug": "sunny_market", "slug": "sunny_market",
@@ -61,20 +330,148 @@
"poses": [ "poses": [
"turning slightly with fabric moving in the breeze", "turning slightly with fabric moving in the breeze",
"standing in warm sunlight with relaxed shoulders", "standing in warm sunlight with relaxed shoulders",
"sitting on a low wall with one knee bent" "sitting on a low wall with one knee bent",
"walking with one hand holding a sunhat",
"leaning on a promenade railing with a soft smile",
"lifting sunglasses while looking toward the light",
"standing barefoot near warm paving stones",
"mid-step with loose fabric trailing behind"
] ]
}, },
{ {
"name": "Cozy lounge", "name": "Cozy lounge",
"slug": "cozy_lounge", "slug": "cozy_lounge",
"weight": 1.0, "weight": 1.0,
"items": [ "scene_pools": ["casual_lounge_scenes"],
"soft knit cardigan with a fitted tee and lounge trousers", "items": ["cozy lounge outfit generator"],
"oversized sweater with leggings and wool socks", "item_templates": [
"relaxed sweatshirt with drawstring joggers", "{layer} over {top}, with {bottom}, {footwear}, and {texture_detail}",
"ribbed lounge set with a long open cardigan", "{set_piece} with {layer}, {accessory}, and {color_mood}",
"simple cotton tee with loose pajama-style trousers" "{top} with {bottom}, {footwear}, {prop}, and {detail}",
"{layer} wrapped around {top}, with {bottom}, {jewelry}, and {texture_detail}",
"{set_piece} styled with {footwear}, {prop}, and {detail}",
"{top} tucked loosely into {bottom}, with {layer}, {accessory}, and {color_mood}",
"{layer} slipping off one shoulder over {top}, with {bottom}, {footwear}, and {texture_detail}",
"{set_piece} with {accessory}, {jewelry}, {prop}, and {detail}"
], ],
"item_axes": {
"accessory": [
"a soft hair clip",
"thin reading glasses",
"a scrunchie at the wrist",
"a loose blanket scarf",
"a simple headband",
"a warm knit beanie",
"a delicate sleep mask pushed up",
"a cotton bandana"
],
"bottom": [
"lounge trousers",
"soft leggings",
"drawstring joggers",
"loose pajama-style trousers",
"ribbed lounge pants",
"wide knit pants",
"cotton sleep shorts",
"thermal leggings",
"slouchy sweatpants",
"soft waffle-knit pants"
],
"color_mood": [
"warm oatmeal and grey tones",
"soft rose and cream colors",
"muted sage and ivory",
"heather grey and white",
"warm mocha neutrals",
"powder blue and cream",
"charcoal and blush accents",
"soft lavender and warm beige"
],
"detail": [
"relaxed draped proportions",
"rolled sleeves",
"softly rumpled fabric",
"a loose off-duty silhouette",
"visible cozy layering",
"a slightly oversized fit",
"bare ankle styling",
"a gentle high-waist line"
],
"footwear": [
"wool socks",
"soft house slippers",
"bare feet",
"fuzzy socks",
"knit ankle socks",
"shearling slippers",
"simple cotton socks",
"ribbed knee socks"
],
"jewelry": [
"tiny hoop earrings",
"a simple pendant necklace",
"a thin bracelet",
"small stud earrings",
"a delicate ring",
"a minimal chain necklace",
"a soft fabric wristband",
"a subtle ankle chain"
],
"layer": [
"soft knit cardigan",
"long open cardigan",
"oversized sweater",
"relaxed sweatshirt",
"chunky cable-knit cardigan",
"brushed fleece hoodie",
"thin robe cardigan",
"cropped lounge hoodie",
"slouchy wrap sweater",
"soft waffle-knit cardigan"
],
"prop": [
"a casual magazine nearby",
"a warm mug in one hand",
"a paperback book nearby",
"a folded blanket at the hip",
"a phone resting on the sofa",
"a small tray on a side table",
"a pillow tucked against the waist",
"a half-open notebook nearby"
],
"set_piece": [
"ribbed lounge set",
"matching sweatshirt and jogger set",
"soft knit co-ord set",
"cotton tee and pajama trouser set",
"waffle-knit lounge set",
"brushed fleece lounge set",
"cardigan and knit pant set",
"simple sleepwear-inspired set"
],
"texture_detail": [
"soft knit texture",
"brushed fleece texture",
"ribbed cotton texture",
"waffle-knit fabric",
"warm wool fibers",
"smooth jersey folds",
"plush cardigan texture",
"softly worn cotton"
],
"top": [
"fitted tee",
"simple cotton tee",
"ribbed tank top",
"soft long-sleeve top",
"thin camisole",
"slouchy henley shirt",
"cropped lounge tee",
"thermal knit top",
"light sleep tank",
"soft V-neck tee"
]
},
"scenes": [ "scenes": [
{ {
"slug": "sunny_apartment", "slug": "sunny_apartment",
@@ -88,7 +485,12 @@
"poses": [ "poses": [
"curled comfortably on a sofa", "curled comfortably on a sofa",
"standing barefoot near a window with a relaxed smile", "standing barefoot near a window with a relaxed smile",
"sitting cross-legged with a casual magazine nearby" "sitting cross-legged with a casual magazine nearby",
"leaning into a couch corner with one knee raised",
"stretching lazily with sleeves falling over the hands",
"kneeling on a rug while reaching for a warm mug",
"standing in profile near soft curtains",
"reclining with one arm draped over a pillow"
] ]
} }
] ]
+7
View File
@@ -10,6 +10,7 @@
"style": "explicit adult erotic fashion illustration, sensual pin-up coloured-pencil comic style, adults only", "style": "explicit adult erotic fashion illustration, sensual pin-up coloured-pencil comic style, adults only",
"positive_suffix": "Use crisp clean comic linework, detailed hatching, soft skin shading, tactile fabric texture, warm intimate lighting, and textured paper.", "positive_suffix": "Use crisp clean comic linework, detailed hatching, soft skin shading, tactile fabric texture, warm intimate lighting, and textured paper.",
"negative_prompt": "minors, childlike appearance, schoolgirl, childlike costume, non-consensual, coercion, violence, injury, watermark", "negative_prompt": "minors, childlike appearance, schoolgirl, childlike costume, non-consensual, coercion, violence, injury, watermark",
"scene_pools": ["softcore_creator_scenes", "mirror_scenes"],
"expressions": [ "expressions": [
"heavy-lidded seductive gaze", "heavy-lidded seductive gaze",
"direct erotic stare", "direct erotic stare",
@@ -47,6 +48,7 @@
"name": "Provocative lingerie", "name": "Provocative lingerie",
"slug": "provocative_lingerie", "slug": "provocative_lingerie",
"weight": 1.0, "weight": 1.0,
"scene_pools": ["boudoir_bedroom_scenes"],
"item_templates": [ "item_templates": [
"{color} {fabric} {bra_style} with {bottom_style}, {garter_detail}, {stocking_style}, and {shoe_style}", "{color} {fabric} {bra_style} with {bottom_style}, {garter_detail}, {stocking_style}, and {shoe_style}",
"{color} {bodywear} with {neckline}, {hip_cut}, {back_detail}, and {trim_detail}", "{color} {bodywear} with {neckline}, {hip_cut}, {back_detail}, and {trim_detail}",
@@ -306,6 +308,7 @@
"name": "Sheer exposed", "name": "Sheer exposed",
"slug": "sheer_exposed", "slug": "sheer_exposed",
"weight": 1.0, "weight": 1.0,
"scene_pools": ["softcore_creator_scenes", "mirror_scenes"],
"item_templates": [ "item_templates": [
"{color} {sheer_fabric} {sheer_garment} with {exposed_breast_detail}, {hip_detail}, and {shoe_style}", "{color} {sheer_fabric} {sheer_garment} with {exposed_breast_detail}, {hip_detail}, and {shoe_style}",
"{color} open sheer robe exposing {exposed_breast_detail}, {lower_exposure}, and {jewelry}", "{color} open sheer robe exposing {exposed_breast_detail}, {lower_exposure}, and {jewelry}",
@@ -549,6 +552,7 @@
"name": "Fetish inspired", "name": "Fetish inspired",
"slug": "fetish_inspired", "slug": "fetish_inspired",
"weight": 1.0, "weight": 1.0,
"scene_pools": ["fetish_studio_scenes"],
"item_templates": [ "item_templates": [
"{color} {material} {latex_piece} with {zipper_detail}, {boot_style}, and {glove_style}", "{color} {material} {latex_piece} with {zipper_detail}, {boot_style}, and {glove_style}",
"{color} {harness_style} over {breast_exposure} with {bottom_detail}, {hardware}, and {shoe_style}", "{color} {harness_style} over {breast_exposure} with {bottom_detail}, {hardware}, and {shoe_style}",
@@ -808,6 +812,7 @@
"name": "Nude accessories", "name": "Nude accessories",
"slug": "nude_accessories", "slug": "nude_accessories",
"weight": 1.0, "weight": 1.0,
"scene_pools": ["boudoir_bedroom_scenes", "mirror_scenes"],
"item_templates": [ "item_templates": [
"fully nude body styled only with {stocking_style}, {shoe_style}, and {jewelry}", "fully nude body styled only with {stocking_style}, {shoe_style}, and {jewelry}",
"bare breasts and bare hips framed by {accessory_set}, {stocking_style}, and {shoe_style}", "bare breasts and bare hips framed by {accessory_set}, {stocking_style}, and {shoe_style}",
@@ -971,6 +976,7 @@
"name": "Microwear and body tape", "name": "Microwear and body tape",
"slug": "microwear_body_tape", "slug": "microwear_body_tape",
"weight": 1.0, "weight": 1.0,
"scene_pools": ["softcore_creator_scenes", "fetish_studio_scenes"],
"item_templates": [ "item_templates": [
"{color} micro bikini with {top_detail}, {bottom_detail}, {body_tape}, and {shoe_style}", "{color} micro bikini with {top_detail}, {bottom_detail}, {body_tape}, and {shoe_style}",
"{color} body tape design covering only {tape_coverage}, with {bottom_detail}, {jewelry}, and {shoe_style}", "{color} body tape design covering only {tape_coverage}, with {bottom_detail}, {jewelry}, and {shoe_style}",
@@ -1160,6 +1166,7 @@
"name": "Erotic costumes", "name": "Erotic costumes",
"slug": "erotic_costumes", "slug": "erotic_costumes",
"weight": 1.0, "weight": 1.0,
"scene_pools": ["costume_backstage_scenes", "softcore_creator_scenes"],
"item_templates": [ "item_templates": [
"{color} adult {costume_role} look with {top_detail}, {bottom_detail}, {stocking_style}, and {shoe_style}", "{color} adult {costume_role} look with {top_detail}, {bottom_detail}, {stocking_style}, and {shoe_style}",
"{color} fantasy {costume_role} costume with {corset_detail}, {exposure_detail}, {accessory}, and {shoe_style}", "{color} fantasy {costume_role} costume with {corset_detail}, {exposure_detail}, {accessory}, and {shoe_style}",
+181
View File
@@ -0,0 +1,181 @@
{
"version": 1,
"scene_pools": {
"casual_urban_scenes": [
{"slug": "city_crosswalk_phone_snap", "prompt": "sunlit city crosswalk with storefront reflections and a casual phone-snapshot angle"},
{"slug": "subway_tile_selfie_corner", "prompt": "clean subway platform with tiled walls, overhead lights, and a quiet selfie corner"},
{"slug": "parking_rooftop_streetwear", "prompt": "parking garage rooftop with painted lines, city haze, and late-afternoon light"},
{"slug": "record_shop_mirror_wall", "prompt": "record shop aisle with warm neon, poster walls, and a small mirror behind the counter"},
{"slug": "coffee_window_counter", "prompt": "coffee shop window counter with street reflections and soft morning light"},
{"slug": "brick_alley_fire_escape", "prompt": "brick alley beside a fire escape with clean pavement and reflected city light"},
{"slug": "boutique_changing_mirror", "prompt": "boutique changing-room mirror with clothing hooks, soft bulbs, and a candid outfit-check angle"},
{"slug": "streetwear_elevator_lobby", "prompt": "modern apartment elevator lobby with brushed metal doors and a full-length mirror"}
],
"casual_summer_scenes": [
{"slug": "seaside_prom_phone_photo", "prompt": "seaside promenade with bright sky, warm paving stones, and casual phone-photo framing"},
{"slug": "weekend_market_canvas_awning", "prompt": "open-air weekend market with fruit stands, canvas awnings, and sunlit walkway space"},
{"slug": "rooftop_day_terrace", "prompt": "daytime rooftop terrace with potted plants, white chairs, and clear summer light"},
{"slug": "beach_cafe_table", "prompt": "beach cafe table with woven chairs, linen shade, and ocean light in the background"},
{"slug": "poolside_daybed_casual", "prompt": "poolside daybed with white towels, glass railings, and soft resort sunlight"},
{"slug": "garden_wall_summer", "prompt": "garden wall with climbing flowers, pale stone, and warm afternoon shadows"},
{"slug": "lake_boardwalk_summer", "prompt": "wooden lakeside boardwalk with reeds, clean sky, and relaxed vacation light"},
{"slug": "sunny_balcony_outfit_check", "prompt": "sunny apartment balcony with plants, city rooftops, and a casual outfit-check composition"}
],
"casual_lounge_scenes": [
{"slug": "sunny_apartment_phone_tripod", "prompt": "sunny apartment corner with bookshelves, a warm rug, and a phone on a small tripod"},
{"slug": "window_seat_soft_curtains", "prompt": "comfortable window seat with soft curtains, pillows, and afternoon light"},
{"slug": "bedroom_floor_lounge", "prompt": "cozy bedroom floor with folded blankets, low shelves, and soft window light"},
{"slug": "sofa_ring_light_corner", "prompt": "living-room sofa corner with a ring light stand, plants, and warm lamps"},
{"slug": "loft_kitchen_lounge", "prompt": "open loft kitchen with a breakfast counter, wood floor, and relaxed home light"},
{"slug": "reading_nook_phone_snap", "prompt": "reading nook with stacked books, a small mirror, and candid phone-snapshot framing"},
{"slug": "hotel_morning_lounge", "prompt": "hotel room lounge chair with rumpled travel bags, curtains, and soft morning sun"},
{"slug": "studio_apartment_mirror", "prompt": "small studio apartment with a full-length mirror, neutral bedding, and warm lamp light"}
],
"softcore_creator_scenes": [
{"slug": "creator_bedroom_ring_light", "prompt": "private creator bedroom with a ring light, phone tripod, rumpled bedding, and warm lamps"},
{"slug": "onlyfans_mirror_bedroom", "prompt": "bedroom mirror selfie setup with a visible phone, messy sheets, and soft amber light"},
{"slug": "walk_in_closet_tryon", "prompt": "mirrored walk-in closet with open drawers, hanging outfits, and warm boutique bulbs"},
{"slug": "hotel_bed_phone_tripod", "prompt": "hotel bed content setup with a phone on a mini tripod, city lights, and satin bedding"},
{"slug": "bathroom_counter_selfie", "prompt": "private bathroom counter with mirror haze, phone reflection, towels, and warm vanity lights"},
{"slug": "vanity_ring_light_close", "prompt": "vanity corner with makeup lights, perfume bottles, silk fabric, and close creator-shot framing"},
{"slug": "apartment_floor_content", "prompt": "apartment floor content setup with a low mirror, pillows, and soft practical lamps"},
{"slug": "balcony_phone_selfie", "prompt": "private balcony with city lights, glass railing, and handheld phone-selfie perspective"},
{"slug": "car_interior_creator_selfie", "prompt": "parked car interior with seat reflections, dashboard glow, and close phone-selfie framing"},
{"slug": "shower_steam_phone_reflection", "prompt": "steamy private shower room with wet tile, glass reflections, and implied phone-shot framing"},
{"slug": "studio_bedroom_backdrop", "prompt": "small creator studio with a bed, seamless backdrop, ring light, and visible phone stand"},
{"slug": "couch_lamp_creator_clip", "prompt": "private couch corner with scattered clothes, warm lamp glow, and vertical creator-video framing"}
],
"mirror_scenes": [
{"slug": "large_bedroom_mirror_selfie", "prompt": "large bedroom mirror with the phone visible, bed behind the subject, and warm side lamps"},
{"slug": "antique_mirror_boudoir", "prompt": "antique mirror corner with dark wood, perfume bottles, and golden lamplight"},
{"slug": "bathroom_mirror_haze", "prompt": "bathroom mirror selfie setup with steam haze, marble tile, and warm vanity bulbs"},
{"slug": "closet_full_length_mirror", "prompt": "full-length closet mirror with outfit racks, shoe shelves, and soft boutique lighting"},
{"slug": "hotel_mirror_city_view", "prompt": "hotel suite mirror reflecting city lights, satin bedding, and a phone in hand"},
{"slug": "neon_mirror_wall", "prompt": "neon mirror wall with glossy floor reflections and saturated magenta-blue edge light"},
{"slug": "gold_vanity_mirror", "prompt": "gold-framed vanity mirror with makeup lights, silk fabric, and close reflected framing"},
{"slug": "black_lacquer_mirror_room", "prompt": "black lacquer mirror room with glossy furniture, velvet curtains, and sharp rim light"}
],
"hardcore_mirror_scenes": [
{"slug": "hardcore_bedroom_mirror_pair", "prompt": "large bedroom mirror placed beside a rumpled bed, reflecting explicit adult body contact and the phone-camera angle", "min_people": 2, "max_people": 3},
{"slug": "hardcore_hotel_mirror_pair", "prompt": "hotel suite mirror facing a messy bed, city lights behind it, and enough space for explicit adult positioning", "min_people": 2, "max_people": 3},
{"slug": "hardcore_floor_mirror_set", "prompt": "floor mattress beside a full-length mirror with reflected bodies, warm lamps, and close creator-shot framing", "min_people": 2, "max_people": 3},
{"slug": "hardcore_shower_mirror_pair", "prompt": "private shower room with a fogged mirror wall, wet tile, and reflected explicit adult contact", "min_people": 2, "max_people": 3},
{"slug": "hardcore_vanity_mirror_floor", "prompt": "vanity mirror floor setup with bulbs, scattered clothing, low phone-camera angle, and reflected adult bodies", "min_people": 2, "max_people": 3},
{"slug": "hardcore_lacquer_mirror_bed", "prompt": "black lacquer mirror bedroom with glossy reflections, a low bed, and warm rim light around explicit adult contact", "min_people": 2, "max_people": 3},
{"slug": "hardcore_tripod_mirror_bed", "prompt": "creator bedroom mirror setup with a phone on tripod, bed sheets, reflected bodies, and clear adult-only framing", "min_people": 2, "max_people": 3},
{"slug": "hardcore_threesome_mirror_suite", "prompt": "wide mirror-wall suite arranged for three adults, with a bed, floor cushions, and all bodies visible in direct and reflected views", "min_people": 3, "max_people": 3}
],
"boudoir_bedroom_scenes": [
{"slug": "warm_boudoir_canopy_bed", "prompt": "warm boudoir bedroom with satin sheets, canopy curtains, low lamplight, and bedside phone framing"},
{"slug": "silk_bed_close_creator", "prompt": "silk-sheet bed with pillows, a phone on the nightstand, and intimate creator-shot light"},
{"slug": "velvet_headboard_bedroom", "prompt": "velvet headboard bedroom with gold lamps, rumpled bedding, and close sensual framing"},
{"slug": "four_poster_lingerie_room", "prompt": "four-poster bed with sheer drapes, warm lamps, and soft floor shadows"},
{"slug": "hotel_satin_bedroom", "prompt": "luxury hotel bedroom with satin bedding, city glow, and a visible mirror near the bed"},
{"slug": "rose_lamp_bedroom", "prompt": "intimate bedroom with rose-colored lamps, silk sheets, and soft shadows"}
],
"fetish_studio_scenes": [
{"slug": "black_latex_studio_floor", "prompt": "dark private studio with glossy black floor reflections, rim light, and a phone tripod"},
{"slug": "red_velvet_lacquer_room", "prompt": "red velvet room with black lacquer furniture, low spotlights, and reflective surfaces"},
{"slug": "industrial_loft_private_set", "prompt": "private industrial loft with brick walls, metal beams, chains, and dramatic light"},
{"slug": "neon_lacquer_private_room", "prompt": "private neon-lit lacquer room with magenta highlights, mirrors, and glossy floor"},
{"slug": "harness_wall_studio", "prompt": "private harness-wall studio with leather props, matte black backdrop, and controlled rim light"},
{"slug": "chrome_fetish_set", "prompt": "chrome studio set with reflective panels, black curtains, and hard-edged erotic lighting"}
],
"costume_backstage_scenes": [
{"slug": "costume_dressing_room_phone", "prompt": "private costume dressing room with racks, warm mirror bulbs, velvet curtains, and a phone selfie angle"},
{"slug": "burlesque_stage_close", "prompt": "small private burlesque stage with red curtains, warm spotlights, and close audience-level framing"},
{"slug": "cabaret_backstage_vanity", "prompt": "cabaret backstage corner with feather props, vanity mirrors, and dark wood"},
{"slug": "after_dark_private_office", "prompt": "stylized private office after dark with blinds, desk lamp, and city glow"},
{"slug": "fantasy_parlor_content_set", "prompt": "dark fantasy parlor with velvet chair, candlelight, antique wallpaper, and creator-shot framing"},
{"slug": "cosplay_hotel_mirror", "prompt": "hotel mirror cosplay try-on setup with costume pieces on chairs and warm vanity bulbs"}
],
"hardcore_private_scenes": [
{"slug": "hardcore_bedroom_phone_tripod", "prompt": "private bedroom sex-content setup with a phone tripod, rumpled sheets, pillows, and warm lamps"},
{"slug": "hardcore_hotel_bed_city", "prompt": "luxury hotel suite with city lights, messy satin bedding, floor clothes, and low amber light"},
{"slug": "hardcore_mirror_bedroom", "prompt": "bedroom with a large mirror reflecting the explicit adult scene and a visible phone angle"},
{"slug": "hardcore_low_mattress_studio", "prompt": "private photo studio with a low mattress, fabric drapes, phone tripod, and controlled warm spotlighting"},
{"slug": "hardcore_velvet_room", "prompt": "private velvet room with dark curtains, soft cushions, scattered clothes, and warm red light"},
{"slug": "hardcore_shower_room", "prompt": "large private shower room with steam, wet tile, glass reflections, and warm reflected light"},
{"slug": "hardcore_lounge_couch", "prompt": "dim private lounge with a wide couch, scattered clothing, side lamps, and soft golden shadows"},
{"slug": "hardcore_floor_cushion_room", "prompt": "intimate room with floor cushions, silk sheets, low candles, and close vertical camera framing"},
{"slug": "hardcore_ring_light_bed", "prompt": "creator bedroom with ring light reflection, phone on tripod, bed sheets, and visible content setup"},
{"slug": "hardcore_bathroom_counter", "prompt": "private bathroom with counter mirror, wet towels, steam, and explicit creator-shot framing"},
{"slug": "hardcore_walk_in_closet_floor", "prompt": "mirrored walk-in closet floor with clothes scattered, warm bulbs, and a phone reflection"},
{"slug": "hardcore_car_backseat", "prompt": "parked private car backseat with tinted windows, dashboard glow, and tight phone-camera framing"}
],
"hardcore_bed_scenes": [
{"slug": "bed_edge_close_contact", "prompt": "edge of a rumpled bed with pillows pushed aside, sheets pulled tight, and close phone-camera framing"},
{"slug": "low_bed_mirror_angle", "prompt": "low bed beside a full-length mirror with visible reflected bodies and warm lamps"},
{"slug": "hotel_bed_overhead", "prompt": "hotel bed arranged for an overhead phone shot with satin sheets and city light"},
{"slug": "floor_mattress_creator_set", "prompt": "floor mattress content setup with fabric drapes, ring light shadow, and scattered clothes"},
{"slug": "canopy_bed_explicit_set", "prompt": "canopy bed with sheer curtains, warm bedside light, and intimate full-body framing"},
{"slug": "velvet_bedroom_wide", "prompt": "velvet bedroom with wide bed, dark curtains, soft cushions, and warm red side light"}
],
"hardcore_penetrative_scenes": [
{"slug": "penetration_mirror_bedroom", "prompt": "mirror-facing bedroom setup designed to show explicit body contact and the phone angle"},
{"slug": "penetration_edge_of_bed", "prompt": "edge-of-bed setup with hips near the camera, rumpled sheets, and warm lamp light"},
{"slug": "penetration_low_mattress", "prompt": "low mattress studio with side lighting, fabric drapes, and all bodies visible"},
{"slug": "penetration_couch_lounge", "prompt": "wide private couch with pillows pushed aside, scattered clothes, and golden shadows"},
{"slug": "penetration_shower_bench", "prompt": "wet shower bench with steam, tile reflections, and close explicit framing"},
{"slug": "penetration_floor_cushions", "prompt": "floor cushions and silk sheets arranged for full-body explicit contact"}
],
"hardcore_oral_scenes": [
{"slug": "oral_bed_kneeling_close", "prompt": "bedside kneeling setup with pillows, warm lamps, and close mouth-level camera framing"},
{"slug": "oral_mirror_floor", "prompt": "mirror-facing floor setup with bodies reflected and phone held low"},
{"slug": "oral_couch_front_view", "prompt": "private couch arranged for front-view oral contact with soft side lamps"},
{"slug": "oral_shower_steam", "prompt": "steamy shower room with wet tile, glass reflections, and close explicit framing"},
{"slug": "oral_vanity_floor", "prompt": "vanity-room floor with mirror bulbs, scattered lingerie, and low phone-camera angle"},
{"slug": "oral_hotel_bed_close", "prompt": "hotel bed close-up setup with satin sheets, city light, and tight vertical framing"}
],
"hardcore_anal_scenes": [
{"slug": "anal_rear_mirror_bed", "prompt": "bedroom mirror setup emphasizing rear-view body alignment and explicit contact"},
{"slug": "anal_bent_over_couch", "prompt": "wide private couch arranged for bent-over explicit contact and low camera angle"},
{"slug": "anal_edge_bed_low_angle", "prompt": "edge-of-bed low-angle setup with sheets pulled aside and hips near the lens"},
{"slug": "anal_shower_wall", "prompt": "wet shower wall with steam, tile reflections, and hard side lighting"},
{"slug": "anal_velvet_bench", "prompt": "private velvet bench with dark curtains, red light, and clear full-body framing"},
{"slug": "anal_floor_mattress_mirror", "prompt": "floor mattress beside a full-length mirror with both direct and reflected views"}
],
"hardcore_threesome_scenes": [
{"slug": "threesome_wide_bedroom", "prompt": "wide bedroom setup with a large bed, mirror wall, phone tripod, and all three bodies visible"},
{"slug": "threesome_hotel_suite", "prompt": "hotel suite bed and couch area arranged for three adults and city-window light"},
{"slug": "threesome_floor_cushions", "prompt": "floor cushion room with silk sheets, low lamps, and enough space for three bodies"},
{"slug": "threesome_studio_mattress", "prompt": "private studio mattress with fabric drapes, ring light shadow, and three-person framing"},
{"slug": "threesome_shower_room", "prompt": "large shower room with wet tile, steam, glass reflections, and three-person spacing"},
{"slug": "threesome_velvet_lounge", "prompt": "private velvet lounge with wide couch, cushions, and warm red-gold light"}
],
"hardcore_group_scenes": [
{"slug": "group_suite_wide_bed", "prompt": "large private suite with a wide bed, couch area, scattered clothes, and all participants visible"},
{"slug": "group_studio_mattress_room", "prompt": "private studio with multiple low mattresses, fabric drapes, ring lights, and full group visibility"},
{"slug": "group_velvet_orgy_room", "prompt": "private velvet orgy room with dark curtains, floor cushions, soft lamps, and open floor space"},
{"slug": "group_lounge_couches", "prompt": "dim private lounge with multiple couches, pillows, warm side lamps, and wide group framing"},
{"slug": "group_floor_pillow_room", "prompt": "large floor-pillow room with silk sheets, low candles, and overhead camera possibility"},
{"slug": "group_shower_spa_room", "prompt": "large private shower spa with wet tile, steam, benches, and space for multiple adults"},
{"slug": "group_rooftop_private_party", "prompt": "private rooftop after-party suite with glass railings, couches, and city lights"},
{"slug": "group_hotel_party_bedroom", "prompt": "messy hotel party bedroom with a king bed, side couch, bottles, and warm practical lights"},
{"slug": "group_backstage_private_room", "prompt": "private backstage green room with costume racks, couches, mirror bulbs, and scattered clothes"},
{"slug": "group_neon_loft_room", "prompt": "private neon loft with mattresses, glossy floor reflections, and wide explicit group composition"},
{"slug": "group_mirror_wall_suite", "prompt": "large mirror-wall suite with a wide bed, floor cushions, phone tripod, and enough space to reflect a full adult group"},
{"slug": "group_lacquer_mirror_lounge", "prompt": "wide black-lacquer mirror lounge with multiple couches, glossy reflections, warm rim light, and all participants visible"}
],
"hardcore_climax_scenes": [
{"slug": "climax_bed_close_flash", "prompt": "rumpled bed close-up setup with direct phone flash, sheets, and visible fluid detail"},
{"slug": "climax_mirror_counter", "prompt": "mirror-facing vanity counter setup with phone reflection and explicit aftermath framing"},
{"slug": "climax_floor_sheets", "prompt": "floor sheets with pillows pushed aside, low lamp light, and close body-detail framing"},
{"slug": "climax_hotel_bed_flash", "prompt": "hotel bed with phone-flash lighting, messy satin sheets, and city light behind"},
{"slug": "climax_shower_tile", "prompt": "wet shower tile scene with steam, reflected light, and visible fluid detail"},
{"slug": "climax_velvet_couch", "prompt": "velvet couch with dark curtains, warm red light, and close explicit aftermath framing"}
]
},
"pool_extensions": {
"group_scenes": [
{"slug": "private_suite_group_party", "prompt": "large private suite with a wide bed, couch area, scattered clothes, and warm party lighting"},
{"slug": "private_studio_group_mattresses", "prompt": "private studio with multiple low mattresses, fabric drapes, and wide group visibility"},
{"slug": "velvet_lounge_group_couches", "prompt": "private velvet lounge with multiple couches, pillows, and low red-gold light"},
{"slug": "rooftop_afterparty_suite", "prompt": "private rooftop after-party suite with glass railings, couches, and city lights"},
{"slug": "hotel_party_bedroom_group", "prompt": "messy hotel party bedroom with a king bed, side couch, bottles, and warm practical lights"},
{"slug": "neon_loft_group_room", "prompt": "private neon loft with glossy floor reflections, mattresses, and wide group composition"},
{"slug": "backstage_green_room_group", "prompt": "private backstage green room with costume racks, mirror bulbs, couches, and scattered clothes"},
{"slug": "shower_spa_group_room", "prompt": "large private shower spa room with benches, steam, wet tile, and multiple adults"}
]
}
}
+8
View File
@@ -10,6 +10,7 @@
"style": "explicit consensual adult hardcore sex illustration, anatomically clear erotic comic pin-up style, adults only", "style": "explicit consensual adult hardcore sex illustration, anatomically clear erotic comic pin-up style, adults only",
"positive_suffix": "Use clear adult anatomy, visible sexual contact, intense body language, crisp comic linework, detailed hatching, warm erotic lighting, and tactile textured paper.", "positive_suffix": "Use clear adult anatomy, visible sexual contact, intense body language, crisp comic linework, detailed hatching, warm erotic lighting, and tactile textured paper.",
"negative_prompt": "minors, childlike appearance, teen, schoolgirl, incest, bestiality, non-consensual, coercion, rape, violence, injury, blood, gore, watermark", "negative_prompt": "minors, childlike appearance, teen, schoolgirl, incest, bestiality, non-consensual, coercion, rape, violence, injury, blood, gore, watermark",
"scene_pools": ["hardcore_private_scenes"],
"prompt_template": "{subject_phrase}, all 21+ consenting adults: {style}. Cast: {cast_summary}. Role graph: {role_graph} Sexual pose: {item}. Setting: {scene}. Composition: {composition}. Facial expressions: {expression}. Make the scene explicit, hardcore, and anatomically clear, with visible genital contact and adult bodies only. {positive_suffix} Avoid: {negative_prompt}.", "prompt_template": "{subject_phrase}, all 21+ consenting adults: {style}. Cast: {cast_summary}. Role graph: {role_graph} Sexual pose: {item}. Setting: {scene}. Composition: {composition}. Facial expressions: {expression}. Make the scene explicit, hardcore, and anatomically clear, with visible genital contact and adult bodies only. {positive_suffix} Avoid: {negative_prompt}.",
"caption_template": "{trigger}, {scene_kind}, {cast_summary}, {role_graph}, {item}, {scene}, {composition}, explicit consensual adult hardcore sex illustration", "caption_template": "{trigger}, {scene_kind}, {cast_summary}, {role_graph}, {item}, {scene}, {composition}, explicit consensual adult hardcore sex illustration",
"expressions": [ "expressions": [
@@ -84,6 +85,7 @@
"slug": "penetrative_sex", "slug": "penetrative_sex",
"min_people": 2, "min_people": 2,
"weight": 1.0, "weight": 1.0,
"scene_pools": ["hardcore_penetrative_scenes", "hardcore_bed_scenes", "hardcore_mirror_scenes"],
"item_templates": [ "item_templates": [
"{penetration_act} in {position}, with {body_contact}, {intensity}, and {visibility}", "{penetration_act} in {position}, with {body_contact}, {intensity}, and {visibility}",
"{position} while {penetration_act}, {hand_detail}, {mouth_detail}, and {visibility}", "{position} while {penetration_act}, {hand_detail}, {mouth_detail}, and {visibility}",
@@ -248,6 +250,7 @@
"slug": "oral_sex", "slug": "oral_sex",
"min_people": 2, "min_people": 2,
"weight": 1.0, "weight": 1.0,
"scene_pools": ["hardcore_oral_scenes", "hardcore_bed_scenes", "hardcore_mirror_scenes"],
"item_templates": [ "item_templates": [
"{oral_act} in {position}, with {hand_detail}, {expression_detail}, and {visibility}", "{oral_act} in {position}, with {hand_detail}, {expression_detail}, and {visibility}",
"{position} featuring {oral_act}, {body_contact}, {saliva_detail}, and {climax_hint}", "{position} featuring {oral_act}, {body_contact}, {saliva_detail}, and {climax_hint}",
@@ -380,6 +383,7 @@
"slug": "anal_double_penetration", "slug": "anal_double_penetration",
"min_people": 2, "min_people": 2,
"weight": 1.0, "weight": 1.0,
"scene_pools": ["hardcore_anal_scenes", "hardcore_bed_scenes", "hardcore_mirror_scenes"],
"item_templates": [ "item_templates": [
"{anal_act} in {position}, with {leg_detail}, {hand_detail}, and {visibility}", "{anal_act} in {position}, with {leg_detail}, {hand_detail}, and {visibility}",
"{double_act} with {body_arrangement}, {intensity}, {mouth_detail}, and {visibility}", "{double_act} with {body_arrangement}, {intensity}, {mouth_detail}, and {visibility}",
@@ -584,6 +588,7 @@
"slug": "threesomes", "slug": "threesomes",
"min_people": 3, "min_people": 3,
"weight": 1.0, "weight": 1.0,
"scene_pools": ["hardcore_threesome_scenes", "hardcore_group_scenes", "hardcore_mirror_scenes"],
"item_templates": [ "item_templates": [
"{threesome_act} with {body_arrangement}, {oral_detail}, {penetration_detail}, and {visibility}", "{threesome_act} with {body_arrangement}, {oral_detail}, {penetration_detail}, and {visibility}",
"{body_arrangement} while {threesome_act}, with {hand_detail}, {mouth_detail}, and {climax_hint}", "{body_arrangement} while {threesome_act}, with {hand_detail}, {mouth_detail}, and {climax_hint}",
@@ -760,7 +765,9 @@
"name": "Group sex and orgy", "name": "Group sex and orgy",
"slug": "group_sex_orgy", "slug": "group_sex_orgy",
"min_people": 4, "min_people": 4,
"inherit_scenes": false,
"weight": 1.0, "weight": 1.0,
"scene_pools": ["hardcore_group_scenes"],
"item_templates": [ "item_templates": [
"{group_act} with {arrangement}, {contact_detail}, {fluid_detail}, and {visibility}", "{group_act} with {arrangement}, {contact_detail}, {fluid_detail}, and {visibility}",
"{arrangement} featuring {group_act}, {oral_detail}, {penetration_detail}, and {intensity}", "{arrangement} featuring {group_act}, {oral_detail}, {penetration_detail}, and {intensity}",
@@ -928,6 +935,7 @@
"slug": "cumshot_climax", "slug": "cumshot_climax",
"min_people": 1, "min_people": 1,
"weight": 1.0, "weight": 1.0,
"scene_pools": ["hardcore_climax_scenes", "hardcore_bed_scenes", "hardcore_mirror_scenes"],
"item_templates": [ "item_templates": [
"{climax_act} with {fluid_location}, {body_position}, {expression_detail}, and {visibility}", "{climax_act} with {fluid_location}, {body_position}, {expression_detail}, and {visibility}",
"{body_position} during {climax_act}, with {hand_detail}, {fluid_location}, and {fluid_detail}", "{body_position} during {climax_act}, with {hand_detail}, {fluid_location}, and {fluid_detail}",
+2 -1
View File
@@ -1331,9 +1331,10 @@ def _expand_scenes() -> list[tuple[str, str]]:
additions: list[tuple[str, str]] = [] additions: list[tuple[str, str]] = []
for base_slug, base_description in bases: for base_slug, base_description in bases:
for mood_slug, mood_description in moods: for mood_slug, mood_description in moods:
separator = ", " if mood_description.startswith("with ") else " "
additions.append(( additions.append((
_scene_slug(f"{base_slug}_{mood_slug}"), _scene_slug(f"{base_slug}_{mood_slug}"),
f"{base_description} {mood_description}", f"{base_description}{separator}{mood_description}",
)) ))
additions.extend( additions.extend(
[ [
+380
View File
@@ -0,0 +1,380 @@
from __future__ import annotations
import json
import re
from typing import Any
TRIGGER_CANDIDATES = (
"sxcpinup_coloredpencil",
"sxcppnl7",
)
PROMPT_FIELD_LABELS = (
"Ages",
"Body types",
"Cast",
"Scene",
"Setting",
"Pose",
"Sexual pose",
"Facial expression",
"Facial expressions",
"Clothing",
"Erotic outfit",
"Prop/detail",
"Composition",
"Role graph",
"Use",
"Avoid",
)
def _clean(value: Any) -> str:
text = "" if value is None else str(value)
text = text.replace("\n", " ")
text = re.sub(r"\s+", " ", text).strip()
text = re.sub(r"\s+([,.;:])", r"\1", text)
return text
def _sentence(text: str) -> str:
text = _clean(text).strip(" ,;")
if not text:
return ""
text = text[:1].upper() + text[1:]
if text[-1] not in ".!?":
text += "."
return text
def _paragraph(parts: list[str]) -> str:
return " ".join(part for part in (_sentence(part) for part in parts) if part)
def _maybe_json(text: str) -> dict[str, Any] | None:
text = _clean(text)
if not text.startswith("{"):
return None
try:
value = json.loads(text)
except json.JSONDecodeError:
return None
return value if isinstance(value, dict) else None
def _row_from_inputs(source_text: str, metadata_json: str, input_hint: str) -> tuple[dict[str, Any] | None, str]:
candidates: list[tuple[str, str]] = []
if input_hint in ("auto", "metadata_json"):
candidates.append((metadata_json, "metadata_json"))
candidates.append((source_text, "source_json"))
for text, method in candidates:
row = _maybe_json(text)
if row is not None:
return row, method
return None, "text"
def _strip_trigger(text: str, preserve_trigger: bool) -> str:
text = _clean(text)
if preserve_trigger:
return text
for trigger in TRIGGER_CANDIDATES:
if text.lower().startswith(trigger.lower() + ","):
return text[len(trigger) + 1 :].strip(" ,")
if text.lower().startswith(trigger.lower() + "."):
return text[len(trigger) + 1 :].strip(" ,")
return text
def _split_avoid(text: str) -> tuple[str, str]:
match = re.search(r"\bAvoid:\s*(.*)$", text)
if not match:
return text, ""
return text[: match.start()].strip(" ."), match.group(1).strip(" .")
def _prompt_field(text: str, label: str) -> str:
text = _clean(text)
if not text:
return ""
labels = "|".join(re.escape(name) for name in PROMPT_FIELD_LABELS)
pattern = rf"{re.escape(label)}:\s*(.*?)(?=\. (?:{labels}):|\. Use\b|\. Avoid\b|$)"
match = re.search(pattern, text)
if not match:
return ""
return _clean(match.group(1)).rstrip(".")
def _row_value(row: dict[str, Any], key: str, labels: tuple[str, ...] = ()) -> str:
value = _clean(row.get(key, ""))
if value:
return value
prompt = _clean(row.get("prompt", ""))
for label in labels:
value = _prompt_field(prompt, label)
if value:
return value
return ""
def _single_caption_front(row: dict[str, Any]) -> dict[str, str]:
caption = _strip_trigger(_clean(row.get("caption")), False)
if not caption:
return {}
subject = _clean(row.get("primary_subject"))
age = _clean(row.get("age_band") or row.get("age"))
body = _clean(row.get("body_phrase"))
if not body:
body_type = _clean(row.get("body_type") or row.get("body"))
figure = _clean(row.get("figure"))
body = f"{body_type} figure with {figure}" if body_type and figure else f"{body_type} figure".strip()
front = f"{subject}, {age}, {body}, "
if subject in ("woman", "man") and age and body and caption.startswith(front):
try:
skin, hair, eyes, _rest = caption[len(front) :].split(", ", 3)
except ValueError:
return {}
return {"body_phrase": body, "skin": skin, "hair": hair, "eyes": eyes}
return {}
def _combine_negative(*parts: str) -> str:
cleaned = [_clean(part).strip(" ,.") for part in parts if _clean(part).strip(" ,.")]
return ", ".join(cleaned)
def _clean_age(age: Any) -> str:
return _clean(age)
def _age_subject(row: dict[str, Any], fallback_subject: str = "adult person") -> str:
subject = _clean(row.get("subject_phrase") or row.get("primary_subject") or row.get("subject") or fallback_subject)
age = _clean_age(row.get("age_band") or row.get("age"))
if row.get("subject_type") == "configured_cast":
return _clean(row.get("subject_phrase") or subject)
if subject in ("woman", "man"):
if age:
return f"{age} {subject}" if "adult" in age.lower() else f"{age} adult {subject}"
return f"adult {subject}"
if age and "adult" not in subject.lower():
return f"{age} {subject}"
return subject or fallback_subject
def _appearance_phrase(row: dict[str, Any]) -> str:
front = _single_caption_front(row)
parts = [
_row_value(row, "body_phrase") or front.get("body_phrase"),
_row_value(row, "skin") or front.get("skin"),
_row_value(row, "hair") or front.get("hair"),
_row_value(row, "eyes") or front.get("eyes"),
]
return ", ".join(_clean(part) for part in parts if _clean(part))
def _camera_phrase(row: dict[str, Any]) -> str:
directive = _clean(row.get("camera_directive"))
if directive:
return directive
config = row.get("camera_config")
if isinstance(config, dict):
mode = _clean(config.get("camera_mode")).replace("_", " ")
shot = _clean(config.get("shot_size")).replace("_", " ")
angle = _clean(config.get("angle")).replace("_", " ")
pieces = [piece for piece in (mode, shot, angle) if piece and piece != "auto" and piece != "standard"]
if pieces:
return "Camera framing uses " + ", ".join(pieces)
return ""
def _style_phrase(row: dict[str, Any], style_mode: str) -> str:
if style_mode == "minimal":
return ""
if style_mode == "photographic":
return "realistic creator-shot photography with natural lighting, tactile skin and fabric detail, and clean social-media composition"
style = _clean(row.get("style"))
suffix = _clean(row.get("positive_suffix")) or _prompt_field(_clean(row.get("prompt")), "Use")
if style and suffix:
return f"{style}; {suffix}"
return style or suffix
def _normal_row_to_krea(row: dict[str, Any], detail_level: str, style_mode: str) -> tuple[str, str]:
subject_type = _clean(row.get("subject_type"))
primary = _clean(row.get("primary_subject"))
item = _row_value(row, "item", ("Sexual pose", "Erotic outfit", "Clothing")) or _clean(row.get("custom_item"))
item = re.sub(r",?\s*(fashion editorial|resort) styling$", "", item, flags=re.IGNORECASE)
scene = _row_value(row, "scene_text", ("Setting", "Scene")) or _clean(row.get("scene"))
pose = _row_value(row, "pose", ("Sexual pose", "Pose"))
expression = _row_value(row, "expression", ("Facial expressions", "Facial expression"))
composition = re.sub(r"^vertical\s+", "", _row_value(row, "composition", ("Composition",)), flags=re.IGNORECASE)
camera = _camera_phrase(row)
style = _style_phrase(row, style_mode)
if subject_type == "configured_cast" or _clean(row.get("cast_summary")):
subject = _clean(row.get("subject_phrase") or primary or "adult sexual scene")
cast = _clean(row.get("cast_summary"))
role_graph = _clean(row.get("role_graph"))
parts = [
f"A consensual explicit adult scene with {subject}, all participants 21+ and visibly adult",
f"The cast includes {cast}" if cast else "",
role_graph,
f"The sexual action is {item}" if item else "",
f"The setting is {scene}" if scene else "",
f"Facial expressions are {expression}" if expression else "",
f"The image is framed as {composition}" if composition else "",
camera,
style if detail_level != "concise" else "",
]
return _paragraph(parts), "metadata(configured_cast)"
if primary in ("woman", "man") or subject_type in ("woman", "man", "single_any"):
subject = _age_subject(row, "adult woman")
appearance = _appearance_phrase(row)
parts = [
f"A {subject}" if not subject.lower().startswith(("a ", "an ")) else subject,
f"with {appearance}" if appearance else "",
f"wearing {item}" if item else "",
f"{pose}" if pose else "",
f"with {expression}" if expression else "",
f"in {scene}" if scene else "",
f"framed as {composition}" if composition else "",
camera,
style if detail_level != "concise" else "",
]
return _paragraph([", ".join(part for part in parts[:6] if part), *parts[6:]]), "metadata(single)"
subject = _age_subject(row, primary or "adult scene")
parts = [
f"{subject}",
f"featuring {item}" if item else "",
f"in {scene}" if scene else "",
f"with {expression}" if expression else "",
f"framed as {composition}" if composition else "",
camera,
style if detail_level != "concise" else "",
]
return _paragraph(parts), "metadata(generic)"
def _insta_pair_to_krea(row: dict[str, Any], detail_level: str, style_mode: str) -> tuple[str, str, str, str]:
descriptor = _clean(row.get("shared_descriptor"))
soft = row.get("softcore_row") if isinstance(row.get("softcore_row"), dict) else {}
hard = row.get("hardcore_row") if isinstance(row.get("hardcore_row"), dict) else {}
soft_camera = _clean(row.get("softcore_camera_directive")) or _camera_phrase(soft)
hard_camera = _clean(row.get("hardcore_camera_directive")) or _camera_phrase(hard)
soft_style = _style_phrase(soft, style_mode)
hard_style = _style_phrase(hard, style_mode)
options = row.get("options") if isinstance(row.get("options"), dict) else {}
soft_level = _clean(options.get("softcore_level")).replace("_", " ")
hard_level = _clean(options.get("hardcore_level")).replace("_", " ")
hard_cast = _clean(row.get("hardcore_women_count"))
hard_men = _clean(row.get("hardcore_men_count"))
hard_cast_text = _clean(hard.get("cast_summary")) or (
f"{hard_cast} adult women and {hard_men} adult men" if hard_cast or hard_men else ""
)
soft_parts = [
f"A visibly adult creator, {descriptor}",
f"shown in a {soft_level or 'softcore'} Insta/OF creator image",
f"wearing {soft.get('item')}" if soft.get("item") else "",
f"{soft.get('pose')}" if soft.get("pose") else "",
f"with {soft.get('expression')}" if soft.get("expression") else "",
f"in {soft.get('scene_text')}" if soft.get("scene_text") else "",
f"framed as {soft.get('composition')}" if soft.get("composition") else "",
soft_camera,
soft_style if detail_level != "concise" else "",
]
hard_parts = [
f"The same visibly adult creator, {descriptor}, is the visually central woman in a consensual explicit adult {hard_level or 'hardcore'} scene",
f"all participants are 21+ and visibly adult; the cast includes {hard_cast_text}" if hard_cast_text else "all participants are 21+ and visibly adult",
_clean(hard.get("role_graph")),
f"The sexual action is {hard.get('item')}" if hard.get("item") else "",
f"set in {row.get('hardcore_row', {}).get('scene_text') or hard.get('scene_text')}" if hard.get("scene_text") else "",
f"with {hard.get('expression')}" if hard.get("expression") else "",
f"framed as {hard.get('composition')}" if hard.get("composition") else "",
hard_camera,
hard_style if detail_level != "concise" else "",
]
return (
_paragraph(soft_parts),
_combine_negative(row.get("softcore_negative_prompt")),
_paragraph(hard_parts),
_combine_negative(row.get("hardcore_negative_prompt")),
)
def _fallback_text_to_krea(
source_text: str,
preserve_trigger: bool,
detail_level: str,
style_mode: str,
) -> tuple[str, str, str]:
positive, negative = _split_avoid(_strip_trigger(source_text, preserve_trigger))
positive = re.sub(r"\b(?:Scene|Setting):", "The setting is", positive)
positive = re.sub(r"\b(?:Pose|Sexual pose):", "The pose is", positive)
positive = re.sub(r"\bFacial expressions?:", "The facial expression is", positive)
positive = re.sub(r"\bComposition:", "The composition is", positive)
positive = re.sub(r"\bRole graph:", "The role choreography is", positive)
positive = re.sub(r"\bUse\b", "Use", positive)
positive = _clean(positive)
return _paragraph([positive]), negative, "text(fallback)"
def format_krea2_prompt(
source_text: str,
metadata_json: str = "",
negative_prompt: str = "",
input_hint: str = "auto",
target: str = "auto",
detail_level: str = "balanced",
style_mode: str = "preserve",
preserve_trigger: bool = False,
extra_positive: str = "",
extra_negative: str = "",
) -> dict[str, str]:
detail_level = detail_level if detail_level in ("concise", "balanced", "dense") else "balanced"
style_mode = style_mode if style_mode in ("preserve", "photographic", "minimal") else "preserve"
target = target if target in ("auto", "single", "softcore", "hardcore") else "auto"
row, method = _row_from_inputs(source_text, metadata_json, input_hint)
extracted_negative = ""
if row and row.get("mode") == "Insta/OF":
soft_prompt, soft_negative, hard_prompt, hard_negative = _insta_pair_to_krea(row, detail_level, style_mode)
selected = hard_prompt if target == "hardcore" else soft_prompt if target == "softcore" else soft_prompt
selected_negative = hard_negative if target == "hardcore" else soft_negative
if extra_positive.strip():
selected = f"{selected.rstrip()} {extra_positive.strip()}"
soft_prompt = f"{soft_prompt.rstrip()} {extra_positive.strip()}"
hard_prompt = f"{hard_prompt.rstrip()} {extra_positive.strip()}"
negative = _combine_negative(selected_negative, negative_prompt, extra_negative)
return {
"krea_prompt": selected,
"negative_prompt": negative,
"krea_softcore_prompt": soft_prompt,
"krea_hardcore_prompt": hard_prompt,
"softcore_negative_prompt": _combine_negative(soft_negative, extra_negative),
"hardcore_negative_prompt": _combine_negative(hard_negative, extra_negative),
"method": f"{method}:krea2(insta_of_pair)",
}
if row:
prompt, kind = _normal_row_to_krea(row, detail_level, style_mode)
extracted_negative = _clean(row.get("negative_prompt"))
method = f"{method}:krea2({kind})"
else:
prompt, extracted_negative, method = _fallback_text_to_krea(source_text, preserve_trigger, detail_level, style_mode)
if extra_positive.strip():
prompt = f"{prompt.rstrip()} {extra_positive.strip()}"
negative = _combine_negative(extracted_negative, negative_prompt, extra_negative)
return {
"krea_prompt": prompt,
"negative_prompt": negative,
"krea_softcore_prompt": "",
"krea_hardcore_prompt": "",
"softcore_negative_prompt": "",
"hardcore_negative_prompt": "",
"method": method,
}
+47 -1
View File
@@ -202,6 +202,14 @@ def _list_from(value: Any) -> list[Any]:
return [value] return [value]
def _is_false(value: Any) -> bool:
if isinstance(value, bool):
return value is False
if isinstance(value, str):
return value.strip().lower() in ("false", "0", "no", "off")
return False
def _unique_extend(target: list[Any], additions: list[Any]) -> None: def _unique_extend(target: list[Any], additions: list[Any]) -> None:
seen = set() seen = set()
for item in target: for item in target:
@@ -554,6 +562,24 @@ def load_category_library() -> list[dict[str, Any]]:
return categories return categories
def load_scene_pool_library() -> dict[str, list[Any]]:
pools: dict[str, list[Any]] = {}
for path in _json_files():
data = _read_json(path)
raw_pools = data.get("scene_pools", {})
if not raw_pools:
continue
if not isinstance(raw_pools, dict):
raise ValueError(f"scene_pools in {path} must be an object")
for name, entries in raw_pools.items():
pool_name = str(name).strip()
if not pool_name:
continue
pools.setdefault(pool_name, [])
_unique_extend(pools[pool_name], _list_from(entries))
return pools
def _extension_targets() -> dict[str, tuple[list[Any], bool]]: def _extension_targets() -> dict[str, tuple[list[Any], bool]]:
return { return {
"women_clothes": (g.WOMEN_CLOTHES, False), "women_clothes": (g.WOMEN_CLOTHES, False),
@@ -1335,7 +1361,27 @@ def _subject_context(
def _scene_pool(category: dict[str, Any], subcategory: dict[str, Any], item: Any, subject_type: str) -> list[Any]: def _scene_pool(category: dict[str, Any], subcategory: dict[str, Any], item: Any, subject_type: str) -> list[Any]:
fallback = g.GROUP_SCENES if subject_type in ("group", "configured_cast") else g.SCENES fallback = g.GROUP_SCENES if subject_type in ("group", "configured_cast") else g.SCENES
return _list_from(_merged_field(category, subcategory, item, "scenes", fallback)) scene_entries: list[Any] = []
scene_pools = load_scene_pool_library()
item_source = item if isinstance(item, dict) else None
if item_source is not None and _is_false(item_source.get("inherit_scenes")):
sources = (item_source,)
elif _is_false(subcategory.get("inherit_scenes")):
sources = (subcategory, item_source)
else:
sources = (category, subcategory, item_source)
for source in sources:
if not isinstance(source, dict):
continue
if "scenes" in source:
_unique_extend(scene_entries, _list_from(source["scenes"]))
refs = _list_from(source.get("scene_pool")) + _list_from(source.get("scene_pools"))
for ref in refs:
ref_name = str(ref).strip()
if ref_name not in scene_pools:
raise ValueError(f"Unknown scene pool '{ref_name}'")
_unique_extend(scene_entries, scene_pools[ref_name])
return scene_entries or fallback
def _pose_pool(category: dict[str, Any], subcategory: dict[str, Any], item: Any, subject_type: str, poses: str) -> list[Any]: def _pose_pool(category: dict[str, Any], subcategory: dict[str, Any], item: Any, subject_type: str, poses: str) -> list[Any]: