Extract row generation policy
This commit is contained in:
@@ -129,6 +129,9 @@ Already isolated:
|
|||||||
- row item selection, weighted item/pair choice, item-template axis filling,
|
- row item selection, weighted item/pair choice, item-template axis filling,
|
||||||
and oral/outercourse axis compatibility filters live in `row_item.py`;
|
and oral/outercourse axis compatibility filters live in `row_item.py`;
|
||||||
`prompt_builder.py` keeps public delegate wrappers.
|
`prompt_builder.py` keeps public delegate wrappers.
|
||||||
|
- built-in legacy row generation, auto-weighted/auto-full selection, row mode
|
||||||
|
randomization, ratio clamps, and expression-intensity randomization live in
|
||||||
|
`row_generation.py`; `prompt_builder.py` keeps public delegate wrappers.
|
||||||
- category/cast route preset schemas, config JSON builders, choice lists, and
|
- category/cast route preset schemas, config JSON builders, choice lists, and
|
||||||
parsers live in `category_cast_config.py`; `prompt_builder.py` keeps public
|
parsers live in `category_cast_config.py`; `prompt_builder.py` keeps public
|
||||||
delegate wrappers for existing nodes and tests.
|
delegate wrappers for existing nodes and tests.
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ Core helper ownership:
|
|||||||
| `category_library.py` | JSON category loading, subcategory normalization, named scene/expression/composition pool loading, cast compatibility filtering, exact subcategory lookup, and inheritance-based pool merging. |
|
| `category_library.py` | JSON category loading, subcategory normalization, named scene/expression/composition pool loading, cast compatibility filtering, exact subcategory lookup, and inheritance-based pool merging. |
|
||||||
| `category_template_metadata.py` | Object-style item-template metadata extraction, action/position family normalization, position-key normalization, key merging, and audit validation errors. |
|
| `category_template_metadata.py` | Object-style item-template metadata extraction, action/position family normalization, position-key normalization, key merging, and audit validation errors. |
|
||||||
| `row_item.py` | Row item selection, weighted item/pair choice, item-template axis filling, and oral/outercourse axis compatibility filters. |
|
| `row_item.py` | Row item selection, weighted item/pair choice, item-template axis filling, and oral/outercourse axis compatibility filters. |
|
||||||
|
| `row_generation.py` | Built-in legacy row generation, auto-weighted/auto-full selection, row mode randomization, ratio clamps, and expression-intensity randomization. |
|
||||||
| `category_cast_config.py` | Category preset and cast preset schemas, category/cast config JSON builders, choice lists, and config parsers used by route nodes. |
|
| `category_cast_config.py` | Category preset and cast preset schemas, category/cast config JSON builders, choice lists, and config parsers used by route nodes. |
|
||||||
| `cast_context.py` | Generation-time cast count phrases, configured-cast context metadata, character-slot label assignment, cast-summary wording, scene-kind labels, and couple count normalization. |
|
| `cast_context.py` | Generation-time cast count phrases, configured-cast context metadata, character-slot label assignment, cast-summary wording, scene-kind labels, and couple count normalization. |
|
||||||
| `camera_config.py` | Camera option schema, direct/orbit/Qwen camera JSON builders, camera config parsing, plain camera directive text, and camera caption labels. |
|
| `camera_config.py` | Camera option schema, direct/orbit/Qwen camera JSON builders, camera config parsing, plain camera directive text, and camera caption labels. |
|
||||||
@@ -198,7 +199,7 @@ There are two category systems.
|
|||||||
|
|
||||||
| Source | Files/functions | Notes |
|
| Source | Files/functions | Notes |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Built-in legacy generator | `generate_prompt_batches.py`, `_build_direct_builtin_row`, `_build_auto_weighted_row` | Handles legacy `woman`, `man`, `couple`, `group_or_layout`, `auto_weighted`, and `auto_full`. |
|
| Built-in legacy generator | `generate_prompt_batches.py`, `row_generation.py` | Handles legacy `woman`, `man`, `couple`, `group_or_layout`, `auto_weighted`, and `auto_full`. |
|
||||||
| JSON category library | `categories/*.json`, `category_library.load_category_library`, `_build_custom_row` | Handles expandable categories such as casual clothes, erotic clothes, and hardcore sexual poses. |
|
| JSON category library | `categories/*.json`, `category_library.load_category_library`, `_build_custom_row` | Handles expandable categories such as casual clothes, erotic clothes, and hardcore sexual poses. |
|
||||||
|
|
||||||
JSON categories are the scalable system. Add new main categories or subcategories
|
JSON categories are the scalable system. Add new main categories or subcategories
|
||||||
|
|||||||
+26
-90
@@ -40,6 +40,7 @@ try:
|
|||||||
from . import row_normalization as row_policy
|
from . import row_normalization as row_policy
|
||||||
from . import row_camera as row_camera_policy
|
from . import row_camera as row_camera_policy
|
||||||
from . import row_expression as row_expression_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_item as row_item_policy
|
||||||
from . import row_location as row_location_policy
|
from . import row_location as row_location_policy
|
||||||
from . import row_pools as row_pool_policy
|
from . import row_pools as row_pool_policy
|
||||||
@@ -84,6 +85,7 @@ except ImportError: # Allows local smoke tests with `python -c`.
|
|||||||
import row_normalization as row_policy
|
import row_normalization as row_policy
|
||||||
import row_camera as row_camera_policy
|
import row_camera as row_camera_policy
|
||||||
import row_expression as row_expression_policy
|
import row_expression as row_expression_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_pools as row_pool_policy
|
import row_pools as row_pool_policy
|
||||||
@@ -771,21 +773,11 @@ def _apply_hardcore_position_config_to_subcategory(
|
|||||||
|
|
||||||
|
|
||||||
def _ratio_or_none(value: float) -> float | None:
|
def _ratio_or_none(value: float) -> float | None:
|
||||||
try:
|
return row_generation_policy.ratio_or_none(value)
|
||||||
ratio = float(value)
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
return None
|
|
||||||
if ratio < 0:
|
|
||||||
return None
|
|
||||||
return max(0.0, min(1.0, ratio))
|
|
||||||
|
|
||||||
|
|
||||||
def _clamped_float(value: Any, default: float = 0.5, min_value: float = 0.0, max_value: float = 1.0) -> float:
|
def _clamped_float(value: Any, default: float = 0.5, min_value: float = 0.0, max_value: float = 1.0) -> float:
|
||||||
try:
|
return row_generation_policy.clamped_float(value, default, min_value, max_value)
|
||||||
number = float(value)
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
return default
|
|
||||||
return max(min_value, min(max_value, number))
|
|
||||||
|
|
||||||
|
|
||||||
def build_seed_config_json(
|
def build_seed_config_json(
|
||||||
@@ -1251,35 +1243,19 @@ def _row_seed(seed: int, row_number: int, salt: int = 0) -> int:
|
|||||||
|
|
||||||
|
|
||||||
def _pick_clothing_mode(rng: random.Random, clothing: str, minimal_ratio: float | None) -> str:
|
def _pick_clothing_mode(rng: random.Random, clothing: str, minimal_ratio: float | None) -> str:
|
||||||
if clothing == "random":
|
return row_generation_policy.pick_clothing_mode(rng, clothing, minimal_ratio)
|
||||||
return "minimal" if rng.random() < 0.5 else "full"
|
|
||||||
if minimal_ratio is None:
|
|
||||||
return clothing
|
|
||||||
return "minimal" if rng.random() < minimal_ratio else "full"
|
|
||||||
|
|
||||||
|
|
||||||
def _pick_pose_mode(rng: random.Random, poses: str, standard_ratio: float | None) -> str:
|
def _pick_pose_mode(rng: random.Random, poses: str, standard_ratio: float | None) -> str:
|
||||||
if poses == "random":
|
return row_generation_policy.pick_pose_mode(rng, poses, standard_ratio)
|
||||||
return "standard" if rng.random() < 0.5 else "evocative"
|
|
||||||
if standard_ratio is None:
|
|
||||||
return poses
|
|
||||||
return "standard" if rng.random() < standard_ratio else "evocative"
|
|
||||||
|
|
||||||
|
|
||||||
def _pick_figure_bias(rng: random.Random, figure: str) -> str:
|
def _pick_figure_bias(rng: random.Random, figure: str) -> str:
|
||||||
if figure in ("curvy", "balanced", "bombshell"):
|
return row_generation_policy.pick_figure_bias(rng, figure)
|
||||||
return figure
|
|
||||||
return g.choose(rng, ["curvy", "balanced", "bombshell"])
|
|
||||||
|
|
||||||
|
|
||||||
def _pick_expression_intensity(rng: random.Random, expression_intensity: Any) -> tuple[float, str]:
|
def _pick_expression_intensity(rng: random.Random, expression_intensity: Any) -> tuple[float, str]:
|
||||||
try:
|
return row_generation_policy.pick_expression_intensity(rng, expression_intensity)
|
||||||
value = float(expression_intensity)
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
return 0.5, "default"
|
|
||||||
if value < 0:
|
|
||||||
return round(rng.random(), 2), "random"
|
|
||||||
return _clamped_float(value, 0.5), "input"
|
|
||||||
|
|
||||||
|
|
||||||
def _build_auto_weighted_row(
|
def _build_auto_weighted_row(
|
||||||
@@ -1296,9 +1272,8 @@ def _build_auto_weighted_row(
|
|||||||
standard_pose_ratio: float | None,
|
standard_pose_ratio: float | None,
|
||||||
seed: int,
|
seed: int,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
batch_number = max(1, ((row_number - 1) // g.BATCH_SIZE) + 1)
|
return row_generation_policy.build_auto_weighted_row(
|
||||||
rows = g.build_rows(
|
row_number,
|
||||||
batch_number * g.BATCH_SIZE,
|
|
||||||
start_index,
|
start_index,
|
||||||
clothing,
|
clothing,
|
||||||
ethnicity,
|
ethnicity,
|
||||||
@@ -1310,13 +1285,7 @@ def _build_auto_weighted_row(
|
|||||||
minimal_clothing_ratio,
|
minimal_clothing_ratio,
|
||||||
standard_pose_ratio,
|
standard_pose_ratio,
|
||||||
seed,
|
seed,
|
||||||
g.EXPRESSION_SEED + seed,
|
|
||||||
)
|
)
|
||||||
row = rows[row_number - 1]
|
|
||||||
row["main_category"] = "auto_weighted"
|
|
||||||
row["subcategory"] = row.get("primary_subject", "auto")
|
|
||||||
row["source"] = "built_in_generator"
|
|
||||||
return row
|
|
||||||
|
|
||||||
|
|
||||||
def _build_direct_builtin_row(
|
def _build_direct_builtin_row(
|
||||||
@@ -1334,58 +1303,25 @@ def _build_direct_builtin_row(
|
|||||||
standard_pose_ratio: float | None,
|
standard_pose_ratio: float | None,
|
||||||
seed: int,
|
seed: int,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
rng = random.Random(_row_seed(seed, row_number))
|
return row_generation_policy.build_direct_builtin_row(
|
||||||
expr_deck = g.ExpressionDeck(g.EXPRESSIONS, random.Random(_row_seed(g.EXPRESSION_SEED + seed, row_number)))
|
category,
|
||||||
batch = max(1, ((row_number - 1) // g.BATCH_SIZE) + 1)
|
row_number,
|
||||||
index = start_index + row_number - 1
|
start_index,
|
||||||
row_clothing = _pick_clothing_mode(rng, clothing, minimal_clothing_ratio)
|
clothing,
|
||||||
row_poses = _pick_pose_mode(rng, poses, standard_pose_ratio)
|
ethnicity,
|
||||||
|
poses,
|
||||||
if category == "woman":
|
backside_bias,
|
||||||
row = g.make_single(
|
figure,
|
||||||
index,
|
no_plus_women,
|
||||||
batch,
|
no_black,
|
||||||
rng,
|
minimal_clothing_ratio,
|
||||||
"woman",
|
standard_pose_ratio,
|
||||||
expr_deck,
|
seed,
|
||||||
row_clothing,
|
)
|
||||||
ethnicity,
|
|
||||||
row_poses,
|
|
||||||
backside_bias,
|
|
||||||
figure,
|
|
||||||
no_plus_women,
|
|
||||||
no_black,
|
|
||||||
)
|
|
||||||
elif category == "man":
|
|
||||||
row = g.make_single(index, batch, rng, "man", expr_deck, row_clothing, ethnicity, row_poses, backside_bias, figure)
|
|
||||||
elif category == "couple":
|
|
||||||
row = g.make_couple(index, batch, rng, expr_deck, row_clothing, ethnicity, no_plus_women)
|
|
||||||
elif category == "group_or_layout":
|
|
||||||
row = g.make_group_or_layout(index, batch, rng, expr_deck, row_clothing, ethnicity, no_plus_women)
|
|
||||||
else:
|
|
||||||
raise ValueError(f"Unknown built-in category: {category}")
|
|
||||||
|
|
||||||
row["main_category"] = category
|
|
||||||
row["subcategory"] = row.get("pose_mode", category)
|
|
||||||
row["source"] = "built_in_generator"
|
|
||||||
return row
|
|
||||||
|
|
||||||
|
|
||||||
def _auto_full_choice(seed_config: dict[str, int], seed: int, row_number: int) -> str:
|
def _auto_full_choice(seed_config: dict[str, int], seed: int, row_number: int) -> str:
|
||||||
categories = load_category_library()
|
return row_generation_policy.auto_full_choice(seed_config, seed, row_number)
|
||||||
if not categories:
|
|
||||||
return "auto_weighted"
|
|
||||||
category_rng = _axis_rng(seed_config, "category", seed, row_number)
|
|
||||||
choices: list[dict[str, Any]] = [{"category": "auto_weighted", "weight": 1.0}]
|
|
||||||
choices.extend(
|
|
||||||
{
|
|
||||||
"category": category["name"],
|
|
||||||
"weight": category.get("weight", 1.0),
|
|
||||||
}
|
|
||||||
for category in categories
|
|
||||||
)
|
|
||||||
choice = _weighted_choice(category_rng, choices)
|
|
||||||
return str(choice.get("category") or "auto_weighted")
|
|
||||||
|
|
||||||
|
|
||||||
def _body_phrase(body: Any, figure_note: Any = "") -> str:
|
def _body_phrase(body: Any, figure_note: Any = "") -> str:
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import random
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
try:
|
||||||
|
from . import category_library as category_policy
|
||||||
|
from . import generate_prompt_batches as g
|
||||||
|
from . import row_item as row_item_policy
|
||||||
|
from . import seed_config as seed_policy
|
||||||
|
except ImportError: # Allows local smoke tests with top-level imports.
|
||||||
|
import category_library as category_policy
|
||||||
|
import generate_prompt_batches as g
|
||||||
|
import row_item as row_item_policy
|
||||||
|
import seed_config as seed_policy
|
||||||
|
|
||||||
|
|
||||||
|
def ratio_or_none(value: float) -> float | None:
|
||||||
|
try:
|
||||||
|
ratio = float(value)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return None
|
||||||
|
if ratio < 0:
|
||||||
|
return None
|
||||||
|
return max(0.0, min(1.0, ratio))
|
||||||
|
|
||||||
|
|
||||||
|
def clamped_float(value: Any, default: float = 0.5, min_value: float = 0.0, max_value: float = 1.0) -> float:
|
||||||
|
try:
|
||||||
|
number = float(value)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return default
|
||||||
|
return max(min_value, min(max_value, number))
|
||||||
|
|
||||||
|
|
||||||
|
def pick_clothing_mode(rng: random.Random, clothing: str, minimal_ratio: float | None) -> str:
|
||||||
|
if clothing == "random":
|
||||||
|
return "minimal" if rng.random() < 0.5 else "full"
|
||||||
|
if minimal_ratio is None:
|
||||||
|
return clothing
|
||||||
|
return "minimal" if rng.random() < minimal_ratio else "full"
|
||||||
|
|
||||||
|
|
||||||
|
def pick_pose_mode(rng: random.Random, poses: str, standard_ratio: float | None) -> str:
|
||||||
|
if poses == "random":
|
||||||
|
return "standard" if rng.random() < 0.5 else "evocative"
|
||||||
|
if standard_ratio is None:
|
||||||
|
return poses
|
||||||
|
return "standard" if rng.random() < standard_ratio else "evocative"
|
||||||
|
|
||||||
|
|
||||||
|
def pick_figure_bias(rng: random.Random, figure: str) -> str:
|
||||||
|
if figure in ("curvy", "balanced", "bombshell"):
|
||||||
|
return figure
|
||||||
|
return g.choose(rng, ["curvy", "balanced", "bombshell"])
|
||||||
|
|
||||||
|
|
||||||
|
def pick_expression_intensity(rng: random.Random, expression_intensity: Any) -> tuple[float, str]:
|
||||||
|
try:
|
||||||
|
value = float(expression_intensity)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return 0.5, "default"
|
||||||
|
if value < 0:
|
||||||
|
return round(rng.random(), 2), "random"
|
||||||
|
return clamped_float(value, 0.5), "input"
|
||||||
|
|
||||||
|
|
||||||
|
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]:
|
||||||
|
batch_number = max(1, ((row_number - 1) // g.BATCH_SIZE) + 1)
|
||||||
|
rows = g.build_rows(
|
||||||
|
batch_number * g.BATCH_SIZE,
|
||||||
|
start_index,
|
||||||
|
clothing,
|
||||||
|
ethnicity,
|
||||||
|
poses,
|
||||||
|
backside_bias,
|
||||||
|
figure,
|
||||||
|
no_plus_women,
|
||||||
|
no_black,
|
||||||
|
minimal_clothing_ratio,
|
||||||
|
standard_pose_ratio,
|
||||||
|
seed,
|
||||||
|
g.EXPRESSION_SEED + seed,
|
||||||
|
)
|
||||||
|
row = rows[row_number - 1]
|
||||||
|
row["main_category"] = "auto_weighted"
|
||||||
|
row["subcategory"] = row.get("primary_subject", "auto")
|
||||||
|
row["source"] = "built_in_generator"
|
||||||
|
return row
|
||||||
|
|
||||||
|
|
||||||
|
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]:
|
||||||
|
rng = random.Random(seed_policy.row_seed(seed, row_number))
|
||||||
|
expr_deck = g.ExpressionDeck(
|
||||||
|
g.EXPRESSIONS,
|
||||||
|
random.Random(seed_policy.row_seed(g.EXPRESSION_SEED + seed, row_number)),
|
||||||
|
)
|
||||||
|
batch = max(1, ((row_number - 1) // g.BATCH_SIZE) + 1)
|
||||||
|
index = start_index + row_number - 1
|
||||||
|
row_clothing = pick_clothing_mode(rng, clothing, minimal_clothing_ratio)
|
||||||
|
row_poses = pick_pose_mode(rng, poses, standard_pose_ratio)
|
||||||
|
|
||||||
|
if category == "woman":
|
||||||
|
row = g.make_single(
|
||||||
|
index,
|
||||||
|
batch,
|
||||||
|
rng,
|
||||||
|
"woman",
|
||||||
|
expr_deck,
|
||||||
|
row_clothing,
|
||||||
|
ethnicity,
|
||||||
|
row_poses,
|
||||||
|
backside_bias,
|
||||||
|
figure,
|
||||||
|
no_plus_women,
|
||||||
|
no_black,
|
||||||
|
)
|
||||||
|
elif category == "man":
|
||||||
|
row = g.make_single(index, batch, rng, "man", expr_deck, row_clothing, ethnicity, row_poses, backside_bias, figure)
|
||||||
|
elif category == "couple":
|
||||||
|
row = g.make_couple(index, batch, rng, expr_deck, row_clothing, ethnicity, no_plus_women)
|
||||||
|
elif category == "group_or_layout":
|
||||||
|
row = g.make_group_or_layout(index, batch, rng, expr_deck, row_clothing, ethnicity, no_plus_women)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unknown built-in category: {category}")
|
||||||
|
|
||||||
|
row["main_category"] = category
|
||||||
|
row["subcategory"] = row.get("pose_mode", category)
|
||||||
|
row["source"] = "built_in_generator"
|
||||||
|
return row
|
||||||
|
|
||||||
|
|
||||||
|
def auto_full_choice(seed_config: dict[str, int], seed: int, row_number: int) -> str:
|
||||||
|
categories = category_policy.load_category_library()
|
||||||
|
if not categories:
|
||||||
|
return "auto_weighted"
|
||||||
|
category_rng = seed_policy.axis_rng(seed_config, "category", seed, row_number)
|
||||||
|
choices: list[dict[str, Any]] = [{"category": "auto_weighted", "weight": 1.0}]
|
||||||
|
choices.extend(
|
||||||
|
{
|
||||||
|
"category": category["name"],
|
||||||
|
"weight": category.get("weight", 1.0),
|
||||||
|
}
|
||||||
|
for category in categories
|
||||||
|
)
|
||||||
|
choice = row_item_policy.weighted_choice(category_rng, choices)
|
||||||
|
return str(choice.get("category") or "auto_weighted")
|
||||||
@@ -52,6 +52,7 @@ import row_normalization # noqa: E402
|
|||||||
import route_metadata # noqa: E402
|
import route_metadata # noqa: E402
|
||||||
import row_camera # noqa: E402
|
import row_camera # noqa: E402
|
||||||
import row_expression # noqa: E402
|
import row_expression # noqa: E402
|
||||||
|
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
|
||||||
@@ -810,6 +811,77 @@ def smoke_row_item_policy() -> None:
|
|||||||
_expect(metadata.get("action_family") == "oral", "Row item compose lost template metadata")
|
_expect(metadata.get("action_family") == "oral", "Row item compose lost template metadata")
|
||||||
|
|
||||||
|
|
||||||
|
def smoke_row_generation_policy() -> None:
|
||||||
|
_expect(pb._ratio_or_none(-1) is None, "Prompt builder ratio helper should treat negative as unset")
|
||||||
|
_expect(pb._ratio_or_none(1.5) == row_generation.ratio_or_none(1.5) == 1.0, "Row generation ratio clamp changed")
|
||||||
|
_expect(pb._clamped_float("bad", 0.4) == row_generation.clamped_float("bad", 0.4) == 0.4, "Row generation float default changed")
|
||||||
|
|
||||||
|
_expect(
|
||||||
|
pb._pick_clothing_mode(random.Random(1), "random", None)
|
||||||
|
== row_generation.pick_clothing_mode(random.Random(1), "random", None),
|
||||||
|
"Prompt builder clothing mode picker should delegate to row_generation",
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
row_generation.pick_pose_mode(random.Random(2), "evocative", 1.0) == "standard",
|
||||||
|
"Row generation standard pose ratio override changed",
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
pb._pick_figure_bias(random.Random(3), "random") == row_generation.pick_figure_bias(random.Random(3), "random"),
|
||||||
|
"Prompt builder figure picker should delegate to row_generation",
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
row_generation.pick_expression_intensity(random.Random(4), -1) == (0.24, "random"),
|
||||||
|
"Row generation random expression intensity changed",
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
pb._pick_expression_intensity(random.Random(4), 2.0) == row_generation.pick_expression_intensity(random.Random(4), 2.0) == (1.0, "input"),
|
||||||
|
"Prompt builder expression intensity picker should delegate to row_generation",
|
||||||
|
)
|
||||||
|
|
||||||
|
direct_args = dict(
|
||||||
|
category="woman",
|
||||||
|
row_number=3,
|
||||||
|
start_index=41,
|
||||||
|
clothing="full",
|
||||||
|
ethnicity="any",
|
||||||
|
poses="standard",
|
||||||
|
backside_bias=0.25,
|
||||||
|
figure="curvy",
|
||||||
|
no_plus_women=False,
|
||||||
|
no_black=False,
|
||||||
|
minimal_clothing_ratio=None,
|
||||||
|
standard_pose_ratio=None,
|
||||||
|
seed=5050,
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
pb._build_direct_builtin_row(**direct_args) == row_generation.build_direct_builtin_row(**direct_args),
|
||||||
|
"Prompt builder direct built-in row should delegate to row_generation",
|
||||||
|
)
|
||||||
|
auto_args = dict(
|
||||||
|
row_number=2,
|
||||||
|
start_index=41,
|
||||||
|
clothing="minimal",
|
||||||
|
ethnicity="any",
|
||||||
|
poses="evocative",
|
||||||
|
backside_bias=0.0,
|
||||||
|
figure="balanced",
|
||||||
|
no_plus_women=False,
|
||||||
|
no_black=False,
|
||||||
|
minimal_clothing_ratio=None,
|
||||||
|
standard_pose_ratio=None,
|
||||||
|
seed=6060,
|
||||||
|
)
|
||||||
|
auto_row = row_generation.build_auto_weighted_row(**auto_args)
|
||||||
|
_expect(pb._build_auto_weighted_row(**auto_args) == auto_row, "Prompt builder auto-weighted row should delegate to row_generation")
|
||||||
|
_expect(auto_row.get("source") == "built_in_generator", "Row generation auto-weighted row lost source metadata")
|
||||||
|
|
||||||
|
seed_cfg = seed_config.parse_seed_config({"category_seed": 123})
|
||||||
|
_expect(
|
||||||
|
pb._auto_full_choice(seed_cfg, 7070, 1) == row_generation.auto_full_choice(seed_cfg, 7070, 1),
|
||||||
|
"Prompt builder auto-full choice should delegate to row_generation",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def smoke_category_cast_config_policy() -> None:
|
def smoke_category_cast_config_policy() -> None:
|
||||||
_expect(pb.CATEGORY_PRESETS is category_cast_config.CATEGORY_PRESETS, "Prompt builder category presets are not delegated")
|
_expect(pb.CATEGORY_PRESETS is category_cast_config.CATEGORY_PRESETS, "Prompt builder category presets are not delegated")
|
||||||
_expect(pb.CAST_PRESETS is category_cast_config.CAST_PRESETS, "Prompt builder cast presets are not delegated")
|
_expect(pb.CAST_PRESETS is category_cast_config.CAST_PRESETS, "Prompt builder cast presets are not delegated")
|
||||||
@@ -4010,6 +4082,7 @@ SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
|
|||||||
("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_item_policy", smoke_row_item_policy),
|
("row_item_policy", smoke_row_item_policy),
|
||||||
|
("row_generation_policy", smoke_row_generation_policy),
|
||||||
("category_cast_config_policy", smoke_category_cast_config_policy),
|
("category_cast_config_policy", smoke_category_cast_config_policy),
|
||||||
("generation_profile_config_policy", smoke_generation_profile_config_policy),
|
("generation_profile_config_policy", smoke_generation_profile_config_policy),
|
||||||
("filter_config_policy", smoke_filter_config_policy),
|
("filter_config_policy", smoke_filter_config_policy),
|
||||||
|
|||||||
Reference in New Issue
Block a user