from __future__ import annotations import json try: from .prompt_builder import ( build_camera_config_json, build_cast_config_json, build_category_config_json, build_character_slot_json, build_character_profile_json, build_filter_config_json, build_generation_profile_json, build_insta_of_options_json, build_insta_of_pair, build_prompt, build_prompt_from_configs, build_seed_config_json, build_seed_lock_config_json, camera_angle_choices, camera_detail_choices, camera_distance_choices, camera_lens_choices, camera_mode_choices, camera_orientation_choices, camera_phone_choices, camera_priority_choices, camera_shot_choices, cast_preset_choices, category_preset_choices, category_choices, character_age_choices, character_body_choices, character_ethnicity_choices, character_figure_choices, character_label_choices, character_man_body_choices, character_profile_choices, character_woman_body_choices, ethnicity_choices, generation_profile_choices, load_character_profile_json, subcategory_choices, ) from .caption_naturalizer import naturalize_caption from .krea_formatter import format_krea2_prompt except ImportError: from prompt_builder import ( build_camera_config_json, build_cast_config_json, build_category_config_json, build_character_slot_json, build_character_profile_json, build_filter_config_json, build_generation_profile_json, build_insta_of_options_json, build_insta_of_pair, build_prompt, build_prompt_from_configs, build_seed_config_json, build_seed_lock_config_json, camera_angle_choices, camera_detail_choices, camera_distance_choices, camera_lens_choices, camera_mode_choices, camera_orientation_choices, camera_phone_choices, camera_priority_choices, camera_shot_choices, cast_preset_choices, category_preset_choices, category_choices, character_age_choices, character_body_choices, character_ethnicity_choices, character_figure_choices, character_label_choices, character_man_body_choices, character_profile_choices, character_woman_body_choices, ethnicity_choices, generation_profile_choices, load_character_profile_json, subcategory_choices, ) from caption_naturalizer import naturalize_caption from krea_formatter import format_krea2_prompt class SxCPPromptBuilder: @classmethod def INPUT_TYPES(cls): return { "required": { "category": (category_choices(), {"default": "auto_weighted"}), "subcategory": (subcategory_choices(), {"default": "random"}), "row_number": ("INT", {"default": 1, "min": 1, "max": 1000000, "step": 1}), "start_index": ("INT", {"default": 41, "min": 1, "max": 1000000, "step": 1}), "seed": ("INT", {"default": 20260614, "min": 0, "max": 0xFFFFFFFF, "step": 1}), "clothing": (["full", "minimal"], {"default": "full"}), "ethnicity": (ethnicity_choices(), {"default": "any"}), "poses": (["standard", "evocative"], {"default": "standard"}), "expression_intensity": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}), "backside_bias": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}), "figure": (["curvy", "balanced", "bombshell"], {"default": "curvy"}), "women_count": ("INT", {"default": 1, "min": 0, "max": 12, "step": 1}), "men_count": ("INT", {"default": 1, "min": 0, "max": 12, "step": 1}), "minimal_clothing_ratio": ("FLOAT", {"default": -1.0, "min": -1.0, "max": 1.0, "step": 0.01}), "standard_pose_ratio": ("FLOAT", {"default": -1.0, "min": -1.0, "max": 1.0, "step": 0.01}), "trigger": ("STRING", {"default": "sxcpinup_coloredpencil"}), "prepend_trigger_to_prompt": ("BOOLEAN", {"default": True}), }, "optional": { "seed_config": ("STRING", {"default": "", "multiline": True}), "camera_config": ("STRING", {"default": "", "multiline": True}), "character_profile": ("STRING", {"default": "", "multiline": True}), "character_cast": ("STRING", {"default": "", "multiline": True}), "extra_positive": ("STRING", {"default": "", "multiline": True}), "extra_negative": ("STRING", {"default": "", "multiline": True}), }, } RETURN_TYPES = ("STRING", "STRING", "STRING", "STRING", "STRING", "STRING") RETURN_NAMES = ("prompt", "negative_prompt", "caption", "metadata_json", "category", "subcategory") FUNCTION = "build" CATEGORY = "prompt_builder" def build( self, category, subcategory, row_number, start_index, seed, clothing, ethnicity, poses, expression_intensity, backside_bias, figure, women_count, men_count, minimal_clothing_ratio, standard_pose_ratio, trigger, prepend_trigger_to_prompt, seed_config="", camera_config="", character_profile="", character_cast="", extra_positive="", extra_negative="", no_plus_women=False, no_black=False, ): row = build_prompt( category=category, subcategory=subcategory, row_number=row_number, start_index=start_index, seed=seed, clothing=clothing, ethnicity=ethnicity, poses=poses, expression_intensity=expression_intensity, backside_bias=backside_bias, figure=figure, no_plus_women=no_plus_women, no_black=no_black, women_count=women_count, men_count=men_count, minimal_clothing_ratio=minimal_clothing_ratio, standard_pose_ratio=standard_pose_ratio, trigger=trigger, prepend_trigger_to_prompt=prepend_trigger_to_prompt, extra_positive=extra_positive or "", extra_negative=extra_negative or "", seed_config=seed_config or "", camera_config=camera_config or "", character_profile=character_profile or "", character_cast=character_cast or "", ) return ( row["prompt"], row["negative_prompt"], row["caption"], json.dumps(row, ensure_ascii=True, sort_keys=True), row.get("main_category", category), row.get("subcategory", subcategory), ) class SxCPSeedControl: @classmethod def INPUT_TYPES(cls): seed_spec = {"default": -1, "min": -1, "max": 0xFFFFFFFF, "step": 1} return { "required": { "category_seed": ("INT", seed_spec), "subcategory_seed": ("INT", seed_spec), "content_seed": ("INT", seed_spec), "person_seed": ("INT", seed_spec), "scene_seed": ("INT", seed_spec), "pose_seed": ("INT", seed_spec), "role_seed": ("INT", seed_spec), "expression_seed": ("INT", seed_spec), "composition_seed": ("INT", seed_spec), } } RETURN_TYPES = ("STRING",) RETURN_NAMES = ("seed_config",) FUNCTION = "build" CATEGORY = "prompt_builder" def build( self, category_seed, subcategory_seed, content_seed, person_seed, scene_seed, pose_seed, role_seed, expression_seed, composition_seed, ): return ( build_seed_config_json( category_seed=category_seed, subcategory_seed=subcategory_seed, content_seed=content_seed, person_seed=person_seed, scene_seed=scene_seed, pose_seed=pose_seed, role_seed=role_seed, expression_seed=expression_seed, composition_seed=composition_seed, ), ) class SxCPSeedLocker: @classmethod def INPUT_TYPES(cls): seed_spec = {"default": 20260614, "min": 0, "max": 0xFFFFFFFF, "step": 1} reroll_seed_spec = {"default": -1, "min": -1, "max": 0xFFFFFFFF, "step": 1} return { "required": { "base_seed": ("INT", seed_spec), "reroll_axis": ( [ "none", "category", "subcategory", "content", "person", "scene", "pose", "role", "expression", "composition", "content_pose", "scene_pose", ], {"default": "none"}, ), "reroll_seed": ("INT", reroll_seed_spec), } } RETURN_TYPES = ("STRING", "STRING") RETURN_NAMES = ("seed_config", "summary") FUNCTION = "build" CATEGORY = "prompt_builder" def build(self, base_seed, reroll_axis, reroll_seed): config = build_seed_lock_config_json(base_seed=base_seed, reroll_axis=reroll_axis, reroll_seed=reroll_seed) summary = f"base {base_seed}; reroll {reroll_axis} with {'main seed' if int(reroll_seed) < 0 else reroll_seed}" return config, summary class SxCPCameraControl: @classmethod def INPUT_TYPES(cls): return { "required": { "camera_mode": (camera_mode_choices(), {"default": "handheld_selfie"}), "shot_size": (camera_shot_choices(), {"default": "auto"}), "angle": (camera_angle_choices(), {"default": "auto"}), "lens": (camera_lens_choices(), {"default": "smartphone_wide"}), "distance": (camera_distance_choices(), {"default": "arm_length"}), "orientation": (camera_orientation_choices(), {"default": "vertical_story"}), "phone_visibility": (camera_phone_choices(), {"default": "phone_visible"}), "priority": (camera_priority_choices(), {"default": "locked"}), "camera_detail": (camera_detail_choices(), {"default": "compact"}), } } RETURN_TYPES = ("STRING",) RETURN_NAMES = ("camera_config",) FUNCTION = "build" CATEGORY = "prompt_builder" def build( self, camera_mode, shot_size, angle, lens, distance, orientation, phone_visibility, priority, camera_detail, ): return ( build_camera_config_json( camera_mode=camera_mode, shot_size=shot_size, angle=angle, lens=lens, distance=distance, orientation=orientation, phone_visibility=phone_visibility, priority=priority, camera_detail=camera_detail, ), ) class SxCPCategoryPreset: @classmethod def INPUT_TYPES(cls): return { "required": { "preset": (category_preset_choices(), {"default": "auto_weighted"}), "subcategory": (subcategory_choices(), {"default": "random"}), } } RETURN_TYPES = ("STRING", "STRING", "STRING") RETURN_NAMES = ("category_config", "category", "subcategory") FUNCTION = "build" CATEGORY = "prompt_builder" def build(self, preset, subcategory): config = build_category_config_json(preset=preset, subcategory=subcategory) parsed = json.loads(config) return config, parsed["category"], parsed["subcategory"] class SxCPCastControl: @classmethod def INPUT_TYPES(cls): return { "required": { "cast_mode": (cast_preset_choices(), {"default": "mixed_couple"}), "women_count": ("INT", {"default": 1, "min": 0, "max": 12, "step": 1}), "men_count": ("INT", {"default": 1, "min": 0, "max": 12, "step": 1}), } } RETURN_TYPES = ("STRING", "INT", "INT", "STRING") RETURN_NAMES = ("cast_config", "women_count", "men_count", "cast_summary") FUNCTION = "build" CATEGORY = "prompt_builder" def build(self, cast_mode, women_count, men_count): config = build_cast_config_json(cast_mode=cast_mode, women_count=women_count, men_count=men_count) parsed = json.loads(config) summary = f"{parsed['women_count']} women, {parsed['men_count']} men" return config, parsed["women_count"], parsed["men_count"], summary class SxCPGenerationProfile: @classmethod def INPUT_TYPES(cls): return { "required": { "profile": (generation_profile_choices(), {"default": "balanced"}), "clothing_override": (["profile_default", "full", "minimal"], {"default": "profile_default"}), "poses_override": (["profile_default", "standard", "evocative"], {"default": "profile_default"}), "expression_intensity": ("FLOAT", {"default": -1.0, "min": -1.0, "max": 1.0, "step": 0.01}), "backside_bias": ("FLOAT", {"default": -1.0, "min": -1.0, "max": 1.0, "step": 0.01}), "minimal_clothing_ratio": ("FLOAT", {"default": -1.0, "min": -1.0, "max": 1.0, "step": 0.01}), "standard_pose_ratio": ("FLOAT", {"default": -1.0, "min": -1.0, "max": 1.0, "step": 0.01}), "trigger_policy": (["profile_default", "prepend_trigger", "do_not_prepend"], {"default": "profile_default"}), } } RETURN_TYPES = ("STRING", "STRING") RETURN_NAMES = ("generation_profile", "summary") FUNCTION = "build" CATEGORY = "prompt_builder" def build( self, profile, clothing_override, poses_override, expression_intensity, backside_bias, minimal_clothing_ratio, standard_pose_ratio, trigger_policy, ): config = build_generation_profile_json( profile=profile, clothing_override=clothing_override, poses_override=poses_override, expression_intensity=expression_intensity, backside_bias=backside_bias, minimal_clothing_ratio=minimal_clothing_ratio, standard_pose_ratio=standard_pose_ratio, trigger_policy=trigger_policy, ) parsed = json.loads(config) summary = f"{parsed['profile']}: {parsed['clothing']}, {parsed['poses']}, expression {parsed['expression_intensity']}" return config, summary class SxCPAdvancedFilters: @classmethod def INPUT_TYPES(cls): return { "required": { "include_european": ("BOOLEAN", {"default": True}), "include_mediterranean_mena": ("BOOLEAN", {"default": True}), "include_latina": ("BOOLEAN", {"default": True}), "include_east_asian": ("BOOLEAN", {"default": True}), "include_southeast_asian": ("BOOLEAN", {"default": True}), "include_south_asian": ("BOOLEAN", {"default": True}), "include_black_african": ("BOOLEAN", {"default": True}), "include_indigenous": ("BOOLEAN", {"default": True}), "include_mixed": ("BOOLEAN", {"default": True}), "include_plus_size": ("BOOLEAN", {"default": True}), "figure": (["curvy", "balanced", "bombshell"], {"default": "curvy"}), } } RETURN_TYPES = ("STRING",) RETURN_NAMES = ("filter_config",) FUNCTION = "build" CATEGORY = "prompt_builder" def build( self, include_european, include_mediterranean_mena, include_latina, include_east_asian, include_southeast_asian, include_south_asian, include_black_african, include_indigenous, include_mixed, include_plus_size, figure, ): return ( build_filter_config_json( figure=figure, include_european=include_european, include_mediterranean_mena=include_mediterranean_mena, include_latina=include_latina, include_east_asian=include_east_asian, include_southeast_asian=include_southeast_asian, include_south_asian=include_south_asian, include_black_african=include_black_african, include_indigenous=include_indigenous, include_mixed=include_mixed, include_plus_size=include_plus_size, ), ) class SxCPPromptBuilderFromConfigs: @classmethod def INPUT_TYPES(cls): return { "required": { "row_number": ("INT", {"default": 1, "min": 1, "max": 1000000, "step": 1}), "start_index": ("INT", {"default": 41, "min": 1, "max": 1000000, "step": 1}), "seed": ("INT", {"default": 20260614, "min": 0, "max": 0xFFFFFFFF, "step": 1}), }, "optional": { "category_config": ("STRING", {"default": "", "multiline": True}), "cast_config": ("STRING", {"default": "", "multiline": True}), "generation_profile": ("STRING", {"default": "", "multiline": True}), "filter_config": ("STRING", {"default": "", "multiline": True}), "seed_config": ("STRING", {"default": "", "multiline": True}), "camera_config": ("STRING", {"default": "", "multiline": True}), "character_profile": ("STRING", {"default": "", "multiline": True}), "character_cast": ("STRING", {"default": "", "multiline": True}), "extra_positive": ("STRING", {"default": "", "multiline": True}), "extra_negative": ("STRING", {"default": "", "multiline": True}), }, } RETURN_TYPES = ("STRING", "STRING", "STRING", "STRING", "STRING", "STRING") RETURN_NAMES = ("prompt", "negative_prompt", "caption", "metadata_json", "category", "subcategory") FUNCTION = "build" CATEGORY = "prompt_builder" def build( self, row_number, start_index, seed, category_config="", cast_config="", generation_profile="", filter_config="", seed_config="", camera_config="", character_profile="", character_cast="", extra_positive="", extra_negative="", ): row = build_prompt_from_configs( row_number=row_number, start_index=start_index, seed=seed, category_config=category_config or "", cast_config=cast_config or "", generation_profile=generation_profile or "", filter_config=filter_config or "", seed_config=seed_config or "", camera_config=camera_config or "", character_profile=character_profile or "", character_cast=character_cast or "", extra_positive=extra_positive or "", extra_negative=extra_negative or "", ) return ( row["prompt"], row["negative_prompt"], row["caption"], json.dumps(row, ensure_ascii=True, sort_keys=True), row.get("main_category", ""), row.get("subcategory", ""), ) class SxCPCharacterSlot: @classmethod def INPUT_TYPES(cls): return { "required": { "enabled": ("BOOLEAN", {"default": True}), "subject_type": (["woman", "man"], {"default": "woman"}), "label": (character_label_choices(), {"default": "auto_chain"}), "age": (character_age_choices(), {"default": "random"}), "manual_age": ("STRING", {"default": ""}), "ethnicity": (character_ethnicity_choices(), {"default": "random"}), "figure": (character_figure_choices(), {"default": "random"}), "body": (character_body_choices(), {"default": "random"}), "manual_body": ("STRING", {"default": ""}), "body_phrase": ("STRING", {"default": ""}), "skin": ("STRING", {"default": ""}), "hair": ("STRING", {"default": ""}), "eyes": ("STRING", {"default": ""}), }, "optional": { "character_cast": ("STRING", {"default": "", "multiline": True}), }, } RETURN_TYPES = ("STRING", "STRING", "STRING", "STRING") RETURN_NAMES = ("character_cast", "character_slot", "summary", "status") FUNCTION = "build" CATEGORY = "prompt_builder" def build( self, enabled, subject_type, label, age, manual_age, ethnicity, figure, body, manual_body, body_phrase, skin, hair, eyes, character_cast="", ): result = build_character_slot_json( subject_type=subject_type, label=label, age=age, manual_age=manual_age, ethnicity=ethnicity, figure=figure, body=body, manual_body=manual_body, body_phrase=body_phrase, skin=skin, hair=hair, eyes=eyes, enabled=enabled, character_cast=character_cast or "", ) return result["character_cast"], result["character_slot"], result["summary"], result["status"] class SxCPWomanSlot: @classmethod def INPUT_TYPES(cls): return { "required": { "enabled": ("BOOLEAN", {"default": True}), "label": (character_label_choices(), {"default": "auto_chain"}), "age": (character_age_choices(), {"default": "random"}), "manual_age": ("STRING", {"default": ""}), "ethnicity": (character_ethnicity_choices(), {"default": "random"}), "figure_bias": (character_figure_choices(), {"default": "random"}), "body": (character_woman_body_choices(), {"default": "random"}), "manual_body": ("STRING", {"default": ""}), "body_phrase": ("STRING", {"default": ""}), "skin": ("STRING", {"default": ""}), "hair": ("STRING", {"default": ""}), "eyes": ("STRING", {"default": ""}), }, "optional": { "character_cast": ("STRING", {"default": "", "multiline": True}), }, } RETURN_TYPES = ("STRING", "STRING", "STRING", "STRING") RETURN_NAMES = ("character_cast", "character_slot", "summary", "status") FUNCTION = "build" CATEGORY = "prompt_builder" def build( self, enabled, label, age, manual_age, ethnicity, figure_bias, body, manual_body, body_phrase, skin, hair, eyes, character_cast="", ): result = build_character_slot_json( subject_type="woman", label=label, age=age, manual_age=manual_age, ethnicity=ethnicity, figure=figure_bias, body=body, manual_body=manual_body, body_phrase=body_phrase, skin=skin, hair=hair, eyes=eyes, enabled=enabled, character_cast=character_cast or "", ) return result["character_cast"], result["character_slot"], result["summary"], result["status"] class SxCPManSlot: @classmethod def INPUT_TYPES(cls): return { "required": { "enabled": ("BOOLEAN", {"default": True}), "label": (character_label_choices(), {"default": "auto_chain"}), "age": (character_age_choices(), {"default": "random"}), "manual_age": ("STRING", {"default": ""}), "ethnicity": (character_ethnicity_choices(), {"default": "random"}), "body": (character_man_body_choices(), {"default": "random"}), "manual_body": ("STRING", {"default": ""}), "body_phrase": ("STRING", {"default": ""}), "skin": ("STRING", {"default": ""}), "hair": ("STRING", {"default": ""}), "eyes": ("STRING", {"default": ""}), }, "optional": { "character_cast": ("STRING", {"default": "", "multiline": True}), }, } RETURN_TYPES = ("STRING", "STRING", "STRING", "STRING") RETURN_NAMES = ("character_cast", "character_slot", "summary", "status") FUNCTION = "build" CATEGORY = "prompt_builder" def build( self, enabled, label, age, manual_age, ethnicity, body, manual_body, body_phrase, skin, hair, eyes, character_cast="", ): result = build_character_slot_json( subject_type="man", label=label, age=age, manual_age=manual_age, ethnicity=ethnicity, figure="random", body=body, manual_body=manual_body, body_phrase=body_phrase, skin=skin, hair=hair, eyes=eyes, enabled=enabled, character_cast=character_cast or "", ) return result["character_cast"], result["character_slot"], result["summary"], result["status"] class SxCPCharacterProfileSave: @classmethod def INPUT_TYPES(cls): return { "required": { "profile_name": ("STRING", {"default": "saved_character"}), "source": (["metadata_json", "manual"], {"default": "metadata_json"}), "subject_type": (["woman", "man"], {"default": "woman"}), "age": ("STRING", {"default": ""}), "body": ("STRING", {"default": ""}), "body_phrase": ("STRING", {"default": ""}), "skin": ("STRING", {"default": ""}), "hair": ("STRING", {"default": ""}), "eyes": ("STRING", {"default": ""}), "figure": ("STRING", {"default": ""}), "save_now": ("BOOLEAN", {"default": False}), }, "optional": { "metadata_json": ("STRING", {"default": "", "multiline": True}), }, } RETURN_TYPES = ("STRING", "STRING", "STRING", "STRING", "STRING") RETURN_NAMES = ("character_profile", "descriptor", "profile_name", "saved_path", "status") FUNCTION = "build" CATEGORY = "prompt_builder" def build( self, profile_name, source, subject_type, age, body, body_phrase, skin, hair, eyes, figure, save_now, metadata_json="", ): profile = build_character_profile_json( profile_name=profile_name, source=source, metadata_json=metadata_json or "", subject_type=subject_type, age=age, body=body, body_phrase=body_phrase, skin=skin, hair=hair, eyes=eyes, figure=figure, save_now=save_now, ) return profile["profile_json"], profile["descriptor"], profile["profile_name"], profile["saved_path"], profile["status"] class SxCPCharacterProfileLoad: @classmethod def INPUT_TYPES(cls): return { "required": { "enabled": ("BOOLEAN", {"default": True}), "profile_name": (character_profile_choices(), {"default": "manual"}), "rename_to": ("STRING", {"default": ""}), "delete_now": ("BOOLEAN", {"default": False}), "rename_now": ("BOOLEAN", {"default": False}), }, "optional": { "manual_profile_name": ("STRING", {"default": ""}), "fallback_profile_json": ("STRING", {"default": "", "multiline": True}), }, } RETURN_TYPES = ("STRING", "STRING", "STRING", "STRING", "STRING") RETURN_NAMES = ("character_profile", "descriptor", "profile_name", "saved_path", "status") FUNCTION = "build" CATEGORY = "prompt_builder" def build( self, enabled, profile_name, rename_to, delete_now, rename_now, manual_profile_name="", fallback_profile_json="", ): chosen_name = manual_profile_name.strip() if profile_name == "manual" and manual_profile_name.strip() else profile_name profile = load_character_profile_json( profile_name=chosen_name, fallback_profile_json=fallback_profile_json or "", enabled=enabled, delete_now=delete_now, rename_now=rename_now, rename_to=rename_to, ) return profile["profile_json"], profile["descriptor"], profile["profile_name"], profile["saved_path"], profile["status"] class SxCPCaptionNaturalizer: @classmethod def INPUT_TYPES(cls): return { "required": { "source_text": ("STRING", {"default": "", "multiline": True}), "input_hint": (["auto", "metadata_json", "caption_or_prompt"], {"default": "auto"}), "detail_level": (["balanced", "concise", "dense"], {"default": "balanced"}), "style_policy": (["drop_style_tail", "keep_style_terms"], {"default": "drop_style_tail"}), "trigger": ("STRING", {"default": "sxcppnl7"}), "include_trigger": ("BOOLEAN", {"default": True}), }, "optional": { "metadata_json": ("STRING", {"default": "", "multiline": True}), }, } RETURN_TYPES = ("STRING", "STRING") RETURN_NAMES = ("natural_caption", "method") FUNCTION = "build" CATEGORY = "prompt_builder" def build( self, source_text, input_hint, detail_level, style_policy, trigger, include_trigger, metadata_json="", ): return naturalize_caption( source_text=source_text or "", metadata_json=metadata_json or "", input_hint=input_hint, trigger=trigger, include_trigger=include_trigger, detail_level=detail_level, style_policy=style_policy, ) 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: @classmethod def INPUT_TYPES(cls): return { "required": { "softcore_cast": (["solo", "same_as_hardcore"], {"default": "solo"}), "hardcore_cast": (["use_counts", "couple", "threesome", "group"], {"default": "use_counts"}), "hardcore_women_count": ("INT", {"default": 1, "min": 0, "max": 12, "step": 1}), "hardcore_men_count": ("INT", {"default": 1, "min": 0, "max": 12, "step": 1}), "softcore_level": (["social_tease", "lingerie_tease", "implied_nude", "explicit_tease", "explicit_nude"], {"default": "lingerie_tease"}), "hardcore_level": (["explicit", "hardcore"], {"default": "hardcore"}), "softcore_expression_intensity": ("FLOAT", {"default": 0.45, "min": 0.0, "max": 1.0, "step": 0.01}), "hardcore_expression_intensity": ("FLOAT", {"default": 0.85, "min": 0.0, "max": 1.0, "step": 0.01}), "platform_style": (["hybrid", "instagram", "onlyfans"], {"default": "hybrid"}), "continuity": (["same_creator_same_room", "same_creator_new_scene"], {"default": "same_creator_same_room"}), "hardcore_clothing_continuity": (["none", "same_outfit", "partially_removed", "implied_nude", "explicit_nude"], {"default": "partially_removed"}), "softcore_camera_mode": (camera_mode_choices(), {"default": "handheld_selfie"}), "hardcore_camera_mode": (["same_as_softcore"] + camera_mode_choices(), {"default": "same_as_softcore"}), "camera_detail": (camera_detail_choices(), {"default": "compact"}), } } RETURN_TYPES = ("STRING",) RETURN_NAMES = ("options_json",) FUNCTION = "build" CATEGORY = "prompt_builder" def build( self, softcore_cast, hardcore_cast, hardcore_women_count, hardcore_men_count, softcore_level, hardcore_level, softcore_expression_intensity, hardcore_expression_intensity, platform_style, continuity, hardcore_clothing_continuity, softcore_camera_mode, hardcore_camera_mode, camera_detail, ): return ( build_insta_of_options_json( softcore_cast=softcore_cast, hardcore_cast=hardcore_cast, hardcore_women_count=hardcore_women_count, hardcore_men_count=hardcore_men_count, softcore_level=softcore_level, hardcore_level=hardcore_level, softcore_expression_intensity=softcore_expression_intensity, hardcore_expression_intensity=hardcore_expression_intensity, platform_style=platform_style, continuity=continuity, hardcore_clothing_continuity=hardcore_clothing_continuity, softcore_camera_mode=softcore_camera_mode, hardcore_camera_mode=hardcore_camera_mode, camera_detail=camera_detail, ), ) class SxCPInstaOFPromptPair: @classmethod def INPUT_TYPES(cls): return { "required": { "row_number": ("INT", {"default": 1, "min": 1, "max": 1000000, "step": 1}), "start_index": ("INT", {"default": 41, "min": 1, "max": 1000000, "step": 1}), "seed": ("INT", {"default": 20260614, "min": 0, "max": 0xFFFFFFFF, "step": 1}), "ethnicity": (ethnicity_choices(), {"default": "any"}), "figure": (["curvy", "balanced", "bombshell"], {"default": "curvy"}), "trigger": ("STRING", {"default": "sxcpinup_coloredpencil"}), "prepend_trigger_to_prompt": ("BOOLEAN", {"default": True}), }, "optional": { "seed_config": ("STRING", {"default": "", "multiline": True}), "options_json": ("STRING", {"default": "", "multiline": True}), "filter_config": ("STRING", {"default": "", "multiline": True}), "camera_config": ("STRING", {"default": "", "multiline": True}), "character_profile": ("STRING", {"default": "", "multiline": True}), "character_cast": ("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", "STRING") RETURN_NAMES = ( "softcore_prompt", "hardcore_prompt", "softcore_negative_prompt", "hardcore_negative_prompt", "softcore_caption", "hardcore_caption", "shared_descriptor", "metadata_json", ) FUNCTION = "build" CATEGORY = "prompt_builder" def build( self, row_number, start_index, seed, ethnicity, figure, trigger, prepend_trigger_to_prompt, seed_config="", options_json="", filter_config="", camera_config="", character_profile="", character_cast="", extra_positive="", extra_negative="", no_plus_women=False, no_black=False, ): row = build_insta_of_pair( row_number=row_number, start_index=start_index, seed=seed, ethnicity=ethnicity, figure=figure, no_plus_women=no_plus_women, no_black=no_black, trigger=trigger, prepend_trigger_to_prompt=prepend_trigger_to_prompt, seed_config=seed_config or "", options_json=options_json or "", filter_config=filter_config or "", camera_config=camera_config or "", character_profile=character_profile or "", character_cast=character_cast or "", extra_positive=extra_positive or "", extra_negative=extra_negative or "", ) return ( row["softcore_prompt"], row["hardcore_prompt"], row["softcore_negative_prompt"], row["hardcore_negative_prompt"], row["softcore_caption"], row["hardcore_caption"], row["shared_descriptor"], json.dumps(row, ensure_ascii=True, sort_keys=True), ) NODE_CLASS_MAPPINGS = { "SxCPPromptBuilder": SxCPPromptBuilder, "SxCPSeedControl": SxCPSeedControl, "SxCPSeedLocker": SxCPSeedLocker, "SxCPCameraControl": SxCPCameraControl, "SxCPCategoryPreset": SxCPCategoryPreset, "SxCPCastControl": SxCPCastControl, "SxCPGenerationProfile": SxCPGenerationProfile, "SxCPAdvancedFilters": SxCPAdvancedFilters, "SxCPPromptBuilderFromConfigs": SxCPPromptBuilderFromConfigs, "SxCPWomanSlot": SxCPWomanSlot, "SxCPManSlot": SxCPManSlot, "SxCPCharacterSlot": SxCPCharacterSlot, "SxCPCharacterProfileSave": SxCPCharacterProfileSave, "SxCPCharacterProfileLoad": SxCPCharacterProfileLoad, "SxCPCaptionNaturalizer": SxCPCaptionNaturalizer, "SxCPKrea2Formatter": SxCPKrea2Formatter, "SxCPInstaOFOptions": SxCPInstaOFOptions, "SxCPInstaOFPromptPair": SxCPInstaOFPromptPair, } NODE_DISPLAY_NAME_MAPPINGS = { "SxCPPromptBuilder": "SxCP Prompt Builder", "SxCPSeedControl": "SxCP Seed Control", "SxCPSeedLocker": "SxCP Seed Locker", "SxCPCameraControl": "SxCP Camera Control", "SxCPCategoryPreset": "SxCP Category Preset", "SxCPCastControl": "SxCP Cast Control", "SxCPGenerationProfile": "SxCP Generation Profile", "SxCPAdvancedFilters": "SxCP Advanced Filters", "SxCPPromptBuilderFromConfigs": "SxCP Prompt Builder From Configs", "SxCPWomanSlot": "SxCP Woman Slot", "SxCPManSlot": "SxCP Man Slot", "SxCPCharacterSlot": "SxCP Character Slot", "SxCPCharacterProfileSave": "SxCP Character Profile Save", "SxCPCharacterProfileLoad": "SxCP Character Profile Load", "SxCPCaptionNaturalizer": "SxCP Caption Naturalizer", "SxCPKrea2Formatter": "SxCP Krea2 Formatter", "SxCPInstaOFOptions": "SxCP Insta/OF Options", "SxCPInstaOFPromptPair": "SxCP Insta/OF Prompt Pair", } WEB_DIRECTORY = "./web" __all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]