Extract row rendering policy
This commit is contained in:
@@ -131,6 +131,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.
|
||||||
|
- row prompt/caption template selection, safe formatting, default prompt
|
||||||
|
templates, configured-cast descriptor insertion, and POV directive insertion
|
||||||
|
live in `row_rendering.py`; `prompt_builder.py` keeps compatibility aliases.
|
||||||
- row action/position route metadata resolution, template metadata precedence,
|
- row action/position route metadata resolution, template metadata precedence,
|
||||||
inferred position-key merging, and source action-family fallback live in
|
inferred position-key merging, and source action-family fallback live in
|
||||||
`row_route_metadata.py`; `prompt_builder.py` keeps a public delegate wrapper.
|
`row_route_metadata.py`; `prompt_builder.py` keeps a public delegate wrapper.
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ Core helper ownership:
|
|||||||
| `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. |
|
||||||
| `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_rendering.py` | Row prompt/caption template selection, safe formatting, default prompt templates, configured-cast descriptor insertion, and POV directive insertion. |
|
||||||
| `row_route_metadata.py` | Row action/position route metadata resolution, template metadata precedence, inferred position-key merging, and source action-family fallback. |
|
| `row_route_metadata.py` | Row action/position route metadata resolution, template metadata precedence, inferred position-key merging, and source action-family fallback. |
|
||||||
| `row_generation.py` | Built-in legacy row generation, auto-weighted/auto-full selection, row mode randomization, ratio clamps, and expression-intensity randomization. |
|
| `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. |
|
||||||
@@ -245,7 +246,8 @@ Important JSON keys:
|
|||||||
- `expression_pool` / `expression_pools` or direct `expressions`: expression road.
|
- `expression_pool` / `expression_pools` or direct `expressions`: expression road.
|
||||||
- `composition_pool` / `composition_pools` or direct `compositions`: framing road.
|
- `composition_pool` / `composition_pools` or direct `compositions`: framing road.
|
||||||
- `poses`: category-specific pose fallback.
|
- `poses`: category-specific pose fallback.
|
||||||
- `prompt_template` / `caption_template`: final prompt assembly for that category.
|
- `prompt_template` / `caption_template`: final row prompt/caption assembly,
|
||||||
|
selected and formatted by `row_rendering.py`.
|
||||||
- `inherit_scenes`, `inherit_expressions`, `inherit_compositions`: stop or allow
|
- `inherit_scenes`, `inherit_expressions`, `inherit_compositions`: stop or allow
|
||||||
inheritance from category/subcategory/item levels.
|
inheritance from category/subcategory/item levels.
|
||||||
- `pool_extensions`: patch legacy pools from JSON through `category_extensions.py`.
|
- `pool_extensions`: patch legacy pools from JSON through `category_extensions.py`.
|
||||||
|
|||||||
+19
-66
@@ -1,9 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import random
|
import random
|
||||||
import re
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from string import Formatter
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -42,6 +40,7 @@ try:
|
|||||||
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
|
||||||
|
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
|
||||||
from . import seed_config as seed_policy
|
from . import seed_config as seed_policy
|
||||||
from . import subject_context as subject_context_policy
|
from . import subject_context as subject_context_policy
|
||||||
@@ -86,6 +85,7 @@ except ImportError: # Allows local smoke tests with `python -c`.
|
|||||||
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
|
||||||
|
import row_rendering as row_rendering_policy
|
||||||
import row_route_metadata as row_route_policy
|
import row_route_metadata as row_route_policy
|
||||||
import seed_config as seed_policy
|
import seed_config as seed_policy
|
||||||
import subject_context as subject_context_policy
|
import subject_context as subject_context_policy
|
||||||
@@ -146,34 +146,11 @@ def _hardcore_position_keys(*parts: Any, axis_values: dict[str, Any] | None = No
|
|||||||
CAMERA_ORBIT_FRAMING_CHOICES = camera_policy.CAMERA_ORBIT_FRAMING_CHOICES
|
CAMERA_ORBIT_FRAMING_CHOICES = camera_policy.CAMERA_ORBIT_FRAMING_CHOICES
|
||||||
CAMERA_ORBIT_FOCUS_CHOICES = camera_policy.CAMERA_ORBIT_FOCUS_CHOICES
|
CAMERA_ORBIT_FOCUS_CHOICES = camera_policy.CAMERA_ORBIT_FOCUS_CHOICES
|
||||||
|
|
||||||
GENERIC_POSITIVE_SUFFIX = (
|
GENERIC_POSITIVE_SUFFIX = row_rendering_policy.GENERIC_POSITIVE_SUFFIX
|
||||||
"Use crisp clean comic linework, detailed hatching, soft blended shading, "
|
SINGLE_TEMPLATE = row_rendering_policy.SINGLE_TEMPLATE
|
||||||
"pastel skin tones, muted blues and pinks, warm sensual lighting, and tactile textured paper."
|
COUPLE_TEMPLATE = row_rendering_policy.COUPLE_TEMPLATE
|
||||||
)
|
GROUP_TEMPLATE = row_rendering_policy.GROUP_TEMPLATE
|
||||||
|
LAYOUT_TEMPLATE = row_rendering_policy.LAYOUT_TEMPLATE
|
||||||
SINGLE_TEMPLATE = (
|
|
||||||
"A {subject}: {style}, {age}, {body_phrase}, {skin}, {hair}, {eyes}. "
|
|
||||||
"{item_label}: {item}. Scene: {scene}. Pose: {pose}. Facial expression: {expression}. "
|
|
||||||
"Composition: {composition_prompt}. {positive_suffix} Avoid: {negative_prompt}."
|
|
||||||
)
|
|
||||||
|
|
||||||
COUPLE_TEMPLATE = (
|
|
||||||
"{subject_phrase}: {style}. Ages: {age}. Body types: {body}. {item_label}: {item}. "
|
|
||||||
"Scene: {scene}. Pose: {pose}. Facial expressions: {expression}. "
|
|
||||||
"Composition: {composition_prompt}. {positive_suffix} Avoid: {negative_prompt}."
|
|
||||||
)
|
|
||||||
|
|
||||||
GROUP_TEMPLATE = (
|
|
||||||
"{subject_phrase}: {style}, ages {age}, diverse adult body types. {item_label}: {item}. "
|
|
||||||
"Scene: {scene}. Facial expressions: {expression}. Composition: {composition_prompt}. "
|
|
||||||
"{positive_suffix} Avoid: {negative_prompt}."
|
|
||||||
)
|
|
||||||
|
|
||||||
LAYOUT_TEMPLATE = (
|
|
||||||
"{item}: {style}, adults only, clean designed composition. Scene: {scene}. "
|
|
||||||
"Facial expression: {expression}. Composition: {composition}. {positive_suffix} "
|
|
||||||
"Avoid: {negative_prompt}. Use no readable text unless the layout naturally needs small decorative placeholder marks."
|
|
||||||
)
|
|
||||||
|
|
||||||
CAMERA_MODE_PROMPTS = camera_policy.CAMERA_MODE_PROMPTS
|
CAMERA_MODE_PROMPTS = camera_policy.CAMERA_MODE_PROMPTS
|
||||||
CAMERA_COMPACT_LABELS = camera_policy.CAMERA_COMPACT_LABELS
|
CAMERA_COMPACT_LABELS = camera_policy.CAMERA_COMPACT_LABELS
|
||||||
@@ -186,9 +163,7 @@ CAMERA_PHONE_PROMPTS = camera_policy.CAMERA_PHONE_PROMPTS
|
|||||||
CAMERA_PRIORITY_PROMPTS = camera_policy.CAMERA_PRIORITY_PROMPTS
|
CAMERA_PRIORITY_PROMPTS = camera_policy.CAMERA_PRIORITY_PROMPTS
|
||||||
|
|
||||||
|
|
||||||
class SafeFormatDict(dict):
|
SafeFormatDict = row_rendering_policy.SafeFormatDict
|
||||||
def __missing__(self, key: str) -> str:
|
|
||||||
return "{" + key + "}"
|
|
||||||
|
|
||||||
|
|
||||||
def _slug(value: str) -> str:
|
def _slug(value: str) -> str:
|
||||||
@@ -812,11 +787,7 @@ def _is_pose_content_category(category: dict[str, Any], subcategory: dict[str, A
|
|||||||
|
|
||||||
|
|
||||||
def _format(template: str, context: dict[str, Any]) -> str:
|
def _format(template: str, context: dict[str, Any]) -> str:
|
||||||
fields = {key for _, key, _, _ in Formatter().parse(template) if key}
|
return row_rendering_policy.format_template(template, context)
|
||||||
safe_context = SafeFormatDict({key: str(value) for key, value in context.items()})
|
|
||||||
for field in fields:
|
|
||||||
safe_context.setdefault(field, "{" + field + "}")
|
|
||||||
return template.format_map(safe_context)
|
|
||||||
|
|
||||||
|
|
||||||
def _clean_prompt_punctuation(text: str) -> str:
|
def _clean_prompt_punctuation(text: str) -> str:
|
||||||
@@ -2294,35 +2265,17 @@ def _build_custom_row(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if isinstance(item, dict) and "prompt_template" in item:
|
rendered = row_rendering_policy.render_prompt_caption(
|
||||||
template = str(item["prompt_template"])
|
item=item,
|
||||||
else:
|
subcategory=subcategory,
|
||||||
template = str(subcategory.get("prompt_template") or category.get("prompt_template") or "")
|
category=category,
|
||||||
if not template:
|
subject_type=subject_type,
|
||||||
if subject_type in ("woman", "man"):
|
context=context,
|
||||||
template = SINGLE_TEMPLATE
|
cast_descriptor_text=cast_descriptor_text,
|
||||||
elif subject_type == "couple":
|
pov_prompt_directive=_pov_prompt_directive(pov_character_labels) if pov_character_labels else "",
|
||||||
template = COUPLE_TEMPLATE
|
|
||||||
elif subject_type == "group":
|
|
||||||
template = GROUP_TEMPLATE
|
|
||||||
else:
|
|
||||||
template = LAYOUT_TEMPLATE
|
|
||||||
|
|
||||||
caption_template = str(
|
|
||||||
(item.get("caption_template") if isinstance(item, dict) else None)
|
|
||||||
or subcategory.get("caption_template")
|
|
||||||
or category.get("caption_template")
|
|
||||||
or "{trigger}, {subject_phrase}, {age}, {item}, {scene}, {composition}, coloured pencil comic illustration"
|
|
||||||
)
|
)
|
||||||
|
prompt = rendered["prompt"]
|
||||||
prompt = _format(template, context)
|
caption = rendered["caption"]
|
||||||
if subject_type == "configured_cast" and cast_descriptor_text and "{cast_descriptors}" not in template:
|
|
||||||
prompt = _insert_positive_directive(prompt, f"Characters: {cast_descriptor_text}.")
|
|
||||||
if subject_type == "configured_cast" and pov_character_labels:
|
|
||||||
prompt = _insert_positive_directive(prompt, _pov_prompt_directive(pov_character_labels))
|
|
||||||
caption = _format(caption_template, context)
|
|
||||||
if subject_type == "configured_cast" and cast_descriptor_text and "{cast_descriptors}" not in caption_template:
|
|
||||||
caption = f"{caption.rstrip()}, {cast_descriptor_text}"
|
|
||||||
batch = max(1, ((row_number - 1) // g.BATCH_SIZE) + 1)
|
batch = max(1, ((row_number - 1) // g.BATCH_SIZE) + 1)
|
||||||
index = start_index + row_number - 1
|
index = start_index + row_number - 1
|
||||||
row = g.row_base(index, batch, context["subject"], context["age"], context["body"], scene_slug, composition)
|
row = g.row_base(index, batch, context["subject"], context["age"], context["body"], scene_slug, composition)
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from string import Formatter
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
try:
|
||||||
|
from . import row_camera as row_camera_policy
|
||||||
|
except ImportError: # Allows local smoke tests from the repository root.
|
||||||
|
import row_camera as row_camera_policy
|
||||||
|
|
||||||
|
|
||||||
|
GENERIC_POSITIVE_SUFFIX = (
|
||||||
|
"Use crisp clean comic linework, detailed hatching, soft blended shading, "
|
||||||
|
"pastel skin tones, muted blues and pinks, warm sensual lighting, and tactile textured paper."
|
||||||
|
)
|
||||||
|
|
||||||
|
SINGLE_TEMPLATE = (
|
||||||
|
"A {subject}: {style}, {age}, {body_phrase}, {skin}, {hair}, {eyes}. "
|
||||||
|
"{item_label}: {item}. Scene: {scene}. Pose: {pose}. Facial expression: {expression}. "
|
||||||
|
"Composition: {composition_prompt}. {positive_suffix} Avoid: {negative_prompt}."
|
||||||
|
)
|
||||||
|
|
||||||
|
COUPLE_TEMPLATE = (
|
||||||
|
"{subject_phrase}: {style}. Ages: {age}. Body types: {body}. {item_label}: {item}. "
|
||||||
|
"Scene: {scene}. Pose: {pose}. Facial expressions: {expression}. "
|
||||||
|
"Composition: {composition_prompt}. {positive_suffix} Avoid: {negative_prompt}."
|
||||||
|
)
|
||||||
|
|
||||||
|
GROUP_TEMPLATE = (
|
||||||
|
"{subject_phrase}: {style}, ages {age}, diverse adult body types. {item_label}: {item}. "
|
||||||
|
"Scene: {scene}. Facial expressions: {expression}. Composition: {composition_prompt}. "
|
||||||
|
"{positive_suffix} Avoid: {negative_prompt}."
|
||||||
|
)
|
||||||
|
|
||||||
|
LAYOUT_TEMPLATE = (
|
||||||
|
"{item}: {style}, adults only, clean designed composition. Scene: {scene}. "
|
||||||
|
"Facial expression: {expression}. Composition: {composition}. {positive_suffix} "
|
||||||
|
"Avoid: {negative_prompt}. Use no readable text unless the layout naturally needs small decorative placeholder marks."
|
||||||
|
)
|
||||||
|
|
||||||
|
DEFAULT_CAPTION_TEMPLATE = (
|
||||||
|
"{trigger}, {subject_phrase}, {age}, {item}, {scene}, {composition}, coloured pencil comic illustration"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SafeFormatDict(dict):
|
||||||
|
def __missing__(self, key: str) -> str:
|
||||||
|
return "{" + key + "}"
|
||||||
|
|
||||||
|
|
||||||
|
def format_template(template: str, context: dict[str, Any]) -> str:
|
||||||
|
fields = {key for _, key, _, _ in Formatter().parse(template) if key}
|
||||||
|
safe_context = SafeFormatDict({key: str(value) for key, value in context.items()})
|
||||||
|
for field in fields:
|
||||||
|
safe_context.setdefault(field, "{" + field + "}")
|
||||||
|
return template.format_map(safe_context)
|
||||||
|
|
||||||
|
|
||||||
|
def default_prompt_template(subject_type: str) -> str:
|
||||||
|
if subject_type in ("woman", "man"):
|
||||||
|
return SINGLE_TEMPLATE
|
||||||
|
if subject_type == "couple":
|
||||||
|
return COUPLE_TEMPLATE
|
||||||
|
if subject_type == "group":
|
||||||
|
return GROUP_TEMPLATE
|
||||||
|
return LAYOUT_TEMPLATE
|
||||||
|
|
||||||
|
|
||||||
|
def prompt_template_for(item: Any, subcategory: dict[str, Any], category: dict[str, Any], subject_type: str) -> str:
|
||||||
|
if isinstance(item, dict) and "prompt_template" in item:
|
||||||
|
return str(item["prompt_template"])
|
||||||
|
template = str(subcategory.get("prompt_template") or category.get("prompt_template") or "")
|
||||||
|
return template or default_prompt_template(subject_type)
|
||||||
|
|
||||||
|
|
||||||
|
def caption_template_for(item: Any, subcategory: dict[str, Any], category: dict[str, Any]) -> str:
|
||||||
|
return str(
|
||||||
|
(item.get("caption_template") if isinstance(item, dict) else None)
|
||||||
|
or subcategory.get("caption_template")
|
||||||
|
or category.get("caption_template")
|
||||||
|
or DEFAULT_CAPTION_TEMPLATE
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def render_prompt_caption(
|
||||||
|
*,
|
||||||
|
item: Any,
|
||||||
|
subcategory: dict[str, Any],
|
||||||
|
category: dict[str, Any],
|
||||||
|
subject_type: str,
|
||||||
|
context: dict[str, Any],
|
||||||
|
cast_descriptor_text: str = "",
|
||||||
|
pov_prompt_directive: str = "",
|
||||||
|
) -> dict[str, str]:
|
||||||
|
prompt_template = prompt_template_for(item, subcategory, category, subject_type)
|
||||||
|
caption_template = caption_template_for(item, subcategory, category)
|
||||||
|
|
||||||
|
prompt = format_template(prompt_template, context)
|
||||||
|
if subject_type == "configured_cast" and cast_descriptor_text and "{cast_descriptors}" not in prompt_template:
|
||||||
|
prompt = row_camera_policy.insert_positive_directive(prompt, f"Characters: {cast_descriptor_text}.")
|
||||||
|
if subject_type == "configured_cast" and pov_prompt_directive:
|
||||||
|
prompt = row_camera_policy.insert_positive_directive(prompt, pov_prompt_directive)
|
||||||
|
|
||||||
|
caption = format_template(caption_template, context)
|
||||||
|
if subject_type == "configured_cast" and cast_descriptor_text and "{cast_descriptors}" not in caption_template:
|
||||||
|
caption = f"{caption.rstrip()}, {cast_descriptor_text}"
|
||||||
|
|
||||||
|
return {
|
||||||
|
"prompt": prompt,
|
||||||
|
"caption": caption,
|
||||||
|
"prompt_template": prompt_template,
|
||||||
|
"caption_template": caption_template,
|
||||||
|
}
|
||||||
@@ -57,6 +57,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_rendering # noqa: E402
|
||||||
import row_route_metadata # noqa: E402
|
import row_route_metadata # noqa: E402
|
||||||
import server_routes # noqa: E402
|
import server_routes # noqa: E402
|
||||||
import sdxl_formatter # noqa: E402
|
import sdxl_formatter # noqa: E402
|
||||||
@@ -1402,6 +1403,73 @@ def smoke_row_normalization_policy() -> None:
|
|||||||
_expect_no_duplicate_comma_items("row_normalization.pair.hard_row_negative", pair["hardcore_row"].get("negative_prompt"))
|
_expect_no_duplicate_comma_items("row_normalization.pair.hard_row_negative", pair["hardcore_row"].get("negative_prompt"))
|
||||||
|
|
||||||
|
|
||||||
|
def smoke_row_rendering_policy() -> None:
|
||||||
|
_expect(pb.SINGLE_TEMPLATE == row_rendering.SINGLE_TEMPLATE, "Prompt builder single template should delegate to row_rendering")
|
||||||
|
_expect(
|
||||||
|
pb._format("Known {known}, missing {missing}", {"known": 7})
|
||||||
|
== row_rendering.format_template("Known {known}, missing {missing}", {"known": 7}),
|
||||||
|
"Prompt builder safe formatter should delegate to row_rendering",
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
row_rendering.format_template("Known {known}, missing {missing}", {"known": 7}) == "Known 7, missing {missing}",
|
||||||
|
"Row rendering changed missing-field preservation",
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
row_rendering.prompt_template_for({}, {}, {}, "woman") == row_rendering.SINGLE_TEMPLATE,
|
||||||
|
"Row rendering default woman template changed",
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
row_rendering.prompt_template_for({}, {}, {}, "group") == row_rendering.GROUP_TEMPLATE,
|
||||||
|
"Row rendering default group template changed",
|
||||||
|
)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
"trigger": Trigger,
|
||||||
|
"subject": "configured cast",
|
||||||
|
"subject_phrase": "configured adult cast",
|
||||||
|
"age": "adult",
|
||||||
|
"body": "varied",
|
||||||
|
"body_phrase": "varied",
|
||||||
|
"skin": "",
|
||||||
|
"hair": "",
|
||||||
|
"eyes": "",
|
||||||
|
"item_label": "Scene",
|
||||||
|
"item": "shared action",
|
||||||
|
"scene": "warm room",
|
||||||
|
"pose": "standing close",
|
||||||
|
"expression": "focused look",
|
||||||
|
"composition": "centered frame",
|
||||||
|
"composition_prompt": "vertical centered frame",
|
||||||
|
"positive_suffix": "clear readable bodies.",
|
||||||
|
"negative_prompt": "bad anatomy",
|
||||||
|
"cast_descriptors": "Woman A: adult woman; Man A: adult man",
|
||||||
|
}
|
||||||
|
rendered = row_rendering.render_prompt_caption(
|
||||||
|
item={},
|
||||||
|
subcategory={
|
||||||
|
"prompt_template": "Scene: {item}. Composition: {composition_prompt}. Avoid: {negative_prompt}.",
|
||||||
|
"caption_template": "{trigger}, {item}, {scene}",
|
||||||
|
},
|
||||||
|
category={},
|
||||||
|
subject_type="configured_cast",
|
||||||
|
context=context,
|
||||||
|
cast_descriptor_text="Woman A: adult woman; Man A: adult man",
|
||||||
|
pov_prompt_directive="First-person POV from Man A.",
|
||||||
|
)
|
||||||
|
prompt = rendered["prompt"]
|
||||||
|
caption = rendered["caption"]
|
||||||
|
_expect("Characters: Woman A: adult woman; Man A: adult man." in prompt, "Row rendering lost configured-cast descriptors")
|
||||||
|
_expect("First-person POV from Man A." in prompt, "Row rendering lost configured-cast POV directive")
|
||||||
|
_expect(
|
||||||
|
prompt.index("Characters:") < prompt.index("First-person POV") < prompt.index("Avoid:"),
|
||||||
|
"Row rendering did not insert configured-cast directives before negative prompt",
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
caption.endswith("Woman A: adult woman; Man A: adult man"),
|
||||||
|
"Row rendering did not append descriptors to captions without descriptor placeholders",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def smoke_formatter_input_policy() -> None:
|
def smoke_formatter_input_policy() -> None:
|
||||||
source_row = {
|
source_row = {
|
||||||
"prompt": "A simple adult portrait. Setting: quiet studio. Pose: standing calmly. Avoid: low quality.",
|
"prompt": "A simple adult portrait. Setting: quiet studio. Pose: standing calmly. Avoid: low quality.",
|
||||||
@@ -4197,6 +4265,7 @@ SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
|
|||||||
("character_config_policy", smoke_character_config_policy),
|
("character_config_policy", smoke_character_config_policy),
|
||||||
("character_profile_policy", smoke_character_profile_policy),
|
("character_profile_policy", smoke_character_profile_policy),
|
||||||
("row_normalization_policy", smoke_row_normalization_policy),
|
("row_normalization_policy", smoke_row_normalization_policy),
|
||||||
|
("row_rendering_policy", smoke_row_rendering_policy),
|
||||||
("formatter_input_policy", smoke_formatter_input_policy),
|
("formatter_input_policy", smoke_formatter_input_policy),
|
||||||
("formatter_cast_policy", smoke_formatter_cast_policy),
|
("formatter_cast_policy", smoke_formatter_cast_policy),
|
||||||
("caption_policy", smoke_caption_policy),
|
("caption_policy", smoke_caption_policy),
|
||||||
|
|||||||
Reference in New Issue
Block a user