From 74b3cd3f2e917e812c01ee9fd9f1addef22b36da Mon Sep 17 00:00:00 2001 From: Jason Schleifer Date: Wed, 26 Jun 2024 14:20:57 +1200 Subject: [PATCH] added display text node --- __init__.py | 2 ++ js/gtUINodes.js | 80 ++++++++++++++++++++++++++++++++++++++++++ nodes/display_nodes.py | 31 ++++++++++++++-- 3 files changed, 111 insertions(+), 2 deletions(-) diff --git a/__init__.py b/__init__.py index 07efd36..9590939 100644 --- a/__init__.py +++ b/__init__.py @@ -26,6 +26,7 @@ from .nodes.config_nodes import ( ) from .nodes.display_nodes import ( # gtUIOutputArtifactNode, + gtUIOutputDataNode, gtUIOutputImageNode, gtUIOutputStringNode, ) @@ -139,6 +140,7 @@ NODE_CLASS_MAPPINGS = { # DISPLAY "Griptape Display: Image": gtUIOutputImageNode, "Griptape Display: Text": gtUIOutputStringNode, + "Griptape Display: Data as Text": gtUIOutputDataNode, # AUDIO "Griptape Load: Audio": gtUILoadAudio, "Griptape Run: Audio Transcription": gtUIAudioTranscriptionTask, diff --git a/js/gtUINodes.js b/js/gtUINodes.js index 9a2932d..30dd468 100644 --- a/js/gtUINodes.js +++ b/js/gtUINodes.js @@ -33,6 +33,50 @@ function get_position_style(ctx, widget_width, y, node_height) { } } +const tabs=2 +// Function to format JSON and display it in the textarea +function formatAndDisplayJSON(text) { + try { + // parse the JSON string + const jsonObject = JSON.parse(text); + const formattedJSON = JSON.stringify(jsonObject, null, tabs); + + return(formattedJSON); + } + catch (jsonError) { + return formatPythonLikeObject(text); + } +} +function formatPythonLikeObject(text) { + let indent = 0; + let inString = false; + const formatted = []; + for (let i = 0; i < text.length; i++) { + const char = text[i]; + if (char === '\'' || char === '"') { + inString = !inString; + formatted.push(char); + } else if (!inString && (char === '{' || char === '[' || char === '(')) { + formatted.push(char); + formatted.push('\n'); + indent++; + formatted.push(' '.repeat(indent * tabs)); + } else if (!inString && (char === '}' || char === ']' || char === ')')) { + formatted.push('\n'); + indent--; + formatted.push(' '.repeat(indent * tabs)); + formatted.push(char); + } else if (!inString && char === ',') { + formatted.push(char); + formatted.push('\n'); + formatted.push(' '.repeat(indent * tabs)); + } else { + formatted.push(char); + } + } + return formatted.join(''); +} + function chainCallback(object, property, callback) { if (object == undefined) { //This should not happen. @@ -355,6 +399,7 @@ app.registerExtension({ }; } + if (nodeData.name === "Griptape Display: Text") { const onNodeCreated = nodeType.prototype.onNodeCreated; nodeType.prototype.onNodeCreated = async function () { @@ -389,6 +434,41 @@ app.registerExtension({ this?.graph?.setDirtyCanvas(true, true); }; }; + if ( nodeData.name === "Griptape Display: Data as Text") { + const onNodeCreated = nodeType.prototype.onNodeCreated; + nodeType.prototype.onNodeCreated = async function () { + const me = onNodeCreated?.apply(this); + this.message = ComfyWidgets.STRING(this, 'Output Text', ['STRING', { multiline: true }], app).widget; + this.message.value = ""; + this.message.inputEl.style.borderRadius = "8px"; + this.message.inputEl.style.padding = "8px"; + this.message.inputEl.style.height = "100%"; + fitHeight(this, true); + return me; + } + + const onExecuted = nodeType.prototype.onExecuted; + nodeType.prototype.onExecuted = function (message) { + onExecuted?.apply(this, arguments); + let lineCount = 0; + for (const widget of this.widgets) { + if (widget.type === "customtext") { + const new_val = message["INPUT"].join(""); + let formattedJSON = formatAndDisplayJSON(new_val); + widget.value = formattedJSON; + + // Count the number of lines in the text + for (let char of formattedJSON) { + if (char === "\n") { + lineCount++; + } + } + } + } + this.onResize?.(this.size); + this?.graph?.setDirtyCanvas(true, true); + }; + }; } }); diff --git a/nodes/display_nodes.py b/nodes/display_nodes.py index 8db0732..aeebf91 100644 --- a/nodes/display_nodes.py +++ b/nodes/display_nodes.py @@ -62,8 +62,35 @@ class gtUIOutputStringNode: def func(self, INPUT=None): if INPUT: return { - "ui": {"INPUT": INPUT}, # UI message for the frontend - "result": (INPUT,), + "ui": {"INPUT": str(INPUT)}, # UI message for the frontend + "result": (str(INPUT),), + } + else: + return { + "ui": {"INPUT": ""}, + "result": ("",), + } + + +class gtUIOutputDataNode: + NAME = "Griptape Display: Data" + DESCRIPTION = "Display output data." + CATEGORY = "Griptape/Display" + + @classmethod + def INPUT_TYPES(s): + return {"required": {}, "optional": {"INPUT": ("*", {"forceInput": True})}} + + RETURN_TYPES = ("STRING",) + RETURN_NAMES = ("OUTPUT",) + FUNCTION = "func" + OUTPUT_NODE = True + + def func(self, INPUT=None): + if INPUT: + return { + "ui": {"INPUT": str(INPUT)}, # UI message for the frontend + "result": (str(INPUT),), } else: return {