Extract builder prompt route
This commit is contained in:
@@ -0,0 +1,219 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Any, Callable
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class PromptBuildRequest:
|
||||||
|
category: str
|
||||||
|
subcategory: str
|
||||||
|
row_number: int
|
||||||
|
start_index: int
|
||||||
|
seed: int
|
||||||
|
clothing: str
|
||||||
|
ethnicity: str
|
||||||
|
poses: str
|
||||||
|
backside_bias: float
|
||||||
|
figure: str
|
||||||
|
no_plus_women: bool
|
||||||
|
no_black: bool
|
||||||
|
minimal_clothing_ratio: float
|
||||||
|
standard_pose_ratio: float
|
||||||
|
trigger: str
|
||||||
|
prepend_trigger_to_prompt: bool
|
||||||
|
extra_positive: str
|
||||||
|
extra_negative: str
|
||||||
|
seed_config: str | dict[str, Any] | None = None
|
||||||
|
women_count: int = 1
|
||||||
|
men_count: int = 1
|
||||||
|
camera_config: str | dict[str, Any] | None = None
|
||||||
|
expression_intensity: float = 0.5
|
||||||
|
character_profile: str | dict[str, Any] | None = None
|
||||||
|
character_cast: str | dict[str, Any] | list[Any] | None = None
|
||||||
|
expression_enabled: bool = True
|
||||||
|
expression_phase: str = ""
|
||||||
|
hardcore_position_config: str | dict[str, Any] | None = None
|
||||||
|
location_config: str | dict[str, Any] | None = None
|
||||||
|
composition_config: str | dict[str, Any] | None = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class PromptBuildRoute:
|
||||||
|
row: dict[str, Any]
|
||||||
|
category: str
|
||||||
|
subcategory: str
|
||||||
|
branch: str
|
||||||
|
parsed_seed_config: dict[str, Any]
|
||||||
|
expression_intensity: float
|
||||||
|
expression_intensity_source: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class PromptBuildDependencies:
|
||||||
|
default_trigger: str
|
||||||
|
default_negative: str
|
||||||
|
random_subcategory: str
|
||||||
|
apply_pool_extensions: Callable[[], Any]
|
||||||
|
normalize_ethnicity_filter: Callable[[Any, str], str]
|
||||||
|
is_false: Callable[[Any], bool]
|
||||||
|
ratio_or_none: Callable[[Any], float | None]
|
||||||
|
parse_seed_config: Callable[[str | dict[str, Any] | None], dict[str, Any]]
|
||||||
|
parse_location_config: Callable[[str | dict[str, Any] | None], dict[str, Any]]
|
||||||
|
parse_composition_config: Callable[[str | dict[str, Any] | None], dict[str, Any]]
|
||||||
|
axis_rng: Callable[[dict[str, Any], str, int, int], Any]
|
||||||
|
pick_clothing_mode: Callable[[Any, str, float | None], str]
|
||||||
|
pick_pose_mode: Callable[[Any, str, float | None], str]
|
||||||
|
pick_figure_bias: Callable[[Any, str], str]
|
||||||
|
pick_expression_intensity: Callable[[Any, Any], tuple[float, str]]
|
||||||
|
auto_full_choice: Callable[[dict[str, Any], int, int], str]
|
||||||
|
build_auto_weighted_row: Callable[..., dict[str, Any]]
|
||||||
|
build_direct_builtin_row: Callable[..., dict[str, Any]]
|
||||||
|
build_custom_row: Callable[..., dict[str, Any]]
|
||||||
|
apply_location_config_to_legacy_row: Callable[..., dict[str, Any]]
|
||||||
|
apply_composition_config_to_legacy_row: Callable[..., dict[str, Any]]
|
||||||
|
disable_row_expression: Callable[[dict[str, Any], str], dict[str, Any]]
|
||||||
|
apply_camera_config: Callable[[dict[str, Any], str | dict[str, Any] | None], dict[str, Any]]
|
||||||
|
normalize_prompt_row: Callable[..., dict[str, Any]]
|
||||||
|
|
||||||
|
|
||||||
|
def build_prompt_result(request: PromptBuildRequest, deps: PromptBuildDependencies) -> PromptBuildRoute:
|
||||||
|
deps.apply_pool_extensions()
|
||||||
|
row_number = max(1, int(request.row_number))
|
||||||
|
start_index = max(1, int(request.start_index))
|
||||||
|
seed = int(request.seed)
|
||||||
|
category = request.category
|
||||||
|
subcategory = request.subcategory
|
||||||
|
ethnicity = deps.normalize_ethnicity_filter(request.ethnicity, "any")
|
||||||
|
expression_enabled = not deps.is_false(request.expression_enabled)
|
||||||
|
minimal_ratio = deps.ratio_or_none(request.minimal_clothing_ratio)
|
||||||
|
pose_ratio = deps.ratio_or_none(request.standard_pose_ratio)
|
||||||
|
parsed_seed_config = deps.parse_seed_config(request.seed_config)
|
||||||
|
parsed_location_config = deps.parse_location_config(request.location_config)
|
||||||
|
parsed_composition_config = deps.parse_composition_config(request.composition_config)
|
||||||
|
content_rng = deps.axis_rng(parsed_seed_config, "content", seed, row_number)
|
||||||
|
pose_axis_rng = deps.axis_rng(parsed_seed_config, "pose", seed, row_number)
|
||||||
|
person_rng = deps.axis_rng(parsed_seed_config, "person", seed, row_number)
|
||||||
|
expression_rng = deps.axis_rng(parsed_seed_config, "expression", seed, row_number)
|
||||||
|
clothing = request.clothing if request.clothing in ("full", "minimal", "random") else "full"
|
||||||
|
poses = request.poses if request.poses in ("standard", "evocative", "random") else "standard"
|
||||||
|
figure = request.figure if request.figure in ("curvy", "balanced", "bombshell", "random") else "curvy"
|
||||||
|
clothing = deps.pick_clothing_mode(content_rng, clothing, minimal_ratio)
|
||||||
|
poses = deps.pick_pose_mode(pose_axis_rng, poses, pose_ratio)
|
||||||
|
figure = deps.pick_figure_bias(person_rng, figure)
|
||||||
|
minimal_ratio = None
|
||||||
|
pose_ratio = None
|
||||||
|
expression_intensity, expression_intensity_source = deps.pick_expression_intensity(
|
||||||
|
expression_rng,
|
||||||
|
request.expression_intensity,
|
||||||
|
)
|
||||||
|
|
||||||
|
exact_custom_subcategory = bool(
|
||||||
|
subcategory and subcategory != deps.random_subcategory and " / " in subcategory
|
||||||
|
)
|
||||||
|
|
||||||
|
if category == "auto_full" and not exact_custom_subcategory:
|
||||||
|
category = deps.auto_full_choice(parsed_seed_config, seed, row_number)
|
||||||
|
|
||||||
|
branch = "custom"
|
||||||
|
if category == "auto_weighted" and not exact_custom_subcategory:
|
||||||
|
branch = "auto_weighted"
|
||||||
|
row = deps.build_auto_weighted_row(
|
||||||
|
row_number,
|
||||||
|
start_index,
|
||||||
|
clothing,
|
||||||
|
ethnicity,
|
||||||
|
poses,
|
||||||
|
float(request.backside_bias),
|
||||||
|
figure,
|
||||||
|
bool(request.no_plus_women),
|
||||||
|
bool(request.no_black),
|
||||||
|
minimal_ratio,
|
||||||
|
pose_ratio,
|
||||||
|
seed,
|
||||||
|
)
|
||||||
|
elif category in ("woman", "man", "couple", "group_or_layout") and not exact_custom_subcategory:
|
||||||
|
branch = "built_in"
|
||||||
|
row = deps.build_direct_builtin_row(
|
||||||
|
category,
|
||||||
|
row_number,
|
||||||
|
start_index,
|
||||||
|
clothing,
|
||||||
|
ethnicity,
|
||||||
|
poses,
|
||||||
|
float(request.backside_bias),
|
||||||
|
figure,
|
||||||
|
bool(request.no_plus_women),
|
||||||
|
bool(request.no_black),
|
||||||
|
minimal_ratio,
|
||||||
|
pose_ratio,
|
||||||
|
seed,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
row = deps.build_custom_row(
|
||||||
|
category,
|
||||||
|
subcategory,
|
||||||
|
row_number,
|
||||||
|
start_index,
|
||||||
|
ethnicity,
|
||||||
|
poses,
|
||||||
|
figure,
|
||||||
|
bool(request.no_plus_women),
|
||||||
|
bool(request.no_black),
|
||||||
|
int(request.women_count),
|
||||||
|
int(request.men_count),
|
||||||
|
seed,
|
||||||
|
parsed_seed_config,
|
||||||
|
expression_enabled,
|
||||||
|
expression_intensity,
|
||||||
|
expression_intensity_source,
|
||||||
|
request.character_profile,
|
||||||
|
request.character_cast,
|
||||||
|
request.expression_phase,
|
||||||
|
request.hardcore_position_config,
|
||||||
|
parsed_location_config,
|
||||||
|
parsed_composition_config,
|
||||||
|
)
|
||||||
|
|
||||||
|
if row.get("source") == "built_in_generator":
|
||||||
|
row = deps.apply_location_config_to_legacy_row(
|
||||||
|
row,
|
||||||
|
parsed_location_config,
|
||||||
|
parsed_seed_config,
|
||||||
|
seed,
|
||||||
|
row_number,
|
||||||
|
)
|
||||||
|
row = deps.apply_composition_config_to_legacy_row(
|
||||||
|
row,
|
||||||
|
parsed_composition_config,
|
||||||
|
parsed_seed_config,
|
||||||
|
seed,
|
||||||
|
row_number,
|
||||||
|
)
|
||||||
|
if not expression_enabled:
|
||||||
|
row = deps.disable_row_expression(row, "disabled")
|
||||||
|
row = deps.apply_camera_config(row, request.camera_config)
|
||||||
|
active_trigger = request.trigger.strip() or deps.default_trigger
|
||||||
|
row = deps.normalize_prompt_row(
|
||||||
|
row,
|
||||||
|
active_trigger=active_trigger,
|
||||||
|
prepend_trigger_to_prompt=bool(request.prepend_trigger_to_prompt),
|
||||||
|
extra_positive=request.extra_positive,
|
||||||
|
extra_negative=request.extra_negative,
|
||||||
|
default_negative=deps.default_negative,
|
||||||
|
)
|
||||||
|
row.setdefault("expression_intensity", expression_intensity)
|
||||||
|
row.setdefault("expression_intensity_source", expression_intensity_source)
|
||||||
|
return PromptBuildRoute(
|
||||||
|
row=row,
|
||||||
|
category=category,
|
||||||
|
subcategory=subcategory,
|
||||||
|
branch=branch,
|
||||||
|
parsed_seed_config=dict(parsed_seed_config),
|
||||||
|
expression_intensity=expression_intensity,
|
||||||
|
expression_intensity_source=expression_intensity_source,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def build_prompt(request: PromptBuildRequest, deps: PromptBuildDependencies) -> dict[str, Any]:
|
||||||
|
return build_prompt_result(request, deps).row
|
||||||
@@ -120,6 +120,10 @@ Move or isolate later:
|
|||||||
|
|
||||||
Already isolated:
|
Already isolated:
|
||||||
|
|
||||||
|
- single-prompt builder orchestration, including input normalization, seed-axis
|
||||||
|
setup, built-in/custom row routing, legacy location/composition handling,
|
||||||
|
camera application, and final prompt-row normalization, lives in
|
||||||
|
`builder_prompt_route.py`; `prompt_builder.py` keeps the public wrapper.
|
||||||
- config-driven prompt-builder request parsing, helper-node config mapping, and
|
- config-driven prompt-builder request parsing, helper-node config mapping, and
|
||||||
direct `build_prompt` kwarg assembly live in `builder_config_route.py`;
|
direct `build_prompt` kwarg assembly live in `builder_config_route.py`;
|
||||||
`prompt_builder.py` keeps the public wrapper.
|
`prompt_builder.py` keeps the public wrapper.
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ call the same core generation functions.
|
|||||||
|
|
||||||
| ComfyUI node | Python entry | What it owns |
|
| ComfyUI node | Python entry | What it owns |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `SxCP Prompt Builder` | `build_prompt` | Direct single prompt generation. Can use built-in categories or JSON categories. |
|
| `SxCP Prompt Builder` | `build_prompt` -> `builder_prompt_route.py` | Direct single prompt generation. Can use built-in categories or JSON categories. |
|
||||||
| `SxCP Prompt Builder From Configs` | `build_prompt_from_configs` -> `builder_config_route.py` -> `build_prompt` | Same generator, but inputs come from category/cast/profile/filter helper nodes. |
|
| `SxCP Prompt Builder From Configs` | `build_prompt_from_configs` -> `builder_config_route.py` -> `build_prompt` -> `builder_prompt_route.py` | Same generator, but inputs come from category/cast/profile/filter helper nodes. |
|
||||||
| `SxCP Insta/OF Prompt Pair` | `build_insta_of_pair` | Builds a softcore row and hardcore row with shared cast/continuity options. |
|
| `SxCP Insta/OF Prompt Pair` | `build_insta_of_pair` | Builds a softcore row and hardcore row with shared cast/continuity options. |
|
||||||
| `SxCP Krea2 Formatter` | `format_krea2_prompt` | Converts metadata rows or pair metadata into Krea2-friendly prose. |
|
| `SxCP Krea2 Formatter` | `format_krea2_prompt` | Converts metadata rows or pair metadata into Krea2-friendly prose. |
|
||||||
| `SxCP SDXL Formatter` | `format_sdxl_prompt` | Converts metadata rows or pair metadata into SDXL/tag style prompts. |
|
| `SxCP SDXL Formatter` | `format_sdxl_prompt` | Converts metadata rows or pair metadata into SDXL/tag style prompts. |
|
||||||
@@ -72,6 +72,7 @@ Core helper ownership:
|
|||||||
| Python module | What it owns |
|
| Python module | What it owns |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `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. |
|
||||||
|
| `builder_prompt_route.py` | Single-prompt builder orchestration, input normalization, seed-axis setup, built-in/custom row routing, legacy location/composition handling, camera application, and final prompt-row normalization. |
|
||||||
| `builder_config_route.py` | Config-driven prompt-builder request parsing, category/cast/profile/filter helper-node mapping, and direct `build_prompt` kwarg assembly. |
|
| `builder_config_route.py` | Config-driven prompt-builder request parsing, category/cast/profile/filter helper-node mapping, and direct `build_prompt` kwarg assembly. |
|
||||||
| `category_extensions.py` | JSON `pool_extensions`, legacy pool patching, built-in category choice lists, and category/subcategory UI choices. |
|
| `category_extensions.py` | JSON `pool_extensions`, legacy pool patching, built-in category choice lists, and category/subcategory UI choices. |
|
||||||
| `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. |
|
||||||
|
|||||||
+65
-116
@@ -6,6 +6,7 @@ from typing import Any
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
from . import builder_config_route as builder_config_route_policy
|
from . import builder_config_route as builder_config_route_policy
|
||||||
|
from . import builder_prompt_route as builder_prompt_route_policy
|
||||||
from .category_library import (
|
from .category_library import (
|
||||||
compatible_entries as _compatible_entries,
|
compatible_entries as _compatible_entries,
|
||||||
compatible_entry as _compatible_entry,
|
compatible_entry as _compatible_entry,
|
||||||
@@ -53,6 +54,7 @@ try:
|
|||||||
)
|
)
|
||||||
except ImportError: # Allows local smoke tests with `python -c`.
|
except ImportError: # Allows local smoke tests with `python -c`.
|
||||||
import builder_config_route as builder_config_route_policy
|
import builder_config_route as builder_config_route_policy
|
||||||
|
import builder_prompt_route as builder_prompt_route_policy
|
||||||
from category_library import (
|
from category_library import (
|
||||||
compatible_entries as _compatible_entries,
|
compatible_entries as _compatible_entries,
|
||||||
compatible_entry as _compatible_entry,
|
compatible_entry as _compatible_entry,
|
||||||
@@ -2460,6 +2462,35 @@ def _build_custom_row(
|
|||||||
return _assemble_custom_row(assembly_request)
|
return _assemble_custom_row(assembly_request)
|
||||||
|
|
||||||
|
|
||||||
|
def _prompt_build_dependencies() -> builder_prompt_route_policy.PromptBuildDependencies:
|
||||||
|
return builder_prompt_route_policy.PromptBuildDependencies(
|
||||||
|
default_trigger=g.TRIGGER,
|
||||||
|
default_negative=g.NEGATIVE_PROMPT,
|
||||||
|
random_subcategory=RANDOM_SUBCATEGORY,
|
||||||
|
apply_pool_extensions=apply_pool_extensions,
|
||||||
|
normalize_ethnicity_filter=normalize_ethnicity_filter,
|
||||||
|
is_false=_is_false,
|
||||||
|
ratio_or_none=_ratio_or_none,
|
||||||
|
parse_seed_config=_parse_seed_config,
|
||||||
|
parse_location_config=_parse_location_config,
|
||||||
|
parse_composition_config=_parse_composition_config,
|
||||||
|
axis_rng=_axis_rng,
|
||||||
|
pick_clothing_mode=_pick_clothing_mode,
|
||||||
|
pick_pose_mode=_pick_pose_mode,
|
||||||
|
pick_figure_bias=_pick_figure_bias,
|
||||||
|
pick_expression_intensity=_pick_expression_intensity,
|
||||||
|
auto_full_choice=_auto_full_choice,
|
||||||
|
build_auto_weighted_row=_build_auto_weighted_row,
|
||||||
|
build_direct_builtin_row=_build_direct_builtin_row,
|
||||||
|
build_custom_row=_build_custom_row,
|
||||||
|
apply_location_config_to_legacy_row=row_location_policy.apply_location_config_to_legacy_row,
|
||||||
|
apply_composition_config_to_legacy_row=row_location_policy.apply_composition_config_to_legacy_row,
|
||||||
|
disable_row_expression=_disable_row_expression,
|
||||||
|
apply_camera_config=_apply_camera_config,
|
||||||
|
normalize_prompt_row=row_policy.normalize_prompt_row,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def build_prompt(
|
def build_prompt(
|
||||||
category: str,
|
category: str,
|
||||||
subcategory: str,
|
subcategory: str,
|
||||||
@@ -2492,123 +2523,41 @@ def build_prompt(
|
|||||||
location_config: str | dict[str, Any] | None = None,
|
location_config: str | dict[str, Any] | None = None,
|
||||||
composition_config: str | dict[str, Any] | None = None,
|
composition_config: str | dict[str, Any] | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
apply_pool_extensions()
|
return builder_prompt_route_policy.build_prompt(
|
||||||
row_number = max(1, int(row_number))
|
builder_prompt_route_policy.PromptBuildRequest(
|
||||||
start_index = max(1, int(start_index))
|
category=category,
|
||||||
seed = int(seed)
|
subcategory=subcategory,
|
||||||
ethnicity = normalize_ethnicity_filter(ethnicity, "any")
|
row_number=row_number,
|
||||||
expression_enabled = not _is_false(expression_enabled)
|
start_index=start_index,
|
||||||
minimal_ratio = _ratio_or_none(minimal_clothing_ratio)
|
seed=seed,
|
||||||
pose_ratio = _ratio_or_none(standard_pose_ratio)
|
clothing=clothing,
|
||||||
parsed_seed_config = _parse_seed_config(seed_config)
|
ethnicity=ethnicity,
|
||||||
parsed_location_config = _parse_location_config(location_config)
|
poses=poses,
|
||||||
parsed_composition_config = _parse_composition_config(composition_config)
|
backside_bias=backside_bias,
|
||||||
content_rng = _axis_rng(parsed_seed_config, "content", seed, row_number)
|
figure=figure,
|
||||||
pose_axis_rng = _axis_rng(parsed_seed_config, "pose", seed, row_number)
|
no_plus_women=no_plus_women,
|
||||||
person_rng = _axis_rng(parsed_seed_config, "person", seed, row_number)
|
no_black=no_black,
|
||||||
expression_rng = _axis_rng(parsed_seed_config, "expression", seed, row_number)
|
minimal_clothing_ratio=minimal_clothing_ratio,
|
||||||
clothing = clothing if clothing in ("full", "minimal", "random") else "full"
|
standard_pose_ratio=standard_pose_ratio,
|
||||||
poses = poses if poses in ("standard", "evocative", "random") else "standard"
|
trigger=trigger,
|
||||||
figure = figure if figure in ("curvy", "balanced", "bombshell", "random") else "curvy"
|
prepend_trigger_to_prompt=prepend_trigger_to_prompt,
|
||||||
clothing = _pick_clothing_mode(content_rng, clothing, minimal_ratio)
|
extra_positive=extra_positive,
|
||||||
poses = _pick_pose_mode(pose_axis_rng, poses, pose_ratio)
|
extra_negative=extra_negative,
|
||||||
figure = _pick_figure_bias(person_rng, figure)
|
seed_config=seed_config,
|
||||||
minimal_ratio = None
|
women_count=women_count,
|
||||||
pose_ratio = None
|
men_count=men_count,
|
||||||
expression_intensity, expression_intensity_source = _pick_expression_intensity(expression_rng, expression_intensity)
|
camera_config=camera_config,
|
||||||
|
expression_intensity=expression_intensity,
|
||||||
exact_custom_subcategory = bool(subcategory and subcategory != RANDOM_SUBCATEGORY and " / " in subcategory)
|
character_profile=character_profile,
|
||||||
|
character_cast=character_cast,
|
||||||
if category == "auto_full" and not exact_custom_subcategory:
|
expression_enabled=expression_enabled,
|
||||||
category = _auto_full_choice(parsed_seed_config, seed, row_number)
|
expression_phase=expression_phase,
|
||||||
|
hardcore_position_config=hardcore_position_config,
|
||||||
if category == "auto_weighted" and not exact_custom_subcategory:
|
location_config=location_config,
|
||||||
row = _build_auto_weighted_row(
|
composition_config=composition_config,
|
||||||
row_number,
|
),
|
||||||
start_index,
|
_prompt_build_dependencies(),
|
||||||
clothing,
|
|
||||||
ethnicity,
|
|
||||||
poses,
|
|
||||||
float(backside_bias),
|
|
||||||
figure,
|
|
||||||
bool(no_plus_women),
|
|
||||||
bool(no_black),
|
|
||||||
minimal_ratio,
|
|
||||||
pose_ratio,
|
|
||||||
seed,
|
|
||||||
)
|
|
||||||
elif category in ("woman", "man", "couple", "group_or_layout") and not exact_custom_subcategory:
|
|
||||||
row = _build_direct_builtin_row(
|
|
||||||
category,
|
|
||||||
row_number,
|
|
||||||
start_index,
|
|
||||||
clothing,
|
|
||||||
ethnicity,
|
|
||||||
poses,
|
|
||||||
float(backside_bias),
|
|
||||||
figure,
|
|
||||||
bool(no_plus_women),
|
|
||||||
bool(no_black),
|
|
||||||
minimal_ratio,
|
|
||||||
pose_ratio,
|
|
||||||
seed,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
row = _build_custom_row(
|
|
||||||
category,
|
|
||||||
subcategory,
|
|
||||||
row_number,
|
|
||||||
start_index,
|
|
||||||
ethnicity,
|
|
||||||
poses,
|
|
||||||
figure,
|
|
||||||
bool(no_plus_women),
|
|
||||||
bool(no_black),
|
|
||||||
int(women_count),
|
|
||||||
int(men_count),
|
|
||||||
seed,
|
|
||||||
parsed_seed_config,
|
|
||||||
expression_enabled,
|
|
||||||
expression_intensity,
|
|
||||||
expression_intensity_source,
|
|
||||||
character_profile,
|
|
||||||
character_cast,
|
|
||||||
expression_phase,
|
|
||||||
hardcore_position_config,
|
|
||||||
parsed_location_config,
|
|
||||||
parsed_composition_config,
|
|
||||||
)
|
|
||||||
|
|
||||||
if row.get("source") == "built_in_generator":
|
|
||||||
row = row_location_policy.apply_location_config_to_legacy_row(
|
|
||||||
row,
|
|
||||||
parsed_location_config,
|
|
||||||
parsed_seed_config,
|
|
||||||
seed,
|
|
||||||
row_number,
|
|
||||||
)
|
|
||||||
row = row_location_policy.apply_composition_config_to_legacy_row(
|
|
||||||
row,
|
|
||||||
parsed_composition_config,
|
|
||||||
parsed_seed_config,
|
|
||||||
seed,
|
|
||||||
row_number,
|
|
||||||
)
|
|
||||||
if not expression_enabled:
|
|
||||||
row = _disable_row_expression(row, "disabled")
|
|
||||||
row = _apply_camera_config(row, camera_config)
|
|
||||||
active_trigger = trigger.strip() or g.TRIGGER
|
|
||||||
row = row_policy.normalize_prompt_row(
|
|
||||||
row,
|
|
||||||
active_trigger=active_trigger,
|
|
||||||
prepend_trigger_to_prompt=bool(prepend_trigger_to_prompt),
|
|
||||||
extra_positive=extra_positive,
|
|
||||||
extra_negative=extra_negative,
|
|
||||||
default_negative=g.NEGATIVE_PROMPT,
|
|
||||||
)
|
)
|
||||||
row.setdefault("expression_intensity", expression_intensity)
|
|
||||||
row.setdefault("expression_intensity_source", expression_intensity_source)
|
|
||||||
return row
|
|
||||||
|
|
||||||
|
|
||||||
def _prompt_from_configs_dependencies() -> builder_config_route_policy.PromptFromConfigsDependencies:
|
def _prompt_from_configs_dependencies() -> builder_config_route_policy.PromptFromConfigsDependencies:
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import caption_metadata_routes # noqa: E402
|
|||||||
import caption_policy # noqa: E402
|
import caption_policy # noqa: E402
|
||||||
import caption_text_policy # noqa: E402
|
import caption_text_policy # noqa: E402
|
||||||
import builder_config_route # noqa: E402
|
import builder_config_route # noqa: E402
|
||||||
|
import builder_prompt_route # noqa: E402
|
||||||
import cast_context # noqa: E402
|
import cast_context # noqa: E402
|
||||||
import category_extensions # noqa: E402
|
import category_extensions # noqa: E402
|
||||||
import category_template_metadata # noqa: E402
|
import category_template_metadata # noqa: E402
|
||||||
@@ -605,6 +606,75 @@ def smoke_config_route_location_theme() -> None:
|
|||||||
_expect_formatter_outputs(row, "config_route_location_theme", target="single")
|
_expect_formatter_outputs(row, "config_route_location_theme", target="single")
|
||||||
|
|
||||||
|
|
||||||
|
def smoke_builder_prompt_route_policy() -> None:
|
||||||
|
seed_config_json = pb.build_seed_lock_config_json(base_seed=3501, reroll_axis="content", reroll_seed=3502)
|
||||||
|
request = builder_prompt_route.PromptBuildRequest(
|
||||||
|
category="Casual clothes",
|
||||||
|
subcategory="Casual clothes / Smart casual",
|
||||||
|
row_number=3,
|
||||||
|
start_index=8,
|
||||||
|
seed=3501,
|
||||||
|
clothing="random",
|
||||||
|
ethnicity="french_european",
|
||||||
|
poses="random",
|
||||||
|
backside_bias=0.2,
|
||||||
|
figure="random",
|
||||||
|
no_plus_women=False,
|
||||||
|
no_black=False,
|
||||||
|
minimal_clothing_ratio=0.3,
|
||||||
|
standard_pose_ratio=0.4,
|
||||||
|
trigger="sxcpinup_coloredpencil",
|
||||||
|
prepend_trigger_to_prompt=True,
|
||||||
|
extra_positive="typed builder route marker",
|
||||||
|
extra_negative="typed builder negative marker",
|
||||||
|
seed_config=seed_config_json,
|
||||||
|
women_count=1,
|
||||||
|
men_count=0,
|
||||||
|
camera_config=_orbit_camera(horizontal_angle=45, vertical_angle=0, zoom=5.5),
|
||||||
|
expression_intensity=0.6,
|
||||||
|
expression_enabled=True,
|
||||||
|
)
|
||||||
|
typed_route = builder_prompt_route.build_prompt_result(request, pb._prompt_build_dependencies())
|
||||||
|
legacy_row = pb.build_prompt(
|
||||||
|
category=request.category,
|
||||||
|
subcategory=request.subcategory,
|
||||||
|
row_number=request.row_number,
|
||||||
|
start_index=request.start_index,
|
||||||
|
seed=request.seed,
|
||||||
|
clothing=request.clothing,
|
||||||
|
ethnicity=request.ethnicity,
|
||||||
|
poses=request.poses,
|
||||||
|
backside_bias=request.backside_bias,
|
||||||
|
figure=request.figure,
|
||||||
|
no_plus_women=request.no_plus_women,
|
||||||
|
no_black=request.no_black,
|
||||||
|
minimal_clothing_ratio=request.minimal_clothing_ratio,
|
||||||
|
standard_pose_ratio=request.standard_pose_ratio,
|
||||||
|
trigger=request.trigger,
|
||||||
|
prepend_trigger_to_prompt=request.prepend_trigger_to_prompt,
|
||||||
|
extra_positive=request.extra_positive,
|
||||||
|
extra_negative=request.extra_negative,
|
||||||
|
seed_config=request.seed_config,
|
||||||
|
women_count=request.women_count,
|
||||||
|
men_count=request.men_count,
|
||||||
|
camera_config=request.camera_config,
|
||||||
|
expression_intensity=request.expression_intensity,
|
||||||
|
expression_enabled=request.expression_enabled,
|
||||||
|
)
|
||||||
|
_expect(typed_route.row == legacy_row, "Typed builder prompt route should match public wrapper output")
|
||||||
|
_expect(typed_route.category == "Casual clothes", "Builder prompt route changed category")
|
||||||
|
_expect(typed_route.subcategory == "Casual clothes / Smart casual", "Builder prompt route changed subcategory")
|
||||||
|
_expect(typed_route.branch == "custom", "Builder prompt route should use custom branch for category JSON route")
|
||||||
|
_expect(typed_route.parsed_seed_config.get("content_seed") == 3502, "Builder prompt route lost seed config")
|
||||||
|
_expect("typed builder route marker" in typed_route.row.get("prompt", ""), "Builder prompt route lost extra positive")
|
||||||
|
_expect("typed builder negative marker" in typed_route.row.get("negative_prompt", ""), "Builder prompt route lost extra negative")
|
||||||
|
_expect(
|
||||||
|
"45-degree front-right quarter view" in typed_route.row.get("camera_directive", ""),
|
||||||
|
"Builder prompt route lost camera config",
|
||||||
|
)
|
||||||
|
_expect_trigger_once("builder_prompt_route_policy.prompt", typed_route.row.get("prompt"), "sxcpinup_coloredpencil")
|
||||||
|
|
||||||
|
|
||||||
def smoke_builder_config_route_policy() -> None:
|
def smoke_builder_config_route_policy() -> None:
|
||||||
category_config = pb.build_category_config_json("women_casual", "Casual clothes / Smart casual")
|
category_config = pb.build_category_config_json("women_casual", "Casual clothes / Smart casual")
|
||||||
cast_config = pb.build_cast_config_json("solo_woman")
|
cast_config = pb.build_cast_config_json("solo_woman")
|
||||||
@@ -5422,6 +5492,7 @@ SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
|
|||||||
("camera_scene_single", smoke_camera_scene_single),
|
("camera_scene_single", smoke_camera_scene_single),
|
||||||
("row_camera_policy", smoke_row_camera_policy),
|
("row_camera_policy", smoke_row_camera_policy),
|
||||||
("config_route_location_theme", smoke_config_route_location_theme),
|
("config_route_location_theme", smoke_config_route_location_theme),
|
||||||
|
("builder_prompt_route_policy", smoke_builder_prompt_route_policy),
|
||||||
("builder_config_route_policy", smoke_builder_config_route_policy),
|
("builder_config_route_policy", smoke_builder_config_route_policy),
|
||||||
("krea_normal_row_routes", smoke_krea_normal_row_routes),
|
("krea_normal_row_routes", smoke_krea_normal_row_routes),
|
||||||
("krea_row_fields_policy", smoke_krea_row_fields_policy),
|
("krea_row_fields_policy", smoke_krea_row_fields_policy),
|
||||||
|
|||||||
Reference in New Issue
Block a user