Add persistent any text preview node
This commit is contained in:
+102
@@ -50,6 +50,7 @@ ACCUMULATOR_PREVIEW_DELETE_ACTIONS = ["none", "delete_entry_id", "delete_index",
|
||||
INDEX_SWITCH_MODES = ["pick_input", "route_output"]
|
||||
INDEX_SWITCH_BASES = ["one_based", "zero_based"]
|
||||
INDEX_SWITCH_MISSING_BEHAVIORS = ["fallback", "none", "clamp", "wrap"]
|
||||
PREVIEW_TEXT_FORMATS = ["auto", "json", "repr", "str"]
|
||||
|
||||
_ACCUMULATOR_STORES: dict[str, list[dict[str, Any]]] = {}
|
||||
|
||||
@@ -248,6 +249,66 @@ def _attach_preview_images(entries: list[dict[str, Any]], images: list[dict[str,
|
||||
entry["preview_image"] = image
|
||||
|
||||
|
||||
def _jsonable_preview_value(value: Any, depth: int = 4, max_items: int = 80) -> Any:
|
||||
if depth < 0:
|
||||
return "..."
|
||||
if value is None or isinstance(value, (str, int, float, bool)):
|
||||
return value
|
||||
if isinstance(value, dict):
|
||||
items = list(value.items())
|
||||
output = {
|
||||
str(key): _jsonable_preview_value(item, depth - 1, max_items)
|
||||
for key, item in items[:max_items]
|
||||
}
|
||||
if len(items) > max_items:
|
||||
output["..."] = f"{len(items) - max_items} more"
|
||||
return output
|
||||
if isinstance(value, (list, tuple, set)):
|
||||
items = list(value)
|
||||
output = [_jsonable_preview_value(item, depth - 1, max_items) for item in items[:max_items]]
|
||||
if len(items) > max_items:
|
||||
output.append(f"... {len(items) - max_items} more")
|
||||
return output
|
||||
shape = getattr(value, "shape", None)
|
||||
if shape is not None:
|
||||
try:
|
||||
return {
|
||||
"type": type(value).__name__,
|
||||
"shape": [int(part) for part in shape],
|
||||
"dtype": str(getattr(value, "dtype", "")),
|
||||
"device": str(getattr(value, "device", "")),
|
||||
}
|
||||
except Exception:
|
||||
pass
|
||||
return str(value)
|
||||
|
||||
|
||||
def _truncate_preview_text(text: str, max_chars: int) -> str:
|
||||
max_chars = max(0, int(max_chars or 0))
|
||||
if max_chars <= 0 or len(text) <= max_chars:
|
||||
return text
|
||||
omitted = len(text) - max_chars
|
||||
return f"{text[:max_chars]}\n... truncated {omitted} characters"
|
||||
|
||||
|
||||
def _any_to_preview_text(value: Any, preview_format: str, max_chars: int) -> str:
|
||||
preview_format = preview_format if preview_format in PREVIEW_TEXT_FORMATS else "auto"
|
||||
if preview_format == "str":
|
||||
text = str(value)
|
||||
elif preview_format == "repr":
|
||||
text = repr(value)
|
||||
elif preview_format == "json":
|
||||
text = json.dumps(_jsonable_preview_value(value), ensure_ascii=True, indent=2, sort_keys=True)
|
||||
elif isinstance(value, str):
|
||||
text = value
|
||||
else:
|
||||
try:
|
||||
text = json.dumps(_jsonable_preview_value(value), ensure_ascii=True, indent=2, sort_keys=True)
|
||||
except Exception:
|
||||
text = str(value)
|
||||
return _truncate_preview_text(text, max_chars)
|
||||
|
||||
|
||||
def _accumulator_status(key: str, store: list[dict[str, Any]]) -> str:
|
||||
images = [entry.get("image") for entry in store if entry.get("image") is not None]
|
||||
shapes = []
|
||||
@@ -1194,6 +1255,45 @@ class SxCPAccumulatorPreview:
|
||||
}
|
||||
|
||||
|
||||
class SxCPPreviewAnyAsText:
|
||||
OUTPUT_NODE = True
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"preview_text": ("STRING", {"default": "", "multiline": True}),
|
||||
"preview_format": (PREVIEW_TEXT_FORMATS, {"default": "auto"}),
|
||||
"max_chars": ("INT", {"default": 20000, "min": 0, "max": 200000, "step": 1000}),
|
||||
},
|
||||
"optional": {
|
||||
"value": (ANY_TYPE, {"forceInput": True}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("text",)
|
||||
FUNCTION = "preview"
|
||||
CATEGORY = "prompt_builder/util"
|
||||
|
||||
@classmethod
|
||||
def IS_CHANGED(cls, *args, **kwargs):
|
||||
return random.random()
|
||||
|
||||
def preview(self, preview_text, preview_format, max_chars, **kwargs):
|
||||
if "value" not in kwargs:
|
||||
text = _truncate_preview_text(str(preview_text or ""), int(max_chars))
|
||||
else:
|
||||
value = kwargs.get("value")
|
||||
text = _any_to_preview_text(value, str(preview_format or "auto"), int(max_chars))
|
||||
return {
|
||||
"ui": {
|
||||
"preview_text": [text],
|
||||
},
|
||||
"result": (text,),
|
||||
}
|
||||
|
||||
|
||||
class SxCPForLoopEnd:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
@@ -1320,6 +1420,7 @@ LOOP_NODE_CLASS_MAPPINGS = {
|
||||
"SxCPIndexSwitch": SxCPIndexSwitch,
|
||||
"SxCPAccumulator": SxCPAccumulator,
|
||||
"SxCPAccumulatorPreview": SxCPAccumulatorPreview,
|
||||
"SxCPPreviewAnyAsText": SxCPPreviewAnyAsText,
|
||||
"SxCPLoopIntAdd": SxCPLoopIntAdd,
|
||||
"SxCPLoopLessThan": SxCPLoopLessThan,
|
||||
"SxCPLoopLessThanOrEqual": SxCPLoopLessThanOrEqual,
|
||||
@@ -1334,6 +1435,7 @@ LOOP_NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"SxCPIndexSwitch": "SxCP Index Switch",
|
||||
"SxCPAccumulator": "SxCP Accumulator",
|
||||
"SxCPAccumulatorPreview": "SxCP Accumulator Preview",
|
||||
"SxCPPreviewAnyAsText": "SxCP Preview Any As Text",
|
||||
"SxCPLoopIntAdd": "SxCP Loop Int Add",
|
||||
"SxCPLoopLessThan": "SxCP Loop Less Than",
|
||||
"SxCPLoopLessThanOrEqual": "SxCP Loop Less Than Or Equal",
|
||||
|
||||
Reference in New Issue
Block a user