diff --git a/README.md b/README.md
index de9ad27..f7b85f4 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,9 @@
# noEmbryo Nodes
A diverse set of nodes for ComfyUI.
-* [PromptTermList (1-6)](#PromptTermList)
-* [Resolution Scale](#ResolutionScale)
-* [Regex Text Chopper](#RegexTextChopper)
+- [PromptTermList (1-6)](#prompttermlist-1-6)
+- [Resolution Scale](#resolution-scale)
+- [Regex Text Chopper](#regex-text-chopper)
+- [Auto Save Workflow](#auto-save-workflow)
You can access them through "Add node > noEmbryo" submenu.
@@ -10,7 +11,7 @@ You can access them through "Add node > noEmbryo" submenu.
[![License: MIT][MIT]](LICENSE)
---
-## PromptTermList (1-6)
+## PromptTermList (1-6)
These are some nodes that help with the creation of Prompts inside [ComfyUI](https://github.com/comfyanonymous/ComfyUI).
@@ -27,20 +28,20 @@ The "label" part is what we see at the node's dropdown menu, and the "value" par
These `json` files are located inside the `TermLists` directory, in the node's folder.
There are two ways to add a new term.
-* From within ComfyUI:
- * Connect a text box to the node's `text` input.
- * Write the "label"/"value" part in the box using the following format:
+- From within ComfyUI:
+ - Connect a text box to the node's `text` input.
+ - Write the "label"/"value" part in the box using the following format:
```
label=Descriptive text
value=masterpiece, artful and cozy
```
- * Enable the `store_input` switch.
- * Run a generation job.
- * Refresh the page.
-* Manually:
- * Just open the `json` file and add/remove/change entries.
+ - Enable the `store_input` switch.
+ - Run a generation job.
+ - Refresh the page.
+- Manually:
+ - Just open the `json` file and add/remove/change entries.
- Of course we must be very careful with this, to keep the `json` format of labels/values (with the appropriate commas), otherwise the file will not be parsed.
+ Ofcourse we must be very careful with this, to keep the `json` format of labels/values (with the appropriate commas), otherwise the file will not be parsed.
This `text` input is also useful if we want to manually add something *after* our term, or as the *only* term if we select the `None` label of the dropdown.
The `strength` value is changing the impact of the term by using the parenthesis format like this: `(a great term:1.3)`
@@ -51,16 +52,30 @@ label=The label to be deleted
value=
```
---
-## Resolution Scale
+## Resolution Scale

A simple node that outputs the resolution of an image using the dimensions of an input image or some custom user-defined dimensions, using a Scale Factor.
If there is an input image connected, setting either `width` or `height` to 0 will use the other dimension to scale the image (but always multiple of 4).
---
-## Regex Text Chopper
+## Regex Text Chopper

-A node that "chops" a text using a regular expression and outputs the chopped parts of the text.
+A node that "chops" a text using a regular expression and outputs the chopped parts of the text.
+
+---
+## Auto Save Workflow
+
+This node can save the current workflow to a `.json` file, every time a generation job is run.
+- **UI controls**
+ - **save_directory** is the directory where the `.json` file will be saved.
+ It can be a relative path inside the ComfyUI's output directory, or an absolute path of your hard drive.
+ - **filename** is the name of the `.json` file.
+ It can contain the `{timestamp}` placeholder, which will be replaced with the current timestamp (for unique filenames).
+ - **trigger** switch will enable (or not) the saving of the workflow.
+- **Outputs**
+ - **status** outputs a text with the status of the saving process (the path of the saved file, or an error message).
+ - **✳️trigger** is a dummy output that's used to trigger the saving process, even if nothing is connected to the node.
---
## Installation
diff --git a/nodes.py b/nodes.py
index 3030ea6..b2269f5 100644
--- a/nodes.py
+++ b/nodes.py
@@ -1,7 +1,8 @@
-import io
-import re
+import os, re, io
import json
from os.path import realpath, join, dirname
+from datetime import datetime
+import folder_paths
MANIFEST = {"name": "noEmbryo Nodes",
"version": (1, 0, 3),
@@ -11,7 +12,7 @@ MANIFEST = {"name": "noEmbryo Nodes",
"license": "MIT",
}
__author__ = "noEmbryo"
-__version__ = "1.0.5"
+__version__ = "1.1.0"
# LISTS_PATH = realpath("./custom_nodes/ComfyUI-noEmbryo/TermLists/")
LISTS_PATH = join(dirname(realpath(__file__)), "TermLists")
@@ -262,6 +263,77 @@ class RegExTextChopper:
return text1, text2, text3, text4, text_all
+class AutoSaveWorkflow:
+ @classmethod
+ def INPUT_TYPES(cls):
+ return {
+ "required": {
+ "save_directory": ("STRING", {
+ "default": "saved_workflows",
+ "tooltip": "Relative to ComfyUI output directory or absolute path"
+ }),
+ "filename": ("STRING", {
+ "default": "workflow_{timestamp}",
+ "tooltip": "Filename (include {timestamp} for unique timestamps)"
+ }),
+ "trigger": ("BOOLEAN", {
+ "default": True,
+ "label_on": "Enabled",
+ "label_off": "Disabled",
+ "tooltip": "Save the workflow if Enabled"
+ }),
+ },
+ "hidden": {
+ "prompt": "PROMPT",
+ "extra_pnginfo": "EXTRA_PNGINFO",
+ "trigger": "BOOLEAN", # Hidden trigger input
+ },
+ }
+
+ RETURN_TYPES = ("STRING", "BOOLEAN")
+ RETURN_NAMES = ("status", "✳️trigger")
+ OUTPUT_TOOLTIPS = ("Get a status report text",
+ "Dammy output, to trigger execution if nothing is connected")
+ FUNCTION = "execute"
+ CATEGORY = "utils"
+ OUTPUT_NODE = True
+
+ def execute(self, trigger, save_directory, filename, prompt=None, extra_pnginfo=None):
+ status = "Trigger disabled - workflow not saved"
+
+ if trigger:
+ try:
+ workflow_data = extra_pnginfo.get("workflow", {}) if extra_pnginfo else {}
+
+ # Process save directory
+ if os.path.isabs(save_directory):
+ output_dir = save_directory
+ else:
+ output_dir = os.path.join(folder_paths.get_output_directory(),
+ save_directory)
+ os.makedirs(output_dir, exist_ok=True)
+
+ # Process filename with timestamp
+ timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
+ processed_filename = filename.replace("{timestamp}", timestamp)
+
+ # Ensure .json extension
+ if not processed_filename.lower().endswith('.json'):
+ processed_filename += '.json'
+
+ save_path = os.path.join(output_dir, processed_filename)
+
+ # Save workflow to JSON
+ with open(save_path, "w", encoding="utf-8") as f:
+ json.dump(workflow_data, f, indent=4)
+
+ status = f"Workflow saved to: {save_path}"
+ except Exception as e:
+ status = f"Error saving workflow: {str(e)}"
+
+ return (status,)
+
+
NODE_CLASS_MAPPINGS = {"PromptTermList1": PromptTermList1,
"PromptTermList2": PromptTermList2,
"PromptTermList3": PromptTermList3,
@@ -270,6 +342,7 @@ NODE_CLASS_MAPPINGS = {"PromptTermList1": PromptTermList1,
"PromptTermList6": PromptTermList6,
f"Resolution Scale /{__author__}": ResolutionScale,
f"Regex Text Chopper /{__author__}": RegExTextChopper,
+ f"Auto Save Workflow /{__author__}": AutoSaveWorkflow
}
NODE_DISPLAY_NAME_MAPPINGS = {"PromptTermList1": f"PromptTermList 1 /{__author__}",
@@ -282,4 +355,6 @@ NODE_DISPLAY_NAME_MAPPINGS = {"PromptTermList1": f"PromptTermList 1 /{__author__
f"Resolution Scale /{__author__}",
f"Regex Text Chopper /{__author__}":
f"Regex Text Chopper /{__author__}",
+ f"Auto Save Workflow /{__author__}":
+ f"Auto Save Workflow /{__author__}",
}
diff --git a/pyproject.toml b/pyproject.toml
index 55d2b8b..a3c1fb6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -2,10 +2,12 @@
name = "comfyui-noembryo"
description = """
A collection of nodes for ComyUI.
-- "PromptTermList (1-6)" nodes to help with the creation of Prompts.
-- "Resolution Scale" is a node that resizes an image using pixels or scale factor.
-- "Regex Text Chopper" is a node that cuts text based on regex."""
-version = "1.0.5"
+* "PromptTermList (1-6)" nodes to help with the creation of Prompts.
+* "Resolution Scale" is a node that resizes an image using pixels or scale factor.
+* "Regex Text Chopper" is a node that cuts text based on regex.
+* "Auto Save Workflow" can save the current workflow to a .json file automatically.
+"""
+version = "1.1.0"
license = {text = "MIT License"}
[project.urls]
diff --git a/stuff/auto_save_workflow.png b/stuff/auto_save_workflow.png
new file mode 100644
index 0000000..90db641
Binary files /dev/null and b/stuff/auto_save_workflow.png differ