commit 470e2237f7139a68a239a24642b26e7a403cd9c0 Author: BRADSEC Date: Sat Jan 25 16:39:27 2025 +1000 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff1302 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# Python +__pycache__/ +*.py[cod] +*.so +.Python +env/ +venv/ +.env +*.egg-info/ +dist/ +build/ + +# Go +*.exe +*.dll +*.so +*.dylib +*.test +*.out +/vendor/ + +# IDEs +.idea/ +.vscode/ +*.swp + +# OS +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b7fa72f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 BRADSEC + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b4c5671 --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +# String Essentials - Custom nodes for ComfyUI + +Custom nodes for ComfyUI that provide text/string manipulation capabilities. Particularly useful for modifying text from LLM outputs (Ollama, Claude.ai, OpenAI ChatGPT), such as prompts or image-to-text description results. + +![stringstrip](stringstrip.png)![stringreplace](stringreplace.png) + +## Features +- Remove or replace text, words, numbers in input strings +- Handle multi-word strings (partial sentences/phrases) +- Case-sensitive/insensitive matching +- Whole string matching option + +## String Strip Node +Removes specified strings from input text. Each line should contain the string to be searched. The string can contain multiple words. To match individual words/strings place on seperate lines. + +### Inputs +- **`input_string`**: The string or text to process +- **`strings_to_remove`**: List of strings to remove (one per line) +- **`match_case`**: Enable/disable case-sensitive matching +- **`match_whole_string`**: Ensure only exact matches are removed +- **`remove_extra_spaces`**: Clean up extra spaces after removal + +### String Strip Example Usage: +![examplestrip](examplestrip.png) + +## String Replace Node +Replaces text strings with new strings. Each line should contain a search and replace pair separated by a colon `:` See example image below. + +### Inputs +- **`input_string`**: The string or text to process +- **`replacement_pairs`**: List of search:replace pairs (one per line) +- **`match_case`**: Enable/disable case-sensitive matching +- **`match_whole_string`**: Ensure only exact matches are replaced +- **`remove_extra_spaces`**: Clean up extra spaces after replacement + +### String Replace Example Usage: +![examplereplace](examplereplace.png) + +## Installation + +1. Navigate to the `custom_nodes` directory in your ComfyUI installation path. +2. Clone the repository: + ```bash + git clone https://github.com/bradsec/ComfyUI_StringEssentials.git + ``` +3. Restart ComfyUI or refresh your nodes. + +4. Select node from the `utils` menu. `Add Node > utils >` `String Strip` or `String Replace` diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..1a8ca7e --- /dev/null +++ b/__init__.py @@ -0,0 +1,18 @@ +"""String manipulation nodes for ComfyUI""" + +from .string_strip_node import StringStripNode +from .string_replace_node import StringReplaceNode + +NODE_CLASS_MAPPINGS = { + "StringStrip": StringStripNode, + "StringReplace": StringReplaceNode +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "StringStrip": "String Strip", + "StringReplace": "String Replace" +} + +WEB_DIRECTORY = "./js" + +__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"] \ No newline at end of file diff --git a/examplereplace.png b/examplereplace.png new file mode 100644 index 0000000..bc40d3e Binary files /dev/null and b/examplereplace.png differ diff --git a/examplestrip.png b/examplestrip.png new file mode 100644 index 0000000..84ce46a Binary files /dev/null and b/examplestrip.png differ diff --git a/js/string_strip.js b/js/string_strip.js new file mode 100644 index 0000000..4d35a6a --- /dev/null +++ b/js/string_strip.js @@ -0,0 +1,25 @@ +import { app } from "../../../scripts/app.js"; + +app.registerExtension({ + name: "string.strip", + async beforeRegisterNodeDef(nodeType) { + if (nodeType.comfyClass === "StringStrip") { + nodeType.prototype.onNodeCreated = function() { + // Add an input port for `input_text` + this.addInput("input_string", "STRING"); + }; + } + } +}); + +app.registerExtension({ + name: "string.replace", + async beforeRegisterNodeDef(nodeType) { + if (nodeType.comfyClass === "StringReplace") { + nodeType.prototype.onNodeCreated = function() { + // Add an input port for `input_text` + this.addInput("input_string", "STRING"); + }; + } + } +}); \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..588c584 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,14 @@ +[project] +name = "comfyui_stringessentials" +description = "Essential string manipulation nodes for ComfyUI." +version = "1.0.0" +license = "MIT" + +[project.urls] +Repository = "https://github.com/bradsec/ComfyUI_StringEssentials" +# Used by Comfy Registry https://comfyregistry.org + +[tool.comfy] +PublisherId = "BRADSEC" +DisplayName = "ComfyUI String Essentials" +Icon = "" \ No newline at end of file diff --git a/string_replace_node.py b/string_replace_node.py new file mode 100644 index 0000000..0ae8adc --- /dev/null +++ b/string_replace_node.py @@ -0,0 +1,54 @@ +import re + +class StringReplaceNode: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "replacement_pairs": ("STRING", {"multiline": True, "default": "", + "tooltip": "Enter replacement pairs, one per line, in format 'search:replace'. Example: 'cat:dog' or 'A drawing of:A photo of'"}), + "match_case": ("BOOLEAN", {"default": False, + "label_on": "enabled", "label_off": "disabled"}), + "match_whole_string": ("BOOLEAN", {"default": True, + "label_on": "enabled", "label_off": "disabled"}), + "remove_extra_spaces": ("BOOLEAN", {"default": True, + "label_on": "enabled", "label_off": "disabled"}) + } + } + + RETURN_TYPES = ("STRING",) + RETURN_NAMES = ("modified_string",) + FUNCTION = "string_replace" + CATEGORY = "utils" + + def string_replace(self, input_string, replacement_pairs, match_case, match_whole_string, remove_extra_spaces): + result = input_string + flags = 0 if match_case else re.IGNORECASE + + for line in replacement_pairs.splitlines(): + line = line.strip() + if not line or ':' not in line: + continue + + search_str, replace_str = line.split(':', 1) + search_str = search_str.strip() + replace_str = replace_str.strip() + + if not search_str: + continue + + if match_whole_string: + pattern = re.escape(search_str) + pattern = r"(?