Files
ComfyUI-Ethanfel-Prompt-Bui…/prompt_builder.py
T

3083 lines
109 KiB
Python

from __future__ import annotations
import json
import random
import re
from pathlib import Path
from string import Formatter
from typing import Any
try:
from .category_library import (
category_json_files as _json_files,
compatible_entries as _compatible_entries,
compatible_entry as _compatible_entry,
find_subcategory as _find_subcategory,
load_category_library,
merged_field as _merged_field,
read_category_json as _read_json,
)
from . import camera_config as camera_policy
from . import cast_context as cast_context_policy
from . import category_template_metadata as item_template_policy
from . import character_appearance as character_appearance_policy
from . import character_config as character_policy
from . import character_profile as character_profile_policy
from . import character_slot as character_slot_policy
from . import category_cast_config as category_cast_policy
from . import filter_config as filter_policy
from . import generate_prompt_batches as g
from . import generation_profile_config as generation_profile_policy
from . import hardcore_position_config as hardcore_position_policy
from . import location_config as location_policy
from . import pair_clothing
from . import pair_camera
from . import pair_cast
from . import pair_output
from . import pair_rows
from . import pair_options
from . import pov_policy
from . import row_normalization as row_policy
from . import row_camera as row_camera_policy
from . import row_expression as row_expression_policy
from . import row_generation as row_generation_policy
from . import row_item as row_item_policy
from . import row_location as row_location_policy
from . import row_pools as row_pool_policy
from . import seed_config as seed_policy
from . import subject_context as subject_context_policy
from .hardcore_text_cleanup import (
sanitize_hardcore_axis_values as _sanitize_hardcore_axis_values,
sanitize_hardcore_environment_anchors as _sanitize_hardcore_environment_anchors,
)
from .hardcore_action_metadata import source_hardcore_action_family
from .hardcore_role_graphs import build_hardcore_role_graph
except ImportError: # Allows local smoke tests with `python -c`.
from category_library import (
category_json_files as _json_files,
compatible_entries as _compatible_entries,
compatible_entry as _compatible_entry,
find_subcategory as _find_subcategory,
load_category_library,
merged_field as _merged_field,
read_category_json as _read_json,
)
import camera_config as camera_policy
import cast_context as cast_context_policy
import category_template_metadata as item_template_policy
import character_appearance as character_appearance_policy
import character_config as character_policy
import character_profile as character_profile_policy
import character_slot as character_slot_policy
import category_cast_config as category_cast_policy
import filter_config as filter_policy
import generate_prompt_batches as g
import generation_profile_config as generation_profile_policy
import hardcore_position_config as hardcore_position_policy
import location_config as location_policy
import pair_clothing
import pair_camera
import pair_cast
import pair_output
import pair_rows
import pair_options
import pov_policy
import row_normalization as row_policy
import row_camera as row_camera_policy
import row_expression as row_expression_policy
import row_generation as row_generation_policy
import row_item as row_item_policy
import row_location as row_location_policy
import row_pools as row_pool_policy
import seed_config as seed_policy
import subject_context as subject_context_policy
from hardcore_text_cleanup import (
sanitize_hardcore_axis_values as _sanitize_hardcore_axis_values,
sanitize_hardcore_environment_anchors as _sanitize_hardcore_environment_anchors,
)
from hardcore_action_metadata import source_hardcore_action_family
from hardcore_role_graphs import build_hardcore_role_graph
ROOT_DIR = Path(__file__).resolve().parent
PROFILE_DIR = character_profile_policy.PROFILE_DIR
BUILTIN_CATEGORIES = [
"auto_weighted",
"auto_full",
"woman",
"man",
"couple",
"group_or_layout",
"custom_random",
]
RANDOM_SUBCATEGORY = "random"
SEED_AXIS_SALTS = seed_policy.SEED_AXIS_SALTS
SEED_AXIS_ALIASES = seed_policy.SEED_AXIS_ALIASES
SEED_LOCK_AXES = seed_policy.SEED_LOCK_AXES
SEED_MODE_CHOICES = seed_policy.SEED_MODE_CHOICES
ETHNICITY_FILTER_CHOICES = filter_policy.ETHNICITY_FILTER_CHOICES
ETHNICITY_LIST_KEYS = filter_policy.ETHNICITY_LIST_KEYS
ETHNICITY_BASE_LIST_KEYS = filter_policy.ETHNICITY_BASE_LIST_KEYS
EUROPEAN_REGIONAL_LIST_KEYS = filter_policy.EUROPEAN_REGIONAL_LIST_KEYS
MEDITERRANEAN_REGIONAL_LIST_KEYS = filter_policy.MEDITERRANEAN_REGIONAL_LIST_KEYS
CHARACTER_LABEL_CHOICES = character_policy.CHARACTER_LABEL_CHOICES
CHARACTER_AGE_CHOICES = character_policy.CHARACTER_AGE_CHOICES
CHARACTER_BODY_CHOICES = character_policy.CHARACTER_BODY_CHOICES
CHARACTER_WOMAN_BODY_CHOICES = character_policy.CHARACTER_WOMAN_BODY_CHOICES
CHARACTER_MAN_BODY_CHOICES = character_policy.CHARACTER_MAN_BODY_CHOICES
CHARACTER_DESCRIPTOR_DETAIL_CHOICES = character_policy.CHARACTER_DESCRIPTOR_DETAIL_CHOICES
CHARACTER_PRESENCE_CHOICES = character_policy.CHARACTER_PRESENCE_CHOICES
CHARACTER_RANDOM_TOKENS = character_policy.CHARACTER_RANDOM_TOKENS
CHARACTER_SLOT_SEED_MAX = character_policy.CHARACTER_SLOT_SEED_MAX
CHARACTER_HAIR_COLOR_CHOICES = character_policy.CHARACTER_HAIR_COLOR_CHOICES
CHARACTER_HAIR_LENGTH_CHOICES = character_policy.CHARACTER_HAIR_LENGTH_CHOICES
CHARACTER_HAIR_STYLE_CHOICES = character_policy.CHARACTER_HAIR_STYLE_CHOICES
CHARACTER_EYE_COLOR_CHOICES = character_policy.CHARACTER_EYE_COLOR_CHOICES
CAMERA_DETAIL_CHOICES = camera_policy.CAMERA_DETAIL_CHOICES
HARDCORE_DETAIL_DENSITY_CHOICES = pair_options.HARDCORE_DETAIL_DENSITY_CHOICES
HARDCORE_POSITION_FAMILY_CHOICES = hardcore_position_policy.HARDCORE_POSITION_FAMILY_CHOICES
HARDCORE_POSITION_FOCUS_CHOICES = hardcore_position_policy.HARDCORE_POSITION_FOCUS_CHOICES
HARDCORE_POSITION_KEY_CHOICES = hardcore_position_policy.HARDCORE_POSITION_KEY_CHOICES
HARDCORE_POSITION_FAMILY_SUBCATEGORIES = hardcore_position_policy.HARDCORE_POSITION_FAMILY_SUBCATEGORIES
HARDCORE_SOURCE_FAMILY_BY_SUBCATEGORY = hardcore_position_policy.HARDCORE_SOURCE_FAMILY_BY_SUBCATEGORY
def _hardcore_source_position_family(subcategory: dict[str, Any], config: dict[str, Any] | None = None) -> str:
return hardcore_position_policy.hardcore_source_position_family(subcategory, config)
def _hardcore_position_keys(*parts: Any, axis_values: dict[str, Any] | None = None) -> list[str]:
return hardcore_position_policy.hardcore_position_keys(*parts, axis_values=axis_values)
CAMERA_ORBIT_FRAMING_CHOICES = camera_policy.CAMERA_ORBIT_FRAMING_CHOICES
CAMERA_ORBIT_FOCUS_CHOICES = camera_policy.CAMERA_ORBIT_FOCUS_CHOICES
GENERIC_POSITIVE_SUFFIX = (
"Use crisp clean comic linework, detailed hatching, soft blended shading, "
"pastel skin tones, muted blues and pinks, warm sensual lighting, and tactile textured paper."
)
SINGLE_TEMPLATE = (
"A {subject}: {style}, {age}, {body_phrase}, {skin}, {hair}, {eyes}. "
"{item_label}: {item}. Scene: {scene}. Pose: {pose}. Facial expression: {expression}. "
"Composition: {composition_prompt}. {positive_suffix} Avoid: {negative_prompt}."
)
COUPLE_TEMPLATE = (
"{subject_phrase}: {style}. Ages: {age}. Body types: {body}. {item_label}: {item}. "
"Scene: {scene}. Pose: {pose}. Facial expressions: {expression}. "
"Composition: {composition_prompt}. {positive_suffix} Avoid: {negative_prompt}."
)
GROUP_TEMPLATE = (
"{subject_phrase}: {style}, ages {age}, diverse adult body types. {item_label}: {item}. "
"Scene: {scene}. Facial expressions: {expression}. Composition: {composition_prompt}. "
"{positive_suffix} Avoid: {negative_prompt}."
)
LAYOUT_TEMPLATE = (
"{item}: {style}, adults only, clean designed composition. Scene: {scene}. "
"Facial expression: {expression}. Composition: {composition}. {positive_suffix} "
"Avoid: {negative_prompt}. Use no readable text unless the layout naturally needs small decorative placeholder marks."
)
CAMERA_MODE_PROMPTS = camera_policy.CAMERA_MODE_PROMPTS
CAMERA_COMPACT_LABELS = camera_policy.CAMERA_COMPACT_LABELS
CAMERA_SHOT_PROMPTS = camera_policy.CAMERA_SHOT_PROMPTS
CAMERA_ANGLE_PROMPTS = camera_policy.CAMERA_ANGLE_PROMPTS
CAMERA_LENS_PROMPTS = camera_policy.CAMERA_LENS_PROMPTS
CAMERA_DISTANCE_PROMPTS = camera_policy.CAMERA_DISTANCE_PROMPTS
CAMERA_ORIENTATION_PROMPTS = camera_policy.CAMERA_ORIENTATION_PROMPTS
CAMERA_PHONE_PROMPTS = camera_policy.CAMERA_PHONE_PROMPTS
CAMERA_PRIORITY_PROMPTS = camera_policy.CAMERA_PRIORITY_PROMPTS
_EXTENSIONS_APPLIED = False
class SafeFormatDict(dict):
def __missing__(self, key: str) -> str:
return "{" + key + "}"
def _slug(value: str) -> str:
return row_item_policy.slug(value)
def _list_from(value: Any) -> list[Any]:
if value is None:
return []
if isinstance(value, list):
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:
seen = set()
for item in target:
try:
seen.add(json.dumps(item, sort_keys=True))
except TypeError:
seen.add(repr(item))
for item in additions:
try:
marker = json.dumps(item, sort_keys=True)
except TypeError:
marker = repr(item)
if marker not in seen:
target.append(item)
seen.add(marker)
def _pair_from(value: Any) -> tuple[str, str]:
return row_item_policy.pair_from(value)
def _weighted_choice(rng: random.Random, items: list[Any]) -> Any:
return row_item_policy.weighted_choice(rng, items)
def _entry_text(item: Any) -> str:
return row_item_policy.entry_text(item)
def _item_text(item: Any) -> str:
return row_item_policy.item_text(item)
def _item_name(item: Any) -> str:
return row_item_policy.item_name(item)
def _template_metadata(item: Any) -> dict[str, Any]:
return item_template_policy.template_metadata(item)
def _template_position_family(metadata: dict[str, Any]) -> str:
return item_template_policy.template_position_family(metadata)
def _template_position_keys(metadata: dict[str, Any]) -> list[str]:
return item_template_policy.template_position_keys(metadata)
def _template_action_family(metadata: dict[str, Any]) -> str:
return item_template_policy.template_action_family(metadata)
def _template_formatter_hints(metadata: dict[str, Any]) -> dict[str, list[str]]:
return item_template_policy.formatter_hints(metadata)
def _merge_position_keys(primary: list[str], fallback: list[str]) -> list[str]:
return item_template_policy.merge_position_keys(primary, fallback)
def _oral_acts_for_position(values: list[Any], position: str) -> list[Any]:
return row_item_policy.oral_acts_for_position(values, position)
def _oral_axis_values_for_context(values: list[Any], position: str, oral_act: str, axis_name: str) -> list[Any]:
return row_item_policy.oral_axis_values_for_context(values, position, oral_act, axis_name)
def _outercourse_acts_for_position(values: list[Any], position: str) -> list[Any]:
return row_item_policy.outercourse_acts_for_position(values, position)
def _outercourse_axis_values_for_position(values: list[Any], position: str, axis_name: str) -> list[Any]:
return row_item_policy.outercourse_axis_values_for_position(values, position, axis_name)
def _compose_item(
rng: random.Random,
category: dict[str, Any],
subcategory: dict[str, Any],
item: Any,
women_count: int = 1,
men_count: int = 1,
) -> tuple[str, str, dict[str, str], dict[str, Any]]:
return row_item_policy.compose_item(
rng,
category,
subcategory,
item,
women_count,
men_count,
)
def _choose_text(rng: random.Random, items: list[Any]) -> str:
return row_item_policy.choose_text(rng, items)
def _choose_distinct_text(rng: random.Random, items: list[Any], first_text: str) -> str:
return row_item_policy.choose_distinct_text(rng, items, first_text)
def _choose_pair(rng: random.Random, items: list[Any]) -> tuple[str, str]:
return row_item_policy.choose_pair(rng, items)
def _extension_targets() -> dict[str, tuple[list[Any], bool]]:
return {
"women_clothes": (g.WOMEN_CLOTHES, False),
"women_clothes_minimal": (g.WOMEN_CLOTHES_MINIMAL, False),
"men_clothes": (g.MEN_CLOTHES, False),
"men_clothes_minimal": (g.MEN_CLOTHES_MINIMAL, False),
"couple_outfits": (g.COUPLE_OUTFITS, False),
"couple_outfits_minimal": (g.COUPLE_OUTFITS_MINIMAL, False),
"poses": (g.POSES, False),
"evocative_poses": (g.EVOCATIVE_POSES, False),
"backside_poses": (g.BACKSIDE_POSES, False),
"expressions": (g.EXPRESSIONS, False),
"compositions": (g.COMPOSITIONS, False),
"props": (g.PROPS, False),
"figure_curvy": (g.FIGURE_CURVY, False),
"figure_athletic": (g.FIGURE_ATHLETIC, False),
"figure_bombshell": (g.FIGURE_BOMBSHELL, False),
"scenes": (g.SCENES, True),
"group_scenes": (g.GROUP_SCENES, True),
"layouts_full": (g.LAYOUTS_FULL, True),
"layouts_minimal": (g.LAYOUTS_MINIMAL, True),
"group_compositions": (g.GROUP_COMPOSITIONS, False),
"group_ages": (g.GROUP_AGES, False),
}
def apply_pool_extensions() -> None:
global _EXTENSIONS_APPLIED
if _EXTENSIONS_APPLIED:
return
targets = _extension_targets()
for path in _json_files():
data = _read_json(path)
extensions = data.get("pool_extensions", {})
if not isinstance(extensions, dict):
raise ValueError(f"pool_extensions in {path} must be an object")
for target_name, additions in extensions.items():
if target_name not in targets:
known = ", ".join(sorted(targets))
raise ValueError(f"Unknown pool extension '{target_name}' in {path}. Known: {known}")
target, expects_pair = targets[target_name]
normalized = [_pair_from(item) for item in _list_from(additions)] if expects_pair else [
_item_text(item) for item in _list_from(additions)
]
_unique_extend(target, normalized)
g.EVOCATIVE_ALL = g.EVOCATIVE_POSES + g.BACKSIDE_POSES
_EXTENSIONS_APPLIED = True
def category_choices() -> list[str]:
apply_pool_extensions()
custom = [category["name"] for category in load_category_library()]
return BUILTIN_CATEGORIES + [name for name in custom if name not in BUILTIN_CATEGORIES]
def subcategory_choices() -> list[str]:
apply_pool_extensions()
choices = [RANDOM_SUBCATEGORY]
for category in load_category_library():
for subcategory in category["subcategories"]:
choices.append(f"{category['name']} / {subcategory['name']}")
return choices
def seed_mode_choices() -> list[str]:
return seed_policy.seed_mode_choices()
CATEGORY_PRESETS = category_cast_policy.CATEGORY_PRESETS
CAST_PRESETS = category_cast_policy.CAST_PRESETS
GENERATION_PROFILE_PRESETS = generation_profile_policy.GENERATION_PROFILE_PRESETS
def category_preset_choices() -> list[str]:
return category_cast_policy.category_preset_choices()
def cast_preset_choices() -> list[str]:
return category_cast_policy.cast_preset_choices()
def generation_profile_choices() -> list[str]:
return generation_profile_policy.generation_profile_choices()
def build_category_config_json(preset: str = "auto_weighted", subcategory: str = RANDOM_SUBCATEGORY) -> str:
return category_cast_policy.build_category_config_json(preset=preset, subcategory=subcategory)
def _parse_category_config(category_config: str | dict[str, Any] | None) -> tuple[str, str]:
return category_cast_policy.parse_category_config(category_config)
def build_cast_config_json(cast_mode: str = "mixed_couple", women_count: int = 1, men_count: int = 1) -> str:
return category_cast_policy.build_cast_config_json(cast_mode=cast_mode, women_count=women_count, men_count=men_count)
def _parse_cast_config(cast_config: str | dict[str, Any] | None) -> dict[str, int | str]:
return category_cast_policy.parse_cast_config(cast_config)
def build_generation_profile_json(
profile: str = "balanced",
clothing_override: str = "profile_default",
poses_override: str = "profile_default",
expression_intensity_mode: str = "profile_default",
expression_intensity: float = -1.0,
backside_bias: float = -1.0,
minimal_clothing_ratio: float = -1.0,
standard_pose_ratio: float = -1.0,
trigger_policy: str = "profile_default",
expression_enabled: bool = True,
) -> str:
return generation_profile_policy.build_generation_profile_json(
profile=profile,
clothing_override=clothing_override,
poses_override=poses_override,
expression_intensity_mode=expression_intensity_mode,
expression_intensity=expression_intensity,
backside_bias=backside_bias,
minimal_clothing_ratio=minimal_clothing_ratio,
standard_pose_ratio=standard_pose_ratio,
trigger_policy=trigger_policy,
expression_enabled=expression_enabled,
)
def _parse_generation_profile(profile_config: str | dict[str, Any] | None) -> dict[str, Any]:
return generation_profile_policy.parse_generation_profile(profile_config)
def build_filter_config_json(
ethnicity: str = "any",
figure: str = "curvy",
no_plus_women: bool = False,
no_black: bool = False,
include_european: bool = True,
include_mediterranean_mena: bool = True,
include_latina: bool = True,
include_east_asian: bool = True,
include_southeast_asian: bool = True,
include_south_asian: bool = True,
include_black_african: bool = True,
include_indigenous: bool = True,
include_mixed: bool = True,
include_plus_size: bool = True,
) -> str:
return filter_policy.build_filter_config_json(
ethnicity=ethnicity,
figure=figure,
no_plus_women=no_plus_women,
no_black=no_black,
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,
)
LOCATION_POOL_PRESETS = location_policy.LOCATION_POOL_PRESETS
COMPOSITION_POOL_PRESETS = location_policy.COMPOSITION_POOL_PRESETS
COMPOSITION_INLINE_PRESETS = location_policy.COMPOSITION_INLINE_PRESETS
THEMATIC_LOCATION_PRESETS = location_policy.THEMATIC_LOCATION_PRESETS
def location_pool_preset_choices() -> list[str]:
return location_policy.location_pool_preset_choices()
def composition_pool_preset_choices() -> list[str]:
return location_policy.composition_pool_preset_choices()
def location_theme_choices() -> list[str]:
return location_policy.location_theme_choices()
def _location_pool_names_for_preset(preset: str) -> list[str]:
return location_policy.location_pool_names_for_preset(preset)
def _custom_location_entries(custom_locations: str) -> list[dict[str, str]]:
return location_policy.custom_location_entries(custom_locations)
def _scene_entries_for_pool_names(pool_names: list[str]) -> list[Any]:
return location_policy.scene_entries_for_pool_names(pool_names)
def build_location_pool_json(
enabled: bool = True,
combine_mode: str = "replace",
preset: str = "custom_only",
custom_locations: str = "",
location_config: str | dict[str, Any] | None = "",
) -> str:
return location_policy.build_location_pool_json(
enabled=enabled,
combine_mode=combine_mode,
preset=preset,
custom_locations=custom_locations,
location_config=location_config,
)
def _parse_location_config(location_config: str | dict[str, Any] | None) -> dict[str, Any]:
return location_policy.parse_location_config(location_config)
def _location_config_active(location_config: dict[str, Any]) -> bool:
return location_policy.location_config_active(location_config)
def _composition_pool_names_for_preset(preset: str) -> list[str]:
return location_policy.composition_pool_names_for_preset(preset)
def _custom_composition_entries(custom_compositions: str) -> list[str]:
return location_policy.custom_composition_entries(custom_compositions)
def _composition_entries_for_pool_names(pool_names: list[str]) -> list[Any]:
return location_policy.composition_entries_for_pool_names(pool_names)
def build_composition_pool_json(
enabled: bool = True,
combine_mode: str = "replace",
preset: str = "custom_only",
custom_compositions: str = "",
composition_config: str | dict[str, Any] | None = "",
) -> str:
return location_policy.build_composition_pool_json(
enabled=enabled,
combine_mode=combine_mode,
preset=preset,
custom_compositions=custom_compositions,
composition_config=composition_config,
)
def _parse_composition_config(composition_config: str | dict[str, Any] | None) -> dict[str, Any]:
return location_policy.parse_composition_config(composition_config)
def _composition_config_active(composition_config: dict[str, Any]) -> bool:
return location_policy.composition_config_active(composition_config)
def build_thematic_location_json(
enabled: bool = True,
combine_mode: str = "replace",
theme: str = "semi_public_affair",
custom_locations: str = "",
custom_compositions: str = "",
location_config: str | dict[str, Any] | None = "",
composition_config: str | dict[str, Any] | None = "",
) -> tuple[str, str, str]:
return location_policy.build_thematic_location_json(
enabled=enabled,
combine_mode=combine_mode,
theme=theme,
custom_locations=custom_locations,
custom_compositions=custom_compositions,
location_config=location_config,
composition_config=composition_config,
)
def _ethnicity_text_from_value(value: Any) -> str:
return filter_policy.ethnicity_text_from_value(value)
def _is_valid_ethnicity_filter(value: Any) -> bool:
return filter_policy.is_valid_ethnicity_filter(value)
def normalize_ethnicity_filter(value: Any, default: str = "any", allow_random: bool = False) -> str:
return filter_policy.normalize_ethnicity_filter(value, default, allow_random)
def build_ethnicity_list_json(
include_european: bool = False,
include_mediterranean_mena: bool = False,
include_latina: bool = False,
include_east_asian: bool = False,
include_southeast_asian: bool = False,
include_south_asian: bool = False,
include_black_african: bool = False,
include_indigenous: bool = False,
include_mixed: bool = False,
include_asian: bool = False,
include_white_asian: bool = False,
include_western_european: bool = False,
include_french_european: bool = False,
include_germanic_european: bool = False,
include_nordic_european: bool = False,
include_celtic_european: bool = False,
include_slavic_european: bool = False,
include_baltic_european: bool = False,
include_alpine_european: bool = False,
include_balkan_european: bool = False,
include_greek_mediterranean: bool = False,
include_italian_mediterranean: bool = False,
include_iberian_mediterranean: bool = False,
strict_excludes: bool = True,
) -> dict[str, str]:
return filter_policy.build_ethnicity_list_json(
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_asian=include_asian,
include_white_asian=include_white_asian,
include_western_european=include_western_european,
include_french_european=include_french_european,
include_germanic_european=include_germanic_european,
include_nordic_european=include_nordic_european,
include_celtic_european=include_celtic_european,
include_slavic_european=include_slavic_european,
include_baltic_european=include_baltic_european,
include_alpine_european=include_alpine_european,
include_balkan_european=include_balkan_european,
include_greek_mediterranean=include_greek_mediterranean,
include_italian_mediterranean=include_italian_mediterranean,
include_iberian_mediterranean=include_iberian_mediterranean,
strict_excludes=strict_excludes,
)
def _parse_filter_config(filter_config: str | dict[str, Any] | None) -> dict[str, Any]:
return filter_policy.parse_filter_config(filter_config)
def _normalize_hardcore_position_family(value: Any, default: str = "any") -> str:
return hardcore_position_policy.normalize_hardcore_position_family(value, default)
def _normalize_hardcore_position_values(values: Any) -> list[str]:
return hardcore_position_policy.normalize_hardcore_position_values(values)
def _empty_hardcore_position_config() -> dict[str, Any]:
return hardcore_position_policy.empty_hardcore_position_config()
def _parse_hardcore_position_config(value: str | dict[str, Any] | None) -> dict[str, Any]:
return hardcore_position_policy.parse_hardcore_position_config(value)
def _hardcore_position_summary(config: dict[str, Any]) -> str:
return hardcore_position_policy.hardcore_position_summary(config)
def build_hardcore_position_pool_json(
hardcore_position_config: str | dict[str, Any] | None = "",
combine_mode: str = "replace",
family: str = "any",
selected_positions: list[str] | tuple[str, ...] | str | None = None,
) -> str:
return hardcore_position_policy.build_hardcore_position_pool_json(
hardcore_position_config=hardcore_position_config,
combine_mode=combine_mode,
family=family,
selected_positions=selected_positions,
)
def build_hardcore_action_filter_json(
hardcore_position_config: str | dict[str, Any] | None = "",
focus: str = "keep_pool",
allow_toys: bool = False,
allow_double: bool = False,
allow_penetration: bool = True,
allow_foreplay: bool = True,
allow_interaction: bool = True,
allow_manual: bool = True,
allow_oral: bool = True,
allow_outercourse: bool = True,
allow_anal: bool = True,
allow_climax: bool = True,
) -> str:
return hardcore_position_policy.build_hardcore_action_filter_json(
hardcore_position_config=hardcore_position_config,
focus=focus,
allow_toys=allow_toys,
allow_double=allow_double,
allow_penetration=allow_penetration,
allow_foreplay=allow_foreplay,
allow_interaction=allow_interaction,
allow_manual=allow_manual,
allow_oral=allow_oral,
allow_outercourse=allow_outercourse,
allow_anal=allow_anal,
allow_climax=allow_climax,
)
def _hardcore_position_config_active(config: dict[str, Any]) -> bool:
return hardcore_position_policy.hardcore_position_config_active(config)
def _is_hardcore_sexual_category(category: dict[str, Any]) -> bool:
return hardcore_position_policy.is_hardcore_sexual_category(category)
def _filter_hardcore_categories_for_position(
categories: list[dict[str, Any]],
config: dict[str, Any],
women_count: int,
men_count: int,
) -> list[dict[str, Any]]:
return hardcore_position_policy.filter_hardcore_categories_for_position(
categories,
config,
women_count,
men_count,
_compatible_entry,
)
def _apply_hardcore_position_config_to_subcategory(
subcategory: dict[str, Any],
config: dict[str, Any],
) -> dict[str, Any]:
return hardcore_position_policy.apply_hardcore_position_config_to_subcategory(subcategory, config)
def _ratio_or_none(value: float) -> float | None:
return row_generation_policy.ratio_or_none(value)
def _clamped_float(value: Any, default: float = 0.5, min_value: float = 0.0, max_value: float = 1.0) -> float:
return row_generation_policy.clamped_float(value, default, min_value, max_value)
def build_seed_config_json(
category_seed: int = -1,
subcategory_seed: int = -1,
content_seed: int = -1,
person_seed: int = -1,
scene_seed: int = -1,
pose_seed: int = -1,
role_seed: int = -1,
expression_seed: int = -1,
composition_seed: int = -1,
category_seed_mode: str = "auto",
subcategory_seed_mode: str = "auto",
content_seed_mode: str = "auto",
person_seed_mode: str = "auto",
scene_seed_mode: str = "auto",
pose_seed_mode: str = "auto",
role_seed_mode: str = "auto",
expression_seed_mode: str = "auto",
composition_seed_mode: str = "auto",
) -> str:
return seed_policy.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,
category_seed_mode=category_seed_mode,
subcategory_seed_mode=subcategory_seed_mode,
content_seed_mode=content_seed_mode,
person_seed_mode=person_seed_mode,
scene_seed_mode=scene_seed_mode,
pose_seed_mode=pose_seed_mode,
role_seed_mode=role_seed_mode,
expression_seed_mode=expression_seed_mode,
composition_seed_mode=composition_seed_mode,
)
def build_seed_lock_config_json(
base_seed: int = 20260614,
reroll_axis: str = "none",
reroll_seed: int = -1,
) -> str:
return seed_policy.build_seed_lock_config_json(
base_seed=base_seed,
reroll_axis=reroll_axis,
reroll_seed=reroll_seed,
)
def _parse_seed_config(seed_config: str | dict[str, Any] | None) -> dict[str, int]:
return seed_policy.parse_seed_config(seed_config)
def _configured_axis_seed(seed_config: dict[str, int], axis: str) -> int | None:
return seed_policy.configured_axis_seed(seed_config, axis)
def _axis_rng(seed_config: dict[str, int], axis: str, base_seed: int, row_number: int) -> random.Random:
return seed_policy.axis_rng(seed_config, axis, base_seed, row_number)
def _is_pose_content_category(category: dict[str, Any], subcategory: dict[str, Any]) -> bool:
haystack = " ".join(
str(value)
for value in (
category.get("name", ""),
category.get("slug", ""),
category.get("item_label", ""),
subcategory.get("name", ""),
subcategory.get("slug", ""),
subcategory.get("item_label", ""),
)
).lower()
return "pose" in haystack or "sex" in haystack
def _format(template: str, context: dict[str, Any]) -> str:
fields = {key for _, key, _, _ in Formatter().parse(template) if key}
safe_context = SafeFormatDict({key: str(value) for key, value in context.items()})
for field in fields:
safe_context.setdefault(field, "{" + field + "}")
return template.format_map(safe_context)
def _clean_prompt_punctuation(text: str) -> str:
return row_expression_policy.clean_prompt_punctuation(text)
def _strip_expression_text(text: str, expression: Any = "") -> str:
return row_expression_policy.strip_expression_text(text, expression)
def _disable_row_expression(row: dict[str, Any], source: str = "disabled") -> dict[str, Any]:
return row_expression_policy.disable_row_expression(row, source)
def _prepend_trigger(prompt: str, trigger: str, enabled: bool) -> str:
return row_policy.prepend_trigger(prompt, trigger, enabled)
def _combined_negative(base: str, extra: str) -> str:
return row_policy.combined_negative(base, extra)
def camera_mode_choices() -> list[str]:
return camera_policy.camera_mode_choices()
def ethnicity_choices() -> list[str]:
return list(ETHNICITY_FILTER_CHOICES)
def character_label_choices() -> list[str]:
return character_policy.character_label_choices()
def character_age_choices() -> list[str]:
return character_policy.character_age_choices()
def character_body_choices() -> list[str]:
return character_policy.character_body_choices()
def character_woman_body_choices() -> list[str]:
return character_policy.character_woman_body_choices()
def character_man_body_choices() -> list[str]:
return character_policy.character_man_body_choices()
def character_descriptor_detail_choices() -> list[str]:
return character_policy.character_descriptor_detail_choices()
def character_presence_choices() -> list[str]:
return character_policy.character_presence_choices()
def character_hair_color_choices() -> list[str]:
return character_policy.character_hair_color_choices()
def character_hair_length_choices() -> list[str]:
return character_policy.character_hair_length_choices()
def character_hair_style_choices() -> list[str]:
return character_policy.character_hair_style_choices()
def character_eye_color_choices() -> list[str]:
return character_policy.character_eye_color_choices()
def character_ethnicity_choices() -> list[str]:
return ["random"] + list(ETHNICITY_FILTER_CHOICES)
def character_figure_choices() -> list[str]:
return character_policy.character_figure_choices()
def camera_detail_choices() -> list[str]:
return camera_policy.camera_detail_choices()
def hardcore_detail_density_choices() -> list[str]:
return pair_options.hardcore_detail_density_choices()
def hardcore_position_family_choices() -> list[str]:
return hardcore_position_policy.hardcore_position_family_choices()
def hardcore_position_focus_choices() -> list[str]:
return hardcore_position_policy.hardcore_position_focus_choices()
def hardcore_position_key_choices() -> list[str]:
return hardcore_position_policy.hardcore_position_key_choices()
def character_softcore_outfit_source_choices() -> list[str]:
return [
"no_change",
"social_tease",
"lingerie_tease",
"implied_nude",
"explicit_tease",
"explicit_nude",
"partner_woman",
"partner_man",
"custom",
]
def character_hardcore_clothing_state_choices() -> list[str]:
return [
"no_change",
"fully_nude",
"partly_exposed",
"same_outfit",
"partially_removed",
"custom",
]
def camera_orbit_framing_choices() -> list[str]:
return camera_policy.camera_orbit_framing_choices()
def camera_orbit_focus_choices() -> list[str]:
return camera_policy.camera_orbit_focus_choices()
def camera_shot_choices() -> list[str]:
return camera_policy.camera_shot_choices()
def camera_angle_choices() -> list[str]:
return camera_policy.camera_angle_choices()
def camera_lens_choices() -> list[str]:
return camera_policy.camera_lens_choices()
def camera_distance_choices() -> list[str]:
return camera_policy.camera_distance_choices()
def camera_orientation_choices() -> list[str]:
return camera_policy.camera_orientation_choices()
def camera_phone_choices() -> list[str]:
return camera_policy.camera_phone_choices()
def camera_priority_choices() -> list[str]:
return camera_policy.camera_priority_choices()
def build_camera_config_json(
camera_mode: str = "standard",
shot_size: str = "auto",
angle: str = "auto",
lens: str = "auto",
distance: str = "auto",
orientation: str = "auto",
phone_visibility: str = "auto",
priority: str = "strong",
camera_detail: str = "compact",
) -> str:
return camera_policy.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,
)
def _camera_orbit_direction(horizontal_angle: Any) -> str:
return camera_policy._camera_orbit_direction(horizontal_angle)
def _camera_orbit_elevation(vertical_angle: Any) -> str:
return camera_policy._camera_orbit_elevation(vertical_angle)
def _camera_orbit_distance(zoom: Any, framing: str = "from_zoom") -> str:
return camera_policy._camera_orbit_distance(zoom, framing)
def _camera_orbit_focus(subject_focus: str) -> str:
return camera_policy._camera_orbit_focus(subject_focus)
def _camera_orbit_prompt(
horizontal_angle: Any,
vertical_angle: Any,
zoom: Any,
framing: str = "from_zoom",
subject_focus: str = "auto",
include_degrees: bool = True,
) -> tuple[str, dict[str, Any]]:
return camera_policy.camera_orbit_prompt(
horizontal_angle,
vertical_angle,
zoom,
framing=framing,
subject_focus=subject_focus,
include_degrees=include_degrees,
)
def build_camera_orbit_config_json(
enabled: bool = True,
camera_mode: str = "standard",
horizontal_angle: int = 0,
vertical_angle: int = 0,
zoom: float = 5.0,
framing: str = "from_zoom",
subject_focus: str = "auto",
lens: str = "auto",
orientation: str = "auto",
phone_visibility: str = "auto",
priority: str = "locked",
camera_detail: str = "compact",
include_degrees: bool = True,
) -> str:
return camera_policy.build_camera_orbit_config_json(
enabled=enabled,
camera_mode=camera_mode,
horizontal_angle=horizontal_angle,
vertical_angle=vertical_angle,
zoom=zoom,
framing=framing,
subject_focus=subject_focus,
lens=lens,
orientation=orientation,
phone_visibility=phone_visibility,
priority=priority,
camera_detail=camera_detail,
include_degrees=include_degrees,
)
QWEN_CAMERA_DIRECTIONS = camera_policy.QWEN_CAMERA_DIRECTIONS
QWEN_CAMERA_ELEVATIONS = camera_policy.QWEN_CAMERA_ELEVATIONS
QWEN_CAMERA_ZOOMS = camera_policy.QWEN_CAMERA_ZOOMS
QWEN_CAMERA_SCENE_CENTER_Y = camera_policy.QWEN_CAMERA_SCENE_CENTER_Y
def _qwen_prompt_camera_values(qwen_prompt: Any) -> tuple[int, int, float]:
return camera_policy._qwen_prompt_camera_values(qwen_prompt)
def _camera_info_dict(camera_info: Any) -> dict[str, Any] | None:
return camera_policy._camera_info_dict(camera_info)
def _qwen_camera_info_values(camera_info: Any) -> tuple[int, int, float] | None:
return camera_policy._qwen_camera_info_values(camera_info)
def build_qwen_camera_config_json(
qwen_prompt: str = "",
camera_info: Any = None,
prefer_camera_info: bool = True,
camera_mode: str = "standard",
subject_focus: str = "auto",
lens: str = "auto",
orientation: str = "auto",
phone_visibility: str = "auto",
priority: str = "locked",
camera_detail: str = "compact",
include_degrees: bool = False,
suppress_phone_visibility: bool = True,
) -> str:
return camera_policy.build_qwen_camera_config_json(
qwen_prompt=qwen_prompt,
camera_info=camera_info,
prefer_camera_info=prefer_camera_info,
camera_mode=camera_mode,
subject_focus=subject_focus,
lens=lens,
orientation=orientation,
phone_visibility=phone_visibility,
priority=priority,
camera_detail=camera_detail,
include_degrees=include_degrees,
suppress_phone_visibility=suppress_phone_visibility,
)
def _choice(value: Any, choices: dict[str, str], default: str) -> str:
return camera_policy._choice(value, choices, default)
def _parse_camera_config(camera_config: str | dict[str, Any] | None) -> dict[str, Any]:
return camera_policy.parse_camera_config(camera_config)
def _camera_config_with_mode(camera_config: str | dict[str, Any] | None, camera_mode: str) -> dict[str, Any]:
return camera_policy.camera_config_with_mode(camera_config, camera_mode)
def _camera_directive(camera_config: str | dict[str, Any] | None) -> tuple[str, dict[str, Any]]:
return camera_policy.camera_directive(camera_config)
def _insert_positive_directive(prompt: str, directive: str) -> str:
return row_camera_policy.insert_positive_directive(prompt, directive)
def _camera_caption_text(parsed: dict[str, Any]) -> str:
return row_camera_policy.camera_caption_text(parsed)
def _coworking_composition_prompt(scene_text: Any, composition: Any, subject_kind: str = "subjects") -> str:
return row_camera_policy.coworking_composition_prompt(scene_text, composition, subject_kind)
def _apply_coworking_composition(row: dict[str, Any], subject_kind: str) -> dict[str, Any]:
return row_camera_policy.apply_contextual_composition(row, subject_kind)
def _camera_scene_directive_for_context(
scene_text: Any,
composition: Any,
camera_config: str | dict[str, Any] | None,
pov_labels: list[str] | None = None,
subject_kind: str = "subjects",
) -> tuple[str, dict[str, Any]]:
directive, parsed = row_camera_policy.camera_scene_directive_for_context(
scene_text,
composition,
camera_config,
pov_labels,
subject_kind,
CAMERA_COMPACT_LABELS,
)
return directive, parsed
def _row_camera_subject_kind(row: dict[str, Any]) -> str:
return row_camera_policy.row_camera_subject_kind(row)
def _camera_pov_labels_for_row(row: dict[str, Any]) -> list[str]:
return _pov_character_labels(
_character_slot_label_map(_parse_character_cast(row.get("character_cast_slots"))),
int(row.get("men_count") or 0) if str(row.get("men_count") or "").isdigit() else 0,
)
def _apply_camera_config(row: dict[str, Any], camera_config: str | dict[str, Any] | None) -> dict[str, Any]:
return row_camera_policy.apply_camera_config(
row,
camera_config,
pov_label_resolver=_camera_pov_labels_for_row,
compact_labels=CAMERA_COMPACT_LABELS,
)
def _row_seed(seed: int, row_number: int, salt: int = 0) -> int:
return seed_policy.row_seed(seed, row_number, salt)
def _pick_clothing_mode(rng: random.Random, clothing: str, minimal_ratio: float | None) -> str:
return row_generation_policy.pick_clothing_mode(rng, clothing, minimal_ratio)
def _pick_pose_mode(rng: random.Random, poses: str, standard_ratio: float | None) -> str:
return row_generation_policy.pick_pose_mode(rng, poses, standard_ratio)
def _pick_figure_bias(rng: random.Random, figure: str) -> str:
return row_generation_policy.pick_figure_bias(rng, figure)
def _pick_expression_intensity(rng: random.Random, expression_intensity: Any) -> tuple[float, str]:
return row_generation_policy.pick_expression_intensity(rng, expression_intensity)
def _build_auto_weighted_row(
row_number: int,
start_index: int,
clothing: str,
ethnicity: str,
poses: str,
backside_bias: float,
figure: str,
no_plus_women: bool,
no_black: bool,
minimal_clothing_ratio: float | None,
standard_pose_ratio: float | None,
seed: int,
) -> dict[str, Any]:
return row_generation_policy.build_auto_weighted_row(
row_number,
start_index,
clothing,
ethnicity,
poses,
backside_bias,
figure,
no_plus_women,
no_black,
minimal_clothing_ratio,
standard_pose_ratio,
seed,
)
def _build_direct_builtin_row(
category: str,
row_number: int,
start_index: int,
clothing: str,
ethnicity: str,
poses: str,
backside_bias: float,
figure: str,
no_plus_women: bool,
no_black: bool,
minimal_clothing_ratio: float | None,
standard_pose_ratio: float | None,
seed: int,
) -> dict[str, Any]:
return row_generation_policy.build_direct_builtin_row(
category,
row_number,
start_index,
clothing,
ethnicity,
poses,
backside_bias,
figure,
no_plus_women,
no_black,
minimal_clothing_ratio,
standard_pose_ratio,
seed,
)
def _auto_full_choice(seed_config: dict[str, int], seed: int, row_number: int) -> str:
return row_generation_policy.auto_full_choice(seed_config, seed, row_number)
def _body_phrase(body: Any, figure_note: Any = "") -> str:
return character_profile_policy.body_phrase(body, figure_note)
def _safe_profile_name(profile_name: str) -> str:
return character_profile_policy.safe_profile_name(profile_name)
def _profile_path(profile_name: str) -> Path:
return character_profile_policy.profile_path(profile_name)
def character_profile_choices() -> list[str]:
return character_profile_policy.character_profile_choices()
def _load_json_object(value: str | dict[str, Any] | None, label: str) -> dict[str, Any]:
return character_profile_policy.load_json_object(value, label)
CHARACTER_MANUAL_FIELDS = character_profile_policy.CHARACTER_MANUAL_FIELDS
def _parse_character_manual_config(value: str | dict[str, Any] | None) -> dict[str, str]:
return character_profile_policy.parse_character_manual_config(value)
def _character_manual_summary(config: dict[str, str]) -> str:
return character_profile_policy.character_manual_summary(config)
def build_character_manual_config_json(
manual: str | dict[str, Any] | None = "",
combine_mode: str = "merge_nonempty",
manual_age: str = "",
manual_body: str = "",
body_phrase: str = "",
skin: str = "",
hair: str = "",
eyes: str = "",
softcore_outfit: str = "",
hardcore_clothing: str = "",
) -> str:
return character_profile_policy.build_character_manual_config_json(
manual=manual,
combine_mode=combine_mode,
manual_age=manual_age,
manual_body=manual_body,
body_phrase=body_phrase,
skin=skin,
hair=hair,
eyes=eyes,
softcore_outfit=softcore_outfit,
hardcore_clothing=hardcore_clothing,
)
def _slot_value(value: Any) -> str:
return character_policy.slot_value(value)
CHARACTER_CHARACTERISTIC_AXES = character_policy.CHARACTER_CHARACTERISTIC_AXES
def _empty_characteristics_config() -> dict[str, Any]:
return character_policy.empty_characteristics_config()
def _normalize_characteristic_choice(value: Any, choices: list[str] | tuple[str, ...]) -> str:
return character_policy.normalize_characteristic_choice(value, choices)
def _normalize_characteristic_values(
values: Any,
choices: list[str] | tuple[str, ...] | None = None,
*,
allow_free_text: bool = False,
) -> list[str]:
return character_policy.normalize_characteristic_values(values, choices, allow_free_text=allow_free_text)
def _parse_characteristics_config(value: str | dict[str, Any] | None) -> dict[str, Any]:
return character_policy.parse_characteristics_config(value)
def _characteristics_summary(config: dict[str, Any]) -> str:
return character_policy.characteristics_summary(config)
def build_characteristics_config_json(
characteristics: str | dict[str, Any] | None = "",
axis: str = "ages",
selected_values: list[str] | tuple[str, ...] | str | None = None,
combine_mode: str = "replace_axis",
) -> str:
return character_policy.build_characteristics_config_json(
characteristics=characteristics,
axis=axis,
selected_values=selected_values,
combine_mode=combine_mode,
)
def _characteristic_choice(config: dict[str, Any], key: str, rng: random.Random) -> str:
return character_policy.characteristic_choice(config, key, rng)
def _eye_phrase_from_key(key: str) -> str:
return character_policy.eye_phrase_from_key(key)
def _normalize_descriptor_detail(value: Any) -> str:
return character_policy.normalize_descriptor_detail(value)
def _normalize_presence_mode(value: Any, subject_type: str) -> str:
return character_policy.normalize_presence_mode(value, subject_type)
def _slot_is_pov(slot: dict[str, Any] | None) -> bool:
return pov_policy.slot_is_pov(slot)
def _normalize_slot_expression_intensity(value: Any) -> float:
return character_slot_policy.normalize_slot_expression_intensity(value)
def _slot_expression_enabled(slot: dict[str, Any] | None) -> bool:
return character_slot_policy.slot_expression_enabled(slot)
def _slot_expression_intensity(slot: dict[str, Any] | None) -> float | None:
return character_slot_policy.slot_expression_intensity(slot)
def _slot_expression_intensity_for_phase(slot: dict[str, Any] | None, phase: str = "") -> float | None:
return character_slot_policy.slot_expression_intensity_for_phase(slot, phase)
def _normalize_slot_seed(value: Any) -> int:
return character_policy.normalize_slot_seed(value)
def _slot_seed(slot: dict[str, Any] | None) -> int:
return character_slot_policy.slot_seed(slot)
def _slot_seeded_rng(slot: dict[str, Any] | None, salt: int) -> random.Random | None:
return character_slot_policy.slot_seeded_rng(slot, salt)
def _slot_context_rng(slot: dict[str, Any], fallback_rng: random.Random) -> random.Random:
return character_slot_policy.slot_context_rng(slot, fallback_rng)
def _slot_effective_figure(
slot: dict[str, Any],
subject_type: str,
fallback_figure: str,
) -> str:
return character_slot_policy.slot_effective_figure(slot, subject_type, fallback_figure)
def _cast_expression_intensity_override(
fallback: float,
label_map: dict[str, dict[str, Any]],
women_count: int,
men_count: int,
expression_phase: str = "",
) -> tuple[float | None, str]:
return row_expression_policy.cast_expression_intensity_override(
fallback,
label_map,
women_count,
men_count,
expression_phase,
)
def _character_expression_entries(
rng: random.Random,
expression_pool: list[Any],
fallback_intensity: float,
label_map: dict[str, dict[str, Any]],
women_count: int,
men_count: int,
expression_phase: str = "",
) -> list[str]:
return row_expression_policy.character_expression_entries(
rng,
expression_pool,
fallback_intensity,
label_map,
women_count,
men_count,
expression_phase,
)
def _sanitize_character_expression_text_for_action(
expression_text: str,
role_graph: Any,
item: Any,
axis_values: Any = None,
) -> str:
text = str(expression_text or "").strip()
if not text:
return ""
context = " ".join(
str(part or "").lower()
for part in (
role_graph,
item,
*((axis_values or {}).values() if isinstance(axis_values, dict) else ()),
)
)
woman_active_outercourse = (
re.search(r"\bwoman [a-z]\b", context)
and re.search(r"\bman [a-z]\b", context)
and any(
term in context
for term in (
"boobjob",
"titjob",
"breast sex",
"breasts tightly",
"testicle",
"balls-licking",
"balls licking",
"penis-licking",
"penis licking",
"handjob",
"hand job",
"footjob",
)
)
)
woman_gives_oral = (
re.search(r"\bwoman [a-z]\b", context)
and re.search(r"\bman [a-z]\b", context)
and any(
term in context
for term in (
"takes man",
"penis in her mouth",
"mouth at penis level",
"fellatio",
"blowjob",
"deepthroat",
"penis sucking",
"lips wrapped",
)
)
)
man_gives_oral = (
re.search(r"\bwoman [a-z]\b", context)
and re.search(r"\bman [a-z]\b", context)
and any(
term in context
for term in (
"mouth on her pussy",
"mouth on woman",
"mouth pressed to her pussy",
"cunnilingus",
"pussy licking",
"tongue on pussy",
)
)
)
mouth_expression_terms = ("mouth", "oral", "tongue", "lips", "gagging", "saliva")
clauses = [clause.strip() for clause in text.split(";") if clause.strip()]
if woman_active_outercourse:
clauses = [clause for clause in clauses if not re.match(r"^Man [A-Z] has\b", clause)]
if woman_gives_oral:
clauses = [
clause
for clause in clauses
if not (
re.match(r"^Man [A-Z] has\b", clause)
and any(term in clause.lower() for term in mouth_expression_terms)
)
]
if man_gives_oral:
clauses = [
clause
for clause in clauses
if not (
re.match(r"^Woman [A-Z] has\b", clause)
and any(term in clause.lower() for term in mouth_expression_terms)
)
]
return "; ".join(clauses)
def _descriptor_detail_for_subject(subject: Any, descriptor_detail: Any) -> str:
return character_profile_policy.descriptor_detail_for_subject(subject, descriptor_detail)
def _descriptor_from_parts(
subject: Any,
age: Any,
body_phrase: Any,
skin: Any,
hair: Any,
eyes: Any,
descriptor_detail: Any = "auto",
) -> str:
return character_profile_policy.descriptor_from_parts(
subject,
age,
body_phrase,
skin,
hair,
eyes,
descriptor_detail,
)
def _slot_manual_or_choice(choice: str, manual_value: str) -> str:
return character_slot_policy.slot_manual_or_choice(choice, manual_value)
def _normalize_slot_ethnicity(value: Any) -> str:
return character_slot_policy.normalize_slot_ethnicity(value)
def _normalize_hair_choice(value: Any, choices: list[str]) -> str:
return character_policy.normalize_hair_choice(value, choices)
def _infer_hair_color_key(text: Any) -> str:
return character_policy.infer_hair_color_key(text)
def _infer_hair_length_key(text: Any) -> str:
return character_policy.infer_hair_length_key(text)
def _infer_hair_style_key(text: Any) -> str:
return character_policy.infer_hair_style_key(text)
def _choose_hair_key(rng: random.Random, choices: list[str]) -> str:
return character_policy.choose_hair_key(rng, choices)
def _normalize_hair_values(values: Any, choices: list[str]) -> list[str]:
return character_policy.normalize_hair_values(values, choices)
def _empty_hair_config() -> dict[str, Any]:
return character_policy.empty_hair_config()
def _parse_hair_config(value: str | dict[str, Any] | None) -> dict[str, Any]:
return character_policy.parse_hair_config(value)
def _hair_config_summary(config: dict[str, Any]) -> str:
return character_policy.hair_config_summary(config)
def build_hair_config_json(
hair_config: str | dict[str, Any] | None = "",
axis: str = "color",
selected_values: list[str] | tuple[str, ...] | str | None = None,
combine_mode: str = "replace_axis",
) -> str:
return character_policy.build_hair_config_json(
hair_config=hair_config,
axis=axis,
selected_values=selected_values,
combine_mode=combine_mode,
)
def _hair_color_text(key: str) -> str:
return character_policy.hair_color_text(key)
def _hair_length_text(key: str) -> str:
return character_policy.hair_length_text(key)
def _hair_phrase_from_parts(color_key: str, length_key: str, style_key: str) -> str:
return character_policy.hair_phrase_from_parts(color_key, length_key, style_key)
def _hair_descriptor_from_slot(base_hair: Any, slot: dict[str, Any], rng: random.Random) -> str:
return character_appearance_policy.hair_descriptor_from_slot(base_hair, slot, rng)
def _normalize_character_slot(slot: dict[str, Any]) -> dict[str, Any]:
return character_slot_policy.normalize_character_slot(slot)
def _parse_character_cast(character_cast: str | dict[str, Any] | list[Any] | None) -> list[dict[str, Any]]:
return character_slot_policy.parse_character_cast(character_cast)
def _character_slot_summary(slot: dict[str, Any]) -> str:
return character_slot_policy.character_slot_summary(slot)
def build_character_slot_json(
subject_type: str = "woman",
label: str = "auto_chain",
slot_seed: int = -1,
age: str = "random",
manual_age: str = "",
manual: str | dict[str, Any] | None = "",
ethnicity: str = "random",
figure: str = "random",
body: str = "random",
manual_body: str = "",
body_phrase: str = "",
skin: str = "",
hair: str = "",
characteristics: str | dict[str, Any] | None = "",
hair_config: str | dict[str, Any] | None = "",
hair_color: str = "random",
hair_length: str = "random",
hair_style: str = "random",
eyes: str = "",
descriptor_detail: str = "auto",
expression_enabled: bool = True,
expression_intensity: float = -1.0,
enabled: bool = True,
character_cast: str | dict[str, Any] | list[Any] | None = "",
presence_mode: str = "visible",
softcore_expression_intensity: float = -1.0,
hardcore_expression_intensity: float = -1.0,
softcore_outfit: str = "",
hardcore_clothing: str = "",
) -> dict[str, str]:
return character_slot_policy.build_character_slot_json(
subject_type=subject_type,
label=label,
slot_seed=slot_seed,
age=age,
manual_age=manual_age,
manual=manual,
ethnicity=ethnicity,
figure=figure,
body=body,
manual_body=manual_body,
body_phrase=body_phrase,
skin=skin,
hair=hair,
characteristics=characteristics,
hair_config=hair_config,
hair_color=hair_color,
hair_length=hair_length,
hair_style=hair_style,
eyes=eyes,
descriptor_detail=descriptor_detail,
expression_enabled=expression_enabled,
expression_intensity=expression_intensity,
enabled=enabled,
character_cast=character_cast,
presence_mode=presence_mode,
softcore_expression_intensity=softcore_expression_intensity,
hardcore_expression_intensity=hardcore_expression_intensity,
softcore_outfit=softcore_outfit,
hardcore_clothing=hardcore_clothing,
)
def _slot_explicit_label(slot: dict[str, Any]) -> str:
return cast_context_policy.explicit_character_slot_label(slot)
def _character_slot_label_map(slots: list[dict[str, Any]]) -> dict[str, dict[str, Any]]:
return cast_context_policy.character_slot_label_map(slots)
def _pov_character_labels(
label_map: dict[str, dict[str, Any]],
men_count: int | None = None,
) -> list[str]:
return pov_policy.pov_character_labels(label_map, men_count)
def _pov_text_with_viewer(text: Any, pov_labels: list[str]) -> str:
return pov_policy.pov_text_with_viewer(text, pov_labels)
def _pov_role_graph_prompt(role_graph: Any, pov_labels: list[str]) -> str:
return pov_policy.pov_role_graph_prompt(role_graph, pov_labels)
def _pov_prompt_directive(pov_labels: list[str]) -> str:
return pov_policy.pov_prompt_directive(pov_labels)
def _pov_composition_prompt(composition: Any, pov_labels: list[str]) -> str:
return pov_policy.pov_composition_prompt(composition, pov_labels)
def _slot_softcore_outfit(slot: dict[str, Any] | None, rng: random.Random | None = None) -> str:
return character_appearance_policy.slot_softcore_outfit(slot, rng)
def _slot_hardcore_clothing(slot: dict[str, Any] | None, rng: random.Random | None = None) -> str:
return character_appearance_policy.slot_hardcore_clothing(slot, rng)
def _context_from_character_slot(
rng: random.Random,
slot: dict[str, Any],
subject_type: str,
ethnicity: str,
figure: str,
no_plus_women: bool,
no_black: bool,
) -> dict[str, str]:
return character_appearance_policy.context_from_character_slot(
rng,
slot,
subject_type,
ethnicity,
figure,
no_plus_women,
no_black,
)
def _character_context_for_label(
label: str,
label_map: dict[str, dict[str, Any]],
rng: random.Random,
ethnicity: str,
figure: str,
no_plus_women: bool,
no_black: bool,
) -> tuple[dict[str, str], dict[str, Any] | None]:
return character_appearance_policy.character_context_for_label(
label,
label_map,
rng,
ethnicity,
figure,
no_plus_women,
no_black,
)
def _apply_character_context_to_row(row: dict[str, Any], context: dict[str, Any]) -> dict[str, Any]:
return character_appearance_policy.apply_character_context_to_row(row, context)
def _cast_descriptor_entries(
seed_config: dict[str, int],
seed: int,
row_number: int,
ethnicity: str,
figure: str,
no_plus_women: bool,
no_black: bool,
women_count: int,
men_count: int,
character_cast: str | dict[str, Any] | list[Any] | None = "",
primary_descriptor: str = "",
) -> tuple[list[str], list[dict[str, Any]]]:
return pair_cast.cast_descriptor_entries(
seed_config=seed_config,
seed=seed,
row_number=row_number,
ethnicity=ethnicity,
figure=figure,
no_plus_women=no_plus_women,
no_black=no_black,
women_count=women_count,
men_count=men_count,
character_cast=character_cast,
primary_descriptor=primary_descriptor,
parse_character_cast=_parse_character_cast,
character_slot_label_map=_character_slot_label_map,
axis_rng=_axis_rng,
character_context_for_label=_character_context_for_label,
slot_is_pov=_slot_is_pov,
)
def _row_from_profile_metadata(metadata_json: str | dict[str, Any] | None) -> dict[str, Any]:
return character_profile_policy.row_from_profile_metadata(metadata_json)
def _row_from_character_slot(character_slot: str | dict[str, Any] | None) -> dict[str, Any]:
return character_appearance_policy.row_from_character_slot(character_slot)
def _character_profile_descriptor(profile: dict[str, Any]) -> str:
return character_profile_policy.character_profile_descriptor(profile)
def _normalize_character_profile(profile: dict[str, Any], profile_name: str = "") -> dict[str, Any]:
return character_profile_policy.normalize_character_profile(profile, profile_name)
def build_character_profile_json(
profile_name: str = "",
source: str = "metadata_json",
metadata_json: str | dict[str, Any] | None = "",
character_slot: str | dict[str, Any] | None = "",
subject_type: str = "woman",
age: str = "",
body: str = "",
body_phrase: str = "",
skin: str = "",
hair: str = "",
eyes: str = "",
figure: str = "",
save_now: bool = False,
) -> dict[str, str]:
character_slot_row = _row_from_character_slot(character_slot or metadata_json) if source == "character_slot" else None
return character_profile_policy.build_character_profile_json(
profile_name=profile_name,
source=source,
metadata_json=metadata_json,
character_slot_row=character_slot_row,
subject_type=subject_type,
age=age,
body=body,
body_phrase_value=body_phrase,
skin=skin,
hair=hair,
eyes=eyes,
figure=figure,
save_now=save_now,
)
def save_character_profile_payload(profile_name: str = "", profile_json: str | dict[str, Any] | None = "") -> dict[str, str]:
return character_profile_policy.save_character_profile_payload(profile_name, profile_json)
def _empty_profile_result(status: str = "empty") -> dict[str, str]:
return character_profile_policy.empty_profile_result(status)
def _apply_character_profile_overrides(
profile: dict[str, Any],
override_subject_type: str = "",
override_age: str = "",
override_body: str = "",
override_body_phrase: str = "",
override_skin: str = "",
override_hair: str = "",
override_eyes: str = "",
override_figure: str = "",
override_descriptor_detail: str = "",
) -> dict[str, Any]:
return character_profile_policy.apply_character_profile_overrides(
profile,
override_subject_type=override_subject_type,
override_age=override_age,
override_body=override_body,
override_body_phrase=override_body_phrase,
override_skin=override_skin,
override_hair=override_hair,
override_eyes=override_eyes,
override_figure=override_figure,
override_descriptor_detail=override_descriptor_detail,
)
def load_character_profile_json(
profile_name: str = "",
fallback_profile_json: str | dict[str, Any] | None = "",
enabled: bool = True,
delete_now: bool = False,
rename_now: bool = False,
rename_to: str = "",
override_subject_type: str = "",
override_age: str = "",
override_body: str = "",
override_body_phrase: str = "",
override_skin: str = "",
override_hair: str = "",
override_eyes: str = "",
override_figure: str = "",
override_descriptor_detail: str = "",
) -> dict[str, str]:
return character_profile_policy.load_character_profile_json(
profile_name=profile_name,
fallback_profile_json=fallback_profile_json,
enabled=enabled,
delete_now=delete_now,
rename_now=rename_now,
rename_to=rename_to,
override_subject_type=override_subject_type,
override_age=override_age,
override_body=override_body,
override_body_phrase=override_body_phrase,
override_skin=override_skin,
override_hair=override_hair,
override_eyes=override_eyes,
override_figure=override_figure,
override_descriptor_detail=override_descriptor_detail,
)
def _parse_character_profile(character_profile: str | dict[str, Any] | None) -> dict[str, Any]:
return character_profile_policy.parse_character_profile(character_profile)
def _apply_character_profile_to_context(
context: dict[str, Any],
character_profile: str | dict[str, Any] | None,
) -> tuple[dict[str, Any], dict[str, Any], str]:
return character_profile_policy.apply_character_profile_to_context(context, character_profile)
def _composition_prompt(composition: str) -> str:
return row_camera_policy.composition_prompt(composition)
def _appearance_for_subject(
rng: random.Random,
subject_type: str,
ethnicity: str,
figure: str,
no_plus_women: bool,
no_black: bool,
) -> dict[str, str]:
return character_appearance_policy.appearance_for_subject(
rng,
subject_type,
ethnicity,
figure,
no_plus_women,
no_black,
)
def _count_phrase(count: int, singular: str, plural: str) -> str:
return cast_context_policy.count_phrase(count, singular, plural)
def _configured_cast_context(women_count: int, men_count: int) -> dict[str, str]:
return cast_context_policy.configured_cast_context(women_count, men_count)
def _couple_type_from_counts(
rng: random.Random,
women_count: int,
men_count: int,
) -> tuple[str, str, str, int, int]:
return cast_context_policy.couple_type_from_counts(
rng,
women_count,
men_count,
choose=g.choose,
couple_types=g.COUPLE_TYPES,
)
def _subject_context(
rng: random.Random,
subject_type: str,
ethnicity: str,
figure: str,
no_plus_women: bool,
no_black: bool,
women_count: int = 1,
men_count: int = 1,
) -> dict[str, str]:
return subject_context_policy.subject_context(
rng,
subject_type,
ethnicity,
figure,
no_plus_women,
no_black,
women_count,
men_count,
)
def _scene_pool(
category: dict[str, Any],
subcategory: dict[str, Any],
item: Any,
subject_type: str,
location_config: dict[str, Any] | None = None,
) -> list[Any]:
return row_pool_policy.scene_pool(category, subcategory, item, subject_type, location_config)
def _expression_pool(category: dict[str, Any], subcategory: dict[str, Any], item: Any) -> list[Any]:
return row_pool_policy.expression_pool(category, subcategory, item)
def _expression_intensity_hint(entry: Any) -> float:
return row_expression_policy.expression_intensity_hint(entry)
def _expression_entries_for_intensity(entries: list[Any], expression_intensity: float) -> list[Any]:
return row_expression_policy.expression_entries_for_intensity(entries, expression_intensity)
def _pose_pool(category: dict[str, Any], subcategory: dict[str, Any], item: Any, subject_type: str, poses: str) -> list[Any]:
return row_pool_policy.pose_pool(category, subcategory, item, subject_type, poses)
def _composition_pool(
category: dict[str, Any],
subcategory: dict[str, Any],
item: Any,
subject_type: str,
composition_config: dict[str, Any] | None = None,
) -> list[Any]:
return row_pool_policy.composition_pool(category, subcategory, item, subject_type, composition_config)
def _build_custom_row(
category_choice: str,
subcategory_choice: str,
row_number: int,
start_index: int,
ethnicity: str,
poses: str,
figure: str,
no_plus_women: bool,
no_black: bool,
women_count: int,
men_count: int,
seed: int,
seed_config: dict[str, int],
expression_enabled: bool,
expression_intensity: float,
expression_intensity_source: str = "input",
character_profile: str | dict[str, Any] | None = None,
character_cast: str | dict[str, Any] | list[Any] | None = None,
expression_phase: str = "",
hardcore_position_config: str | dict[str, Any] | None = None,
location_config: str | dict[str, Any] | None = None,
composition_config: str | dict[str, Any] | None = None,
) -> dict[str, Any]:
categories = load_category_library()
category_rng = _axis_rng(seed_config, "category", seed, row_number)
subcategory_rng = _axis_rng(seed_config, "subcategory", seed, row_number)
person_rng = _axis_rng(seed_config, "person", seed, row_number)
scene_rng = _axis_rng(seed_config, "scene", seed, row_number)
pose_rng = _axis_rng(seed_config, "pose", seed, row_number)
role_rng = _axis_rng(seed_config, "role", seed, row_number)
expression_rng = _axis_rng(seed_config, "expression", seed, row_number)
composition_rng = _axis_rng(seed_config, "composition", seed, row_number)
parsed_hardcore_position_config = _parse_hardcore_position_config(hardcore_position_config)
parsed_location_config = _parse_location_config(location_config)
parsed_composition_config = _parse_composition_config(composition_config)
requested_women_count = women_count
requested_men_count = men_count
categories = _filter_hardcore_categories_for_position(
categories,
parsed_hardcore_position_config,
women_count,
men_count,
)
category, subcategory, women_count, men_count = _find_subcategory(
categories,
category_choice,
subcategory_choice,
category_rng,
subcategory_rng,
women_count,
men_count,
)
count_adjustment = {}
if women_count != requested_women_count or men_count != requested_men_count:
count_adjustment = {
"requested_women_count": requested_women_count,
"requested_men_count": requested_men_count,
"effective_women_count": women_count,
"effective_men_count": men_count,
}
if _is_hardcore_sexual_category(category):
subcategory = _apply_hardcore_position_config_to_subcategory(subcategory, parsed_hardcore_position_config)
content_axis = "pose" if _is_pose_content_category(category, subcategory) else "content"
content_rng = _axis_rng(seed_config, content_axis, seed, row_number)
items = _list_from(subcategory.get("items", [subcategory["name"]]))
item = _weighted_choice(content_rng, items)
item_text, item_name, item_axis_values, item_template_metadata = _compose_item(
content_rng,
category,
subcategory,
item,
women_count,
men_count,
)
is_pose_category = _is_pose_content_category(category, subcategory)
if is_pose_category:
item_text = _sanitize_hardcore_environment_anchors(item_text)
item_axis_values = _sanitize_hardcore_axis_values(item_axis_values)
item_formatter_hints = _template_formatter_hints(item_template_metadata)
subject_type = str(_merged_field(category, subcategory, item, "subject_type", "single_any"))
context = _subject_context(person_rng, subject_type, ethnicity, figure, no_plus_women, no_black, women_count, men_count)
character_slots = _parse_character_cast(character_cast)
character_slot_map = _character_slot_label_map(character_slots)
applied_slot: dict[str, Any] = {}
slot_status = "none"
if context.get("subject_type") in ("woman", "man"):
slot_label = "Woman A" if context["subject_type"] == "woman" else "Man A"
if slot_label in character_slot_map:
context, applied_slot = _character_context_for_label(
slot_label,
character_slot_map,
person_rng,
ethnicity,
figure,
no_plus_women,
no_black,
)
slot_status = f"applied:{slot_label}"
applied_profile, profile_status = {}, "skipped_character_slot"
else:
context, applied_profile, profile_status = _apply_character_profile_to_context(context, character_profile)
else:
context, applied_profile, profile_status = _apply_character_profile_to_context(context, character_profile)
subject_type = context["subject_type"]
pov_character_labels = (
_pov_character_labels(character_slot_map, men_count)
if subject_type == "configured_cast"
else []
)
source_role_graph = build_hardcore_role_graph(role_rng, subcategory, context, item_axis_values, pov_character_labels)
if is_pose_category:
source_role_graph = _sanitize_hardcore_environment_anchors(source_role_graph)
role_graph = _pov_role_graph_prompt(source_role_graph, pov_character_labels)
cast_descriptors: list[str] = []
cast_descriptor_text = ""
expression_intensity_source = expression_intensity_source or "input"
expression_disabled = not bool(expression_enabled)
if expression_disabled:
expression_intensity_source = "disabled"
elif subject_type in ("woman", "man") and applied_slot:
slot_label = "Woman A" if subject_type == "woman" else "Man A"
if not _slot_expression_enabled(applied_slot):
expression_disabled = True
expression_intensity_source = f"character_slot:{slot_label}:disabled"
else:
slot_expression_intensity = _slot_expression_intensity_for_phase(applied_slot, expression_phase)
if slot_expression_intensity is not None:
expression_intensity = slot_expression_intensity
expression_intensity_source = f"character_slot:{slot_label}"
elif subject_type == "configured_cast" and character_slots:
expression_intensity, expression_intensity_source = _cast_expression_intensity_override(
expression_intensity,
character_slot_map,
women_count,
men_count,
expression_phase,
)
if expression_intensity is None:
expression_disabled = True
if subject_type == "configured_cast" and character_slots:
cast_descriptors, _descriptor_slots = _cast_descriptor_entries(
seed_config,
seed,
row_number,
ethnicity,
figure,
no_plus_women,
no_black,
women_count,
men_count,
character_slots,
)
cast_descriptor_text = _insta_of_prompt_cast_descriptors("; ".join(cast_descriptors))
scene_slug, scene = _choose_pair(
scene_rng,
_compatible_entries(
_scene_pool(category, subcategory, item, subject_type, parsed_location_config),
women_count,
men_count,
),
)
pose = str(_merged_field(category, subcategory, item, "pose", "") or context.get("fallback_pose") or _choose_text(
pose_rng, _compatible_entries(_pose_pool(category, subcategory, item, subject_type, poses), women_count, men_count)
))
if is_pose_category:
pose = _sanitize_hardcore_environment_anchors(pose)
expression_pool = _expression_pool(category, subcategory, item)
if expression_disabled:
expression = ""
else:
expression_entries = _compatible_entries(
_expression_entries_for_intensity(expression_pool, expression_intensity),
women_count,
men_count,
)
expression = _choose_text(expression_rng, expression_entries)
if subject_type in ("couple", "group") and ";" not in expression:
secondary_expression = _choose_distinct_text(expression_rng, expression_entries, expression)
if secondary_expression:
expression = f"{expression}; {secondary_expression}"
shared_expression = expression
character_expressions: list[str] = []
character_expression_text = ""
if not expression_disabled and subject_type == "configured_cast" and character_slots:
character_expressions = _character_expression_entries(
expression_rng,
expression_pool,
expression_intensity,
character_slot_map,
women_count,
men_count,
expression_phase,
)
character_expression_text = "; ".join(character_expressions)
character_expression_text = _sanitize_character_expression_text_for_action(
character_expression_text,
source_role_graph,
item,
item_axis_values,
)
character_expressions = [part.strip() for part in character_expression_text.split(";") if part.strip()]
if character_expression_text:
expression = character_expression_text
source_composition = _choose_text(
composition_rng,
_compatible_entries(
_composition_pool(category, subcategory, item, subject_type, parsed_composition_config),
women_count,
men_count,
),
)
if is_pose_category:
source_composition = _sanitize_hardcore_environment_anchors(source_composition)
composition = _pov_composition_prompt(source_composition, pov_character_labels)
position_family = ""
position_keys: list[str] = []
position_key = ""
action_family = ""
if is_pose_category:
template_position_family = _template_position_family(item_template_metadata)
position_family = template_position_family or _hardcore_source_position_family(
subcategory,
parsed_hardcore_position_config,
)
inferred_position_keys = _hardcore_position_keys(
item_text,
source_role_graph,
source_composition,
pose,
axis_values=item_axis_values,
)
position_keys = _merge_position_keys(_template_position_keys(item_template_metadata), inferred_position_keys)
position_key = position_keys[0] if position_keys else ""
action_family = _template_action_family(item_template_metadata)
if not action_family:
action_family = source_hardcore_action_family(
position_family,
source_role_graph,
item_text,
source_composition,
item_axis_values,
)
negative_prompt = str(_merged_field(category, subcategory, item, "negative_prompt", g.NEGATIVE_PROMPT))
positive_suffix = str(_merged_field(category, subcategory, item, "positive_suffix", GENERIC_POSITIVE_SUFFIX))
style = str(
_merged_field(
category,
subcategory,
item,
"style",
"sexy but tasteful adult pin-up coloured-pencil comic illustration",
)
)
item_label = str(_merged_field(category, subcategory, item, "item_label", category["name"]))
context.update(
{
"trigger": g.TRIGGER,
"main_category": category["name"],
"subcategory": subcategory["name"],
"category": category["name"],
"item": item_text,
"item_name": item_name,
"item_label": item_label,
"style": style,
"scene": scene,
"scene_slug": scene_slug,
"pose": pose,
"expression": expression,
"shared_expression": shared_expression,
"character_expressions": character_expressions,
"character_expression_text": character_expression_text,
"expression_enabled": not expression_disabled,
"expression_disabled": expression_disabled,
"expression_intensity": expression_intensity,
"expression_intensity_source": expression_intensity_source,
"composition": composition,
"source_composition": source_composition,
"composition_prompt": _composition_prompt(composition),
"composition_config": parsed_composition_config if _composition_config_active(parsed_composition_config) else {},
"role_graph": role_graph,
"source_role_graph": source_role_graph,
"action_family": action_family,
"position_family": position_family,
"position_key": position_key,
"position_keys": position_keys,
"pov_character_labels": pov_character_labels,
"pov_prompt_directive": _pov_prompt_directive(pov_character_labels),
"cast_descriptors": cast_descriptor_text,
"positive_suffix": positive_suffix,
"negative_prompt": negative_prompt,
}
)
if isinstance(item, dict) and "prompt_template" in item:
template = str(item["prompt_template"])
else:
template = str(subcategory.get("prompt_template") or category.get("prompt_template") or "")
if not template:
if subject_type in ("woman", "man"):
template = SINGLE_TEMPLATE
elif subject_type == "couple":
template = COUPLE_TEMPLATE
elif subject_type == "group":
template = GROUP_TEMPLATE
else:
template = LAYOUT_TEMPLATE
caption_template = str(
(item.get("caption_template") if isinstance(item, dict) else None)
or subcategory.get("caption_template")
or category.get("caption_template")
or "{trigger}, {subject_phrase}, {age}, {item}, {scene}, {composition}, coloured pencil comic illustration"
)
prompt = _format(template, context)
if subject_type == "configured_cast" and cast_descriptor_text and "{cast_descriptors}" not in template:
prompt = _insert_positive_directive(prompt, f"Characters: {cast_descriptor_text}.")
if subject_type == "configured_cast" and pov_character_labels:
prompt = _insert_positive_directive(prompt, _pov_prompt_directive(pov_character_labels))
caption = _format(caption_template, context)
if subject_type == "configured_cast" and cast_descriptor_text and "{cast_descriptors}" not in caption_template:
caption = f"{caption.rstrip()}, {cast_descriptor_text}"
batch = max(1, ((row_number - 1) // g.BATCH_SIZE) + 1)
index = start_index + row_number - 1
row = g.row_base(index, batch, context["subject"], context["age"], context["body"], scene_slug, composition)
row.update(
{
"prompt": prompt,
"caption": caption,
"negative_prompt": negative_prompt,
"expression": expression,
"main_category": category["name"],
"subcategory": subcategory["name"],
"category_slug": category["slug"],
"subcategory_slug": subcategory["slug"],
"subject_type": subject_type,
"subject_phrase": context.get("subject_phrase", ""),
"body_phrase": context.get("body_phrase", ""),
"skin": context.get("skin", ""),
"hair": context.get("hair", ""),
"eyes": context.get("eyes", ""),
"style": style,
"item": item_text,
"item_label": item_label,
"positive_suffix": positive_suffix,
"custom_item": item_name,
"item_axis_values": item_axis_values,
"item_template_metadata": item_template_metadata,
"formatter_hints": item_formatter_hints,
"scene_text": scene,
"location_config": parsed_location_config if _location_config_active(parsed_location_config) else {},
"pose": pose,
"seed_config": seed_config,
"hardcore_position_config": (
parsed_hardcore_position_config
if _hardcore_position_config_active(parsed_hardcore_position_config)
else {}
),
"content_seed_axis": content_axis,
"role_graph": role_graph,
"source_role_graph": source_role_graph,
"action_family": action_family,
"position_family": position_family,
"position_key": position_key,
"position_keys": position_keys,
"source_composition": source_composition,
"pov_character_labels": pov_character_labels,
"pov_prompt_directive": _pov_prompt_directive(pov_character_labels),
"shared_expression": shared_expression,
"character_expressions": character_expressions,
"character_expression_text": character_expression_text,
"expression_enabled": not expression_disabled,
"expression_disabled": expression_disabled,
"cast_summary": context.get("cast_summary", ""),
"cast_descriptors": cast_descriptors,
"cast_descriptor_text": cast_descriptor_text,
"scene_kind": context.get("scene_kind", ""),
"women_count": context.get("women_count", ""),
"men_count": context.get("men_count", ""),
"person_count": context.get("person_count", ""),
"cast_count_adjustment": count_adjustment if subject_type == "configured_cast" else {},
"character_profile": applied_profile,
"character_profile_status": profile_status,
"character_slot": applied_slot,
"character_slot_status": slot_status,
"character_cast_slots": character_slots,
"expression_intensity": expression_intensity,
"expression_intensity_source": expression_intensity_source,
"source": "json_category",
}
)
if context.get("figure"):
row["figure"] = context["figure"]
if expression_disabled:
row = _disable_row_expression(row, expression_intensity_source)
return row
def build_prompt(
category: str,
subcategory: str,
row_number: int,
start_index: int,
seed: int,
clothing: str,
ethnicity: str,
poses: str,
backside_bias: float,
figure: str,
no_plus_women: bool,
no_black: bool,
minimal_clothing_ratio: float,
standard_pose_ratio: float,
trigger: str,
prepend_trigger_to_prompt: bool,
extra_positive: str,
extra_negative: str,
seed_config: str | dict[str, Any] | None = None,
women_count: int = 1,
men_count: int = 1,
camera_config: str | dict[str, Any] | None = None,
expression_intensity: float = 0.5,
character_profile: str | dict[str, Any] | None = None,
character_cast: str | dict[str, Any] | list[Any] | None = None,
expression_enabled: bool = True,
expression_phase: str = "",
hardcore_position_config: str | dict[str, Any] | None = None,
location_config: str | dict[str, Any] | None = None,
composition_config: str | dict[str, Any] | None = None,
) -> dict[str, Any]:
apply_pool_extensions()
row_number = max(1, int(row_number))
start_index = max(1, int(start_index))
seed = int(seed)
ethnicity = normalize_ethnicity_filter(ethnicity, "any")
expression_enabled = not _is_false(expression_enabled)
minimal_ratio = _ratio_or_none(minimal_clothing_ratio)
pose_ratio = _ratio_or_none(standard_pose_ratio)
parsed_seed_config = _parse_seed_config(seed_config)
parsed_location_config = _parse_location_config(location_config)
parsed_composition_config = _parse_composition_config(composition_config)
content_rng = _axis_rng(parsed_seed_config, "content", seed, row_number)
pose_axis_rng = _axis_rng(parsed_seed_config, "pose", seed, row_number)
person_rng = _axis_rng(parsed_seed_config, "person", seed, row_number)
expression_rng = _axis_rng(parsed_seed_config, "expression", seed, row_number)
clothing = clothing if clothing in ("full", "minimal", "random") else "full"
poses = poses if poses in ("standard", "evocative", "random") else "standard"
figure = figure if figure in ("curvy", "balanced", "bombshell", "random") else "curvy"
clothing = _pick_clothing_mode(content_rng, clothing, minimal_ratio)
poses = _pick_pose_mode(pose_axis_rng, poses, pose_ratio)
figure = _pick_figure_bias(person_rng, figure)
minimal_ratio = None
pose_ratio = None
expression_intensity, expression_intensity_source = _pick_expression_intensity(expression_rng, expression_intensity)
exact_custom_subcategory = bool(subcategory and subcategory != RANDOM_SUBCATEGORY and " / " in subcategory)
if category == "auto_full" and not exact_custom_subcategory:
category = _auto_full_choice(parsed_seed_config, seed, row_number)
if category == "auto_weighted" and not exact_custom_subcategory:
row = _build_auto_weighted_row(
row_number,
start_index,
clothing,
ethnicity,
poses,
float(backside_bias),
figure,
bool(no_plus_women),
bool(no_black),
minimal_ratio,
pose_ratio,
seed,
)
elif category in ("woman", "man", "couple", "group_or_layout") and not exact_custom_subcategory:
row = _build_direct_builtin_row(
category,
row_number,
start_index,
clothing,
ethnicity,
poses,
float(backside_bias),
figure,
bool(no_plus_women),
bool(no_black),
minimal_ratio,
pose_ratio,
seed,
)
else:
row = _build_custom_row(
category,
subcategory,
row_number,
start_index,
ethnicity,
poses,
figure,
bool(no_plus_women),
bool(no_black),
int(women_count),
int(men_count),
seed,
parsed_seed_config,
expression_enabled,
expression_intensity,
expression_intensity_source,
character_profile,
character_cast,
expression_phase,
hardcore_position_config,
parsed_location_config,
parsed_composition_config,
)
if row.get("source") == "built_in_generator":
row = row_location_policy.apply_location_config_to_legacy_row(
row,
parsed_location_config,
parsed_seed_config,
seed,
row_number,
)
row = row_location_policy.apply_composition_config_to_legacy_row(
row,
parsed_composition_config,
parsed_seed_config,
seed,
row_number,
)
if not expression_enabled:
row = _disable_row_expression(row, "disabled")
row = _apply_camera_config(row, camera_config)
active_trigger = trigger.strip() or g.TRIGGER
row = row_policy.normalize_prompt_row(
row,
active_trigger=active_trigger,
prepend_trigger_to_prompt=bool(prepend_trigger_to_prompt),
extra_positive=extra_positive,
extra_negative=extra_negative,
default_negative=g.NEGATIVE_PROMPT,
)
row.setdefault("expression_intensity", expression_intensity)
row.setdefault("expression_intensity_source", expression_intensity_source)
return row
def build_prompt_from_configs(
row_number: int,
start_index: int,
seed: int,
category_config: str | dict[str, Any] | None = "",
cast_config: str | dict[str, Any] | None = "",
generation_profile: str | dict[str, Any] | None = "",
filter_config: str | dict[str, Any] | None = "",
seed_config: str | dict[str, Any] | None = "",
camera_config: str | dict[str, Any] | None = "",
character_profile: str | dict[str, Any] | None = "",
character_cast: str | dict[str, Any] | list[Any] | None = "",
hardcore_position_config: str | dict[str, Any] | None = "",
location_config: str | dict[str, Any] | None = "",
composition_config: str | dict[str, Any] | None = "",
extra_positive: str = "",
extra_negative: str = "",
) -> dict[str, Any]:
category, subcategory = _parse_category_config(category_config)
cast = _parse_cast_config(cast_config)
profile = _parse_generation_profile(generation_profile)
filters = _parse_filter_config(filter_config)
return build_prompt(
category=category,
subcategory=subcategory,
row_number=row_number,
start_index=start_index,
seed=seed,
clothing=profile["clothing"],
ethnicity=filters["ethnicity"],
poses=profile["poses"],
expression_enabled=profile["expression_enabled"],
expression_intensity=profile["expression_intensity"],
backside_bias=profile["backside_bias"],
figure=filters["figure"],
no_plus_women=filters["no_plus_women"],
no_black=filters["no_black"],
women_count=int(cast["women_count"]),
men_count=int(cast["men_count"]),
minimal_clothing_ratio=profile["minimal_clothing_ratio"],
standard_pose_ratio=profile["standard_pose_ratio"],
trigger=profile["trigger"],
prepend_trigger_to_prompt=profile["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 "",
hardcore_position_config=hardcore_position_config or "",
location_config=location_config or "",
composition_config=composition_config or "",
)
INSTA_OF_SOFT_LEVELS = pair_options.INSTA_OF_SOFT_LEVELS
INSTA_OF_HARDCORE_LEVELS = pair_options.INSTA_OF_HARDCORE_LEVELS
INSTA_OF_PLATFORM_STYLES = pair_options.INSTA_OF_PLATFORM_STYLES
INSTA_OF_HARDCORE_CLOTHING_CONTINUITY = pair_options.INSTA_OF_HARDCORE_CLOTHING_CONTINUITY
INSTA_OF_NEGATIVE = pair_options.INSTA_OF_NEGATIVE
INSTA_OF_SOFT_NEGATIVE = pair_options.INSTA_OF_SOFT_NEGATIVE
INSTA_OF_SOFTCORE_SUBCATEGORY_BY_LEVEL = pair_options.INSTA_OF_SOFTCORE_SUBCATEGORY_BY_LEVEL
INSTA_OF_SOFTCORE_OUTFITS = pair_options.INSTA_OF_SOFTCORE_OUTFITS
INSTA_OF_SOFTCORE_POSES = pair_options.INSTA_OF_SOFTCORE_POSES
INSTA_OF_SOFTCORE_PARTNER_WOMEN_OUTFITS = pair_options.INSTA_OF_SOFTCORE_PARTNER_WOMEN_OUTFITS
INSTA_OF_SOFTCORE_PARTNER_MEN_OUTFITS = pair_options.INSTA_OF_SOFTCORE_PARTNER_MEN_OUTFITS
def character_softcore_outfit_values(source: str, custom_outfits: str = "") -> list[str]:
return pair_options.character_softcore_outfit_values(source, custom_outfits)
def character_hardcore_clothing_values(state: str, custom_clothing: str = "") -> list[str]:
return pair_options.character_hardcore_clothing_values(state, custom_clothing)
def build_insta_of_options_json(
softcore_cast: str = "solo",
hardcore_cast: str = "use_counts",
hardcore_women_count: int = 1,
hardcore_men_count: int = 1,
softcore_level: str = "lingerie_tease",
hardcore_level: str = "hardcore",
platform_style: str = "hybrid",
continuity: str = "same_creator_same_room",
hardcore_clothing_continuity: str = "partially_removed",
softcore_camera_mode: str = "handheld_selfie",
hardcore_camera_mode: str = "from_camera_config",
camera_detail: str = "from_camera_config",
softcore_expression_intensity: float = 0.45,
hardcore_expression_intensity: float = 0.85,
softcore_expression_enabled: bool = True,
hardcore_expression_enabled: bool = True,
hardcore_detail_density: str = "balanced",
) -> str:
return pair_options.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,
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,
softcore_expression_intensity=softcore_expression_intensity,
hardcore_expression_intensity=hardcore_expression_intensity,
softcore_expression_enabled=softcore_expression_enabled,
hardcore_expression_enabled=hardcore_expression_enabled,
hardcore_detail_density=hardcore_detail_density,
hardcore_detail_density_choices=HARDCORE_DETAIL_DENSITY_CHOICES,
)
def _parse_insta_of_options(options_json: str | dict[str, Any] | None) -> dict[str, Any]:
return pair_options.parse_insta_of_options(
options_json,
camera_mode_choices=CAMERA_MODE_PROMPTS,
camera_detail_choices=CAMERA_DETAIL_CHOICES,
hardcore_detail_density_choices=HARDCORE_DETAIL_DENSITY_CHOICES,
)
def _insta_of_hardcore_counts(options: dict[str, Any]) -> tuple[int, int]:
return pair_options.hardcore_counts(options)
def _insta_of_descriptor(row: dict[str, Any]) -> str:
return pair_cast.insta_descriptor_from_row(row)
def _insta_of_descriptor_from_context(context: dict[str, Any]) -> str:
return pair_cast.insta_descriptor_from_context(context)
def _insta_of_prompt_cast_descriptors(text: str) -> str:
return pair_cast.prompt_cast_descriptors(text)
def _insta_of_softcore_category(level: str) -> tuple[str, str]:
return pair_options.softcore_category(level)
def _insta_of_softcore_outfit(rng: random.Random, level: str) -> str:
return g.choose(rng, pair_options.softcore_outfit_pool(level))
def _insta_of_softcore_item_prompt_label(level: str) -> str:
return pair_options.softcore_item_prompt_label(level)
def _insta_of_softcore_pose(rng: random.Random, level: str) -> str:
return g.choose(rng, pair_options.softcore_pose_pool(level))
def build_insta_of_pair(
row_number: int,
start_index: int,
seed: int,
ethnicity: str,
figure: str,
no_plus_women: bool,
no_black: bool,
trigger: str,
prepend_trigger_to_prompt: bool,
seed_config: str | dict[str, Any] | None = None,
options_json: str | dict[str, Any] | None = None,
filter_config: str | dict[str, Any] | None = None,
camera_config: str | dict[str, Any] | None = None,
softcore_camera_config: str | dict[str, Any] | None = None,
hardcore_camera_config: str | dict[str, Any] | None = None,
character_profile: str | dict[str, Any] | None = "",
character_cast: str | dict[str, Any] | list[Any] | None = "",
hardcore_position_config: str | dict[str, Any] | None = "",
location_config: str | dict[str, Any] | None = "",
composition_config: str | dict[str, Any] | None = "",
extra_positive: str = "",
extra_negative: str = "",
) -> dict[str, Any]:
options = _parse_insta_of_options(options_json)
if filter_config:
filters = _parse_filter_config(filter_config)
ethnicity = filters["ethnicity"]
figure = filters["figure"]
no_plus_women = filters["no_plus_women"]
no_black = filters["no_black"]
hard_women_count, hard_men_count = _insta_of_hardcore_counts(options)
active_trigger = trigger.strip() or g.TRIGGER
parsed_seed_config = _parse_seed_config(seed_config)
character_slots = _parse_character_cast(character_cast)
character_slot_map = _character_slot_label_map(character_slots)
pov_character_labels = _pov_character_labels(character_slot_map, hard_men_count)
softcore_level_key = str(options["softcore_level"])
soft_category, soft_subcategory = _insta_of_softcore_category(softcore_level_key)
row_route = pair_rows.build_insta_pair_rows(
row_number=row_number,
start_index=start_index,
seed=seed,
active_trigger=active_trigger,
parsed_seed_config=parsed_seed_config,
options=options,
ethnicity=ethnicity,
figure=figure,
no_plus_women=no_plus_women,
no_black=no_black,
character_profile=character_profile,
character_cast=character_cast or "",
character_slot_map=character_slot_map,
pov_character_labels=pov_character_labels,
hard_women_count=hard_women_count,
hard_men_count=hard_men_count,
soft_category=soft_category,
soft_subcategory=soft_subcategory,
softcore_level_key=softcore_level_key,
hardcore_random_subcategory=RANDOM_SUBCATEGORY,
hardcore_position_config=hardcore_position_config,
location_config=location_config or "",
composition_config=composition_config or "",
build_prompt=build_prompt,
axis_rng=_axis_rng,
cast_expression_intensity_override=_cast_expression_intensity_override,
context_from_character_slot=_context_from_character_slot,
apply_character_context_to_row=_apply_character_context_to_row,
disable_row_expression=_disable_row_expression,
slot_softcore_outfit=_slot_softcore_outfit,
softcore_outfit=_insta_of_softcore_outfit,
softcore_pose=_insta_of_softcore_pose,
softcore_item_prompt_label=_insta_of_softcore_item_prompt_label,
pov_prompt_directive=_pov_prompt_directive,
pov_composition_prompt=_pov_composition_prompt,
)
soft_row = row_route["soft_row"]
hard_row = row_route["hard_row"]
hard_content_rng = row_route["hard_content_rng"]
cast_context = pair_cast.resolve_insta_pair_cast_context(
soft_row=soft_row,
options=options,
parsed_seed_config=parsed_seed_config,
seed=seed,
row_number=row_number,
ethnicity=ethnicity,
figure=figure,
no_plus_women=no_plus_women,
no_black=no_black,
hard_women_count=hard_women_count,
hard_men_count=hard_men_count,
character_slots=character_slots,
character_slot_map=character_slot_map,
pov_character_labels=pov_character_labels,
platform_styles=INSTA_OF_PLATFORM_STYLES,
soft_levels=INSTA_OF_SOFT_LEVELS,
hardcore_levels=INSTA_OF_HARDCORE_LEVELS,
axis_rng=_axis_rng,
character_context_for_label=_character_context_for_label,
slot_is_pov=_slot_is_pov,
choose=g.choose,
slot_softcore_outfit=_slot_softcore_outfit,
)
descriptor = cast_context["descriptor"]
cast_descriptors = cast_context["cast_descriptors"]
cast_descriptor_text = cast_context["cast_descriptor_text"]
soft_partner_styling = cast_context["soft_partner_styling"]
soft_partner_outfit_text = cast_context["soft_partner_outfit_text"]
platform_style = cast_context["platform_style"]
soft_level = cast_context["soft_level"]
hard_level = cast_context["hard_level"]
camera_route = pair_camera.resolve_insta_pair_camera(
soft_row=soft_row,
hard_row=hard_row,
options=options,
camera_config=camera_config,
softcore_camera_config=softcore_camera_config,
hardcore_camera_config=hardcore_camera_config,
hard_women_count=hard_women_count,
hard_men_count=hard_men_count,
pov_character_labels=pov_character_labels,
camera_detail_choices=CAMERA_DETAIL_CHOICES,
camera_config_with_mode=_camera_config_with_mode,
camera_directive=_camera_directive,
apply_contextual_composition=_apply_coworking_composition,
contextual_composition_prompt=_coworking_composition_prompt,
composition_prompt=_composition_prompt,
camera_scene_directive_for_context=_camera_scene_directive_for_context,
)
soft_row = camera_route["soft_row"]
hard_row = camera_route["hard_row"]
hard_scene = camera_route["hard_scene"]
hard_composition = camera_route["hard_composition"]
soft_camera_config = camera_route["soft_camera_config"]
hard_camera_config = camera_route["hard_camera_config"]
soft_camera_directive = camera_route["soft_camera_directive"]
hard_camera_directive = camera_route["hard_camera_directive"]
soft_camera_scene_directive = camera_route["soft_camera_scene_directive"]
hard_camera_scene_directive = camera_route["hard_camera_scene_directive"]
soft_camera_scene_sentence = camera_route["soft_camera_scene_sentence"]
hard_camera_scene_sentence = camera_route["hard_camera_scene_sentence"]
soft_camera_sentence = camera_route["soft_camera_sentence"]
hard_camera_sentence = camera_route["hard_camera_sentence"]
soft_cast = cast_context["soft_cast"]
soft_cast_presence = cast_context["soft_cast_presence"]
soft_cast_styling_sentence = cast_context["soft_cast_styling_sentence"]
hard_cast = cast_context["hard_cast"]
character_hardcore_clothing_entries = pair_clothing.character_hardcore_clothing_entries(
character_slot_map,
hard_women_count,
hard_men_count,
pov_character_labels,
hard_content_rng,
_slot_hardcore_clothing,
)
clothing_route = pair_clothing.resolve_hardcore_pair_clothing(
hard_row=hard_row,
mode=options["hardcore_clothing_continuity"],
softcore_outfit=soft_row["item"],
character_hardcore_clothing_entries=character_hardcore_clothing_entries,
men_count=hard_men_count,
pov_labels=pov_character_labels,
rng=hard_content_rng,
continuity_map=INSTA_OF_HARDCORE_CLOTHING_CONTINUITY,
choose=g.choose,
)
default_man_hardcore_clothing_entries = clothing_route["default_man_hardcore_clothing"]
hard_clothing_state = clothing_route["hardcore_clothing_state"]
hard_clothing_sentence = clothing_route["hardcore_clothing_sentence"]
if clothing_route["requires_body_exposure_scene"]:
hard_scene = pair_clothing.body_exposure_scene_text(hard_scene)
hard_row["source_scene_text"] = hard_row.get("source_scene_text") or hard_row.get("scene_text", "")
hard_row["scene_text"] = hard_scene
hard_detail_density = options["hardcore_detail_density"]
hard_detail_directive = pair_options.hardcore_detail_directive(hard_detail_density)
pov_directive = _pov_prompt_directive(pov_character_labels)
soft_descriptor_sentence = cast_context["soft_descriptor_sentence"]
return pair_output.assemble_insta_pair_metadata(
active_trigger=active_trigger,
prepend_trigger_to_prompt=bool(prepend_trigger_to_prompt),
extra_positive=extra_positive,
extra_negative=extra_negative,
soft_negative_base=INSTA_OF_SOFT_NEGATIVE,
hard_negative_base=INSTA_OF_NEGATIVE,
options=options,
platform_style=platform_style,
soft_descriptor_sentence=soft_descriptor_sentence,
soft_level=soft_level,
soft_cast=soft_cast,
soft_cast_presence=soft_cast_presence,
soft_cast_styling_sentence=soft_cast_styling_sentence,
soft_row=soft_row,
soft_camera_scene_sentence=soft_camera_scene_sentence,
soft_camera_sentence=soft_camera_sentence,
hard_level=hard_level,
hard_cast=hard_cast,
cast_descriptor_text=cast_descriptor_text,
pov_directive=pov_directive,
pov_character_labels=pov_character_labels,
hard_clothing_sentence=hard_clothing_sentence,
hard_row=hard_row,
hard_scene=hard_scene,
hard_camera_scene_sentence=hard_camera_scene_sentence,
hard_composition=hard_composition,
hard_detail_directive=hard_detail_directive,
hard_camera_sentence=hard_camera_sentence,
descriptor=descriptor,
soft_partner_outfit_text=soft_partner_outfit_text,
soft_partner_styling=soft_partner_styling,
soft_camera_scene_directive=soft_camera_scene_directive,
soft_camera_config=soft_camera_config,
soft_camera_directive=soft_camera_directive,
hard_camera_scene_directive=hard_camera_scene_directive,
hard_camera_config=hard_camera_config,
hard_camera_directive=hard_camera_directive,
camera_caption_text=_camera_caption_text,
cast_descriptors=cast_descriptors,
character_hardcore_clothing_entries=character_hardcore_clothing_entries,
default_man_hardcore_clothing_entries=default_man_hardcore_clothing_entries,
hard_clothing_state=hard_clothing_state,
hard_detail_density=hard_detail_density,
hard_women_count=hard_women_count,
hard_men_count=hard_men_count,
character_slots=character_slots,
character_slot_map=character_slot_map,
)