DirectorNode: lock + seed control + custom intro modes + next_seed output
This commit is contained in:
+44
-22
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
|
||||
def _pick(arr: Any, fallback: str = "") -> str:
|
||||
@@ -14,33 +14,57 @@ def _join_nonempty(parts: List[str]) -> str:
|
||||
return ", ".join([p.strip() for p in parts if p and p.strip()])
|
||||
|
||||
|
||||
def _select_custom_intro(
|
||||
world: Dict[str, Any],
|
||||
mode: str = "auto",
|
||||
index: Optional[int] = None,
|
||||
) -> str:
|
||||
ci = world.get("CUSTOM_INTRO")
|
||||
if not isinstance(ci, dict) or not ci:
|
||||
return ""
|
||||
|
||||
# Normalizza keys/values in stringhe
|
||||
keys = list(ci.keys())
|
||||
values = [str(ci[k]) for k in keys if ci.get(k) is not None]
|
||||
|
||||
if not values:
|
||||
return ""
|
||||
|
||||
mode = (mode or "auto").lower().strip()
|
||||
|
||||
if mode == "index":
|
||||
if index is None:
|
||||
return ""
|
||||
k = str(index)
|
||||
return str(ci.get(k, "")) if k in ci else ""
|
||||
|
||||
if mode == "random":
|
||||
return str(random.choice(values))
|
||||
|
||||
# auto: prova 0..6, altrimenti random
|
||||
for k in ["0", "1", "2", "3", "4", "5", "6"]:
|
||||
if k in ci:
|
||||
return str(ci[k])
|
||||
return str(random.choice(values))
|
||||
|
||||
|
||||
def build_prompt_from_world(
|
||||
world: Dict[str, Any],
|
||||
seed: Optional[int] = None,
|
||||
custom_intro_mode: str = "auto",
|
||||
custom_intro_index: Optional[int] = None,
|
||||
) -> str:
|
||||
) -> Tuple[str, str]:
|
||||
if seed is not None:
|
||||
random.seed(seed)
|
||||
|
||||
# 1) system prompt (se ti serve per debug/log o per ritorni futuri)
|
||||
system_prompt = str(world.get("SYSTEM_PROMPT", "")).strip()
|
||||
|
||||
# 2) prendi un custom_intro (se c’è)
|
||||
custom_intro = ""
|
||||
ci = world.get("CUSTOM_INTRO")
|
||||
if isinstance(ci, dict) and ci:
|
||||
if custom_intro_index is not None and str(custom_intro_index) in ci:
|
||||
custom_intro = str(ci[str(custom_intro_index)])
|
||||
else:
|
||||
# prova 0..6, altrimenti random tra valori
|
||||
for k in ["0", "1", "2", "3", "4", "5", "6"]:
|
||||
if k in ci:
|
||||
custom_intro = str(ci[k])
|
||||
break
|
||||
if not custom_intro:
|
||||
custom_intro = str(random.choice(list(ci.values())))
|
||||
custom_intro = _select_custom_intro(
|
||||
world,
|
||||
mode=custom_intro_mode,
|
||||
index=custom_intro_index,
|
||||
)
|
||||
|
||||
# 3) selezioni modulari (liste)
|
||||
outfits = _pick(world.get("OUTFITS"), "simple dark outfit")
|
||||
lighting = _pick(world.get("LIGHTING"), "low ambient light")
|
||||
backgrounds = _pick(world.get("BACKGROUNDS"), "intimate interior")
|
||||
@@ -51,8 +75,7 @@ def build_prompt_from_world(
|
||||
atmos = _pick(world.get("ATMOSPHERES"), "quiet cinematic mood")
|
||||
accessories = _pick(world.get("ACCESSORIES"), "")
|
||||
|
||||
# 4) compone una frase unica (poi la raffiniamo nello step successivo)
|
||||
core = _join_nonempty([
|
||||
prompt = _join_nonempty([
|
||||
custom_intro,
|
||||
outfits,
|
||||
lighting,
|
||||
@@ -65,5 +88,4 @@ def build_prompt_from_world(
|
||||
accessories,
|
||||
])
|
||||
|
||||
# system_prompt lo teniamo separato: qui ritorniamo solo il prompt “artistico”
|
||||
return core.strip(), system_prompt
|
||||
return (prompt.strip(), system_prompt)
|
||||
|
||||
+48
-10
@@ -1,3 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
|
||||
from ..core.world_registry import WorldRegistry
|
||||
from ..core.prompt_engine import build_prompt_from_world
|
||||
|
||||
@@ -13,22 +17,56 @@ class DirectorNode:
|
||||
"required": {
|
||||
"world": (names,),
|
||||
"seed": ("INT", {"default": 0, "min": 0, "max": 2**31 - 1}),
|
||||
},
|
||||
"optional": {
|
||||
"lock": ("BOOLEAN", {"default": False}),
|
||||
"control_after_generate": (["keep", "increment", "randomize"],),
|
||||
"custom_intro_mode": (["auto", "index", "random"],),
|
||||
"custom_intro_index": ("INT", {"default": -1, "min": -1, "max": 6}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING", "STRING")
|
||||
RETURN_NAMES = ("prompt", "system_prompt")
|
||||
RETURN_TYPES = ("STRING", "STRING", "INT")
|
||||
RETURN_NAMES = ("prompt", "system_prompt", "next_seed")
|
||||
FUNCTION = "run"
|
||||
CATEGORY = "PFN/Director"
|
||||
|
||||
def run(self, world: str, seed: int, custom_intro_index: int = -1):
|
||||
def run(
|
||||
self,
|
||||
world: str,
|
||||
seed: int,
|
||||
lock: bool,
|
||||
control_after_generate: str,
|
||||
custom_intro_mode: str,
|
||||
custom_intro_index: int,
|
||||
):
|
||||
w = WorldRegistry.get(world)
|
||||
if not w:
|
||||
return ("(world not found)", "")
|
||||
return ("(world not found)", "", seed)
|
||||
|
||||
idx = None if custom_intro_index < 0 else int(custom_intro_index)
|
||||
prompt, system_prompt = build_prompt_from_world(w, seed=seed, custom_intro_index=idx)
|
||||
return (prompt, system_prompt)
|
||||
# Seed effettivo per generare
|
||||
effective_seed = int(seed)
|
||||
|
||||
# Custom intro index valido solo in modalità index
|
||||
idx = None
|
||||
if (custom_intro_mode == "index") and (custom_intro_index is not None) and (int(custom_intro_index) >= 0):
|
||||
idx = int(custom_intro_index)
|
||||
|
||||
prompt, system_prompt = build_prompt_from_world(
|
||||
w,
|
||||
seed=effective_seed,
|
||||
custom_intro_mode=custom_intro_mode,
|
||||
custom_intro_index=idx,
|
||||
)
|
||||
|
||||
# Next seed (utile da collegare ad altri nodi)
|
||||
if lock:
|
||||
next_seed = effective_seed
|
||||
else:
|
||||
mode = (control_after_generate or "keep").lower().strip()
|
||||
if mode == "increment":
|
||||
next_seed = (effective_seed + 1) % (2**31)
|
||||
elif mode == "randomize":
|
||||
next_seed = random.randint(0, 2**31 - 1)
|
||||
else:
|
||||
next_seed = effective_seed
|
||||
|
||||
return (prompt, system_prompt, next_seed)
|
||||
|
||||
Reference in New Issue
Block a user