Centralize formatter detail levels

This commit is contained in:
2026-06-27 13:56:21 +02:00
parent 6f6afb4d22
commit 333fa5eae6
8 changed files with 70 additions and 9 deletions
+5 -6
View File
@@ -4,9 +4,11 @@ import re
from typing import Any
try:
from . import formatter_detail as detail_policy
from . import formatter_input as input_policy
from . import route_metadata as route_metadata_policy
except ImportError: # Allows local smoke tests with `python tools/prompt_smoke.py`.
import formatter_detail as detail_policy
import formatter_input as input_policy
import route_metadata as route_metadata_policy
@@ -14,7 +16,7 @@ except ImportError: # Allows local smoke tests with `python tools/prompt_smoke.
OLD_TRIGGER = "sxcpinup_coloredpencil"
DEFAULT_TRIGGER = "sxcppnl7"
DETAIL_LEVELS = ("balanced", "concise", "dense")
DETAIL_LEVELS = detail_policy.DETAIL_LEVELS
STYLE_POLICIES = ("drop_style_tail", "keep_style_terms")
CAPTION_PROFILE_DEFAULT = "manual_controls"
@@ -72,7 +74,7 @@ POSITION_FAMILY_CAPTION_LABELS = {
def normalize_detail_level(value: str) -> str:
return value if value in DETAIL_LEVELS else "balanced"
return detail_policy.normalize_detail_level(value)
def normalize_style_policy(value: str) -> str:
@@ -107,10 +109,7 @@ def keep_style_terms(style_policy: str) -> bool:
def detail_allows(level: str, dense_only: bool = False) -> bool:
level = normalize_detail_level((level or "balanced").strip().lower())
if dense_only:
return level == "dense"
return level != "concise"
return detail_policy.detail_allows(level, dense_only=dense_only)
def strip_style_tail(text: str) -> str:
@@ -84,6 +84,15 @@ routes:
It must not make formatter-style decisions. Krea prose, SDXL tags, and training
caption sentence shape stay in their formatter modules.
Formatter detail-level handling now has one home:
- `formatter_detail.py`
It owns route-neutral prose detail levels, node choice lists, normalization, and
the concise/balanced/dense inclusion gate used by Krea2 and natural-caption
routes. It must not own route-specific style controls such as Krea photographic
mode or caption style-tail policy.
Formatter target handling now has one home:
- `formatter_target.py`
+1
View File
@@ -126,6 +126,7 @@ Core helper ownership:
| `krea_cast.py` | Shared formatter cast descriptor parsing, cast labels, cast prose, natural cast descriptor text, and label replacement used by Krea2 and caption routes. |
| `prompt_hygiene.py` | Generic prompt, caption, and negative-prompt cleanup. |
| `row_normalization.py` | Final prompt-row and pair metadata normalization: trigger prepending, extra-positive append, negative merge/dedupe, caption-part joining, embedded soft/hard row output and side-metadata synchronization, and embedded row sanitation. |
| `formatter_detail.py` | Shared formatter detail-level choices, normalization, and concise/balanced/dense gates used by Krea2 and caption routes. |
| `formatter_input.py` | Shared formatter input parsing: text cleanup, metadata/source JSON detection, trigger-prefix stripping, shared prompt field-label inventory, fallback field-label stripping, `Avoid:` splitting, prompt-field extraction, and metadata row-value fallback. |
| `formatter_target.py` | Shared formatter target choices and normalization for `auto`, `single`, `softcore`, and `hardcore`, including pair-side selection and combined-caption inclusion policy. |
| `node_tooltips.py` | Node input tooltip inventory, node-specific overrides, dynamic-input fallback rules, and tooltip injection installer used by `__init__.py`. |
+23
View File
@@ -0,0 +1,23 @@
from __future__ import annotations
from typing import Any
DETAIL_LEVELS = ("balanced", "concise", "dense")
DEFAULT_DETAIL_LEVEL = "balanced"
def detail_level_choices() -> list[str]:
return list(DETAIL_LEVELS)
def normalize_detail_level(value: Any) -> str:
level = str(value or "").strip().lower().replace("-", "_").replace(" ", "_")
return level if level in DETAIL_LEVELS else DEFAULT_DETAIL_LEVEL
def detail_allows(level: Any, dense_only: bool = False) -> bool:
level = normalize_detail_level(level)
if dense_only:
return level == "dense"
return level != "concise"
+3 -1
View File
@@ -4,8 +4,10 @@ from dataclasses import dataclass
from typing import Any, Callable
try:
from . import formatter_detail as detail_policy
from . import formatter_target as target_policy
except ImportError: # pragma: no cover - plain-script smoke tests
import formatter_detail as detail_policy
import formatter_target as target_policy
@@ -48,7 +50,7 @@ class KreaFormatDependencies:
def format_krea2_prompt_result(request: KreaFormatRequest, deps: KreaFormatDependencies) -> KreaFormatRoute:
detail_level = request.detail_level if request.detail_level in ("concise", "balanced", "dense") else "balanced"
detail_level = detail_policy.normalize_detail_level(request.detail_level)
style_mode = request.style_mode if request.style_mode in ("preserve", "photographic", "minimal") else "preserve"
target = target_policy.normalize_target(request.target)
row, method = deps.row_from_inputs(request.source_text, request.metadata_json, request.input_hint)
+4 -2
View File
@@ -3,6 +3,7 @@ from __future__ import annotations
try:
from .caption_naturalizer import naturalize_caption
from .caption_policy import caption_profile_choices
from .formatter_detail import detail_level_choices
from .formatter_input import INPUT_HINT_CAPTION_OR_PROMPT, INPUT_HINT_PROMPT, input_hint_choices
from .formatter_target import target_choices
from .krea_formatter import format_krea2_prompt
@@ -15,6 +16,7 @@ try:
except ImportError: # Allows local smoke tests from the repository root.
from caption_naturalizer import naturalize_caption
from caption_policy import caption_profile_choices
from formatter_detail import detail_level_choices
from formatter_input import INPUT_HINT_CAPTION_OR_PROMPT, INPUT_HINT_PROMPT, input_hint_choices
from formatter_target import target_choices
from krea_formatter import format_krea2_prompt
@@ -34,7 +36,7 @@ class SxCPCaptionNaturalizer:
"source_text": ("STRING", {"default": "", "multiline": True}),
"input_hint": (input_hint_choices(text_hint=INPUT_HINT_CAPTION_OR_PROMPT), {"default": "auto"}),
"caption_profile": (caption_profile_choices(), {"default": "manual_controls"}),
"detail_level": (["balanced", "concise", "dense"], {"default": "balanced"}),
"detail_level": (detail_level_choices(), {"default": "balanced"}),
"style_policy": (["drop_style_tail", "keep_style_terms"], {"default": "drop_style_tail"}),
"trigger": ("STRING", {"default": "sxcppnl7"}),
"include_trigger": ("BOOLEAN", {"default": True}),
@@ -86,7 +88,7 @@ class SxCPKrea2Formatter:
"source_text": ("STRING", {"default": "", "multiline": True}),
"input_hint": (input_hint_choices(text_hint=INPUT_HINT_PROMPT), {"default": "auto"}),
"target": (target_choices(), {"default": "auto"}),
"detail_level": (["balanced", "concise", "dense"], {"default": "balanced"}),
"detail_level": (detail_level_choices(), {"default": "balanced"}),
"style_mode": (["preserve", "photographic", "minimal"], {"default": "preserve"}),
"preserve_trigger": ("BOOLEAN", {"default": False}),
},
+1
View File
@@ -38,6 +38,7 @@ CRITICAL_ROUTE_MODULES: tuple[tuple[str, str], ...] = (
("krea_format_route.py", "krea_format_route_policy"),
("sdxl_format_route.py", "sdxl_format_route_policy"),
("caption_format_route.py", "caption_format_route_policy"),
("formatter_detail.py", "formatter_detail_policy"),
("formatter_input.py", "formatter_input_policy"),
("formatter_target.py", "formatter_target_policy"),
("pair_builder.py", "pair_builder_policy"),
+24
View File
@@ -41,6 +41,7 @@ import character_slot # noqa: E402
import category_cast_config # noqa: E402
import category_library # noqa: E402
import filter_config # noqa: E402
import formatter_detail # noqa: E402
import formatter_input # noqa: E402
import formatter_target # noqa: E402
import hardcore_position_config # noqa: E402
@@ -2842,6 +2843,26 @@ def smoke_formatter_target_policy() -> None:
_expect(not hard_pair.include_softcore and hard_pair.include_hardcore, "Pair hardcore should include only hard side")
def smoke_formatter_detail_policy() -> None:
_expect(
formatter_detail.detail_level_choices() == ["balanced", "concise", "dense"],
"Formatter detail choices changed",
)
_expect(formatter_detail.normalize_detail_level("dense") == "dense", "Formatter detail lost dense")
_expect(formatter_detail.normalize_detail_level("BAD") == "balanced", "Formatter detail should normalize invalid values")
_expect(formatter_detail.detail_allows("concise") is False, "Formatter detail concise gate changed")
_expect(formatter_detail.detail_allows("dense", dense_only=True) is True, "Formatter detail dense-only gate changed")
_expect(caption_policy.DETAIL_LEVELS is formatter_detail.DETAIL_LEVELS, "Caption detail levels should delegate")
_expect(
caption_policy.normalize_detail_level("bad") == formatter_detail.normalize_detail_level("bad"),
"Caption detail normalization should delegate",
)
_expect(
caption_policy.detail_allows("dense", dense_only=True) == formatter_detail.detail_allows("dense", dense_only=True),
"Caption detail gate should delegate",
)
def smoke_krea_format_route_policy() -> None:
row = _prompt_row(
name="krea_format_route_single",
@@ -6264,8 +6285,10 @@ def smoke_node_formatter_registration() -> None:
_expect("caption_profile" in caption_inputs, "Caption Naturalizer lost caption_profile input")
_expect("target" in caption_inputs, "Caption Naturalizer lost target input")
_expect(caption_inputs["target"][0] == formatter_target.target_choices(), "Caption Naturalizer target choices drifted")
_expect(caption_inputs["detail_level"][0] == formatter_detail.detail_level_choices(), "Caption Naturalizer detail choices drifted")
_expect("tooltip" in caption_inputs["caption_profile"][1], "Caption profile tooltip injection missing")
_expect(krea_inputs["target"][0] == formatter_target.target_choices(), "Krea2 Formatter target choices drifted")
_expect(krea_inputs["detail_level"][0] == formatter_detail.detail_level_choices(), "Krea2 Formatter detail choices drifted")
krea_output = krea_node().build(
"sxcppnl7 A woman standing by a window",
@@ -6644,6 +6667,7 @@ SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
("row_assembly_policy", smoke_row_assembly_policy),
("formatter_input_policy", smoke_formatter_input_policy),
("formatter_target_policy", smoke_formatter_target_policy),
("formatter_detail_policy", smoke_formatter_detail_policy),
("krea_format_route_policy", smoke_krea_format_route_policy),
("formatter_cast_policy", smoke_formatter_cast_policy),
("caption_policy", smoke_caption_policy),