Extract row rendering policy

This commit is contained in:
2026-06-27 09:35:37 +02:00
parent 55fec890a5
commit c076b22b75
5 changed files with 207 additions and 67 deletions
+19 -66
View File
@@ -1,9 +1,7 @@
from __future__ import annotations
import random
import re
from pathlib import Path
from string import Formatter
from typing import Any
try:
@@ -42,6 +40,7 @@ try:
from . import row_item as row_item_policy
from . import row_location as row_location_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 seed_config as seed_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_location as row_location_policy
import row_pools as row_pool_policy
import row_rendering as row_rendering_policy
import row_route_metadata as row_route_policy
import seed_config as seed_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_FOCUS_CHOICES = camera_policy.CAMERA_ORBIT_FOCUS_CHOICES
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."
)
GENERIC_POSITIVE_SUFFIX = row_rendering_policy.GENERIC_POSITIVE_SUFFIX
SINGLE_TEMPLATE = row_rendering_policy.SINGLE_TEMPLATE
COUPLE_TEMPLATE = row_rendering_policy.COUPLE_TEMPLATE
GROUP_TEMPLATE = row_rendering_policy.GROUP_TEMPLATE
LAYOUT_TEMPLATE = row_rendering_policy.LAYOUT_TEMPLATE
CAMERA_MODE_PROMPTS = camera_policy.CAMERA_MODE_PROMPTS
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
class SafeFormatDict(dict):
def __missing__(self, key: str) -> str:
return "{" + key + "}"
SafeFormatDict = row_rendering_policy.SafeFormatDict
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:
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)
return row_rendering_policy.format_template(template, context)
def _clean_prompt_punctuation(text: str) -> str:
@@ -2294,35 +2265,17 @@ def _build_custom_row(
}
)
if isinstance(item, dict) and "prompt_template" in item:
template = str(item["prompt_template"])
else:
template = str(subcategory.get("prompt_template") or category.get("prompt_template") or "")
if not template:
if subject_type in ("woman", "man"):
template = SINGLE_TEMPLATE
elif subject_type == "couple":
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"
rendered = row_rendering_policy.render_prompt_caption(
item=item,
subcategory=subcategory,
category=category,
subject_type=subject_type,
context=context,
cast_descriptor_text=cast_descriptor_text,
pov_prompt_directive=_pov_prompt_directive(pov_character_labels) if pov_character_labels else "",
)
prompt = _format(template, context)
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}"
prompt = rendered["prompt"]
caption = rendered["caption"]
batch = max(1, ((row_number - 1) // g.BATCH_SIZE) + 1)
index = start_index + row_number - 1
row = g.row_base(index, batch, context["subject"], context["age"], context["body"], scene_slug, composition)