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())
