Extract Insta pair builder orchestration
This commit is contained in:
@@ -275,13 +275,13 @@ Already isolated:
|
|||||||
|
|
||||||
### Pair / Adapter Layer
|
### Pair / Adapter Layer
|
||||||
|
|
||||||
Owner today: `build_insta_of_pair`.
|
Owner today: `pair_builder.py`; `prompt_builder.build_insta_of_pair` is the
|
||||||
|
public wrapper used by the node layer.
|
||||||
|
|
||||||
Keep here:
|
Keep here:
|
||||||
|
|
||||||
- pair route sequencing;
|
- the public wrapper signature and dependency bridge needed by existing nodes
|
||||||
- top-level continuity option handoff between row, camera, clothing, and output
|
and tests.
|
||||||
adapters.
|
|
||||||
|
|
||||||
Already isolated:
|
Already isolated:
|
||||||
|
|
||||||
@@ -290,6 +290,10 @@ Already isolated:
|
|||||||
policy, plus hardcore detail-density directive text, live in
|
policy, plus hardcore detail-density directive text, live in
|
||||||
`pair_options.py`; `prompt_builder.py` keeps public delegate wrappers for
|
`pair_options.py`; `prompt_builder.py` keeps public delegate wrappers for
|
||||||
existing nodes and tests.
|
existing nodes and tests.
|
||||||
|
- pair route sequencing now lives in `pair_builder.py` behind
|
||||||
|
`InstaPairBuildRequest` and `InstaPairBuildDependencies`, covering
|
||||||
|
option/filter/seed/cast parsing handoff, soft/hard row orchestration, cast
|
||||||
|
context, camera route, clothing route, and final output assembly delegation.
|
||||||
- soft/hard row creation lives in `pair_rows.py` behind `InstaPairRowsRoute`,
|
- soft/hard row creation lives in `pair_rows.py` behind `InstaPairRowsRoute`,
|
||||||
including softcore expression override resolution, Woman A slot context
|
including softcore expression override resolution, Woman A slot context
|
||||||
application, soft outfit/pose overrides, POV row fields, hardcore row
|
application, soft outfit/pose overrides, POV row fields, hardcore row
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ Core helper ownership:
|
|||||||
| `row_prompt_axes.py` | Row scene/pose/expression/composition axis selection behind `PromptAxesRoute`, compatible-entry filtering, expression-disabled handling, per-character expression promotion, legacy dict compatibility, POV composition adaptation, and pose-category environment sanitizing. |
|
| `row_prompt_axes.py` | Row scene/pose/expression/composition axis selection behind `PromptAxesRoute`, compatible-entry filtering, expression-disabled handling, per-character expression promotion, legacy dict compatibility, POV composition adaptation, and pose-category environment sanitizing. |
|
||||||
| `hardcore_position_config.py` | Hardcore position/action-filter choices, selected-position normalization, config JSON builders/parsers, focus-policy toggles, subcategory allow-list policy, position-key detection, and category/template/axis filtering. |
|
| `hardcore_position_config.py` | Hardcore position/action-filter choices, selected-position normalization, config JSON builders/parsers, focus-policy toggles, subcategory allow-list policy, position-key detection, and category/template/axis filtering. |
|
||||||
| `pair_options.py` | Insta/OF option schema/defaults, softcore category/outfit/pose pools, partner outfit pools, clothing-continuity labels, negatives, hardcore cast count policy, and hardcore detail-density directives. |
|
| `pair_options.py` | Insta/OF option schema/defaults, softcore category/outfit/pose pools, partner outfit pools, clothing-continuity labels, negatives, hardcore cast count policy, and hardcore detail-density directives. |
|
||||||
|
| `pair_builder.py` | Insta/OF pair route sequencing behind `InstaPairBuildRequest` and `InstaPairBuildDependencies`, including option/filter/seed/cast parsing handoff, soft/hard row, cast, camera, clothing, and final output adapter orchestration. |
|
||||||
| `pair_rows.py` | Insta/OF soft/hard row creation behind `InstaPairRowsRoute`, softcore expression override resolution, Woman A slot context application, soft outfit/pose overrides, POV row fields, and legacy dict compatibility. |
|
| `pair_rows.py` | Insta/OF soft/hard row creation behind `InstaPairRowsRoute`, softcore expression override resolution, Woman A slot context application, soft outfit/pose overrides, POV row fields, and legacy dict compatibility. |
|
||||||
| `pair_cast.py` | Insta/OF descriptor prose, descriptor-entry assembly, shared descriptors, cast-label cleanup, same-cast softcore descriptor text, partner styling selection, cast-summary wording, platform/level labels, softcore cast presence text, and hard cast summary text. |
|
| `pair_cast.py` | Insta/OF descriptor prose, descriptor-entry assembly, shared descriptors, cast-label cleanup, same-cast softcore descriptor text, partner styling selection, cast-summary wording, platform/level labels, softcore cast presence text, and hard cast summary text. |
|
||||||
| `pair_camera.py` | Insta/OF soft/hard camera route resolution behind `InstaPairCameraRoute`, same-as-softcore camera mode, camera-detail override, camera-aware composition mutation, POV camera suppression, synchronized row/root camera metadata, and legacy dict compatibility. |
|
| `pair_camera.py` | Insta/OF soft/hard camera route resolution behind `InstaPairCameraRoute`, same-as-softcore camera mode, camera-detail override, camera-aware composition mutation, POV camera suppression, synchronized row/root camera metadata, and legacy dict compatibility. |
|
||||||
@@ -420,13 +421,14 @@ Edit targets:
|
|||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart TD
|
flowchart TD
|
||||||
O[SxCP Insta/OF Options] --> P[build_insta_of_pair]
|
O[SxCP Insta/OF Options] --> P[prompt_builder wrapper]
|
||||||
C[character_cast] --> P
|
C[character_cast] --> P
|
||||||
S[seed_config] --> P
|
S[seed_config] --> P
|
||||||
L[location_config] --> P
|
L[location_config] --> P
|
||||||
M[composition_config] --> P
|
M[composition_config] --> P
|
||||||
H[hardcore_position_config] --> P
|
H[hardcore_position_config] --> P
|
||||||
P --> R[pair_rows.py]
|
P --> Q[pair_builder.py]
|
||||||
|
Q --> R[pair_rows.py]
|
||||||
R --> A[soft_row via build_prompt]
|
R --> A[soft_row via build_prompt]
|
||||||
R --> B[hard_row via build_prompt]
|
R --> B[hard_row via build_prompt]
|
||||||
A --> D[pair_cast.py]
|
A --> D[pair_cast.py]
|
||||||
|
|||||||
+288
@@ -0,0 +1,288 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Any, Callable
|
||||||
|
|
||||||
|
try:
|
||||||
|
from . import pair_camera
|
||||||
|
from . import pair_cast
|
||||||
|
from . import pair_clothing
|
||||||
|
from . import pair_output
|
||||||
|
from . import pair_rows
|
||||||
|
except ImportError: # Allows local smoke tests with top-level imports.
|
||||||
|
import pair_camera
|
||||||
|
import pair_cast
|
||||||
|
import pair_clothing
|
||||||
|
import pair_output
|
||||||
|
import pair_rows
|
||||||
|
|
||||||
|
|
||||||
|
BuildPrompt = Callable[..., dict[str, Any]]
|
||||||
|
AxisRng = Callable[[dict[str, int], str, int, int], Any]
|
||||||
|
Choose = Callable[[Any, list[str]], str]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class InstaPairBuildRequest:
|
||||||
|
row_number: int
|
||||||
|
start_index: int
|
||||||
|
seed: int
|
||||||
|
ethnicity: str
|
||||||
|
figure: str
|
||||||
|
no_plus_women: bool
|
||||||
|
no_black: bool
|
||||||
|
trigger: str
|
||||||
|
prepend_trigger_to_prompt: bool
|
||||||
|
seed_config: str | dict[str, Any] | None = None
|
||||||
|
options_json: str | dict[str, Any] | None = None
|
||||||
|
filter_config: str | dict[str, Any] | None = None
|
||||||
|
camera_config: str | dict[str, Any] | None = None
|
||||||
|
softcore_camera_config: str | dict[str, Any] | None = None
|
||||||
|
hardcore_camera_config: str | dict[str, Any] | None = None
|
||||||
|
character_profile: str | dict[str, Any] | None = ""
|
||||||
|
character_cast: str | dict[str, Any] | list[Any] | None = ""
|
||||||
|
hardcore_position_config: str | dict[str, Any] | None = ""
|
||||||
|
location_config: str | dict[str, Any] | None = ""
|
||||||
|
composition_config: str | dict[str, Any] | None = ""
|
||||||
|
extra_positive: str = ""
|
||||||
|
extra_negative: str = ""
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class InstaPairBuildDependencies:
|
||||||
|
default_trigger: str
|
||||||
|
random_subcategory: str
|
||||||
|
soft_negative_base: str
|
||||||
|
hard_negative_base: str
|
||||||
|
camera_detail_choices: list[str] | tuple[str, ...]
|
||||||
|
hardcore_clothing_continuity: dict[str, str]
|
||||||
|
platform_styles: dict[str, str]
|
||||||
|
soft_levels: dict[str, str]
|
||||||
|
hardcore_levels: dict[str, str]
|
||||||
|
parse_options: Callable[[str | dict[str, Any] | None], dict[str, Any]]
|
||||||
|
parse_filter_config: Callable[[str | dict[str, Any] | None], dict[str, Any]]
|
||||||
|
parse_seed_config: Callable[[str | dict[str, Any] | None], dict[str, int]]
|
||||||
|
parse_character_cast: Callable[[str | dict[str, Any] | list[Any] | None], list[dict[str, Any]]]
|
||||||
|
character_slot_label_map: Callable[[list[dict[str, Any]]], dict[str, dict[str, Any]]]
|
||||||
|
pov_character_labels: Callable[[dict[str, dict[str, Any]], int], list[str]]
|
||||||
|
softcore_category: Callable[[str], tuple[str, str]]
|
||||||
|
build_prompt: BuildPrompt
|
||||||
|
axis_rng: AxisRng
|
||||||
|
cast_expression_intensity_override: Callable[
|
||||||
|
[float, dict[str, dict[str, Any]], int, int, str],
|
||||||
|
tuple[float | None, str],
|
||||||
|
]
|
||||||
|
context_from_character_slot: Callable[[Any, dict[str, Any], str, str, str, bool, bool], dict[str, Any]]
|
||||||
|
apply_character_context_to_row: Callable[[dict[str, Any], dict[str, Any]], dict[str, Any]]
|
||||||
|
disable_row_expression: Callable[[dict[str, Any], str], dict[str, Any]]
|
||||||
|
slot_softcore_outfit: Callable[[dict[str, Any] | None, Any], str]
|
||||||
|
softcore_outfit: Callable[[Any, str], str]
|
||||||
|
softcore_pose: Callable[[Any, str], str]
|
||||||
|
softcore_item_prompt_label: Callable[[str], str]
|
||||||
|
pov_prompt_directive: Callable[[list[str]], str]
|
||||||
|
pov_composition_prompt: Callable[[Any, list[str]], str]
|
||||||
|
hardcore_counts: Callable[[dict[str, Any]], tuple[int, int]]
|
||||||
|
character_context_for_label: Callable[
|
||||||
|
[str, dict[str, dict[str, Any]], Any, str, str, bool, bool],
|
||||||
|
tuple[dict[str, Any], dict[str, Any] | None],
|
||||||
|
]
|
||||||
|
slot_is_pov: Callable[[dict[str, Any] | None], bool]
|
||||||
|
choose: Choose
|
||||||
|
camera_config_with_mode: Callable[[str | dict[str, Any] | None, str], dict[str, Any]]
|
||||||
|
camera_directive: Callable[[str | dict[str, Any] | None], tuple[str, dict[str, Any]]]
|
||||||
|
apply_contextual_composition: Callable[[dict[str, Any], str], dict[str, Any]]
|
||||||
|
contextual_composition_prompt: Callable[[Any, Any, str], str]
|
||||||
|
composition_prompt: Callable[[Any], str]
|
||||||
|
camera_scene_directive_for_context: Callable[
|
||||||
|
[Any, Any, str | dict[str, Any] | None, list[str] | None, str],
|
||||||
|
tuple[str, dict[str, Any]],
|
||||||
|
]
|
||||||
|
slot_hardcore_clothing: Callable[[dict[str, Any] | None, Any], str]
|
||||||
|
hardcore_detail_directive: Callable[[Any], str]
|
||||||
|
camera_caption_text: Callable[[dict[str, Any]], str]
|
||||||
|
|
||||||
|
|
||||||
|
def build_insta_of_pair(request: InstaPairBuildRequest, deps: InstaPairBuildDependencies) -> dict[str, Any]:
|
||||||
|
options = deps.parse_options(request.options_json)
|
||||||
|
ethnicity = request.ethnicity
|
||||||
|
figure = request.figure
|
||||||
|
no_plus_women = request.no_plus_women
|
||||||
|
no_black = request.no_black
|
||||||
|
if request.filter_config:
|
||||||
|
filters = deps.parse_filter_config(request.filter_config)
|
||||||
|
ethnicity = filters["ethnicity"]
|
||||||
|
figure = filters["figure"]
|
||||||
|
no_plus_women = filters["no_plus_women"]
|
||||||
|
no_black = filters["no_black"]
|
||||||
|
|
||||||
|
hard_women_count, hard_men_count = deps.hardcore_counts(options)
|
||||||
|
active_trigger = request.trigger.strip() or deps.default_trigger
|
||||||
|
parsed_seed_config = deps.parse_seed_config(request.seed_config)
|
||||||
|
character_slots = deps.parse_character_cast(request.character_cast)
|
||||||
|
character_slot_map = deps.character_slot_label_map(character_slots)
|
||||||
|
pov_character_labels = deps.pov_character_labels(character_slot_map, hard_men_count)
|
||||||
|
softcore_level_key = str(options["softcore_level"])
|
||||||
|
soft_category, soft_subcategory = deps.softcore_category(softcore_level_key)
|
||||||
|
|
||||||
|
row_route = pair_rows.build_insta_pair_rows_result(
|
||||||
|
row_number=request.row_number,
|
||||||
|
start_index=request.start_index,
|
||||||
|
seed=request.seed,
|
||||||
|
active_trigger=active_trigger,
|
||||||
|
parsed_seed_config=parsed_seed_config,
|
||||||
|
options=options,
|
||||||
|
ethnicity=ethnicity,
|
||||||
|
figure=figure,
|
||||||
|
no_plus_women=no_plus_women,
|
||||||
|
no_black=no_black,
|
||||||
|
character_profile=request.character_profile,
|
||||||
|
character_cast=request.character_cast or "",
|
||||||
|
character_slot_map=character_slot_map,
|
||||||
|
pov_character_labels=pov_character_labels,
|
||||||
|
hard_women_count=hard_women_count,
|
||||||
|
hard_men_count=hard_men_count,
|
||||||
|
soft_category=soft_category,
|
||||||
|
soft_subcategory=soft_subcategory,
|
||||||
|
softcore_level_key=softcore_level_key,
|
||||||
|
hardcore_random_subcategory=deps.random_subcategory,
|
||||||
|
hardcore_position_config=request.hardcore_position_config,
|
||||||
|
location_config=request.location_config or "",
|
||||||
|
composition_config=request.composition_config or "",
|
||||||
|
build_prompt=deps.build_prompt,
|
||||||
|
axis_rng=deps.axis_rng,
|
||||||
|
cast_expression_intensity_override=deps.cast_expression_intensity_override,
|
||||||
|
context_from_character_slot=deps.context_from_character_slot,
|
||||||
|
apply_character_context_to_row=deps.apply_character_context_to_row,
|
||||||
|
disable_row_expression=deps.disable_row_expression,
|
||||||
|
slot_softcore_outfit=deps.slot_softcore_outfit,
|
||||||
|
softcore_outfit=deps.softcore_outfit,
|
||||||
|
softcore_pose=deps.softcore_pose,
|
||||||
|
softcore_item_prompt_label=deps.softcore_item_prompt_label,
|
||||||
|
pov_prompt_directive=deps.pov_prompt_directive,
|
||||||
|
pov_composition_prompt=deps.pov_composition_prompt,
|
||||||
|
)
|
||||||
|
soft_row = row_route.soft_row
|
||||||
|
hard_row = row_route.hard_row
|
||||||
|
hard_content_rng = row_route.hard_content_rng
|
||||||
|
|
||||||
|
cast_context = pair_cast.resolve_insta_pair_cast_context(
|
||||||
|
soft_row=soft_row,
|
||||||
|
options=options,
|
||||||
|
parsed_seed_config=parsed_seed_config,
|
||||||
|
seed=request.seed,
|
||||||
|
row_number=request.row_number,
|
||||||
|
ethnicity=ethnicity,
|
||||||
|
figure=figure,
|
||||||
|
no_plus_women=no_plus_women,
|
||||||
|
no_black=no_black,
|
||||||
|
hard_women_count=hard_women_count,
|
||||||
|
hard_men_count=hard_men_count,
|
||||||
|
character_slots=character_slots,
|
||||||
|
character_slot_map=character_slot_map,
|
||||||
|
pov_character_labels=pov_character_labels,
|
||||||
|
platform_styles=deps.platform_styles,
|
||||||
|
soft_levels=deps.soft_levels,
|
||||||
|
hardcore_levels=deps.hardcore_levels,
|
||||||
|
axis_rng=deps.axis_rng,
|
||||||
|
character_context_for_label=deps.character_context_for_label,
|
||||||
|
slot_is_pov=deps.slot_is_pov,
|
||||||
|
choose=deps.choose,
|
||||||
|
slot_softcore_outfit=deps.slot_softcore_outfit,
|
||||||
|
)
|
||||||
|
|
||||||
|
camera_route = pair_camera.resolve_insta_pair_camera_result(
|
||||||
|
soft_row=soft_row,
|
||||||
|
hard_row=hard_row,
|
||||||
|
options=options,
|
||||||
|
camera_config=request.camera_config,
|
||||||
|
softcore_camera_config=request.softcore_camera_config,
|
||||||
|
hardcore_camera_config=request.hardcore_camera_config,
|
||||||
|
hard_women_count=hard_women_count,
|
||||||
|
hard_men_count=hard_men_count,
|
||||||
|
pov_character_labels=pov_character_labels,
|
||||||
|
camera_detail_choices=deps.camera_detail_choices,
|
||||||
|
camera_config_with_mode=deps.camera_config_with_mode,
|
||||||
|
camera_directive=deps.camera_directive,
|
||||||
|
apply_contextual_composition=deps.apply_contextual_composition,
|
||||||
|
contextual_composition_prompt=deps.contextual_composition_prompt,
|
||||||
|
composition_prompt=deps.composition_prompt,
|
||||||
|
camera_scene_directive_for_context=deps.camera_scene_directive_for_context,
|
||||||
|
)
|
||||||
|
soft_row = camera_route.soft_row
|
||||||
|
hard_row = camera_route.hard_row
|
||||||
|
hard_scene = camera_route.hard_scene
|
||||||
|
|
||||||
|
character_hardcore_clothing_entries = pair_clothing.character_hardcore_clothing_entries(
|
||||||
|
character_slot_map,
|
||||||
|
hard_women_count,
|
||||||
|
hard_men_count,
|
||||||
|
pov_character_labels,
|
||||||
|
hard_content_rng,
|
||||||
|
deps.slot_hardcore_clothing,
|
||||||
|
)
|
||||||
|
clothing_route = pair_clothing.resolve_hardcore_pair_clothing_result(
|
||||||
|
hard_row=hard_row,
|
||||||
|
mode=options["hardcore_clothing_continuity"],
|
||||||
|
softcore_outfit=soft_row["item"],
|
||||||
|
character_hardcore_clothing_entries=character_hardcore_clothing_entries,
|
||||||
|
men_count=hard_men_count,
|
||||||
|
pov_labels=pov_character_labels,
|
||||||
|
rng=hard_content_rng,
|
||||||
|
continuity_map=deps.hardcore_clothing_continuity,
|
||||||
|
choose=deps.choose,
|
||||||
|
)
|
||||||
|
if clothing_route.requires_body_exposure_scene:
|
||||||
|
hard_scene = pair_clothing.body_exposure_scene_text(hard_scene)
|
||||||
|
hard_row["source_scene_text"] = hard_row.get("source_scene_text") or hard_row.get("scene_text", "")
|
||||||
|
hard_row["scene_text"] = hard_scene
|
||||||
|
|
||||||
|
hard_detail_density = options["hardcore_detail_density"]
|
||||||
|
return pair_output.assemble_insta_pair_metadata(
|
||||||
|
active_trigger=active_trigger,
|
||||||
|
prepend_trigger_to_prompt=bool(request.prepend_trigger_to_prompt),
|
||||||
|
extra_positive=request.extra_positive,
|
||||||
|
extra_negative=request.extra_negative,
|
||||||
|
soft_negative_base=deps.soft_negative_base,
|
||||||
|
hard_negative_base=deps.hard_negative_base,
|
||||||
|
options=options,
|
||||||
|
platform_style=cast_context["platform_style"],
|
||||||
|
soft_descriptor_sentence=cast_context["soft_descriptor_sentence"],
|
||||||
|
soft_level=cast_context["soft_level"],
|
||||||
|
soft_cast=cast_context["soft_cast"],
|
||||||
|
soft_cast_presence=cast_context["soft_cast_presence"],
|
||||||
|
soft_cast_styling_sentence=cast_context["soft_cast_styling_sentence"],
|
||||||
|
soft_row=soft_row,
|
||||||
|
soft_camera_scene_sentence=camera_route.soft_camera_scene_sentence,
|
||||||
|
soft_camera_sentence=camera_route.soft_camera_sentence,
|
||||||
|
hard_level=cast_context["hard_level"],
|
||||||
|
hard_cast=cast_context["hard_cast"],
|
||||||
|
cast_descriptor_text=cast_context["cast_descriptor_text"],
|
||||||
|
pov_directive=deps.pov_prompt_directive(pov_character_labels),
|
||||||
|
pov_character_labels=pov_character_labels,
|
||||||
|
hard_clothing_sentence=clothing_route.hardcore_clothing_sentence,
|
||||||
|
hard_row=hard_row,
|
||||||
|
hard_scene=hard_scene,
|
||||||
|
hard_camera_scene_sentence=camera_route.hard_camera_scene_sentence,
|
||||||
|
hard_composition=camera_route.hard_composition,
|
||||||
|
hard_detail_directive=deps.hardcore_detail_directive(hard_detail_density),
|
||||||
|
hard_camera_sentence=camera_route.hard_camera_sentence,
|
||||||
|
descriptor=cast_context["descriptor"],
|
||||||
|
soft_partner_outfit_text=cast_context["soft_partner_outfit_text"],
|
||||||
|
soft_partner_styling=cast_context["soft_partner_styling"],
|
||||||
|
soft_camera_scene_directive=camera_route.soft_camera_scene_directive,
|
||||||
|
soft_camera_config=camera_route.soft_camera_config,
|
||||||
|
soft_camera_directive=camera_route.soft_camera_directive,
|
||||||
|
hard_camera_scene_directive=camera_route.hard_camera_scene_directive,
|
||||||
|
hard_camera_config=camera_route.hard_camera_config,
|
||||||
|
hard_camera_directive=camera_route.hard_camera_directive,
|
||||||
|
camera_caption_text=deps.camera_caption_text,
|
||||||
|
cast_descriptors=cast_context["cast_descriptors"],
|
||||||
|
character_hardcore_clothing_entries=character_hardcore_clothing_entries,
|
||||||
|
default_man_hardcore_clothing_entries=clothing_route.default_man_hardcore_clothing,
|
||||||
|
hard_clothing_state=clothing_route.hardcore_clothing_state,
|
||||||
|
hard_detail_density=hard_detail_density,
|
||||||
|
hard_women_count=hard_women_count,
|
||||||
|
hard_men_count=hard_men_count,
|
||||||
|
character_slots=character_slots,
|
||||||
|
character_slot_map=character_slot_map,
|
||||||
|
)
|
||||||
+60
-199
@@ -26,11 +26,8 @@ try:
|
|||||||
from . import generation_profile_config as generation_profile_policy
|
from . import generation_profile_config as generation_profile_policy
|
||||||
from . import hardcore_position_config as hardcore_position_policy
|
from . import hardcore_position_config as hardcore_position_policy
|
||||||
from . import location_config as location_policy
|
from . import location_config as location_policy
|
||||||
from . import pair_clothing
|
from . import pair_builder
|
||||||
from . import pair_camera
|
|
||||||
from . import pair_cast
|
from . import pair_cast
|
||||||
from . import pair_output
|
|
||||||
from . import pair_rows
|
|
||||||
from . import pair_options
|
from . import pair_options
|
||||||
from . import pov_policy
|
from . import pov_policy
|
||||||
from . import row_normalization as row_policy
|
from . import row_normalization as row_policy
|
||||||
@@ -75,11 +72,8 @@ except ImportError: # Allows local smoke tests with `python -c`.
|
|||||||
import generation_profile_config as generation_profile_policy
|
import generation_profile_config as generation_profile_policy
|
||||||
import hardcore_position_config as hardcore_position_policy
|
import hardcore_position_config as hardcore_position_policy
|
||||||
import location_config as location_policy
|
import location_config as location_policy
|
||||||
import pair_clothing
|
import pair_builder
|
||||||
import pair_camera
|
|
||||||
import pair_cast
|
import pair_cast
|
||||||
import pair_output
|
|
||||||
import pair_rows
|
|
||||||
import pair_options
|
import pair_options
|
||||||
import pov_policy
|
import pov_policy
|
||||||
import row_normalization as row_policy
|
import row_normalization as row_policy
|
||||||
@@ -2773,6 +2767,52 @@ def _insta_of_softcore_pose(rng: random.Random, level: str) -> str:
|
|||||||
return g.choose(rng, pair_options.softcore_pose_pool(level))
|
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(
|
def build_insta_of_pair(
|
||||||
row_number: int,
|
row_number: int,
|
||||||
start_index: int,
|
start_index: int,
|
||||||
@@ -2797,207 +2837,28 @@ def build_insta_of_pair(
|
|||||||
extra_positive: str = "",
|
extra_positive: str = "",
|
||||||
extra_negative: str = "",
|
extra_negative: str = "",
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
options = _parse_insta_of_options(options_json)
|
request = pair_builder.InstaPairBuildRequest(
|
||||||
if filter_config:
|
|
||||||
filters = _parse_filter_config(filter_config)
|
|
||||||
ethnicity = filters["ethnicity"]
|
|
||||||
figure = filters["figure"]
|
|
||||||
no_plus_women = filters["no_plus_women"]
|
|
||||||
no_black = filters["no_black"]
|
|
||||||
hard_women_count, hard_men_count = _insta_of_hardcore_counts(options)
|
|
||||||
active_trigger = trigger.strip() or g.TRIGGER
|
|
||||||
parsed_seed_config = _parse_seed_config(seed_config)
|
|
||||||
character_slots = _parse_character_cast(character_cast)
|
|
||||||
character_slot_map = _character_slot_label_map(character_slots)
|
|
||||||
pov_character_labels = _pov_character_labels(character_slot_map, hard_men_count)
|
|
||||||
softcore_level_key = str(options["softcore_level"])
|
|
||||||
soft_category, soft_subcategory = _insta_of_softcore_category(softcore_level_key)
|
|
||||||
row_route = pair_rows.build_insta_pair_rows_result(
|
|
||||||
row_number=row_number,
|
row_number=row_number,
|
||||||
start_index=start_index,
|
start_index=start_index,
|
||||||
seed=seed,
|
seed=seed,
|
||||||
active_trigger=active_trigger,
|
|
||||||
parsed_seed_config=parsed_seed_config,
|
|
||||||
options=options,
|
|
||||||
ethnicity=ethnicity,
|
ethnicity=ethnicity,
|
||||||
figure=figure,
|
figure=figure,
|
||||||
no_plus_women=no_plus_women,
|
no_plus_women=no_plus_women,
|
||||||
no_black=no_black,
|
no_black=no_black,
|
||||||
character_profile=character_profile,
|
trigger=trigger,
|
||||||
character_cast=character_cast or "",
|
prepend_trigger_to_prompt=prepend_trigger_to_prompt,
|
||||||
character_slot_map=character_slot_map,
|
seed_config=seed_config,
|
||||||
pov_character_labels=pov_character_labels,
|
options_json=options_json,
|
||||||
hard_women_count=hard_women_count,
|
filter_config=filter_config,
|
||||||
hard_men_count=hard_men_count,
|
|
||||||
soft_category=soft_category,
|
|
||||||
soft_subcategory=soft_subcategory,
|
|
||||||
softcore_level_key=softcore_level_key,
|
|
||||||
hardcore_random_subcategory=RANDOM_SUBCATEGORY,
|
|
||||||
hardcore_position_config=hardcore_position_config,
|
|
||||||
location_config=location_config or "",
|
|
||||||
composition_config=composition_config or "",
|
|
||||||
build_prompt=build_prompt,
|
|
||||||
axis_rng=_axis_rng,
|
|
||||||
cast_expression_intensity_override=_cast_expression_intensity_override,
|
|
||||||
context_from_character_slot=_context_from_character_slot,
|
|
||||||
apply_character_context_to_row=_apply_character_context_to_row,
|
|
||||||
disable_row_expression=_disable_row_expression,
|
|
||||||
slot_softcore_outfit=_slot_softcore_outfit,
|
|
||||||
softcore_outfit=_insta_of_softcore_outfit,
|
|
||||||
softcore_pose=_insta_of_softcore_pose,
|
|
||||||
softcore_item_prompt_label=_insta_of_softcore_item_prompt_label,
|
|
||||||
pov_prompt_directive=_pov_prompt_directive,
|
|
||||||
pov_composition_prompt=_pov_composition_prompt,
|
|
||||||
)
|
|
||||||
soft_row = row_route.soft_row
|
|
||||||
hard_row = row_route.hard_row
|
|
||||||
hard_content_rng = row_route.hard_content_rng
|
|
||||||
|
|
||||||
cast_context = pair_cast.resolve_insta_pair_cast_context(
|
|
||||||
soft_row=soft_row,
|
|
||||||
options=options,
|
|
||||||
parsed_seed_config=parsed_seed_config,
|
|
||||||
seed=seed,
|
|
||||||
row_number=row_number,
|
|
||||||
ethnicity=ethnicity,
|
|
||||||
figure=figure,
|
|
||||||
no_plus_women=no_plus_women,
|
|
||||||
no_black=no_black,
|
|
||||||
hard_women_count=hard_women_count,
|
|
||||||
hard_men_count=hard_men_count,
|
|
||||||
character_slots=character_slots,
|
|
||||||
character_slot_map=character_slot_map,
|
|
||||||
pov_character_labels=pov_character_labels,
|
|
||||||
platform_styles=INSTA_OF_PLATFORM_STYLES,
|
|
||||||
soft_levels=INSTA_OF_SOFT_LEVELS,
|
|
||||||
hardcore_levels=INSTA_OF_HARDCORE_LEVELS,
|
|
||||||
axis_rng=_axis_rng,
|
|
||||||
character_context_for_label=_character_context_for_label,
|
|
||||||
slot_is_pov=_slot_is_pov,
|
|
||||||
choose=g.choose,
|
|
||||||
slot_softcore_outfit=_slot_softcore_outfit,
|
|
||||||
)
|
|
||||||
descriptor = cast_context["descriptor"]
|
|
||||||
cast_descriptors = cast_context["cast_descriptors"]
|
|
||||||
cast_descriptor_text = cast_context["cast_descriptor_text"]
|
|
||||||
soft_partner_styling = cast_context["soft_partner_styling"]
|
|
||||||
soft_partner_outfit_text = cast_context["soft_partner_outfit_text"]
|
|
||||||
platform_style = cast_context["platform_style"]
|
|
||||||
soft_level = cast_context["soft_level"]
|
|
||||||
hard_level = cast_context["hard_level"]
|
|
||||||
camera_route = pair_camera.resolve_insta_pair_camera_result(
|
|
||||||
soft_row=soft_row,
|
|
||||||
hard_row=hard_row,
|
|
||||||
options=options,
|
|
||||||
camera_config=camera_config,
|
camera_config=camera_config,
|
||||||
softcore_camera_config=softcore_camera_config,
|
softcore_camera_config=softcore_camera_config,
|
||||||
hardcore_camera_config=hardcore_camera_config,
|
hardcore_camera_config=hardcore_camera_config,
|
||||||
hard_women_count=hard_women_count,
|
character_profile=character_profile,
|
||||||
hard_men_count=hard_men_count,
|
character_cast=character_cast,
|
||||||
pov_character_labels=pov_character_labels,
|
hardcore_position_config=hardcore_position_config,
|
||||||
camera_detail_choices=CAMERA_DETAIL_CHOICES,
|
location_config=location_config,
|
||||||
camera_config_with_mode=_camera_config_with_mode,
|
composition_config=composition_config,
|
||||||
camera_directive=_camera_directive,
|
|
||||||
apply_contextual_composition=_apply_coworking_composition,
|
|
||||||
contextual_composition_prompt=_coworking_composition_prompt,
|
|
||||||
composition_prompt=_composition_prompt,
|
|
||||||
camera_scene_directive_for_context=_camera_scene_directive_for_context,
|
|
||||||
)
|
|
||||||
soft_row = camera_route.soft_row
|
|
||||||
hard_row = camera_route.hard_row
|
|
||||||
hard_scene = camera_route.hard_scene
|
|
||||||
hard_composition = camera_route.hard_composition
|
|
||||||
soft_camera_config = camera_route.soft_camera_config
|
|
||||||
hard_camera_config = camera_route.hard_camera_config
|
|
||||||
soft_camera_directive = camera_route.soft_camera_directive
|
|
||||||
hard_camera_directive = camera_route.hard_camera_directive
|
|
||||||
soft_camera_scene_directive = camera_route.soft_camera_scene_directive
|
|
||||||
hard_camera_scene_directive = camera_route.hard_camera_scene_directive
|
|
||||||
soft_camera_scene_sentence = camera_route.soft_camera_scene_sentence
|
|
||||||
hard_camera_scene_sentence = camera_route.hard_camera_scene_sentence
|
|
||||||
soft_camera_sentence = camera_route.soft_camera_sentence
|
|
||||||
hard_camera_sentence = camera_route.hard_camera_sentence
|
|
||||||
soft_cast = cast_context["soft_cast"]
|
|
||||||
soft_cast_presence = cast_context["soft_cast_presence"]
|
|
||||||
soft_cast_styling_sentence = cast_context["soft_cast_styling_sentence"]
|
|
||||||
hard_cast = cast_context["hard_cast"]
|
|
||||||
character_hardcore_clothing_entries = pair_clothing.character_hardcore_clothing_entries(
|
|
||||||
character_slot_map,
|
|
||||||
hard_women_count,
|
|
||||||
hard_men_count,
|
|
||||||
pov_character_labels,
|
|
||||||
hard_content_rng,
|
|
||||||
_slot_hardcore_clothing,
|
|
||||||
)
|
|
||||||
clothing_route = pair_clothing.resolve_hardcore_pair_clothing_result(
|
|
||||||
hard_row=hard_row,
|
|
||||||
mode=options["hardcore_clothing_continuity"],
|
|
||||||
softcore_outfit=soft_row["item"],
|
|
||||||
character_hardcore_clothing_entries=character_hardcore_clothing_entries,
|
|
||||||
men_count=hard_men_count,
|
|
||||||
pov_labels=pov_character_labels,
|
|
||||||
rng=hard_content_rng,
|
|
||||||
continuity_map=INSTA_OF_HARDCORE_CLOTHING_CONTINUITY,
|
|
||||||
choose=g.choose,
|
|
||||||
)
|
|
||||||
default_man_hardcore_clothing_entries = clothing_route.default_man_hardcore_clothing
|
|
||||||
hard_clothing_state = clothing_route.hardcore_clothing_state
|
|
||||||
hard_clothing_sentence = clothing_route.hardcore_clothing_sentence
|
|
||||||
if clothing_route.requires_body_exposure_scene:
|
|
||||||
hard_scene = pair_clothing.body_exposure_scene_text(hard_scene)
|
|
||||||
hard_row["source_scene_text"] = hard_row.get("source_scene_text") or hard_row.get("scene_text", "")
|
|
||||||
hard_row["scene_text"] = hard_scene
|
|
||||||
hard_detail_density = options["hardcore_detail_density"]
|
|
||||||
hard_detail_directive = pair_options.hardcore_detail_directive(hard_detail_density)
|
|
||||||
pov_directive = _pov_prompt_directive(pov_character_labels)
|
|
||||||
soft_descriptor_sentence = cast_context["soft_descriptor_sentence"]
|
|
||||||
|
|
||||||
return pair_output.assemble_insta_pair_metadata(
|
|
||||||
active_trigger=active_trigger,
|
|
||||||
prepend_trigger_to_prompt=bool(prepend_trigger_to_prompt),
|
|
||||||
extra_positive=extra_positive,
|
extra_positive=extra_positive,
|
||||||
extra_negative=extra_negative,
|
extra_negative=extra_negative,
|
||||||
soft_negative_base=INSTA_OF_SOFT_NEGATIVE,
|
|
||||||
hard_negative_base=INSTA_OF_NEGATIVE,
|
|
||||||
options=options,
|
|
||||||
platform_style=platform_style,
|
|
||||||
soft_descriptor_sentence=soft_descriptor_sentence,
|
|
||||||
soft_level=soft_level,
|
|
||||||
soft_cast=soft_cast,
|
|
||||||
soft_cast_presence=soft_cast_presence,
|
|
||||||
soft_cast_styling_sentence=soft_cast_styling_sentence,
|
|
||||||
soft_row=soft_row,
|
|
||||||
soft_camera_scene_sentence=soft_camera_scene_sentence,
|
|
||||||
soft_camera_sentence=soft_camera_sentence,
|
|
||||||
hard_level=hard_level,
|
|
||||||
hard_cast=hard_cast,
|
|
||||||
cast_descriptor_text=cast_descriptor_text,
|
|
||||||
pov_directive=pov_directive,
|
|
||||||
pov_character_labels=pov_character_labels,
|
|
||||||
hard_clothing_sentence=hard_clothing_sentence,
|
|
||||||
hard_row=hard_row,
|
|
||||||
hard_scene=hard_scene,
|
|
||||||
hard_camera_scene_sentence=hard_camera_scene_sentence,
|
|
||||||
hard_composition=hard_composition,
|
|
||||||
hard_detail_directive=hard_detail_directive,
|
|
||||||
hard_camera_sentence=hard_camera_sentence,
|
|
||||||
descriptor=descriptor,
|
|
||||||
soft_partner_outfit_text=soft_partner_outfit_text,
|
|
||||||
soft_partner_styling=soft_partner_styling,
|
|
||||||
soft_camera_scene_directive=soft_camera_scene_directive,
|
|
||||||
soft_camera_config=soft_camera_config,
|
|
||||||
soft_camera_directive=soft_camera_directive,
|
|
||||||
hard_camera_scene_directive=hard_camera_scene_directive,
|
|
||||||
hard_camera_config=hard_camera_config,
|
|
||||||
hard_camera_directive=hard_camera_directive,
|
|
||||||
camera_caption_text=_camera_caption_text,
|
|
||||||
cast_descriptors=cast_descriptors,
|
|
||||||
character_hardcore_clothing_entries=character_hardcore_clothing_entries,
|
|
||||||
default_man_hardcore_clothing_entries=default_man_hardcore_clothing_entries,
|
|
||||||
hard_clothing_state=hard_clothing_state,
|
|
||||||
hard_detail_density=hard_detail_density,
|
|
||||||
hard_women_count=hard_women_count,
|
|
||||||
hard_men_count=hard_men_count,
|
|
||||||
character_slots=character_slots,
|
|
||||||
character_slot_map=character_slot_map,
|
|
||||||
)
|
)
|
||||||
|
return pair_builder.build_insta_of_pair(request, _insta_pair_build_dependencies())
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import krea_cast # noqa: E402
|
|||||||
import krea_formatter # noqa: E402
|
import krea_formatter # noqa: E402
|
||||||
import location_config # noqa: E402
|
import location_config # noqa: E402
|
||||||
import loop_nodes # noqa: E402
|
import loop_nodes # noqa: E402
|
||||||
|
import pair_builder # noqa: E402
|
||||||
import pair_camera # noqa: E402
|
import pair_camera # noqa: E402
|
||||||
import pair_cast # noqa: E402
|
import pair_cast # noqa: E402
|
||||||
import pair_clothing # noqa: E402
|
import pair_clothing # noqa: E402
|
||||||
@@ -3066,6 +3067,50 @@ def smoke_pair_route_policy() -> None:
|
|||||||
_expect(clothing_route.requires_body_exposure_scene is True, "Typed pair clothing route lost exposure-scene flag")
|
_expect(clothing_route.requires_body_exposure_scene is True, "Typed pair clothing route lost exposure-scene flag")
|
||||||
|
|
||||||
|
|
||||||
|
def smoke_pair_builder_policy() -> None:
|
||||||
|
request = pair_builder.InstaPairBuildRequest(
|
||||||
|
row_number=1,
|
||||||
|
start_index=1,
|
||||||
|
seed=2101,
|
||||||
|
ethnicity="any",
|
||||||
|
figure="random",
|
||||||
|
no_plus_women=False,
|
||||||
|
no_black=False,
|
||||||
|
trigger=Trigger,
|
||||||
|
prepend_trigger_to_prompt=True,
|
||||||
|
options_json=_insta_options(),
|
||||||
|
character_cast=_character_cast(),
|
||||||
|
hardcore_position_config=_action_filter("penetration_only"),
|
||||||
|
)
|
||||||
|
built = pair_builder.build_insta_of_pair(request, pb._insta_pair_build_dependencies())
|
||||||
|
delegated = pb.build_insta_of_pair(
|
||||||
|
row_number=request.row_number,
|
||||||
|
start_index=request.start_index,
|
||||||
|
seed=request.seed,
|
||||||
|
ethnicity=request.ethnicity,
|
||||||
|
figure=request.figure,
|
||||||
|
no_plus_women=request.no_plus_women,
|
||||||
|
no_black=request.no_black,
|
||||||
|
trigger=request.trigger,
|
||||||
|
prepend_trigger_to_prompt=request.prepend_trigger_to_prompt,
|
||||||
|
seed_config=request.seed_config,
|
||||||
|
options_json=request.options_json,
|
||||||
|
filter_config=request.filter_config,
|
||||||
|
camera_config=request.camera_config,
|
||||||
|
softcore_camera_config=request.softcore_camera_config,
|
||||||
|
hardcore_camera_config=request.hardcore_camera_config,
|
||||||
|
character_profile=request.character_profile,
|
||||||
|
character_cast=request.character_cast,
|
||||||
|
hardcore_position_config=request.hardcore_position_config,
|
||||||
|
location_config=request.location_config,
|
||||||
|
composition_config=request.composition_config,
|
||||||
|
extra_positive=request.extra_positive,
|
||||||
|
extra_negative=request.extra_negative,
|
||||||
|
)
|
||||||
|
_expect(built == delegated, "Prompt builder Insta/OF wrapper should delegate to pair_builder without output drift")
|
||||||
|
_expect_pair(built, "pair_builder_policy")
|
||||||
|
|
||||||
|
|
||||||
def _expect_pair(pair: dict[str, Any], name: str) -> None:
|
def _expect_pair(pair: dict[str, Any], name: str) -> None:
|
||||||
_expect(pair.get("mode") == "Insta/OF", f"{name}.mode should be Insta/OF")
|
_expect(pair.get("mode") == "Insta/OF", f"{name}.mode should be Insta/OF")
|
||||||
_expect_row_base(pair.get("softcore_row") or {}, f"{name}.softcore_row")
|
_expect_row_base(pair.get("softcore_row") or {}, f"{name}.softcore_row")
|
||||||
@@ -4968,6 +5013,7 @@ SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
|
|||||||
("krea_close_foreplay_route", smoke_krea_close_foreplay_route),
|
("krea_close_foreplay_route", smoke_krea_close_foreplay_route),
|
||||||
("pair_options_policy", smoke_pair_options_policy),
|
("pair_options_policy", smoke_pair_options_policy),
|
||||||
("pair_route_policy", smoke_pair_route_policy),
|
("pair_route_policy", smoke_pair_route_policy),
|
||||||
|
("pair_builder_policy", smoke_pair_builder_policy),
|
||||||
("insta_pair_same_cast", smoke_insta_pair),
|
("insta_pair_same_cast", smoke_insta_pair),
|
||||||
("krea_pair_clothing_state", smoke_krea_pair_clothing_state),
|
("krea_pair_clothing_state", smoke_krea_pair_clothing_state),
|
||||||
("insta_pair_pov_man", smoke_insta_pair_pov),
|
("insta_pair_pov_man", smoke_insta_pair_pov),
|
||||||
|
|||||||
Reference in New Issue
Block a user