Extract row prompt axes policy
This commit is contained in:
@@ -191,6 +191,10 @@ Already isolated:
|
|||||||
runtime location/composition pool overrides, and generator fallback pool
|
runtime location/composition pool overrides, and generator fallback pool
|
||||||
selection live in `row_pools.py`; `prompt_builder.py` keeps public delegate
|
selection live in `row_pools.py`; `prompt_builder.py` keeps public delegate
|
||||||
wrappers.
|
wrappers.
|
||||||
|
- row scene/pose/expression/composition axis selection, compatible-entry
|
||||||
|
filtering, expression-disabled handling, per-character expression promotion,
|
||||||
|
POV composition adaptation, and pose-category environment sanitizing live in
|
||||||
|
`row_prompt_axes.py`; `prompt_builder.py` keeps a public delegate wrapper.
|
||||||
- row expression text cleanup, expression intensity weighting,
|
- row expression text cleanup, expression intensity weighting,
|
||||||
character-slot/cast expression override resolution, and per-character
|
character-slot/cast expression override resolution, and per-character
|
||||||
expression picking plus action-aware character-expression sanitizing live in
|
expression picking plus action-aware character-expression sanitizing live in
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ Core helper ownership:
|
|||||||
| `row_location.py` | Built-in row location/composition config application, deterministic scene/composition choice, source metadata, and legacy prompt/caption rewrites. |
|
| `row_location.py` | Built-in row location/composition config application, deterministic scene/composition choice, source metadata, and legacy prompt/caption rewrites. |
|
||||||
| `row_expression.py` | Row expression cleanup, expression intensity weighting, character-slot/cast expression override resolution, per-character expression selection, and action-aware character-expression sanitizing. |
|
| `row_expression.py` | Row expression cleanup, expression intensity weighting, character-slot/cast expression override resolution, per-character expression selection, and action-aware character-expression sanitizing. |
|
||||||
| `row_pools.py` | Row scene/expression/pose/composition pool routing, category inheritance handling, runtime location/composition pool overrides, and generator fallback pools. |
|
| `row_pools.py` | Row scene/expression/pose/composition pool routing, category inheritance handling, runtime location/composition pool overrides, and generator fallback pools. |
|
||||||
|
| `row_prompt_axes.py` | Row scene/pose/expression/composition axis selection, compatible-entry filtering, expression-disabled handling, per-character expression promotion, 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_rows.py` | Insta/OF soft/hard row creation, softcore expression override resolution, Woman A slot context application, soft outfit/pose overrides, and POV row fields. |
|
| `pair_rows.py` | Insta/OF soft/hard row creation, softcore expression override resolution, Woman A slot context application, soft outfit/pose overrides, and POV row fields. |
|
||||||
@@ -484,17 +485,17 @@ plain prompt text. When debugging, inspect these fields before editing pools.
|
|||||||
| `custom_item`, `item_label` | Category/pair route | Formatters and debug | Label/name for item route. |
|
| `custom_item`, `item_label` | Category/pair route | Formatters and debug | Label/name for item route. |
|
||||||
| `role_graph` | `_role_graph`, POV adapter | Krea/Naturalizer | Choreography/action relationship text after POV adaptation. |
|
| `role_graph` | `_role_graph`, POV adapter | Krea/Naturalizer | Choreography/action relationship text after POV adaptation. |
|
||||||
| `source_role_graph` | `_role_graph` before POV rewrite | Krea hardcore rewrite | Raw action graph used to infer position and contact. |
|
| `source_role_graph` | `_role_graph` before POV rewrite | Krea hardcore rewrite | Raw action graph used to infer position and contact. |
|
||||||
| `scene_text` | `_scene_pool` or location config | All formatters | Final location text. |
|
| `scene_text` | `row_prompt_axes.resolve_prompt_axes` | All formatters | Final location text. |
|
||||||
| `source_scene_text` | location/body-exposure/camera adapters | Debug/continuity | Previous scene text before an override. |
|
| `source_scene_text` | location/body-exposure/camera adapters | Debug/continuity | Previous scene text before an override. |
|
||||||
| `location_config` | Location config parser | Debug | Active location pool config, if connected. |
|
| `location_config` | Location config parser | Debug | Active location pool config, if connected. |
|
||||||
| `pose` | `_pose_pool` or category item route | Formatters | Generic pose text. Less important for hardcore action categories than `item`/`role_graph`. |
|
| `pose` | `row_prompt_axes.resolve_prompt_axes` | Formatters | Generic pose text. Less important for hardcore action categories than `item`/`role_graph`. |
|
||||||
| `expression` | `_expression_pool` and intensity filter | All formatters | Final expression text unless disabled. |
|
| `expression` | `row_prompt_axes.resolve_prompt_axes` | All formatters | Final expression text unless disabled. |
|
||||||
| `shared_expression` | Expression selection | Debug | Expression before character-specific expansion. |
|
| `shared_expression` | `row_prompt_axes.resolve_prompt_axes` | Debug | Expression before character-specific expansion. |
|
||||||
| `character_expression_text` | Character slot expression route | Krea/Naturalizer | Per-character expression clauses. |
|
| `character_expression_text` | `row_prompt_axes.resolve_prompt_axes` | Krea/Naturalizer | Per-character expression clauses. |
|
||||||
| `expression_enabled`, `expression_disabled` | Builder/slot override | All formatters | Hard gate for whether expression text should appear. |
|
| `expression_enabled`, `expression_disabled` | Builder/slot override | All formatters | Hard gate for whether expression text should appear. |
|
||||||
| `expression_intensity_source` | Builder/slot override | Debug | Explains whether intensity came from input, random, slot, or disabled state. |
|
| `expression_intensity_source` | Builder/slot override | Debug | Explains whether intensity came from input, random, slot, or disabled state. |
|
||||||
| `composition` | `_composition_pool`, POV/camera adapter | All formatters | Final framing phrase. |
|
| `composition` | `row_prompt_axes.resolve_prompt_axes` | All formatters | Final framing phrase. |
|
||||||
| `source_composition` | Composition adapter | Krea hardcore rewrite | Previous/raw composition, often better for action inference. |
|
| `source_composition` | `row_prompt_axes.resolve_prompt_axes` | Krea hardcore rewrite | Previous/raw composition, often better for action inference. |
|
||||||
| `composition_config` | Composition config parser | Debug | Active composition pool config, if connected. |
|
| `composition_config` | Composition config parser | Debug | Active composition pool config, if connected. |
|
||||||
| `camera_config` | Camera nodes/parser | Krea/SDXL/debug | Structured camera settings. |
|
| `camera_config` | Camera nodes/parser | Krea/SDXL/debug | Structured camera settings. |
|
||||||
| `camera_directive` | `_camera_directive` | Krea/Naturalizer/prompt text | Human camera sentence. Suppressed for POV. |
|
| `camera_directive` | `_camera_directive` | Krea/Naturalizer/prompt text | Human camera sentence. Suppressed for POV. |
|
||||||
|
|||||||
+88
-60
@@ -40,6 +40,7 @@ try:
|
|||||||
from . import row_generation as row_generation_policy
|
from . import row_generation as row_generation_policy
|
||||||
from . import row_item as row_item_policy
|
from . import row_item as row_item_policy
|
||||||
from . import row_location as row_location_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_pools as row_pool_policy
|
||||||
from . import row_rendering as row_rendering_policy
|
from . import row_rendering as row_rendering_policy
|
||||||
from . import row_route_metadata as row_route_policy
|
from . import row_route_metadata as row_route_policy
|
||||||
@@ -87,6 +88,7 @@ except ImportError: # Allows local smoke tests with `python -c`.
|
|||||||
import row_generation as row_generation_policy
|
import row_generation as row_generation_policy
|
||||||
import row_item as row_item_policy
|
import row_item as row_item_policy
|
||||||
import row_location as row_location_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_pools as row_pool_policy
|
||||||
import row_rendering as row_rendering_policy
|
import row_rendering as row_rendering_policy
|
||||||
import row_route_metadata as row_route_policy
|
import row_route_metadata as row_route_policy
|
||||||
@@ -2029,6 +2031,59 @@ def _composition_pool(
|
|||||||
return row_pool_policy.composition_pool(category, subcategory, item, subject_type, composition_config)
|
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 _build_custom_row(
|
def _build_custom_row(
|
||||||
category_choice: str,
|
category_choice: str,
|
||||||
subcategory_choice: str,
|
subcategory_choice: str,
|
||||||
@@ -2140,67 +2195,40 @@ def _build_custom_row(
|
|||||||
if expression_intensity is None:
|
if expression_intensity is None:
|
||||||
expression_disabled = True
|
expression_disabled = True
|
||||||
|
|
||||||
scene_slug, scene = _choose_pair(
|
prompt_axes = _prompt_axes_route(
|
||||||
scene_rng,
|
category=category,
|
||||||
_compatible_entries(
|
subcategory=subcategory,
|
||||||
_scene_pool(category, subcategory, item, subject_type, parsed_location_config),
|
item=item,
|
||||||
women_count,
|
subject_type=subject_type,
|
||||||
men_count,
|
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,
|
||||||
)
|
)
|
||||||
pose = str(_merged_field(category, subcategory, item, "pose", "") or context.get("fallback_pose") or _choose_text(
|
scene_slug = str(prompt_axes.get("scene_slug") or "")
|
||||||
pose_rng, _compatible_entries(_pose_pool(category, subcategory, item, subject_type, poses), women_count, men_count)
|
scene = str(prompt_axes.get("scene") or "")
|
||||||
))
|
pose = str(prompt_axes.get("pose") or "")
|
||||||
if is_pose_category:
|
expression = str(prompt_axes.get("expression") or "")
|
||||||
pose = _sanitize_hardcore_environment_anchors(pose)
|
shared_expression = str(prompt_axes.get("shared_expression") or "")
|
||||||
expression_pool = _expression_pool(category, subcategory, item)
|
character_expressions = list(prompt_axes.get("character_expressions") or [])
|
||||||
if expression_disabled:
|
character_expression_text = str(prompt_axes.get("character_expression_text") or "")
|
||||||
expression = ""
|
source_composition = str(prompt_axes.get("source_composition") or "")
|
||||||
else:
|
composition = str(prompt_axes.get("composition") or "")
|
||||||
expression_entries = _compatible_entries(
|
|
||||||
_expression_entries_for_intensity(expression_pool, expression_intensity),
|
|
||||||
women_count,
|
|
||||||
men_count,
|
|
||||||
)
|
|
||||||
expression = _choose_text(expression_rng, expression_entries)
|
|
||||||
if subject_type in ("couple", "group") and ";" not in expression:
|
|
||||||
secondary_expression = _choose_distinct_text(expression_rng, expression_entries, expression)
|
|
||||||
if secondary_expression:
|
|
||||||
expression = f"{expression}; {secondary_expression}"
|
|
||||||
shared_expression = expression
|
|
||||||
character_expressions: list[str] = []
|
|
||||||
character_expression_text = ""
|
|
||||||
if not expression_disabled and subject_type == "configured_cast" and character_slots:
|
|
||||||
character_expressions = _character_expression_entries(
|
|
||||||
expression_rng,
|
|
||||||
expression_pool,
|
|
||||||
expression_intensity,
|
|
||||||
character_slot_map,
|
|
||||||
women_count,
|
|
||||||
men_count,
|
|
||||||
expression_phase,
|
|
||||||
)
|
|
||||||
character_expression_text = "; ".join(character_expressions)
|
|
||||||
character_expression_text = _sanitize_character_expression_text_for_action(
|
|
||||||
character_expression_text,
|
|
||||||
source_role_graph,
|
|
||||||
item,
|
|
||||||
item_axis_values,
|
|
||||||
)
|
|
||||||
character_expressions = [part.strip() for part in character_expression_text.split(";") if part.strip()]
|
|
||||||
if character_expression_text:
|
|
||||||
expression = character_expression_text
|
|
||||||
source_composition = _choose_text(
|
|
||||||
composition_rng,
|
|
||||||
_compatible_entries(
|
|
||||||
_composition_pool(category, subcategory, item, subject_type, parsed_composition_config),
|
|
||||||
women_count,
|
|
||||||
men_count,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
if is_pose_category:
|
|
||||||
source_composition = _sanitize_hardcore_environment_anchors(source_composition)
|
|
||||||
composition = _pov_composition_prompt(source_composition, pov_character_labels)
|
|
||||||
action_route = _action_position_route_metadata(
|
action_route = _action_position_route_metadata(
|
||||||
is_pose_category=is_pose_category,
|
is_pose_category=is_pose_category,
|
||||||
subcategory=subcategory,
|
subcategory=subcategory,
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
try:
|
||||||
|
from . import category_library as category_policy
|
||||||
|
from . import row_expression as row_expression_policy
|
||||||
|
from . import row_item as row_item_policy
|
||||||
|
from . import row_pools as row_pool_policy
|
||||||
|
from . import pov_policy
|
||||||
|
from .hardcore_text_cleanup import sanitize_hardcore_environment_anchors
|
||||||
|
except ImportError: # Allows local smoke tests from the repository root.
|
||||||
|
import category_library as category_policy
|
||||||
|
import row_expression as row_expression_policy
|
||||||
|
import row_item as row_item_policy
|
||||||
|
import row_pools as row_pool_policy
|
||||||
|
import pov_policy
|
||||||
|
from hardcore_text_cleanup import sanitize_hardcore_environment_anchors
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_prompt_axes(
|
||||||
|
*,
|
||||||
|
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: Any,
|
||||||
|
pose_rng: Any,
|
||||||
|
expression_rng: Any,
|
||||||
|
composition_rng: Any,
|
||||||
|
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]:
|
||||||
|
character_slots = character_slots or []
|
||||||
|
character_slot_map = character_slot_map or {}
|
||||||
|
pov_character_labels = pov_character_labels or []
|
||||||
|
|
||||||
|
scene_slug, scene = row_item_policy.choose_pair(
|
||||||
|
scene_rng,
|
||||||
|
category_policy.compatible_entries(
|
||||||
|
row_pool_policy.scene_pool(category, subcategory, item, subject_type, location_config),
|
||||||
|
women_count,
|
||||||
|
men_count,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
pose = str(
|
||||||
|
category_policy.merged_field(category, subcategory, item, "pose", "")
|
||||||
|
or context.get("fallback_pose")
|
||||||
|
or row_item_policy.choose_text(
|
||||||
|
pose_rng,
|
||||||
|
category_policy.compatible_entries(
|
||||||
|
row_pool_policy.pose_pool(category, subcategory, item, subject_type, poses),
|
||||||
|
women_count,
|
||||||
|
men_count,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if is_pose_category:
|
||||||
|
pose = sanitize_hardcore_environment_anchors(pose)
|
||||||
|
|
||||||
|
expression_pool = row_pool_policy.expression_pool(category, subcategory, item)
|
||||||
|
if expression_disabled:
|
||||||
|
expression = ""
|
||||||
|
else:
|
||||||
|
expression_entries = category_policy.compatible_entries(
|
||||||
|
row_expression_policy.expression_entries_for_intensity(expression_pool, expression_intensity),
|
||||||
|
women_count,
|
||||||
|
men_count,
|
||||||
|
)
|
||||||
|
expression = row_item_policy.choose_text(expression_rng, expression_entries)
|
||||||
|
if subject_type in ("couple", "group") and ";" not in expression:
|
||||||
|
secondary_expression = row_item_policy.choose_distinct_text(expression_rng, expression_entries, expression)
|
||||||
|
if secondary_expression:
|
||||||
|
expression = f"{expression}; {secondary_expression}"
|
||||||
|
|
||||||
|
shared_expression = expression
|
||||||
|
character_expressions: list[str] = []
|
||||||
|
character_expression_text = ""
|
||||||
|
if not expression_disabled and subject_type == "configured_cast" and character_slots:
|
||||||
|
character_expressions = row_expression_policy.character_expression_entries(
|
||||||
|
expression_rng,
|
||||||
|
expression_pool,
|
||||||
|
expression_intensity,
|
||||||
|
character_slot_map,
|
||||||
|
women_count,
|
||||||
|
men_count,
|
||||||
|
expression_phase,
|
||||||
|
)
|
||||||
|
character_expression_text = "; ".join(character_expressions)
|
||||||
|
character_expression_text = row_expression_policy.sanitize_character_expression_text_for_action(
|
||||||
|
character_expression_text,
|
||||||
|
source_role_graph,
|
||||||
|
item,
|
||||||
|
item_axis_values or {},
|
||||||
|
)
|
||||||
|
character_expressions = [part.strip() for part in character_expression_text.split(";") if part.strip()]
|
||||||
|
if character_expression_text:
|
||||||
|
expression = character_expression_text
|
||||||
|
|
||||||
|
source_composition = row_item_policy.choose_text(
|
||||||
|
composition_rng,
|
||||||
|
category_policy.compatible_entries(
|
||||||
|
row_pool_policy.composition_pool(category, subcategory, item, subject_type, composition_config),
|
||||||
|
women_count,
|
||||||
|
men_count,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if is_pose_category:
|
||||||
|
source_composition = sanitize_hardcore_environment_anchors(source_composition)
|
||||||
|
composition = pov_policy.pov_composition_prompt(source_composition, pov_character_labels)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"scene_slug": scene_slug,
|
||||||
|
"scene": scene,
|
||||||
|
"pose": pose,
|
||||||
|
"expression": expression,
|
||||||
|
"shared_expression": shared_expression,
|
||||||
|
"character_expressions": character_expressions,
|
||||||
|
"character_expression_text": character_expression_text,
|
||||||
|
"source_composition": source_composition,
|
||||||
|
"composition": composition,
|
||||||
|
}
|
||||||
@@ -58,6 +58,7 @@ import row_generation # noqa: E402
|
|||||||
import row_item # noqa: E402
|
import row_item # noqa: E402
|
||||||
import row_location # noqa: E402
|
import row_location # noqa: E402
|
||||||
import row_pools # noqa: E402
|
import row_pools # noqa: E402
|
||||||
|
import row_prompt_axes # noqa: E402
|
||||||
import row_rendering # noqa: E402
|
import row_rendering # noqa: E402
|
||||||
import row_route_metadata # noqa: E402
|
import row_route_metadata # noqa: E402
|
||||||
import row_subject_route # noqa: E402
|
import row_subject_route # noqa: E402
|
||||||
@@ -758,6 +759,91 @@ def smoke_row_expression_policy() -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def smoke_row_prompt_axes_policy() -> None:
|
||||||
|
category = {
|
||||||
|
"name": "Axis Test",
|
||||||
|
"slug": "axis_test",
|
||||||
|
"scenes": [{"slug": "studio", "prompt": "quiet studio with repeatable anchors"}],
|
||||||
|
"poses": ["standing fallback pose"],
|
||||||
|
"expressions": ["quiet focus", "heated smirk"],
|
||||||
|
"compositions": ["all participants visible centered frame"],
|
||||||
|
}
|
||||||
|
subcategory = {"name": "Axis Sub", "slug": "axis_sub", "items": ["axis item"]}
|
||||||
|
item = "axis item"
|
||||||
|
base_kwargs = {
|
||||||
|
"category": category,
|
||||||
|
"subcategory": subcategory,
|
||||||
|
"item": item,
|
||||||
|
"subject_type": "woman",
|
||||||
|
"context": {"fallback_pose": ""},
|
||||||
|
"poses": "standard",
|
||||||
|
"women_count": 1,
|
||||||
|
"men_count": 0,
|
||||||
|
"expression_disabled": True,
|
||||||
|
"expression_intensity": 0.5,
|
||||||
|
"is_pose_category": False,
|
||||||
|
"location_config": {},
|
||||||
|
"composition_config": {},
|
||||||
|
}
|
||||||
|
route = row_prompt_axes.resolve_prompt_axes(
|
||||||
|
**base_kwargs,
|
||||||
|
scene_rng=random.Random(1),
|
||||||
|
pose_rng=random.Random(2),
|
||||||
|
expression_rng=random.Random(3),
|
||||||
|
composition_rng=random.Random(4),
|
||||||
|
)
|
||||||
|
delegated = pb._prompt_axes_route(
|
||||||
|
**base_kwargs,
|
||||||
|
scene_rng=random.Random(1),
|
||||||
|
pose_rng=random.Random(2),
|
||||||
|
expression_rng=random.Random(3),
|
||||||
|
composition_rng=random.Random(4),
|
||||||
|
)
|
||||||
|
_expect(delegated == route, "Prompt builder prompt-axes route should delegate to row_prompt_axes")
|
||||||
|
_expect(route["scene_slug"] == "studio", "Prompt axes route lost selected scene slug")
|
||||||
|
_expect(route["scene"] == "quiet studio with repeatable anchors", "Prompt axes route lost selected scene text")
|
||||||
|
_expect(route["pose"] == "standing fallback pose", "Prompt axes route lost selected fallback pose")
|
||||||
|
_expect(route["expression"] == "", "Prompt axes route should omit expression when disabled")
|
||||||
|
_expect(route["shared_expression"] == "", "Prompt axes route should omit shared expression when disabled")
|
||||||
|
_expect(route["source_composition"] == "all participants visible centered frame", "Prompt axes route lost source composition")
|
||||||
|
|
||||||
|
pov_route = row_prompt_axes.resolve_prompt_axes(
|
||||||
|
**{**base_kwargs, "expression_disabled": True},
|
||||||
|
scene_rng=random.Random(1),
|
||||||
|
pose_rng=random.Random(2),
|
||||||
|
expression_rng=random.Random(3),
|
||||||
|
composition_rng=random.Random(4),
|
||||||
|
pov_character_labels=["Man A"],
|
||||||
|
)
|
||||||
|
_expect("first-person POV" in pov_route["composition"], "Prompt axes route did not adapt composition for POV")
|
||||||
|
|
||||||
|
woman_slot = character_slot.normalize_character_slot(
|
||||||
|
{"subject_type": "woman", "label": "A", "expression_intensity": 0.25}
|
||||||
|
)
|
||||||
|
configured_route = row_prompt_axes.resolve_prompt_axes(
|
||||||
|
**{
|
||||||
|
**base_kwargs,
|
||||||
|
"subject_type": "configured_cast",
|
||||||
|
"context": {"subject_type": "configured_cast"},
|
||||||
|
"expression_disabled": False,
|
||||||
|
"character_slots": [woman_slot],
|
||||||
|
"character_slot_map": {"Woman A": woman_slot},
|
||||||
|
},
|
||||||
|
scene_rng=random.Random(1),
|
||||||
|
pose_rng=random.Random(2),
|
||||||
|
expression_rng=random.Random(3),
|
||||||
|
composition_rng=random.Random(4),
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
configured_route["character_expression_text"].startswith("Woman A has "),
|
||||||
|
"Prompt axes route lost configured-cast character expression",
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
configured_route["expression"] == configured_route["character_expression_text"],
|
||||||
|
"Prompt axes route did not promote character expression text to row expression",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def smoke_row_item_policy() -> None:
|
def smoke_row_item_policy() -> None:
|
||||||
weighted_entries = [
|
weighted_entries = [
|
||||||
{"text": "first", "weight": 0.0},
|
{"text": "first", "weight": 0.0},
|
||||||
@@ -4387,6 +4473,7 @@ SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
|
|||||||
("location_config_policy", smoke_location_config_policy),
|
("location_config_policy", smoke_location_config_policy),
|
||||||
("row_location_policy", smoke_row_location_policy),
|
("row_location_policy", smoke_row_location_policy),
|
||||||
("row_expression_policy", smoke_row_expression_policy),
|
("row_expression_policy", smoke_row_expression_policy),
|
||||||
|
("row_prompt_axes_policy", smoke_row_prompt_axes_policy),
|
||||||
("row_item_policy", smoke_row_item_policy),
|
("row_item_policy", smoke_row_item_policy),
|
||||||
("row_category_route_policy", smoke_row_category_route_policy),
|
("row_category_route_policy", smoke_row_category_route_policy),
|
||||||
("row_generation_policy", smoke_row_generation_policy),
|
("row_generation_policy", smoke_row_generation_policy),
|
||||||
|
|||||||
Reference in New Issue
Block a user