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

2983 lines
101 KiB
Python

from __future__ import annotations
import random
from pathlib import Path
from typing import Any
try:
from . import builder_config_route as builder_config_route_policy
from . import builder_prompt_route as builder_prompt_route_policy
from .category_library import (
compatible_entries as _compatible_entries,
compatible_entry as _compatible_entry,
find_subcategory as _find_subcategory,
load_category_library,
merged_field as _merged_field,
)
from . import camera_config as camera_policy
from . import cast_context as cast_context_policy
from . import category_extensions as category_extensions_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 krea2_pose_variant_catalog
from . import location_config as location_policy
from . import pair_builder
from . import pair_cast
from . import pair_options
from . import pov_policy
from . import row_normalization as row_policy
from . import row_assembly as row_assembly_policy
from . import row_camera as row_camera_policy
from . import row_category_route as row_category_route_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_prompt_axes as row_prompt_axes_policy
from . import row_pools as row_pool_policy
from . import row_rendering as row_rendering_policy
from . import row_role_graph as row_role_graph_policy
from . import row_route_metadata as row_route_policy
from . import row_subject_route as row_subject_route_policy
from . import seed_config as seed_policy
from . import style_config as style_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,
)
except ImportError: # Allows local smoke tests with `python -c`.
import builder_config_route as builder_config_route_policy
import builder_prompt_route as builder_prompt_route_policy
from category_library import (
compatible_entries as _compatible_entries,
compatible_entry as _compatible_entry,
find_subcategory as _find_subcategory,
load_category_library,
merged_field as _merged_field,
)
import camera_config as camera_policy
import cast_context as cast_context_policy
import category_extensions as category_extensions_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 krea2_pose_variant_catalog
import location_config as location_policy
import pair_builder
import pair_cast
import pair_options
import pov_policy
import row_normalization as row_policy
import row_assembly as row_assembly_policy
import row_camera as row_camera_policy
import row_category_route as row_category_route_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_prompt_axes as row_prompt_axes_policy
import row_pools as row_pool_policy
import row_rendering as row_rendering_policy
import row_role_graph as row_role_graph_policy
import row_route_metadata as row_route_policy
import row_subject_route as row_subject_route_policy
import seed_config as seed_policy
import style_config as style_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,
)
ROOT_DIR = Path(__file__).resolve().parent
PROFILE_DIR = character_profile_policy.PROFILE_DIR
BUILTIN_CATEGORIES = category_extensions_policy.BUILTIN_CATEGORIES
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 = row_rendering_policy.GENERIC_POSITIVE_SUFFIX
SINGLE_TEMPLATE = row_rendering_policy.SINGLE_TEMPLATE
COUPLE_TEMPLATE = row_rendering_policy.COUPLE_TEMPLATE
GROUP_TEMPLATE = row_rendering_policy.GROUP_TEMPLATE
LAYOUT_TEMPLATE = row_rendering_policy.LAYOUT_TEMPLATE
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
SafeFormatDict = row_rendering_policy.SafeFormatDict
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:
category_extensions_policy.unique_extend(target, additions)
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 _action_position_route_metadata(
*,
is_pose_category: bool,
subcategory: dict[str, Any],
hardcore_position_config: dict[str, Any] | None,
item_template_metadata: dict[str, Any] | None,
item_text: Any,
source_role_graph: Any,
source_composition: Any,
pose: Any,
item_axis_values: dict[str, Any] | None = None,
) -> dict[str, Any]:
return row_route_policy.resolve_action_position_route(
is_pose_category=is_pose_category,
subcategory=subcategory,
hardcore_position_config=hardcore_position_config,
item_template_metadata=item_template_metadata,
item_text=item_text,
source_role_graph=source_role_graph,
source_composition=source_composition,
pose=pose,
item_axis_values=item_axis_values,
)
def _action_position_route(
*,
is_pose_category: bool,
subcategory: dict[str, Any],
hardcore_position_config: dict[str, Any] | None,
item_template_metadata: dict[str, Any] | None,
item_text: Any,
source_role_graph: Any,
source_composition: Any,
pose: Any,
item_axis_values: dict[str, Any] | None = None,
) -> row_route_policy.ActionPositionRoute:
return row_route_policy.resolve_action_position_route_result(
is_pose_category=is_pose_category,
subcategory=subcategory,
hardcore_position_config=hardcore_position_config,
item_template_metadata=item_template_metadata,
item_text=item_text,
source_role_graph=source_role_graph,
source_composition=source_composition,
pose=pose,
item_axis_values=item_axis_values,
)
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 _anal_axis_values_for_position(values: list[Any], position: str, axis_name: str) -> list[Any]:
return row_item_policy.anal_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 category_extensions_policy.extension_targets()
def apply_pool_extensions() -> None:
category_extensions_policy.apply_pool_extensions()
def category_choices() -> list[str]:
return category_extensions_policy.category_choices()
def subcategory_choices() -> list[str]:
return category_extensions_policy.subcategory_choices()
def seed_mode_choices() -> list[str]:
return seed_policy.seed_mode_choices()
def seed_reroll_axis_choices() -> list[str]:
return seed_policy.seed_reroll_axis_choices()
def normalize_seed_mode(value: Any) -> str:
return seed_policy.normalize_seed_mode(value)
def normalize_reroll_axis(value: Any) -> str:
return seed_policy.normalize_reroll_axis(value)
CATEGORY_PRESETS = category_cast_policy.CATEGORY_PRESETS
CAST_PRESETS = category_cast_policy.CAST_PRESETS
GENERATION_PROFILE_PRESETS = generation_profile_policy.GENERATION_PROFILE_PRESETS
STYLE_PRESETS = style_policy.STYLE_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 style_pool_preset_choices() -> list[str]:
return style_policy.style_pool_preset_choices()
def style_combine_mode_choices() -> list[str]:
return style_policy.style_combine_mode_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_style_config_json(
enabled: bool = True,
combine_mode: str = "replace",
preset: str = "category_default",
custom_style: str = "",
custom_positive_suffix: str = "",
custom_negative: str = "",
style_config: str | dict[str, Any] | None = "",
) -> str:
return style_policy.build_style_config_json(
enabled=enabled,
combine_mode=combine_mode,
preset=preset,
custom_style=custom_style,
custom_positive_suffix=custom_positive_suffix,
custom_negative=custom_negative,
style_config=style_config,
)
def _parse_style_config(style_config: str | dict[str, Any] | None) -> dict[str, Any]:
return style_policy.parse_style_config(style_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 _axis_values_with_krea2_variant_keys(
axis_values: dict[str, Any],
hardcore_position_config: dict[str, Any],
) -> dict[str, Any]:
variant_keys = hardcore_position_config.get("krea2_variant_keys") if isinstance(hardcore_position_config, dict) else []
if not isinstance(variant_keys, list) or not variant_keys:
return axis_values
merged = dict(axis_values)
merged["krea2_variant_keys"] = [str(key) for key in variant_keys if str(key).strip()]
prompt_variant_indices = hardcore_position_config.get("krea2_prompt_variant_indices")
if isinstance(prompt_variant_indices, dict):
normalized_indices: dict[str, int] = {}
for key, value in prompt_variant_indices.items():
key_text = str(key or "").strip()
if not key_text:
continue
try:
normalized_indices[key_text] = int(value)
except (TypeError, ValueError):
continue
if normalized_indices:
merged["krea2_prompt_variant_indices"] = normalized_indices
return merged
def _axis_values_with_krea2_prompt_variant_indices(
axis_values: dict[str, Any],
*,
seed_config: dict[str, int],
seed: int,
row_number: int,
) -> dict[str, Any]:
variant_keys = axis_values.get("krea2_variant_keys") if isinstance(axis_values, dict) else []
if not isinstance(variant_keys, list) or not variant_keys:
return axis_values
rng = seed_policy.axis_rng(seed_config, "pose", seed, row_number)
existing_indices = axis_values.get("krea2_prompt_variant_indices") if isinstance(axis_values, dict) else {}
indices: dict[str, int] = {}
if isinstance(existing_indices, dict):
for key, value in existing_indices.items():
key_text = str(key or "").strip()
if not key_text:
continue
try:
indices[key_text] = int(value)
except (TypeError, ValueError):
continue
for key in variant_keys:
key_text = str(key)
if key_text in indices:
continue
variant = krea2_pose_variant_catalog.get_variant(str(key))
cue_sets = krea2_pose_variant_catalog.prompt_cue_sets(variant)
if len(cue_sets) > 1:
indices[key_text] = rng.randrange(len(cue_sets))
if not indices:
return axis_values
merged = dict(axis_values)
merged["krea2_prompt_variant_indices"] = indices
return merged
def _axis_values_with_hardcore_route_metadata(
axis_values: dict[str, Any],
*,
action_family: str,
position_family: str,
position_key: str,
position_keys: list[str],
) -> dict[str, Any]:
merged = dict(axis_values)
if action_family:
merged["action_family"] = action_family
if position_family:
merged["position_family"] = position_family
if position_key:
merged["position_key"] = position_key
if position_keys:
merged["position_keys"] = [str(key) for key in position_keys if str(key).strip()]
return merged
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",
clothing_seed: int = -1,
clothing_seed_mode: str = "auto",
) -> str:
return seed_policy.build_seed_config_json(
category_seed=category_seed,
subcategory_seed=subcategory_seed,
content_seed=content_seed,
clothing_seed=clothing_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,
clothing_seed_mode=clothing_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:
return row_category_route_policy.is_pose_content_category(category, subcategory)
def _select_category_item_route(
*,
category_choice: str,
subcategory_choice: str,
seed_config: dict[str, int],
seed: int,
row_number: int,
women_count: int,
men_count: int,
hardcore_position_config: dict[str, Any] | None = None,
categories: list[dict[str, Any]] | None = None,
) -> dict[str, Any]:
return row_category_route_policy.select_category_item_route(
category_choice=category_choice,
subcategory_choice=subcategory_choice,
seed_config=seed_config,
seed=seed,
row_number=row_number,
women_count=women_count,
men_count=men_count,
hardcore_position_config=hardcore_position_config,
categories=categories,
)
def _select_category_item_route_result(
*,
category_choice: str,
subcategory_choice: str,
seed_config: dict[str, int],
seed: int,
row_number: int,
women_count: int,
men_count: int,
hardcore_position_config: dict[str, Any] | None = None,
categories: list[dict[str, Any]] | None = None,
) -> row_category_route_policy.CategoryItemRoute:
return row_category_route_policy.select_category_item_route_result(
category_choice=category_choice,
subcategory_choice=subcategory_choice,
seed_config=seed_config,
seed=seed,
row_number=row_number,
women_count=women_count,
men_count=men_count,
hardcore_position_config=hardcore_position_config,
categories=categories,
)
def _format(template: str, context: dict[str, Any]) -> str:
return row_rendering_policy.format_template(template, context)
def _row_text_fields(
category: dict[str, Any],
subcategory: dict[str, Any],
item: Any,
style_config: str | dict[str, Any] | None = None,
) -> row_rendering_policy.RowTextFields:
return row_rendering_policy.resolve_row_text_fields(category, subcategory, item, style_config)
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 _resolve_expression_route(
*,
expression_enabled: bool,
expression_intensity: float,
expression_intensity_source: str,
subject_type: str,
applied_slot: dict[str, Any] | None = None,
character_slots: list[dict[str, Any]] | None = None,
character_slot_map: dict[str, dict[str, Any]] | None = None,
women_count: int = 1,
men_count: int = 1,
expression_phase: str = "",
) -> row_expression_policy.ExpressionRoute:
return row_expression_policy.resolve_expression_route(
expression_enabled=expression_enabled,
expression_intensity=expression_intensity,
expression_intensity_source=expression_intensity_source,
subject_type=subject_type,
applied_slot=applied_slot,
character_slots=character_slots,
character_slot_map=character_slot_map,
women_count=women_count,
men_count=men_count,
expression_phase=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:
return row_expression_policy.sanitize_character_expression_text_for_action(
expression_text,
role_graph,
item,
axis_values,
)
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 _subject_route(
*,
subject_type: str,
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_profile: str | dict[str, Any] | None = None,
character_cast: str | dict[str, Any] | list[Any] | None = None,
) -> dict[str, Any]:
return row_subject_route_policy.resolve_subject_route(
subject_type=subject_type,
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_profile=character_profile,
character_cast=character_cast,
)
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 _prompt_axes_route(
*,
category: dict[str, Any],
subcategory: dict[str, Any],
item: Any,
subject_type: str,
context: dict[str, Any],
poses: str,
women_count: int,
men_count: int,
scene_rng: random.Random,
pose_rng: random.Random,
expression_rng: random.Random,
composition_rng: random.Random,
expression_disabled: bool,
expression_intensity: float,
character_slots: list[dict[str, Any]] | None = None,
character_slot_map: dict[str, dict[str, Any]] | None = None,
expression_phase: str = "",
source_role_graph: Any = "",
item_axis_values: dict[str, Any] | None = None,
is_pose_category: bool = False,
pov_character_labels: list[str] | None = None,
location_config: dict[str, Any] | None = None,
composition_config: dict[str, Any] | None = None,
) -> dict[str, Any]:
return row_prompt_axes_policy.resolve_prompt_axes(
category=category,
subcategory=subcategory,
item=item,
subject_type=subject_type,
context=context,
poses=poses,
women_count=women_count,
men_count=men_count,
scene_rng=scene_rng,
pose_rng=pose_rng,
expression_rng=expression_rng,
composition_rng=composition_rng,
expression_disabled=expression_disabled,
expression_intensity=expression_intensity,
character_slots=character_slots,
character_slot_map=character_slot_map,
expression_phase=expression_phase,
source_role_graph=source_role_graph,
item_axis_values=item_axis_values,
is_pose_category=is_pose_category,
pov_character_labels=pov_character_labels,
location_config=location_config,
composition_config=composition_config,
)
def _prompt_axes_route_result(
*,
category: dict[str, Any],
subcategory: dict[str, Any],
item: Any,
subject_type: str,
context: dict[str, Any],
poses: str,
women_count: int,
men_count: int,
scene_rng: random.Random,
pose_rng: random.Random,
expression_rng: random.Random,
composition_rng: random.Random,
expression_disabled: bool,
expression_intensity: float,
character_slots: list[dict[str, Any]] | None = None,
character_slot_map: dict[str, dict[str, Any]] | None = None,
expression_phase: str = "",
source_role_graph: Any = "",
item_axis_values: dict[str, Any] | None = None,
is_pose_category: bool = False,
pov_character_labels: list[str] | None = None,
location_config: dict[str, Any] | None = None,
composition_config: dict[str, Any] | None = None,
) -> row_prompt_axes_policy.PromptAxesRoute:
return row_prompt_axes_policy.resolve_prompt_axes_result(
category=category,
subcategory=subcategory,
item=item,
subject_type=subject_type,
context=context,
poses=poses,
women_count=women_count,
men_count=men_count,
scene_rng=scene_rng,
pose_rng=pose_rng,
expression_rng=expression_rng,
composition_rng=composition_rng,
expression_disabled=expression_disabled,
expression_intensity=expression_intensity,
character_slots=character_slots,
character_slot_map=character_slot_map,
expression_phase=expression_phase,
source_role_graph=source_role_graph,
item_axis_values=item_axis_values,
is_pose_category=is_pose_category,
pov_character_labels=pov_character_labels,
location_config=location_config,
composition_config=composition_config,
)
def _role_graph_route(
*,
rng: random.Random,
subcategory: dict[str, Any],
context: dict[str, Any],
item_axis_values: dict[str, Any],
pov_character_labels: list[str],
is_pose_category: bool,
) -> row_role_graph_policy.RoleGraphRoute:
return row_role_graph_policy.resolve_role_graph_route(
rng=rng,
subcategory=subcategory,
context=context,
item_axis_values=item_axis_values,
pov_character_labels=pov_character_labels,
is_pose_category=is_pose_category,
)
def _assemble_custom_row(request: row_assembly_policy.CustomRowAssemblyRequest) -> dict[str, Any]:
return row_assembly_policy.assemble_custom_row(request)
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,
style_config: str | dict[str, Any] | None = None,
) -> dict[str, Any]:
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)
category_route = _select_category_item_route_result(
category_choice=category_choice,
subcategory_choice=subcategory_choice,
seed_config=seed_config,
seed=seed,
row_number=row_number,
women_count=women_count,
men_count=men_count,
hardcore_position_config=parsed_hardcore_position_config,
)
category = category_route.category
subcategory = category_route.subcategory
women_count = category_route.women_count
men_count = category_route.men_count
count_adjustment = dict(category_route.count_adjustment)
content_axis = category_route.content_axis
item = category_route.item
item_text = category_route.item_text
item_name = category_route.item_name
item_axis_values = dict(category_route.item_axis_values)
item_axis_values = _axis_values_with_krea2_variant_keys(
item_axis_values,
parsed_hardcore_position_config,
)
item_axis_values = _axis_values_with_krea2_prompt_variant_indices(
item_axis_values,
seed_config=seed_config,
seed=seed,
row_number=row_number,
)
item_template_metadata = dict(category_route.item_template_metadata)
item_formatter_hints = dict(category_route.formatter_hints)
is_pose_category = category_route.is_pose_category
subject_type = str(_merged_field(category, subcategory, item, "subject_type", "single_any"))
subject_route = _subject_route(
subject_type=subject_type,
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_profile=character_profile,
character_cast=character_cast,
)
context = dict(subject_route["context"])
subject_type = str(subject_route.get("subject_type") or context.get("subject_type") or subject_type)
character_slots = list(subject_route.get("character_slots") or [])
character_slot_map = dict(subject_route.get("character_slot_map") or {})
applied_slot = dict(subject_route.get("applied_slot") or {})
slot_status = str(subject_route.get("character_slot_status") or "none")
applied_profile = dict(subject_route.get("applied_profile") or {})
profile_status = str(subject_route.get("character_profile_status") or "none")
pov_character_labels = list(subject_route.get("pov_character_labels") or [])
cast_descriptors = list(subject_route.get("cast_descriptors") or [])
cast_descriptor_text = str(subject_route.get("cast_descriptor_text") or "")
role_graph_route = _role_graph_route(
rng=role_rng,
subcategory=subcategory,
context=context,
item_axis_values=item_axis_values,
pov_character_labels=pov_character_labels,
is_pose_category=is_pose_category,
)
source_role_graph = role_graph_route.source_role_graph
role_graph = role_graph_route.role_graph
expression_route = _resolve_expression_route(
expression_enabled=expression_enabled,
expression_intensity=expression_intensity,
expression_intensity_source=expression_intensity_source,
subject_type=subject_type,
applied_slot=applied_slot,
character_slots=character_slots,
character_slot_map=character_slot_map,
women_count=women_count,
men_count=men_count,
expression_phase=expression_phase,
)
expression_disabled = expression_route.expression_disabled
expression_intensity = expression_route.expression_intensity
expression_intensity_source = expression_route.expression_intensity_source
prompt_axes = _prompt_axes_route_result(
category=category,
subcategory=subcategory,
item=item,
subject_type=subject_type,
context=context,
poses=poses,
women_count=women_count,
men_count=men_count,
scene_rng=scene_rng,
pose_rng=pose_rng,
expression_rng=expression_rng,
composition_rng=composition_rng,
expression_disabled=expression_disabled,
expression_intensity=expression_intensity,
character_slots=character_slots,
character_slot_map=character_slot_map,
expression_phase=expression_phase,
source_role_graph=source_role_graph,
item_axis_values=item_axis_values,
is_pose_category=is_pose_category,
pov_character_labels=pov_character_labels,
location_config=parsed_location_config,
composition_config=parsed_composition_config,
)
scene_slug = prompt_axes.scene_slug
scene = prompt_axes.scene
scene_entry = dict(prompt_axes.scene_entry)
pose = prompt_axes.pose
expression = prompt_axes.expression
shared_expression = prompt_axes.shared_expression
character_expressions = list(prompt_axes.character_expressions)
character_expression_text = prompt_axes.character_expression_text
source_composition = prompt_axes.source_composition
composition = prompt_axes.composition
composition_entry = dict(prompt_axes.composition_entry)
action_route = _action_position_route(
is_pose_category=is_pose_category,
subcategory=subcategory,
hardcore_position_config=parsed_hardcore_position_config,
item_template_metadata=item_template_metadata,
item_text=item_text,
source_role_graph=source_role_graph,
source_composition=source_composition,
pose=pose,
item_axis_values=item_axis_values,
)
position_family = action_route.position_family
position_keys = list(action_route.position_keys)
position_key = action_route.position_key
action_family = action_route.action_family
item_axis_values = _axis_values_with_hardcore_route_metadata(
item_axis_values,
action_family=action_family,
position_family=position_family,
position_key=position_key,
position_keys=position_keys,
)
text_fields = _row_text_fields(category, subcategory, item, style_config)
assembly_request = row_assembly_policy.CustomRowAssemblyRequest(
row_number=row_number,
start_index=start_index,
category=category,
subcategory=subcategory,
item=item,
context=context,
subject_type=subject_type,
item_text=item_text,
item_name=item_name,
item_axis_values=item_axis_values,
item_template_metadata=item_template_metadata,
formatter_hints=item_formatter_hints,
item_label=text_fields.item_label,
style=text_fields.style,
positive_suffix=text_fields.positive_suffix,
negative_prompt=text_fields.negative_prompt,
scene_slug=scene_slug,
scene=scene,
scene_entry=scene_entry,
pose=pose,
expression=expression,
shared_expression=shared_expression,
character_expressions=character_expressions,
character_expression_text=character_expression_text,
expression_disabled=expression_disabled,
expression_intensity=expression_intensity,
expression_intensity_source=expression_intensity_source,
composition=composition,
source_composition=source_composition,
composition_entry=composition_entry,
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,
cast_descriptors=cast_descriptors,
cast_descriptor_text=cast_descriptor_text,
seed_config=seed_config,
hardcore_position_config=(
parsed_hardcore_position_config
if _hardcore_position_config_active(parsed_hardcore_position_config)
else {}
),
location_config=parsed_location_config if _location_config_active(parsed_location_config) else {},
composition_config=parsed_composition_config if _composition_config_active(parsed_composition_config) else {},
content_seed_axis=content_axis,
count_adjustment=count_adjustment,
applied_profile=applied_profile,
profile_status=profile_status,
applied_slot=applied_slot,
slot_status=slot_status,
character_slots=character_slots,
)
return _assemble_custom_row(assembly_request)
def _prompt_build_dependencies() -> builder_prompt_route_policy.PromptBuildDependencies:
return builder_prompt_route_policy.PromptBuildDependencies(
default_trigger=g.TRIGGER,
default_negative=g.NEGATIVE_PROMPT,
random_subcategory=RANDOM_SUBCATEGORY,
apply_pool_extensions=apply_pool_extensions,
normalize_ethnicity_filter=normalize_ethnicity_filter,
is_false=_is_false,
ratio_or_none=_ratio_or_none,
parse_seed_config=_parse_seed_config,
parse_location_config=_parse_location_config,
parse_composition_config=_parse_composition_config,
axis_rng=_axis_rng,
pick_clothing_mode=_pick_clothing_mode,
pick_pose_mode=_pick_pose_mode,
pick_figure_bias=_pick_figure_bias,
pick_expression_intensity=_pick_expression_intensity,
auto_full_choice=_auto_full_choice,
build_auto_weighted_row=_build_auto_weighted_row,
build_direct_builtin_row=_build_direct_builtin_row,
build_custom_row=_build_custom_row,
apply_location_config_to_legacy_row=row_location_policy.apply_location_config_to_legacy_row,
apply_composition_config_to_legacy_row=row_location_policy.apply_composition_config_to_legacy_row,
disable_row_expression=_disable_row_expression,
apply_camera_config=_apply_camera_config,
normalize_prompt_row=row_policy.normalize_prompt_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,
style_config: str | dict[str, Any] | None = None,
) -> dict[str, Any]:
return builder_prompt_route_policy.build_prompt(
builder_prompt_route_policy.PromptBuildRequest(
category=category,
subcategory=subcategory,
row_number=row_number,
start_index=start_index,
seed=seed,
clothing=clothing,
ethnicity=ethnicity,
poses=poses,
backside_bias=backside_bias,
figure=figure,
no_plus_women=no_plus_women,
no_black=no_black,
minimal_clothing_ratio=minimal_clothing_ratio,
standard_pose_ratio=standard_pose_ratio,
trigger=trigger,
prepend_trigger_to_prompt=prepend_trigger_to_prompt,
extra_positive=extra_positive,
extra_negative=extra_negative,
seed_config=seed_config,
women_count=women_count,
men_count=men_count,
camera_config=camera_config,
expression_intensity=expression_intensity,
character_profile=character_profile,
character_cast=character_cast,
expression_enabled=expression_enabled,
expression_phase=expression_phase,
hardcore_position_config=hardcore_position_config,
location_config=location_config,
composition_config=composition_config,
style_config=style_config,
),
_prompt_build_dependencies(),
)
def _prompt_from_configs_dependencies() -> builder_config_route_policy.PromptFromConfigsDependencies:
return builder_config_route_policy.PromptFromConfigsDependencies(
parse_category_config=_parse_category_config,
parse_cast_config=_parse_cast_config,
parse_generation_profile=_parse_generation_profile,
parse_filter_config=_parse_filter_config,
build_prompt=build_prompt,
)
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 = "",
style_config: str | dict[str, Any] | None = "",
extra_positive: str = "",
extra_negative: str = "",
) -> dict[str, Any]:
return builder_config_route_policy.build_prompt_from_configs(
builder_config_route_policy.PromptFromConfigsRequest(
row_number=row_number,
start_index=start_index,
seed=seed,
category_config=category_config,
cast_config=cast_config,
generation_profile=generation_profile,
filter_config=filter_config,
seed_config=seed_config,
camera_config=camera_config,
character_profile=character_profile,
character_cast=character_cast,
hardcore_position_config=hardcore_position_config,
location_config=location_config,
composition_config=composition_config,
style_config=style_config,
extra_positive=extra_positive,
extra_negative=extra_negative,
),
_prompt_from_configs_dependencies(),
)
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 _insta_pair_build_dependencies() -> pair_builder.InstaPairBuildDependencies:
return pair_builder.InstaPairBuildDependencies(
default_trigger=g.TRIGGER,
random_subcategory=RANDOM_SUBCATEGORY,
soft_negative_base=INSTA_OF_SOFT_NEGATIVE,
hard_negative_base=INSTA_OF_NEGATIVE,
camera_detail_choices=CAMERA_DETAIL_CHOICES,
hardcore_clothing_continuity=INSTA_OF_HARDCORE_CLOTHING_CONTINUITY,
platform_styles=INSTA_OF_PLATFORM_STYLES,
soft_levels=INSTA_OF_SOFT_LEVELS,
hardcore_levels=INSTA_OF_HARDCORE_LEVELS,
parse_options=_parse_insta_of_options,
parse_filter_config=_parse_filter_config,
parse_seed_config=_parse_seed_config,
parse_character_cast=_parse_character_cast,
character_slot_label_map=_character_slot_label_map,
pov_character_labels=_pov_character_labels,
softcore_category=_insta_of_softcore_category,
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,
hardcore_counts=_insta_of_hardcore_counts,
character_context_for_label=_character_context_for_label,
slot_is_pov=_slot_is_pov,
choose=g.choose,
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,
slot_hardcore_clothing=_slot_hardcore_clothing,
hardcore_detail_directive=pair_options.hardcore_detail_directive,
camera_caption_text=_camera_caption_text,
)
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,
softcore_seed_config: str | dict[str, Any] | None = None,
hardcore_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 = "",
style_config: str | dict[str, Any] | None = "",
extra_positive: str = "",
extra_negative: str = "",
) -> dict[str, Any]:
request = pair_builder.InstaPairBuildRequest(
row_number=row_number,
start_index=start_index,
seed=seed,
ethnicity=ethnicity,
figure=figure,
no_plus_women=no_plus_women,
no_black=no_black,
trigger=trigger,
prepend_trigger_to_prompt=prepend_trigger_to_prompt,
seed_config=seed_config,
softcore_seed_config=softcore_seed_config,
hardcore_seed_config=hardcore_seed_config,
options_json=options_json,
filter_config=filter_config,
camera_config=camera_config,
softcore_camera_config=softcore_camera_config,
hardcore_camera_config=hardcore_camera_config,
character_profile=character_profile,
character_cast=character_cast,
hardcore_position_config=hardcore_position_config,
location_config=location_config,
composition_config=composition_config,
style_config=style_config,
extra_positive=extra_positive,
extra_negative=extra_negative,
)
return pair_builder.build_insta_of_pair(request, _insta_pair_build_dependencies())