diff --git a/README.md b/README.md index b4b4eaf..29f9f06 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# πŸ”— Comfyui : Bjornulf_custom_nodes v0.29 πŸ”— +# πŸ”— Comfyui : Bjornulf_custom_nodes v0.31 πŸ”— # ❀️ Coffee : β˜•β˜•β˜•β˜•β˜• 5/5 @@ -77,19 +77,39 @@ wget --content-disposition -P /workspace/ComfyUI/models/checkpoints "https://civ - **v0.27**: Two new nodes : Loop (Model+Clip+Vae) and Random (Model+Clip+Vae) - aka Checkpoint / Model - **v0.28**: Fix random texts and add a lot of screenshots examples for several nodes. - **v0.29**: Fix floating points issues with loop float node. +- **v0.30**: Update the basic Loop node with optional input. +- **v0.31**: ❗Sorry, Breaking changes for Write/Show text nodes, cleaner system : 1 simple write text and the other is 1 advanced with console and special syntax. Also Show can now manage INT, FLOAT, TEXT. # πŸ“ Nodes descriptions -## 1/2/3 - πŸ‘ + βœ’ Show/Write Text -![Show Text](screenshots/write+show_text.png) -![Show Text](screenshots/write_in_console.png) -![Show Text](screenshots/write_text_select.png) +## 1 - πŸ‘ Show (Text, Int, Float) + +![Show Text](screenshots/show.png) **Description:** -Three simple nodes, two to write and one to show text. -Write nodes is a textarea where you can write your text. -The show text node will only display the text. (That's why I made it a different color : green, uneditable, display only.) -Write text nodes now allow for special syntax to accept random variants, like `{hood|helmet}` will randomly choose between hood or helmet. +The show node will only display text, or a list of several texts. (read only node) +3 types are managed : Green is for STRING type, Orange is for FLOAT type and blue is for INT type. + +## 2 - βœ’ Write Text + +![write Text](screenshots/write.png) + +**Description:** +Simple node to write text. + +## 3 - βœ’πŸ—” Advanced Write Text + +![write Text Advanced](screenshots/write_advanced.png) + +**Description:** +Advanced Write Text node allows for special syntax to accept random variants, like `{hood|helmet}` will randomly choose between hood or helmet. +You also have `seed` and `control_after_generate` to manage the randomness. +It is also displaying the text in the comfyui console. (Useful for debugging) +Example of console logs : +``` +Raw text: photo of a {green|blue|red|orange|yellow} {cat|rat|house} +Picked text: photo of a green house +``` ## 4 - πŸ”— Combine Texts ![Combine Texts](screenshots/combine_texts.png) @@ -102,13 +122,19 @@ Combine multiple text inputs into a single output. (can have separation with : c **Description:** Generate and display random text from a predefined list. Great for creating random prompts. -You can change fixed/randomize for `control_after_generate` to have a different text each time you run the workflow. (or not) +You also have `control_after_generate` to manage the randomness. ## 6 - β™» Loop ![Loop](screenshots/loop.png) **Description:** -General-purpose loop node. +General-purpose loop node, you can connect that in between anything. +It has an optional input, if no input is given, it will loop over the value of the STRING "if_no_input" (take you can edit). +❗ Careful this node accept everything as input and output, so you can use it with texts, integers, images, mask, segs etc... but be consistent with your inputs/outputs. +Do not use this Loop if you can do otherwise. + +This is an example together with my node 28, to force a different seed for each iteration : +![Loop](screenshots/loop4.png) ## 7 - β™» Loop Texts ![Loop Texts](screenshots/loop_texts.png) @@ -392,7 +418,7 @@ Loop over a list of images. Usage example : You have a list of images, and you want to apply the same process to all of them. Above is an example of the loop images node sending them to an Ipadapter style transfer workflow. (Same seed of course.) -### 39 - β™» Loop (βœ’ Write Text) +### 39 - β™» Loop (βœ’πŸ—” Advanced Write Text) ![loop write text](screenshots/loop_write_text.png) diff --git a/__init__.py b/__init__.py index cf502d3..4b813d4 100644 --- a/__init__.py +++ b/__init__.py @@ -1,6 +1,5 @@ from .images_to_video import imagesToVideo from .write_text import WriteText -from .write_text_console import WriteTextInConsole from .write_image_environment import WriteImageEnvironment from .write_image_characters import WriteImageCharacters from .write_image_character import WriteImageCharacter @@ -17,8 +16,8 @@ from .loop_samplers import LoopSamplers from .loop_schedulers import LoopSchedulers from .ollama import ollamaLoader from .show_text import ShowText -from .show_int import ShowInt -from .show_float import ShowFloat +# from .show_int import ShowInt +# from .show_float import ShowFloat from .save_text import SaveText from .save_tmp_image import SaveTmpImage from .save_image_path import SaveImagePath @@ -47,6 +46,8 @@ from .random_image import RandomImage from .loop_write_text import LoopWriteText # from .random_checkpoint import RandomCheckpoint from .loop_model_clip_vae import LoopModelClipVae +from .write_text_advanced import WriteTextAdvanced +# from .show import ShowWhatever # from .pass_preview_image import PassPreviewImage # from .check_black_image import CheckBlackImage @@ -57,6 +58,8 @@ from .loop_model_clip_vae import LoopModelClipVae NODE_CLASS_MAPPINGS = { # "Bjornulf_CustomStringType": CustomStringType, "Bjornulf_ollamaLoader": ollamaLoader, + "Bjornulf_WriteText": WriteText, + # "Bjornulf_ShowWhatever": ShowWhatever, "Bjornulf_LoopModelClipVae": LoopModelClipVae, # "Bjoenulf_RandomCheckpoint": RandomCheckpoint, "Bjornulf_LoopWriteText": LoopWriteText, @@ -78,8 +81,7 @@ NODE_CLASS_MAPPINGS = { # "Bjornulf_CheckBlackImage": CheckBlackImage, # "Bjornulf_ClearVRAM": ClearVRAM, "Bjornulf_SaveBjornulfLobeChat": SaveBjornulfLobeChat, - "Bjornulf_WriteText": WriteText, - "Bjornulf_WriteTextInConsole": WriteTextInConsole, + "Bjornulf_WriteTextAdvanced": WriteTextAdvanced, "Bjornulf_RemoveTransparency": RemoveTransparency, "Bjornulf_GrayscaleTransform": GrayscaleTransform, "Bjornulf_CombineBackgroundOverlay": CombineBackgroundOverlay, @@ -88,8 +90,8 @@ NODE_CLASS_MAPPINGS = { # "Bjornulf_WriteImageCharacter": WriteImageCharacter, # "Bjornulf_WriteImageAllInOne": WriteImageAllInOne, "Bjornulf_ShowText": ShowText, - "Bjornulf_ShowInt": ShowInt, - "Bjornulf_ShowFloat": ShowFloat, + # "Bjornulf_ShowInt": ShowInt, + # "Bjornulf_ShowFloat": ShowFloat, "Bjornulf_SaveText": SaveText, "Bjornulf_ResizeImage": ResizeImage, "Bjornulf_SaveImageToFolder": SaveImageToFolder, @@ -111,10 +113,9 @@ NODE_CLASS_MAPPINGS = { } NODE_DISPLAY_NAME_MAPPINGS = { - # "Bjornulf_CustomStringType": "!!! CUSTOM STRING TYPE !!!", "Bjornulf_WriteText": "βœ’ Write Text", - "Bjornulf_WriteTextInConsole": "βœ’πŸ—” Write Text (Console too) ", - "Bjornulf_LoopWriteText": "β™» Loop (βœ’ Write Text)", + "Bjornulf_WriteTextAdvanced": "βœ’πŸ—” Advanced Write Text", + "Bjornulf_LoopWriteTextAdvanced": "β™» Loop (βœ’πŸ—” Advanced Write Text)", "Bjornulf_LoopModelClipVae": "β™» Loop (Model+Clip+Vae)", "Bjornulf_LoopImages": "β™»πŸ–Ό Loop (Images)", "Bjornulf_CombineTextsByLines": "β™» Loop (All Lines from input πŸ”— combine by lines)", @@ -137,9 +138,10 @@ NODE_DISPLAY_NAME_MAPPINGS = { "Bjornulf_SaveBjornulfLobeChat": "πŸ–ΌπŸ’¬ Save image for Bjornulf LobeChat", "Bjornulf_TextToStringAndSeed": "πŸ”’ Text with random Seed", # "Bjornulf_ClearVRAM": "🧹 Clear VRAM", - "Bjornulf_ShowText": "πŸ‘ Show (Text)", - "Bjornulf_ShowInt": "πŸ‘ Show (Int)", - "Bjornulf_ShowFloat": "πŸ‘ Show (Float)", + # "Bjornulf_ShowWhatever": "πŸ‘ Show Anything", + "Bjornulf_ShowText": "πŸ‘ Show (Text, Int, Float)", + # "Bjornulf_ShowInt": "πŸ‘ Show (Int)", + # "Bjornulf_ShowFloat": "πŸ‘ Show (Float)", "Bjornulf_ImageMaskCutter": "πŸ–Όβœ‚ Cut Image with Mask", "Bjornulf_LoadImageWithTransparency": "πŸ–Ό Load Image with Transparency β–’", "Bjornulf_CombineBackgroundOverlay": "πŸ–Ό+πŸ–Ό Combine images (Background+Overlay alpha)", diff --git a/loop_basic_batch.py b/loop_basic_batch.py index 6b37969..a368f18 100644 --- a/loop_basic_batch.py +++ b/loop_basic_batch.py @@ -1,21 +1,39 @@ -class LoopBasicBatch: +class Everything(str): + def __ne__(self, __value: object) -> bool: + return False +class LoopBasicBatch: @classmethod def INPUT_TYPES(s): return { "required": { "nb_loops": ("INT", {"default": 1, "min": 0, "max": 1000, "step": 1}), + "default_text": ("STRING", {"default": "Default input"}) + }, + "optional": { + "input": (Everything("*"),) }, } - RETURN_TYPES = ("INT",) - OUTPUT_IS_LIST = (True, False) + RETURN_TYPES = (Everything("*"),) + RETURN_NAMES = ("output",) + OUTPUT_IS_LIST = (True,) FUNCTION = "create_loop_basic_batch" CATEGORY = "Bjornulf" - def create_loop_basic_batch(self, nb_loops): - range_values = list() - while nb_loops > 0: - range_values.append(1) - nb_loops -= 1 - return (range_values,) \ No newline at end of file + def create_loop_basic_batch(self, nb_loops, default_text, input=None): + if input is not None: + return ([input] * nb_loops,) + + # Determine the type of the default_text + if default_text.isdigit(): + self.RETURN_TYPES = ("INT",) + output = int(default_text) + elif default_text.replace('.', '', 1).isdigit() and default_text.count('.') == 1: + self.RETURN_TYPES = ("FLOAT",) + output = float(default_text) + else: + self.RETURN_TYPES = ("STRING",) + output = default_text + + return ([output] * nb_loops,) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 0a7c638..22e4c6f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "bjornulf_custom_nodes" description = "Nodes: Ollama, Text to Speech, Combine Texts, Random Texts, Save image for Bjornulf LobeChat, Text with random Seed, Random line from input, Combine images, Image to grayscale (black & white), Remove image Transparency (alpha), Resize Image, ..." -version = "0.29" +version = "0.31" license = {file = "LICENSE"} [project.urls] diff --git a/screenshots/loop.png b/screenshots/loop.png index 00ce1b9..ace30bf 100644 Binary files a/screenshots/loop.png and b/screenshots/loop.png differ diff --git a/screenshots/loop3.png b/screenshots/loop3.png new file mode 100644 index 0000000..6ac46d8 Binary files /dev/null and b/screenshots/loop3.png differ diff --git a/screenshots/loop4.png b/screenshots/loop4.png new file mode 100644 index 0000000..6e826c7 Binary files /dev/null and b/screenshots/loop4.png differ diff --git a/screenshots/show.png b/screenshots/show.png new file mode 100644 index 0000000..e519e9f Binary files /dev/null and b/screenshots/show.png differ diff --git a/screenshots/write+show_text.png b/screenshots/write+show_text.png deleted file mode 100644 index 25370a7..0000000 Binary files a/screenshots/write+show_text.png and /dev/null differ diff --git a/screenshots/write.png b/screenshots/write.png new file mode 100644 index 0000000..51f6c7a Binary files /dev/null and b/screenshots/write.png differ diff --git a/screenshots/write_advanced.png b/screenshots/write_advanced.png new file mode 100644 index 0000000..2521340 Binary files /dev/null and b/screenshots/write_advanced.png differ diff --git a/screenshots/write_in_console.png b/screenshots/write_in_console.png deleted file mode 100644 index a04ac09..0000000 Binary files a/screenshots/write_in_console.png and /dev/null differ diff --git a/screenshots/write_text_select.png b/screenshots/write_text_select.png deleted file mode 100644 index 1498952..0000000 Binary files a/screenshots/write_text_select.png and /dev/null differ diff --git a/show_float.py b/show_float.py deleted file mode 100644 index fc42d2e..0000000 --- a/show_float.py +++ /dev/null @@ -1,18 +0,0 @@ -class ShowFloat: - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "float_value": ("FLOAT", {"forceInput": True}), - }, - } - - INPUT_IS_LIST = True - RETURN_TYPES = () - FUNCTION = "show_float" - OUTPUT_NODE = True - INPUT_IS_LIST = (True,) - CATEGORY = "Bjornulf" - - def show_float(self, float_value): - return {"ui": {"text": float_value}} diff --git a/show_int.py b/show_int.py deleted file mode 100644 index 8ba1735..0000000 --- a/show_int.py +++ /dev/null @@ -1,18 +0,0 @@ -class ShowInt: - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "int_value": ("INT", {"forceInput": True}), - }, - } - - INPUT_IS_LIST = True - RETURN_TYPES = () - FUNCTION = "show_int" - OUTPUT_NODE = True - INPUT_IS_LIST = (True,) - CATEGORY = "Bjornulf" - - def show_int(self, int_value): - return {"ui": {"text": int_value}} diff --git a/show_text.py b/show_text.py index 32662c5..d49ddeb 100644 --- a/show_text.py +++ b/show_text.py @@ -1,18 +1,43 @@ +class Everything(str): + def __ne__(self, _): + return False + class ShowText: @classmethod def INPUT_TYPES(cls): return { "required": { - "text_value": ("STRING", {"forceInput": True}), + "text_int_float": (Everything("*"), {"forceInput": True}), }, } - INPUT_IS_LIST = True RETURN_TYPES = () FUNCTION = "show_text" OUTPUT_NODE = True INPUT_IS_LIST = (True,) CATEGORY = "Bjornulf" - def show_text(self, text_value): - return {"ui": {"text": text_value}} + def detect_type(self, value): + if isinstance(value, int): + return 'integer' + elif isinstance(value, float): + # Check if it has a decimal part + if value % 1 == 0: + return 'float' if str(value).endswith('.0') else 'integer' + return 'float' + elif isinstance(value, str): + try: + float_val = float(value) + if '.' in value: + return 'float string' + if float_val.is_integer(): + return 'integer string' + return 'float string' + except ValueError: + return 'normal string' + else: + return 'other type' + + def show_text(self, text_int_float): + type_info = [f"{value}" for value in text_int_float] + return {"ui": {"text": type_info}} \ No newline at end of file diff --git a/web/js/random_line_from_input.js b/web/js/random_line_from_input.js deleted file mode 100644 index 5d40009..0000000 --- a/web/js/random_line_from_input.js +++ /dev/null @@ -1,14 +0,0 @@ -import { app } from "../../../scripts/app.js"; - -app.registerExtension({ - name: "Bjornulf.RandomLineFromInput", - async nodeCreated(node) { - if (node.comfyClass === "Bjornulf_RandomLineFromInput") { - // Set seed widget to hidden input - const seedWidget = node.widgets.find(w => w.name === "seed"); - if (seedWidget) { - seedWidget.type = "HIDDEN"; - } - } - } -}); diff --git a/web/js/random_seed_with_text.js b/web/js/random_seed_with_text.js deleted file mode 100644 index a2ca6eb..0000000 --- a/web/js/random_seed_with_text.js +++ /dev/null @@ -1,19 +0,0 @@ -import { app } from "../../../scripts/app.js"; - -app.registerExtension({ - name: "Bjornulf.TextToStringAndSeed", - async nodeCreated(node) { - if (node.comfyClass === "Bjornulf_TextToStringAndSeed") { - // Set seed widget to hidden input - const seedWidget = node.widgets.find(w => w.name === "seed"); - if (seedWidget) { - seedWidget.type = "HIDDEN"; - } - // Set seed widget to hidden input - const controlWidget = node.widgets.find(w => w.name === "control_after_generate"); - if (controlWidget) { - controlWidget.type = "HIDDEN"; - } - } - } -}); diff --git a/web/js/random_texts.js b/web/js/random_texts.js index e5718cd..3c4a113 100644 --- a/web/js/random_texts.js +++ b/web/js/random_texts.js @@ -36,10 +36,10 @@ app.registerExtension({ }; // Set seed widget to hidden input - const seedWidget = node.widgets.find(w => w.name === "seed"); - if (seedWidget) { - seedWidget.type = "HIDDEN"; - } + // const seedWidget = node.widgets.find(w => w.name === "seed"); + // if (seedWidget) { + // seedWidget.type = "HIDDEN"; + // } // Move number_of_inputs to the top initially const numInputsWidget = node.widgets.find(w => w.name === "number_of_inputs"); diff --git a/web/js/show_float.js b/web/js/show_float.js deleted file mode 100644 index 471b8f1..0000000 --- a/web/js/show_float.js +++ /dev/null @@ -1,76 +0,0 @@ -import { app } from "../../../scripts/app.js"; -import { ComfyWidgets } from "../../../scripts/widgets.js"; - -// Styles for the text area -const textAreaStyles = { - readOnly: true, - opacity: 1, - padding: '10px', - border: '1px solid #ccc', - borderRadius: '5px', - backgroundColor: '#222', - color: 'Lime', - fontFamily: 'Arial, sans-serif', - fontSize: '14px', - lineHeight: '1.4', - resize: 'vertical', - overflowY: 'auto', -}; - -// Displays input text on a node -app.registerExtension({ - name: "Bjornulf.ShowFloat", - async beforeRegisterNodeDef(nodeType, nodeData, app) { - if (nodeData.name === "Bjornulf_ShowFloat") { - function createStyledTextArea(text) { - const widget = ComfyWidgets["STRING"](this, "text", ["STRING", { multiline: true }], app).widget; - widget.inputEl.readOnly = true; - const textArea = widget.inputEl; - - Object.assign(textArea.style, textAreaStyles); - textArea.classList.add('bjornulf-show-text'); - widget.value = text; - return widget; - } - - function populate(text) { - if (this.widgets) { - for (let i = 1; i < this.widgets.length; i++) { - this.widgets[i].onRemove?.(); - } - this.widgets.length = 1; - } - - const v = Array.isArray(text) ? text : [text]; - for (const list of v) { - if (list) { - createStyledTextArea.call(this, list); - } - } - - requestAnimationFrame(() => { - const sz = this.computeSize(); - if (sz[0] < this.size[0]) sz[0] = this.size[0]; - if (sz[1] < this.size[1]) sz[1] = this.size[1]; - this.onResize?.(sz); - app.graph.setDirtyCanvas(true, false); - }); - } - - // When the node is executed we will be sent the input text, display this in the widget - const onExecuted = nodeType.prototype.onExecuted; - nodeType.prototype.onExecuted = function (message) { - onExecuted?.apply(this, arguments); - populate.call(this, message.text); - }; - - const onConfigure = nodeType.prototype.onConfigure; - nodeType.prototype.onConfigure = function () { - onConfigure?.apply(this, arguments); - if (this.widgets_values?.length) { - populate.call(this, this.widgets_values); - } - }; - } - }, -}); \ No newline at end of file diff --git a/web/js/show_int.js b/web/js/show_int.js deleted file mode 100644 index 6234708..0000000 --- a/web/js/show_int.js +++ /dev/null @@ -1,76 +0,0 @@ -import { app } from "../../../scripts/app.js"; -import { ComfyWidgets } from "../../../scripts/widgets.js"; - -// Styles for the text area -const textAreaStyles = { - readOnly: true, - opacity: 1, - padding: '10px', - border: '1px solid #ccc', - borderRadius: '5px', - backgroundColor: '#222', - color: 'Lime', - fontFamily: 'Arial, sans-serif', - fontSize: '14px', - lineHeight: '1.4', - resize: 'vertical', - overflowY: 'auto', -}; - -// Displays input text on a node -app.registerExtension({ - name: "Bjornulf.ShowInt", - async beforeRegisterNodeDef(nodeType, nodeData, app) { - if (nodeData.name === "Bjornulf_ShowInt") { - function createStyledTextArea(text) { - const widget = ComfyWidgets["STRING"](this, "text", ["STRING", { multiline: true }], app).widget; - widget.inputEl.readOnly = true; - const textArea = widget.inputEl; - - Object.assign(textArea.style, textAreaStyles); - textArea.classList.add('bjornulf-show-text'); - widget.value = text; - return widget; - } - - function populate(text) { - if (this.widgets) { - for (let i = 1; i < this.widgets.length; i++) { - this.widgets[i].onRemove?.(); - } - this.widgets.length = 1; - } - - const v = Array.isArray(text) ? text : [text]; - for (const list of v) { - if (list) { - createStyledTextArea.call(this, list); - } - } - - requestAnimationFrame(() => { - const sz = this.computeSize(); - if (sz[0] < this.size[0]) sz[0] = this.size[0]; - if (sz[1] < this.size[1]) sz[1] = this.size[1]; - this.onResize?.(sz); - app.graph.setDirtyCanvas(true, false); - }); - } - - // When the node is executed we will be sent the input text, display this in the widget - const onExecuted = nodeType.prototype.onExecuted; - nodeType.prototype.onExecuted = function (message) { - onExecuted?.apply(this, arguments); - populate.call(this, message.text); - }; - - const onConfigure = nodeType.prototype.onConfigure; - nodeType.prototype.onConfigure = function () { - onConfigure?.apply(this, arguments); - if (this.widgets_values?.length) { - populate.call(this, this.widgets_values); - } - }; - } - }, -}); \ No newline at end of file diff --git a/web/js/show_text.js b/web/js/show_text.js index 2f2a01a..646cd2f 100644 --- a/web/js/show_text.js +++ b/web/js/show_text.js @@ -5,7 +5,8 @@ import { ComfyWidgets } from "../../../scripts/widgets.js"; const textAreaStyles = { readOnly: true, opacity: 1, - padding: '10px', + padding: '4px', + paddingLeft: '7px', border: '1px solid #ccc', borderRadius: '5px', backgroundColor: '#222', @@ -13,7 +14,7 @@ const textAreaStyles = { fontFamily: 'Arial, sans-serif', fontSize: '14px', lineHeight: '1.4', - resize: 'vertical', + resize: 'none', overflowY: 'auto', }; @@ -22,32 +23,36 @@ app.registerExtension({ name: "Bjornulf.ShowText", async beforeRegisterNodeDef(nodeType, nodeData, app) { if (nodeData.name === "Bjornulf_ShowText") { - function createStyledTextArea(text) { - const widget = ComfyWidgets["STRING"](this, "text", ["STRING", { multiline: true }], app).widget; - widget.inputEl.readOnly = true; - const textArea = widget.inputEl; - - Object.assign(textArea.style, textAreaStyles); - textArea.classList.add('bjornulf-show-text'); - widget.value = text; - return widget; - } - function populate(text) { if (this.widgets) { - for (let i = 1; i < this.widgets.length; i++) { - this.widgets[i].onRemove?.(); - } - this.widgets.length = 1; - } - - const v = Array.isArray(text) ? text : [text]; - for (const list of v) { - if (list) { - createStyledTextArea.call(this, list); + const pos = this.widgets.findIndex((w) => w.name === "text"); + if (pos !== -1) { + for (let i = pos; i < this.widgets.length; i++) { + this.widgets[i].onRemove?.(); + } + this.widgets.length = pos; } } - + + for (const list of text) { + const w = ComfyWidgets["STRING"](this, "text", ["STRING", { multiline: true }], app).widget; + w.inputEl.readOnly = true; + Object.assign(w.inputEl.style, textAreaStyles); + + // Improved type detection + let color = 'Lime'; // Default color for strings + const value = list.toString().trim(); + + if (/^-?\d+$/.test(value)) { + color = '#0096FF'; // Integer + } else if (/^-?\d*\.?\d+$/.test(value)) { + color = 'orange'; // Float + } + + w.inputEl.style.color = color; + w.value = list; + } + requestAnimationFrame(() => { const sz = this.computeSize(); if (sz[0] < this.size[0]) sz[0] = this.size[0]; diff --git a/write_text.py b/write_text.py index 250bb89..84c192e 100644 --- a/write_text.py +++ b/write_text.py @@ -1,17 +1,9 @@ -import re -import random -import time - class WriteText: @classmethod def INPUT_TYPES(s): return { "required": { - "text": ("STRING", {"multiline": True}), - }, - "hidden": { - "seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}), - "control_after_update": ("INT", {"default": 0}) + "text": ("STRING", {"multiline": True, "lines": 10}), }, } @@ -21,24 +13,5 @@ class WriteText: OUTPUT_NODE = True CATEGORY = "Bjornulf" - def write_text(self, text, seed=None, control_after_update=None): - # If seed is not provided, generate a new one - if seed is None: - seed = int(time.time() * 1000) - - # Use the seed to initialize the random number generator - random.seed(seed) - - def replace_random(match): - options = match.group(1).split('|') - return random.choice(options) - - pattern = r'\{([^}]+)\}' - result = re.sub(pattern, replace_random, text) - - return (result,) - - @classmethod - def IS_CHANGED(s, text, seed=None, control_after_update=None): - # This method is called to determine if the node needs to be re-executed - return float("nan") # Always re-execute to ensure consistency \ No newline at end of file + def write_text(self, text): + return (text,) \ No newline at end of file diff --git a/write_text_advanced.py b/write_text_advanced.py new file mode 100644 index 0000000..f12e5a8 --- /dev/null +++ b/write_text_advanced.py @@ -0,0 +1,48 @@ +import re +import random +import time +import logging + +class WriteTextAdvanced: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "text": ("STRING", {"multiline": True, "lines": 10}), + }, + "optional": { + "seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}), + }, + } + + RETURN_TYPES = ("STRING",) + RETURN_NAMES = ("text",) + FUNCTION = "write_text_special" + OUTPUT_NODE = True + CATEGORY = "Bjornulf" + + def write_text_special(self, text, seed=None): + logging.info(f"Raw text: {text}") + # If seed is not provided, generate a new one + if len(text) > 10000: + return ("Text too large to process at once. Please split into smaller parts.",) + + if seed is None or seed == 0: + seed = int(time.time() * 1000) + + random.seed(seed) + + pattern = r'\{([^}]+)\}' + + def replace_random(match): + return random.choice(match.group(1).split('|')) + + result = re.sub(pattern, replace_random, text) + logging.info(f"Picked text: {result}") + + return (result,) + + @classmethod + def IS_CHANGED(s, text, seed=None): + return (text, seed) + diff --git a/write_text_console.py b/write_text_console.py deleted file mode 100644 index 4f26021..0000000 --- a/write_text_console.py +++ /dev/null @@ -1,43 +0,0 @@ -import re -import random -import time -import logging -class WriteTextInConsole: - @classmethod - def INPUT_TYPES(s): - return { - "required": { - "text": ("STRING", {"multiline": True}), - } - } - - # INPUT_IS_LIST = True - RETURN_TYPES = ("STRING",) - RETURN_NAMES = ("text",) - FUNCTION = "write_text_in_console" - OUTPUT_NODE = True - OUTPUT_IS_LIST = (False,) - CATEGORY = "Bjornulf" - - def write_text_in_console(self, text, seed=None, control_after_update=None): - logging.info(f"Text: {text}") - # If seed is not provided, generate a new one - if seed is None: - seed = int(time.time() * 1000) - - # Use the seed to initialize the random number generator - random.seed(seed) - - def replace_random(match): - options = match.group(1).split('|') - return random.choice(options) - - pattern = r'\{([^}]+)\}' - result = re.sub(pattern, replace_random, text) - - return (result,) - - @classmethod - def IS_CHANGED(s, text, seed=None, control_after_update=None): - # This method is called to determine if the node needs to be re-executed - return float("nan") # Always re-execute to ensure consistency \ No newline at end of file