Improve random prompt controls

This commit is contained in:
2026-06-25 14:24:34 +02:00
parent f2c768458f
commit 46ccbd3eac
3 changed files with 223 additions and 34 deletions
+52 -14
View File
@@ -1372,6 +1372,7 @@ def build_generation_profile_json(
profile: str = "balanced",
clothing_override: str = "profile_default",
poses_override: str = "profile_default",
expression_intensity_mode: str = "profile_default",
expression_intensity: float = -1.0,
backside_bias: float = -1.0,
minimal_clothing_ratio: float = -1.0,
@@ -1381,12 +1382,14 @@ def build_generation_profile_json(
) -> str:
profile = profile if profile in GENERATION_PROFILE_PRESETS else "balanced"
config = dict(GENERATION_PROFILE_PRESETS[profile])
if clothing_override in ("full", "minimal"):
if clothing_override in ("full", "minimal", "random"):
config["clothing"] = clothing_override
if poses_override in ("standard", "evocative"):
if poses_override in ("standard", "evocative", "random"):
config["poses"] = poses_override
config["expression_enabled"] = not _is_false(expression_enabled)
if float(expression_intensity) >= 0:
if expression_intensity_mode == "random":
config["expression_intensity"] = -1.0
elif expression_intensity_mode == "fixed" and float(expression_intensity) >= 0:
config["expression_intensity"] = _clamped_float(expression_intensity, config["expression_intensity"])
if float(backside_bias) >= 0:
config["backside_bias"] = _clamped_float(backside_bias, config["backside_bias"])
@@ -1417,10 +1420,14 @@ def _parse_generation_profile(profile_config: str | dict[str, Any] | None) -> di
profile = str(raw.get("profile") or "balanced")
parsed = dict(GENERATION_PROFILE_PRESETS.get(profile, GENERATION_PROFILE_PRESETS["balanced"]))
parsed.update(raw)
parsed["clothing"] = parsed["clothing"] if parsed.get("clothing") in ("full", "minimal") else "full"
parsed["poses"] = parsed["poses"] if parsed.get("poses") in ("standard", "evocative") else "standard"
parsed["clothing"] = parsed["clothing"] if parsed.get("clothing") in ("full", "minimal", "random") else "full"
parsed["poses"] = parsed["poses"] if parsed.get("poses") in ("standard", "evocative", "random") else "standard"
parsed["expression_enabled"] = not _is_false(parsed.get("expression_enabled", True))
parsed["expression_intensity"] = _clamped_float(parsed.get("expression_intensity"), 0.5)
try:
raw_expression_intensity = float(parsed.get("expression_intensity"))
except (TypeError, ValueError):
raw_expression_intensity = 0.5
parsed["expression_intensity"] = -1.0 if raw_expression_intensity < 0 else _clamped_float(raw_expression_intensity, 0.5)
parsed["backside_bias"] = _clamped_float(parsed.get("backside_bias"), 0.0)
parsed["minimal_clothing_ratio"] = _clamped_float(parsed.get("minimal_clothing_ratio"), -1.0, -1.0, 1.0)
parsed["standard_pose_ratio"] = _clamped_float(parsed.get("standard_pose_ratio"), -1.0, -1.0, 1.0)
@@ -1469,7 +1476,7 @@ def build_filter_config_json(
{
"ethnicity": ethnicity,
"ethnicity_includes": selected_ethnicities,
"figure": figure if figure in ("curvy", "balanced", "bombshell") else "curvy",
"figure": figure if figure in ("curvy", "balanced", "bombshell", "random") else "curvy",
"include_plus_size": bool(include_plus_size),
"include_black_african": bool(include_black_african),
"no_plus_women": not bool(include_plus_size) or bool(no_plus_women),
@@ -1620,7 +1627,7 @@ def _parse_filter_config(filter_config: str | dict[str, Any] | None) -> dict[str
raise ValueError("filter_config must be a JSON object")
parsed = {**defaults, **raw}
parsed["ethnicity"] = normalize_ethnicity_filter(parsed.get("ethnicity"), "any")
parsed["figure"] = parsed["figure"] if parsed.get("figure") in ("curvy", "balanced", "bombshell") else "curvy"
parsed["figure"] = parsed["figure"] if parsed.get("figure") in ("curvy", "balanced", "bombshell", "random") else "curvy"
parsed["include_plus_size"] = bool(parsed.get("include_plus_size"))
parsed["include_black_african"] = bool(parsed.get("include_black_african"))
parsed["no_plus_women"] = bool(parsed.get("no_plus_women"))
@@ -2765,17 +2772,37 @@ 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:
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,
@@ -5424,6 +5451,7 @@ def _build_custom_row(
seed_config: dict[str, int],
expression_enabled: bool,
expression_intensity: float,
expression_intensity_source: str = "input",
character_profile: str | dict[str, Any] | None = None,
character_cast: str | dict[str, Any] | list[Any] | None = None,
expression_phase: str = "",
@@ -5512,7 +5540,7 @@ def _build_custom_row(
role_graph = _pov_role_graph_prompt(source_role_graph, pov_character_labels)
cast_descriptors: list[str] = []
cast_descriptor_text = ""
expression_intensity_source = "input"
expression_intensity_source = expression_intensity_source or "input"
expression_disabled = not bool(expression_enabled)
if expression_disabled:
expression_intensity_source = "disabled"
@@ -5774,15 +5802,24 @@ def build_prompt(
row_number = max(1, int(row_number))
start_index = max(1, int(start_index))
seed = int(seed)
clothing = clothing if clothing in ("full", "minimal") else "full"
ethnicity = normalize_ethnicity_filter(ethnicity, "any")
poses = poses if poses in ("standard", "evocative") else "standard"
figure = figure if figure in ("curvy", "balanced", "bombshell") else "curvy"
expression_enabled = not _is_false(expression_enabled)
minimal_ratio = _ratio_or_none(minimal_clothing_ratio)
pose_ratio = _ratio_or_none(standard_pose_ratio)
expression_intensity = _clamped_float(expression_intensity, 0.5)
parsed_seed_config = _parse_seed_config(seed_config)
content_rng = _axis_rng(parsed_seed_config, "content", seed, row_number)
pose_axis_rng = _axis_rng(parsed_seed_config, "pose", seed, row_number)
person_rng = _axis_rng(parsed_seed_config, "person", seed, row_number)
expression_rng = _axis_rng(parsed_seed_config, "expression", seed, row_number)
clothing = clothing if clothing in ("full", "minimal", "random") else "full"
poses = poses if poses in ("standard", "evocative", "random") else "standard"
figure = figure if figure in ("curvy", "balanced", "bombshell", "random") else "curvy"
clothing = _pick_clothing_mode(content_rng, clothing, minimal_ratio)
poses = _pick_pose_mode(pose_axis_rng, poses, pose_ratio)
figure = _pick_figure_bias(person_rng, figure)
minimal_ratio = None
pose_ratio = None
expression_intensity, expression_intensity_source = _pick_expression_intensity(expression_rng, expression_intensity)
exact_custom_subcategory = bool(subcategory and subcategory != RANDOM_SUBCATEGORY and " / " in subcategory)
@@ -5834,6 +5871,7 @@ def build_prompt(
parsed_seed_config,
expression_enabled,
expression_intensity,
expression_intensity_source,
character_profile,
character_cast,
expression_phase,
@@ -5850,7 +5888,7 @@ def build_prompt(
row["negative_prompt"] = _combined_negative(row.get("negative_prompt", g.NEGATIVE_PROMPT), extra_negative)
row["trigger"] = active_trigger
row.setdefault("expression_intensity", expression_intensity)
row.setdefault("expression_intensity_source", "input")
row.setdefault("expression_intensity_source", expression_intensity_source)
return row