File size: 3,158 Bytes
38fe5dd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | """JoyEcho Script Picker — a dropdown node for selecting a saved prompt JSON.
The stock JoyEcho_TextEncode 'prompts' field only accepts pasted JSON / a typed
path, which is painful in the canvas. This node lists every *.json in
<ComfyUI>/input/joyecho_prompts/
as a COMBO dropdown and outputs the file's contents, wired straight into
JoyEcho_TextEncode's 'prompts' input (which accepts inline {"prompts":[...]} JSON).
Add a .json to that folder, hit the ComfyUI refresh button (or press R) to
repopulate the dropdown, pick it, run. Editing the file re-triggers execution
automatically (IS_CHANGED tracks mtime) — no need to reselect.
"""
import json
from pathlib import Path
import folder_paths
_PROMPTS_SUBDIR = "joyecho_prompts"
_EMPTY = "(no .json in input/joyecho_prompts)"
def _scripts_dir() -> Path:
d = Path(folder_paths.get_input_directory()) / _PROMPTS_SUBDIR
try:
d.mkdir(parents=True, exist_ok=True)
except OSError:
pass
return d
def _list_scripts() -> list[str]:
d = _scripts_dir()
try:
files = sorted(p.name for p in d.glob("*.json"))
except OSError:
files = []
return files if files else [_EMPTY]
class JoyEcho_ScriptPicker:
"""Pick a prompt-script .json from input/joyecho_prompts via a dropdown."""
@classmethod
def INPUT_TYPES(cls):
return {"required": {"script": (_list_scripts(),)}}
RETURN_TYPES = ("STRING", "STRING",)
RETURN_NAMES = ("prompts_json", "path",)
FUNCTION = "load"
CATEGORY = "JoyAI-Echo"
@classmethod
def IS_CHANGED(cls, script):
# Re-run when the selected file changes on disk, so edits are picked up.
p = _scripts_dir() / script
try:
return f"{script}:{p.stat().st_mtime}"
except OSError:
return script
def load(self, script):
if script == _EMPTY:
raise ValueError(
f"No .json scripts found. Put your prompt JSON in {_scripts_dir()} "
"and press the refresh button (or R) to repopulate the dropdown."
)
p = _scripts_dir() / script
if not p.exists():
raise FileNotFoundError(
f"Script not found: {p}. Refresh the node list (R) after adding files."
)
text = p.read_text(encoding="utf-8")
# Fail early with a clear message rather than deep in the text encoder.
try:
data = json.loads(text)
except json.JSONDecodeError as e:
raise ValueError(f"{script} is not valid JSON: {e}")
arr = data.get("prompts") if isinstance(data, dict) else None
if arr is None and isinstance(data, dict):
arr = data.get("shots")
if not isinstance(arr, list) or not arr:
raise ValueError(f"{script} must contain a non-empty 'prompts' (or 'shots') array.")
print(f"[JoyEcho] ScriptPicker: {script} ({len(arr)} shots).", flush=True)
return (text, str(p),)
NODE_CLASS_MAPPINGS = {"JoyEcho_ScriptPicker": JoyEcho_ScriptPicker}
NODE_DISPLAY_NAME_MAPPINGS = {"JoyEcho_ScriptPicker": "JoyEcho Script Picker (JSON dropdown)"}
|