Extract category extension policy
This commit is contained in:
+8
-83
@@ -1,6 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import random
|
||||
import re
|
||||
from pathlib import Path
|
||||
@@ -9,16 +8,15 @@ from typing import Any
|
||||
|
||||
try:
|
||||
from .category_library import (
|
||||
category_json_files as _json_files,
|
||||
compatible_entries as _compatible_entries,
|
||||
compatible_entry as _compatible_entry,
|
||||
find_subcategory as _find_subcategory,
|
||||
load_category_library,
|
||||
merged_field as _merged_field,
|
||||
read_category_json as _read_json,
|
||||
)
|
||||
from . import camera_config as camera_policy
|
||||
from . import cast_context as cast_context_policy
|
||||
from . import category_extensions as category_extensions_policy
|
||||
from . import category_template_metadata as item_template_policy
|
||||
from . import character_appearance as character_appearance_policy
|
||||
from . import character_config as character_policy
|
||||
@@ -54,16 +52,15 @@ try:
|
||||
from .hardcore_role_graphs import build_hardcore_role_graph
|
||||
except ImportError: # Allows local smoke tests with `python -c`.
|
||||
from category_library import (
|
||||
category_json_files as _json_files,
|
||||
compatible_entries as _compatible_entries,
|
||||
compatible_entry as _compatible_entry,
|
||||
find_subcategory as _find_subcategory,
|
||||
load_category_library,
|
||||
merged_field as _merged_field,
|
||||
read_category_json as _read_json,
|
||||
)
|
||||
import camera_config as camera_policy
|
||||
import cast_context as cast_context_policy
|
||||
import category_extensions as category_extensions_policy
|
||||
import category_template_metadata as item_template_policy
|
||||
import character_appearance as character_appearance_policy
|
||||
import character_config as character_policy
|
||||
@@ -102,15 +99,7 @@ except ImportError: # Allows local smoke tests with `python -c`.
|
||||
ROOT_DIR = Path(__file__).resolve().parent
|
||||
PROFILE_DIR = character_profile_policy.PROFILE_DIR
|
||||
|
||||
BUILTIN_CATEGORIES = [
|
||||
"auto_weighted",
|
||||
"auto_full",
|
||||
"woman",
|
||||
"man",
|
||||
"couple",
|
||||
"group_or_layout",
|
||||
"custom_random",
|
||||
]
|
||||
BUILTIN_CATEGORIES = category_extensions_policy.BUILTIN_CATEGORIES
|
||||
RANDOM_SUBCATEGORY = "random"
|
||||
SEED_AXIS_SALTS = seed_policy.SEED_AXIS_SALTS
|
||||
SEED_AXIS_ALIASES = seed_policy.SEED_AXIS_ALIASES
|
||||
@@ -197,9 +186,6 @@ CAMERA_PHONE_PROMPTS = camera_policy.CAMERA_PHONE_PROMPTS
|
||||
CAMERA_PRIORITY_PROMPTS = camera_policy.CAMERA_PRIORITY_PROMPTS
|
||||
|
||||
|
||||
_EXTENSIONS_APPLIED = False
|
||||
|
||||
|
||||
class SafeFormatDict(dict):
|
||||
def __missing__(self, key: str) -> str:
|
||||
return "{" + key + "}"
|
||||
@@ -226,20 +212,7 @@ def _is_false(value: Any) -> bool:
|
||||
|
||||
|
||||
def _unique_extend(target: list[Any], additions: list[Any]) -> None:
|
||||
seen = set()
|
||||
for item in target:
|
||||
try:
|
||||
seen.add(json.dumps(item, sort_keys=True))
|
||||
except TypeError:
|
||||
seen.add(repr(item))
|
||||
for item in additions:
|
||||
try:
|
||||
marker = json.dumps(item, sort_keys=True)
|
||||
except TypeError:
|
||||
marker = repr(item)
|
||||
if marker not in seen:
|
||||
target.append(item)
|
||||
seen.add(marker)
|
||||
category_extensions_policy.unique_extend(target, additions)
|
||||
|
||||
|
||||
def _pair_from(value: Any) -> tuple[str, str]:
|
||||
@@ -333,67 +306,19 @@ def _choose_pair(rng: random.Random, items: list[Any]) -> tuple[str, str]:
|
||||
|
||||
|
||||
def _extension_targets() -> dict[str, tuple[list[Any], bool]]:
|
||||
return {
|
||||
"women_clothes": (g.WOMEN_CLOTHES, False),
|
||||
"women_clothes_minimal": (g.WOMEN_CLOTHES_MINIMAL, False),
|
||||
"men_clothes": (g.MEN_CLOTHES, False),
|
||||
"men_clothes_minimal": (g.MEN_CLOTHES_MINIMAL, False),
|
||||
"couple_outfits": (g.COUPLE_OUTFITS, False),
|
||||
"couple_outfits_minimal": (g.COUPLE_OUTFITS_MINIMAL, False),
|
||||
"poses": (g.POSES, False),
|
||||
"evocative_poses": (g.EVOCATIVE_POSES, False),
|
||||
"backside_poses": (g.BACKSIDE_POSES, False),
|
||||
"expressions": (g.EXPRESSIONS, False),
|
||||
"compositions": (g.COMPOSITIONS, False),
|
||||
"props": (g.PROPS, False),
|
||||
"figure_curvy": (g.FIGURE_CURVY, False),
|
||||
"figure_athletic": (g.FIGURE_ATHLETIC, False),
|
||||
"figure_bombshell": (g.FIGURE_BOMBSHELL, False),
|
||||
"scenes": (g.SCENES, True),
|
||||
"group_scenes": (g.GROUP_SCENES, True),
|
||||
"layouts_full": (g.LAYOUTS_FULL, True),
|
||||
"layouts_minimal": (g.LAYOUTS_MINIMAL, True),
|
||||
"group_compositions": (g.GROUP_COMPOSITIONS, False),
|
||||
"group_ages": (g.GROUP_AGES, False),
|
||||
}
|
||||
return category_extensions_policy.extension_targets()
|
||||
|
||||
|
||||
def apply_pool_extensions() -> None:
|
||||
global _EXTENSIONS_APPLIED
|
||||
if _EXTENSIONS_APPLIED:
|
||||
return
|
||||
targets = _extension_targets()
|
||||
for path in _json_files():
|
||||
data = _read_json(path)
|
||||
extensions = data.get("pool_extensions", {})
|
||||
if not isinstance(extensions, dict):
|
||||
raise ValueError(f"pool_extensions in {path} must be an object")
|
||||
for target_name, additions in extensions.items():
|
||||
if target_name not in targets:
|
||||
known = ", ".join(sorted(targets))
|
||||
raise ValueError(f"Unknown pool extension '{target_name}' in {path}. Known: {known}")
|
||||
target, expects_pair = targets[target_name]
|
||||
normalized = [_pair_from(item) for item in _list_from(additions)] if expects_pair else [
|
||||
_item_text(item) for item in _list_from(additions)
|
||||
]
|
||||
_unique_extend(target, normalized)
|
||||
g.EVOCATIVE_ALL = g.EVOCATIVE_POSES + g.BACKSIDE_POSES
|
||||
_EXTENSIONS_APPLIED = True
|
||||
category_extensions_policy.apply_pool_extensions()
|
||||
|
||||
|
||||
def category_choices() -> list[str]:
|
||||
apply_pool_extensions()
|
||||
custom = [category["name"] for category in load_category_library()]
|
||||
return BUILTIN_CATEGORIES + [name for name in custom if name not in BUILTIN_CATEGORIES]
|
||||
return category_extensions_policy.category_choices()
|
||||
|
||||
|
||||
def subcategory_choices() -> list[str]:
|
||||
apply_pool_extensions()
|
||||
choices = [RANDOM_SUBCATEGORY]
|
||||
for category in load_category_library():
|
||||
for subcategory in category["subcategories"]:
|
||||
choices.append(f"{category['name']} / {subcategory['name']}")
|
||||
return choices
|
||||
return category_extensions_policy.subcategory_choices()
|
||||
|
||||
|
||||
def seed_mode_choices() -> list[str]:
|
||||
|
||||
Reference in New Issue
Block a user