Add custom nodes, Civitai loras (LFS), and vast.ai setup script
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled
Includes 30 custom nodes committed directly, 7 Civitai-exclusive loras stored via Git LFS, and a setup script that installs all dependencies and downloads HuggingFace-hosted models on vast.ai. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
156
custom_nodes/ComfyUI-Crystools/.gitignore
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintainted in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
*.pyc
|
||||
|
||||
.idea
|
||||
/node_modules
|
||||
/node.zip
|
||||
21
custom_nodes/ComfyUI-Crystools/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Crystian
|
||||
|
||||
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.
|
||||
672
custom_nodes/ComfyUI-Crystools/README.md
Normal file
@@ -0,0 +1,672 @@
|
||||
# comfyui-crystools [](https://paypal.me/crystian77) <a src="https://colab.research.google.com/assets/colab-badge.svg" href="https://colab.research.google.com/drive/1xiTiPmZkcIqNOsLQPO1UNCdJZqgK3U5k?usp=sharing"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open in Colab"></a>
|
||||
|
||||
**_🪛 A powerful set of tools for your belt when you work with ComfyUI 🪛_**
|
||||
|
||||
With this suit, you can see the resources monitor, progress bar & time elapsed, metadata and compare between two images, compare between two JSONs, show any value to console/display, pipes, and more!
|
||||
This provides better nodes to load/save images, previews, etc, and see "hidden" data without loading a new workflow.
|
||||
|
||||

|
||||
|
||||
# Table of contents
|
||||
- [General](#general)
|
||||
- [Metadata](#metadata)
|
||||
- [Debugger](#debugger)
|
||||
- [Image](#image)
|
||||
- [Pipe](#pipe)
|
||||
- [Utils](#utils)
|
||||
- [Primitives](#primitives)
|
||||
- [List](#list)
|
||||
- [Switch](#switch)
|
||||
- Others: [About](#about), [To do](#to-do), [Changelog](#changelog), [Installation](#installation), [Use](#use)
|
||||
|
||||
---
|
||||
|
||||
## General
|
||||
|
||||
### Resources monitor
|
||||
|
||||
**🎉Finally, you can see the resources used by ComfyUI (CPU, GPU, RAM, VRAM, GPU Temp and space) on the menu in real-time!**
|
||||
|
||||
Horizontal:
|
||||

|
||||
|
||||
Vertical:
|
||||

|
||||
|
||||
Now you can identify the bottlenecks in your workflow and know when it's time to restart the server, unload models or even close some tabs!
|
||||
|
||||
You can configure the refresh rate which resources to show:
|
||||
|
||||

|
||||
|
||||
> **Notes:**
|
||||
> - The GPU data is only available when you use CUDA (only NVIDIA cards, sorry AMD users).
|
||||
> - This extension needs ComfyUI 1915 (or higher).
|
||||
> - The cost of the monitor is low (0.1 to 0.5% of utilization), you can disable it from settings (`Refres rate` to `0`).
|
||||
> - Data comes from these libraries:
|
||||
> - [psutil](https://pypi.org/project/psutil/)
|
||||
> - [torch](https://pytorch.org/)
|
||||
> - [pynvml](https://pypi.org/project/pynvml/) (official NVIDIA library)
|
||||
|
||||
|
||||
### Progress bar
|
||||
|
||||
You can see the progress of your workflow with a progress bar on the menu!
|
||||
|
||||

|
||||
|
||||
https://github.com/crystian/comfyui-crystools/assets/3886806/35cc1257-2199-4b85-936e-2e31d892959c
|
||||
|
||||
Additionally, it shows the time elapsed at the end of the workflow, and you can `click` on it to see the **current working node.**
|
||||
|
||||
> **Notes:**
|
||||
> - If you don't want to see it, you can turn it off from settings (`Show progress bar in menu`)
|
||||
|
||||
|
||||
## Metadata
|
||||
|
||||
### Node: Metadata extractor
|
||||
|
||||
This node is used to extract the metadata from the image and handle it as a JSON source for other nodes.
|
||||
You can see **all information**, even metadata from other sources (like Photoshop, see sample).
|
||||
|
||||
The input comes from the [load image with metadata](#node-load-image-with-metadata) or [preview from image](#node-preview-from-image) nodes (and others in the future).
|
||||
|
||||

|
||||
|
||||
**Sample:** [metadata-extractor.json](./samples/metadata-extractor.json)
|
||||
|
||||
><details>
|
||||
> <summary>Other metadata sample (photoshop)</summary>
|
||||
>
|
||||
> With metadata from Photoshop
|
||||

|
||||
></details>
|
||||
|
||||
><details>
|
||||
> <summary><i>Parameters</i></summary>
|
||||
>
|
||||
> - input:
|
||||
> - metadata_raw: The metadata raw from the image or preview node
|
||||
> - Output:
|
||||
> - prompt: The prompt used to produce the image.
|
||||
> - workflow: The workflow used to produce the image (all information about nodes, values, etc).
|
||||
> - file info: The file info of the image/metadata (resolution, size, etc) is human readable.
|
||||
> - raw to JSON: The entire metadata is raw but formatted/readable.
|
||||
> - raw to property: The entire metadata is raw in "properties" format.
|
||||
> - raw to csv: The entire metadata is raw in "csv" format.
|
||||
></details>
|
||||
|
||||
<br />
|
||||
|
||||
### Node: Metadata comparator
|
||||
|
||||
This node is so useful for comparing two metadata and seeing the differences (**the main reason why I created this extension!**)
|
||||
|
||||
You can compare 3 inputs: "Prompt", "Workflow" and "Fileinfo"
|
||||
|
||||
There are three potential "outputs": `values_changed`, `dictionary_item_added`, and `dictionary_item_removed` (in this order of priority).
|
||||
|
||||

|
||||
|
||||
**Sample:** [metadata-comparator.json](./samples/metadata-comparator.json)
|
||||
|
||||
**Notes:**
|
||||
- I use [DeepDiff](https://pypi.org/project/deepdiff) for that. For more info check the link.
|
||||
- If you want to compare two JSONs, you can use the [JSON comparator](#node-JSON-comparator) node.
|
||||
|
||||
|
||||
><details>
|
||||
> <summary><i>Parameters</i></summary>
|
||||
>
|
||||
> - options:
|
||||
> - what: What to compare, you can choose between "Prompt", "Workflow" and "Fileinfo"
|
||||
> - input:
|
||||
> - metadata_raw_old: The metadata raw to start comparing
|
||||
> - metadata_raw_new: The metadata raw to compare
|
||||
> - Output:
|
||||
> - diff: This is the same output you can see in the display of the node; you can use it on other nodes.
|
||||
></details>
|
||||
|
||||
<br />
|
||||
|
||||
---
|
||||
|
||||
## Debugger
|
||||
|
||||
### Node: Show Metadata
|
||||
|
||||
With this node, you will be able to see the JSON produced from your entire prompt and workflow so that you can know all the values (and more) of your prompt quickly without opening the file (PNG or JSON).
|
||||
|
||||

|
||||
|
||||
**Sample:** [debugger-metadata.json](./samples/debugger-metadata.json)
|
||||
|
||||
><details>
|
||||
> <summary><i>Parameters</i></summary>
|
||||
>
|
||||
> - Options:
|
||||
> - Active: Enable/disable the node
|
||||
> - Parsed: Show the parsed JSON or plain text
|
||||
> - What: Show the prompt or workflow (prompt are values to produce the image, and workflow is the entire workflow of ComfyUI)
|
||||
></details>
|
||||
|
||||
<br />
|
||||
|
||||
### Node: Show any
|
||||
|
||||
You can see on the console or display any text or data from the nodes. Connect it to what you want to inspect, and you will see it.
|
||||
|
||||

|
||||
|
||||
**Sample:** [debugger-any.json](./samples/debugger-any.json)
|
||||
|
||||
><details>
|
||||
> <summary><i>Parameters</i></summary>
|
||||
>
|
||||
> - Input:
|
||||
> - any_value: Any value to show, which can be a string, number, etc.
|
||||
> - Options:
|
||||
> - Console: Enable/disable write to console
|
||||
> - Display: Enable/disable write on this node
|
||||
> - Prefix: Prefix to console
|
||||
></details>
|
||||
|
||||
<br />
|
||||
|
||||
### Node: Show any to JSON
|
||||
|
||||
It is the same as the previous one, but it formatted the value to JSON (only display).
|
||||
|
||||

|
||||
|
||||
**Sample:** [debugger-json.json](./samples/debugger-json.json)
|
||||
|
||||
><details>
|
||||
> <summary><i>Parameters</i></summary>
|
||||
>
|
||||
> - Input:
|
||||
> - any_value: Any value to try to convert to JSON
|
||||
> - Output:
|
||||
> - string: The same string is shown on the display
|
||||
></details>
|
||||
|
||||
<br />
|
||||
|
||||
---
|
||||
|
||||
## Image
|
||||
|
||||
### Node: Load image with metadata
|
||||
This node is the same as the default one, but it adds three features: Prompt, Metadata, and supports **subfolders** of the "input" folder.
|
||||
|
||||

|
||||
|
||||
**Sample:** [image-load.json](./samples/image-load.json)
|
||||
|
||||
><details>
|
||||
> <summary><i>Parameters</i></summary>
|
||||
>
|
||||
> - Input:
|
||||
> - image: Read the images from the input folder (and subfolder) (you can drop the image here or even paste an image from the clipboard)
|
||||
> - Output:
|
||||
> - Image/Mask: The same as the default node
|
||||
> - Prompt: The prompt used to produce the image (not the workflow)
|
||||
> - Metadata RAW: The metadata raw of the image (full workflow) as string
|
||||
></details>
|
||||
|
||||
**Note:** The subfolders support inspired on: [comfyui-imagesubfolders](https://github.com/catscandrive/comfyui-imagesubfolders)
|
||||
|
||||
<br />
|
||||
|
||||
### Node: Save image with extra metadata
|
||||
This node is the same as the default one, but it adds two features: Save the workflow in the png or not, and you can add any piece of metadata (as JSON).
|
||||
|
||||
This saves custom data on the image, so you can share it with others, and they can see the workflow and metadata (see [preview from metadata](#node-preview-from-metadata)), even your custom data.
|
||||
|
||||
It can be any type of information that supports text and JSON.
|
||||
|
||||

|
||||
|
||||
**Sample:** [image-save.json](./samples/image-save.json)
|
||||
|
||||
><details>
|
||||
> <summary><i>Parameters</i></summary>
|
||||
>
|
||||
> - options:
|
||||
> - with_workflow: If you want to save into the image workflow (special to share the workflow with others)
|
||||
> - Input:
|
||||
> - image: The image to save (same as the default node)
|
||||
> - Output:
|
||||
> - Metadata RAW: The metadata raw of the image (full workflow) as string
|
||||
></details>
|
||||
|
||||
**Note:** The data is saved as special "exif" (as ComfyUI does) in the png file; you can read it with [Load image with metadata](#node-load-image-with-metadata).
|
||||
|
||||
> **Important:**
|
||||
> - If you want to save your workflow with a particular name and your data as creator, you need to use the [ComfyUI-Crystools-save](https://github.com/crystian/ComfyUI-Crystools-save) extension; try it!
|
||||

|
||||
|
||||
|
||||
<br />
|
||||
|
||||
### Node: Preview from image
|
||||
|
||||
This node is used to preview the image with the **current prompt** and additional features.
|
||||
|
||||

|
||||
|
||||
**Feature:** It supports cache (shows as "CACHED") (not permanent yet!), so you can disconnect the node and still see the image and data, so you can use it to compare with others!
|
||||
|
||||

|
||||
|
||||
As you can see the seed, steps, and cfg were changed
|
||||
|
||||
**Sample:** [image-preview-image.json](./samples/image-preview-image.json)
|
||||
|
||||
><details>
|
||||
> <summary><i>Parameters</i></summary>
|
||||
>
|
||||
> - Input:
|
||||
> - image: Any kind of image link
|
||||
> - Output:
|
||||
> - Metadata RAW: The metadata raw of the image and full workflow.
|
||||
> - You can use it to **compare with others** (see [metadata comparator](#node-metadata-comparator))
|
||||
> - The file info like filename, resolution, datetime and size with **the current prompt, not the original one!** (see important note)
|
||||
></details>
|
||||
|
||||
> **Important:**
|
||||
> - If you want to read the metadata of the image, you need to use the [load image with metadata](#node-load-image-with-metadata) and use the output "metadata RAW" not the image link.
|
||||
> - To do a preview, it is necessary to save it first on the temporal folder, and the data shown is from the temporal image, **not the original one** even **the prompt!**
|
||||
|
||||
<br />
|
||||
|
||||
### Node: Preview from metadata
|
||||
|
||||
This node is used to preview the image from the metadata and shows additional data (all around this one).
|
||||
It supports the same features as [preview from image](#node-preview-from-image) (cache, metadata raw, etc.). But the important difference is you see **real data from the image** (not the temporal one or the current prompt).
|
||||
|
||||

|
||||
|
||||
**Sample:** [image-preview-metadata.json](./samples/image-preview-metadata.json)
|
||||
|
||||
<br />
|
||||
|
||||
### Node: Show resolution
|
||||
|
||||
This node is used to show the resolution of an image.
|
||||
|
||||
> Can be used with any image link.
|
||||
|
||||

|
||||
|
||||
**Sample:** [image-resolution.json](./samples/image-resolution.json)
|
||||
|
||||
><details>
|
||||
> <summary><i>Parameters</i></summary>
|
||||
>
|
||||
> - Input:
|
||||
> - image: Any kind of image link
|
||||
> - Output:
|
||||
> - Width: The width of the image
|
||||
> - Height: The height of the image
|
||||
></details>
|
||||
|
||||
<br />
|
||||
|
||||
---
|
||||
|
||||
## Pipe
|
||||
|
||||
### Nodes: Pipe to/edit any, Pipe from any
|
||||
|
||||
This powerful set of nodes is used to better organize your pipes.
|
||||
|
||||
The "Pipe to/edit any" node is used to encapsulate multiple links into a single one. It includes support for editing and easily adding the modified content back to the same pipe number.
|
||||
|
||||
The "Pipe from any" node is used to extract the content of a pipe.
|
||||
|
||||
Typical example:
|
||||
|
||||

|
||||
|
||||
With pipes:
|
||||
|
||||

|
||||
|
||||
**Sample:** [pipe-1.json](./samples/pipe-1.json)
|
||||
|
||||
Editing pipes:
|
||||
|
||||

|
||||
|
||||
**Sample:** [pipe-2.json](./samples/pipe-2.json)
|
||||
|
||||
><details>
|
||||
> <summary><i>Parameters</i></summary>
|
||||
>
|
||||
> - Input:
|
||||
> - CPipeAny: This is the type of this pipe you can use to edit (see the sample)
|
||||
> - any_*: 6 possible inputs to use
|
||||
> - Output:
|
||||
> - CPipeAny: You can continue the pipe with this output; you can use it to bifurcate the pipe (see the sample)
|
||||
></details>
|
||||
|
||||
>**Important:**
|
||||
> - Please note that it supports "any," meaning it does not validate (not yet!) the correspondence of input nodes with the output ones. When creating the link, it is recommended to link consciously number by number.
|
||||
> - "RecursionError" It's crucial to note that the flow of links **must be in the same direction**, and they cannot be mixed with other flows that use the result of this one. Otherwise, this may lead to recursion and block the server (you need to restart it!)
|
||||
|
||||
|
||||
><details>
|
||||
> <summary><i>Bad example with "RecursionError: maximum recursion depth exceeded"</i></summary>
|
||||
>
|
||||
> If you see something like this on your console, you need to check your pipes. That is bad sample of pipes, you can't mix the flows.
|
||||

|
||||
></details>
|
||||
|
||||
<br />
|
||||
|
||||
---
|
||||
|
||||
## Utils
|
||||
|
||||
Some useful nodes to use in your workflow.
|
||||
|
||||
### Node: JSON comparator
|
||||
|
||||
This node is so useful to compare two JSONs and see the differences.
|
||||
|
||||

|
||||
|
||||
**Sample:** [utils-json-comparator.json](./samples/utils-json-comparator.json)
|
||||
|
||||
|
||||
><details>
|
||||
> <summary><i>Parameters</i></summary>
|
||||
>
|
||||
> - input:
|
||||
> - json_old: The first JSON to start compare
|
||||
> - json_new: The JSON to compare
|
||||
> - Output:
|
||||
> - diff: A new JSON with the differences
|
||||
></details>
|
||||
|
||||
|
||||
**Notes:**
|
||||
As you can see, it is the same as the [metadata comparator](#node-metadata-comparator) but with JSONs.
|
||||
The other is intentionally simple to compare two images metadata; this is more generic.
|
||||
The main difference is that you can compare any JSON, not only metadata.
|
||||
|
||||
<br />
|
||||
|
||||
### Node: Stats system
|
||||
|
||||
This node is used to show the system stats (RAM, VRAM, and Space).
|
||||
It **should** connect as a pipe.
|
||||
|
||||

|
||||
|
||||
**Sample:** [utils-stats.json](./samples/utils-stats.json)
|
||||
|
||||
><details>
|
||||
> <summary><i>Parameters</i></summary>
|
||||
>
|
||||
> - input:
|
||||
> - latent: The latent to use to measure the stats
|
||||
> - Output:
|
||||
> - latent: Return the same latent to continue the pipe
|
||||
></details>
|
||||
|
||||
**Notes:** The original is in [WAS](https://github.com/WASasquatch/was-node-suite-comfyui), I only show it on the display.
|
||||
|
||||
<br />
|
||||
|
||||
---
|
||||
|
||||
## Primitives
|
||||
|
||||
### Nodes: Primitive boolean, Primitive integer, Primitive float, Primitive string, Primitive string multiline
|
||||
|
||||
A set of nodes with primitive values to use in your prompts.
|
||||
|
||||

|
||||
|
||||
<br />
|
||||
|
||||
---
|
||||
|
||||
## List
|
||||
A set of nodes with a list of values (any or strings/texts) for any proposal (news nodes to use it coming soon!).
|
||||
|
||||
> **Important:** You can use other nodes like "Show any" to see the values of the list
|
||||
|
||||
### Node: List of strings
|
||||
|
||||
**Feature:** You can concatenate them.
|
||||
|
||||

|
||||
|
||||
**Sample:** [list-strings.json](./samples/list-strings.json)
|
||||
|
||||
><details>
|
||||
> <summary><i>Parameters</i></summary>
|
||||
>
|
||||
> - Input:
|
||||
> - string_*: 8 possible inputs to use
|
||||
> - delimiter: Use to concatenate the values on the output
|
||||
> - Output:
|
||||
> - concatenated: A string with all values concatenated
|
||||
> - list_string: The list of strings (only with values)
|
||||
></details>
|
||||
|
||||
<br />
|
||||
|
||||
### Node: List of any
|
||||
|
||||
You can concatenate any value (it will try to convert it to a string and show the value), so it is util to see several values at the same time.
|
||||
|
||||

|
||||
|
||||
**Sample:** [list-any.json](./samples/list-any.json)
|
||||
|
||||
><details>
|
||||
> <summary><i>Parameters</i></summary>
|
||||
>
|
||||
> - Input:
|
||||
> - any_*: 8 possible inputs to use
|
||||
> - Output:
|
||||
> - list_any: The list of any elements (only with values)
|
||||
></details>
|
||||
|
||||
<br />
|
||||
|
||||
---
|
||||
|
||||
## Switch
|
||||
A set of nodes to switch between flows.
|
||||
|
||||
All switches are boolean; you can switch between flows by simply changing the value of the switch.
|
||||
You have predefined switches (string, latent, image, conditioning) but you can use "Switch any" for any value/type.
|
||||
|
||||

|
||||
|
||||
**Sample:** [switch.json](./samples/switch.json)
|
||||
|
||||
<br />
|
||||
|
||||
---
|
||||
|
||||
## About
|
||||
|
||||
**Notes from the author:**
|
||||
- This is my first project in python ¯\\_(ツ)_/¯ (PR are welcome!)
|
||||
- I'm a software engineer but in other languages (web technologies)
|
||||
- My Instagram is: https://www.instagram.com/crystian.ia I'll publish my works on it, so consider following me for news! :)
|
||||
- I'm not a native English speaker, so sorry for my English :P
|
||||
|
||||
---
|
||||
|
||||
## To do
|
||||
- [ ] Several unit tests
|
||||
- [ ] Add permanent cache for preview/metadata image (to survive to F5! or restart the server)
|
||||
|
||||
---
|
||||
|
||||
## Changelog
|
||||
|
||||
### Crystools
|
||||
|
||||
### 1.27.0 (17/08/2025)
|
||||
- revert the lower case on name, cannot change on registry ¯\_(ツ)_/¯
|
||||
- zluda check removed, it is not necessary anymore
|
||||
|
||||
### 1.25.3 (27/07/2025)
|
||||
- change the name to lower case
|
||||
|
||||
### 1.25.1 (02/06/2025)
|
||||
- fix issues with switches on settings menu
|
||||
- node: "Switch from any" added
|
||||
- load image with metadata: filtered (exclude hidden folders an typically metadata files)
|
||||
- other fixes
|
||||
|
||||
### 1.24.0 (02/06/2025)
|
||||
- PRs by community merged
|
||||
- Improved VRAM usage/readout
|
||||
- HDD error handling
|
||||
- Lazy switches
|
||||
|
||||
### 1.23.0 (02/06/2025)
|
||||
- Jetson support added by @johnnynunez
|
||||
- some ui fixes
|
||||
|
||||
### 1.20.0 (21/10/2024)
|
||||
- BETA of JSON file reader and extractor, to allow you to read your own JSON files and extract the values to use in your workflow
|
||||
|
||||
### 1.19.0 (06/10/2024)
|
||||
- HORIZONTAL UI! New version is ready! 🎉
|
||||
|
||||
### 1.18.0 (21/09/2024)
|
||||
- HORIZONTAL UI! 🎉
|
||||
- Configurable size of monitors on settings menu
|
||||
|
||||
### 1.17.0 (21/09/2024)
|
||||
- Settings menu reorganized
|
||||
- Preparing for horizontal UI
|
||||
- Update from ComfyUI (typescript and new features)
|
||||
|
||||
### 1.16.0 (31/07/2024)
|
||||
- Rollback of AMD support by manager does not support other repository parameter (https://test.pypi.org/simple by pyrsmi)
|
||||
|
||||
### 1.15.0 (21/07/2024)
|
||||
- AMD Branch merged to the main branch, should work for AMD users on **Linux**
|
||||
|
||||
### 1.14.0 (15/07/2024)
|
||||
- Tried to use AMD info, but it breaks installation on windows, so I removed it ¯\_(ツ)_/¯
|
||||
- AMD Branch added, if you use AMD and Linux, you can try it (not tested for me)
|
||||
|
||||
### 1.13.0 (01/07/2024)
|
||||
- Integrate with new ecosystem of ComfyUI
|
||||
- Webp support added on load image with metadata node
|
||||
|
||||
### 1.12.0 (27/03/2024)
|
||||
- GPU Temperature added
|
||||
|
||||
### 1.10.0 (17/01/2024)
|
||||
- Multi-gpu added
|
||||
|
||||
### 1.9.2 (15/01/2024)
|
||||
- Big refactor on hardwareInfo and monitor.ts, gpu was separated on another file, preparing for multi-gpu support
|
||||
|
||||
### 1.8.0 (14/01/2024) - internal
|
||||
- HDD monitor selector on settings
|
||||
|
||||
### 1.7.0 (11/01/2024) - internal
|
||||
- Typescript added!
|
||||
|
||||
### 1.6.0 (11/01/2024)
|
||||
- Fix issue [#7](https://github.com/crystian/comfyui-crystools/issues/7) to the thread deadlock on concurrency
|
||||
|
||||
### 1.5.0 (10/01/2024)
|
||||
- Improvements on the resources monitor and how handle the threads
|
||||
- Some fixes
|
||||
|
||||
### 1.3.0 (08/01/2024)
|
||||
- Added in general Resources monitor (CPU, GPU, RAM, VRAM, and space)
|
||||
- Added this icon to identify this set of tools: 🪛
|
||||
|
||||
### 1.2.0 (05/01/2024)
|
||||
- progress bar added
|
||||
|
||||
### 1.1.0 (29/12/2023)
|
||||
- Node added: "Save image with extra metadata"
|
||||
- Support to **read** Jpeg metadata added (not save)
|
||||
|
||||
### 1.0.0 (26/12/2023)
|
||||
- First release
|
||||
|
||||
|
||||
### Crystools-save - DEPRECATED (01/06/2025)
|
||||
|
||||
### 1.1.0 (07/01/2024)
|
||||
- Labeling updated according to the new version of Crystools (this project)
|
||||
|
||||
### 1.0.0 (29/12/2023)
|
||||
- Created another extension to save the info about the author on workflow: [ComfyUI-Crystools-save](https://github.com/crystian/ComfyUI-Crystools-save)
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
### Install from GitHub
|
||||
1. Install [ComfyUi](https://github.com/comfyanonymous/ComfyUI).
|
||||
2. Clone this repo into `custom_nodes`:
|
||||
```
|
||||
cd ComfyUI/custom_nodes
|
||||
git clone https://github.com/crystian/comfyui-crystools.git
|
||||
cd comfyui-crystools
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
3. Start up ComfyUI.
|
||||
|
||||
#### For AMD users
|
||||
If you are an AMD user with Linux, you can try the AMD branch:
|
||||
|
||||
**ATTENTION:** Don't install with the manager, you need to install manually:
|
||||
|
||||
```
|
||||
cd ComfyUI/custom_nodes
|
||||
git clone -b AMD https://github.com/crystian/comfyui-crystools.git
|
||||
cd comfyui-crystools
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### Install from manager
|
||||
|
||||
Search for `crystools` in the [manager](https://github.com/ltdrdata/ComfyUI-Manager.git) and install it.
|
||||
|
||||
### Using on Google Colab
|
||||
|
||||
You can use it on Google Colab, but you need to install it manually:
|
||||
|
||||
[Google Colab](https://colab.research.google.com/drive/1xiTiPmZkcIqNOsLQPO1UNCdJZqgK3U5k?usp=sharing)
|
||||
|
||||
* Run the first cell to install ComfyUI and launch the server
|
||||
* After it finishes, use the link to open the a new tab, looking a line like this:
|
||||
```
|
||||
This is the URL to access ComfyUI: https://identifying-complications-fw-some.trycloudflare.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Use
|
||||
|
||||
You can use it as any other node, just using the menu in the category `crystools` or double clicking on the canvas (I recommended using the "oo" to fast filter), all nodes were post fixing with `[Crystools]`.
|
||||
|
||||

|
||||

|
||||
|
||||
If for some reason you need to see the logs, you can define the environment variable `CRYSTOOLS_LOGLEVEL` and set the [value](https://docs.python.org/es/3/howto/logging.html).
|
||||
|
||||
---
|
||||
|
||||
Made with ❤️ by Crystian.
|
||||
108
custom_nodes/ComfyUI-Crystools/__init__.py
Normal file
@@ -0,0 +1,108 @@
|
||||
"""
|
||||
@author: Crystian
|
||||
@title: Crystools
|
||||
@nickname: Crystools
|
||||
@version: 1.27.4
|
||||
@project: "https://github.com/crystian/comfyui-crystools",
|
||||
@description: Plugins for multiples uses, mainly for debugging, you need them! IG: https://www.instagram.com/crystian.ia
|
||||
"""
|
||||
|
||||
from .core import version, logger
|
||||
logger.info(f'Crystools version: {version}')
|
||||
|
||||
from .nodes._names import CLASSES
|
||||
from .nodes.primitive import CBoolean, CText, CTextML, CInteger, CFloat
|
||||
from .nodes.switch import CSwitchBooleanAny, CSwitchBooleanLatent, CSwitchBooleanConditioning, CSwitchBooleanImage, \
|
||||
CSwitchBooleanString, CSwitchBooleanMask, CSwitchFromAny
|
||||
from .nodes.debugger import CConsoleAny, CConsoleAnyToJson
|
||||
from .nodes.image import CImagePreviewFromImage, CImageLoadWithMetadata, CImageGetResolution, CImagePreviewFromMetadata, \
|
||||
CImageSaveWithExtraMetadata
|
||||
from .nodes.list import CListAny, CListString
|
||||
from .nodes.pipe import CPipeToAny, CPipeFromAny
|
||||
from .nodes.utils import CUtilsCompareJsons, CUtilsStatSystem
|
||||
from .nodes.metadata import CMetadataExtractor, CMetadataCompare
|
||||
from .nodes.parameters import CJsonFile, CJsonExtractor
|
||||
from .server import *
|
||||
from .general import *
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
CLASSES.CBOOLEAN_NAME.value: CBoolean,
|
||||
CLASSES.CTEXT_NAME.value: CText,
|
||||
CLASSES.CTEXTML_NAME.value: CTextML,
|
||||
CLASSES.CINTEGER_NAME.value: CInteger,
|
||||
CLASSES.CFLOAT_NAME.value: CFloat,
|
||||
|
||||
CLASSES.CDEBUGGER_CONSOLE_ANY_NAME.value: CConsoleAny,
|
||||
CLASSES.CDEBUGGER_CONSOLE_ANY_TO_JSON_NAME.value: CConsoleAnyToJson,
|
||||
|
||||
CLASSES.CLIST_ANY_NAME.value: CListAny,
|
||||
CLASSES.CLIST_STRING_NAME.value: CListString,
|
||||
|
||||
CLASSES.CSWITCH_FROM_ANY_NAME.value: CSwitchFromAny,
|
||||
CLASSES.CSWITCH_ANY_NAME.value: CSwitchBooleanAny,
|
||||
CLASSES.CSWITCH_LATENT_NAME.value: CSwitchBooleanLatent,
|
||||
CLASSES.CSWITCH_CONDITIONING_NAME.value: CSwitchBooleanConditioning,
|
||||
CLASSES.CSWITCH_IMAGE_NAME.value: CSwitchBooleanImage,
|
||||
CLASSES.CSWITCH_MASK_NAME.value: CSwitchBooleanMask,
|
||||
CLASSES.CSWITCH_STRING_NAME.value: CSwitchBooleanString,
|
||||
|
||||
CLASSES.CPIPE_TO_ANY_NAME.value: CPipeToAny,
|
||||
CLASSES.CPIPE_FROM_ANY_NAME.value: CPipeFromAny,
|
||||
|
||||
CLASSES.CIMAGE_LOAD_METADATA_NAME.value: CImageLoadWithMetadata,
|
||||
CLASSES.CIMAGE_GET_RESOLUTION_NAME.value: CImageGetResolution,
|
||||
CLASSES.CIMAGE_PREVIEW_IMAGE_NAME.value: CImagePreviewFromImage,
|
||||
CLASSES.CIMAGE_PREVIEW_METADATA_NAME.value: CImagePreviewFromMetadata,
|
||||
CLASSES.CIMAGE_SAVE_METADATA_NAME.value: CImageSaveWithExtraMetadata,
|
||||
|
||||
CLASSES.CMETADATA_EXTRACTOR_NAME.value: CMetadataExtractor,
|
||||
CLASSES.CMETADATA_COMPARATOR_NAME.value: CMetadataCompare,
|
||||
CLASSES.CUTILS_JSON_COMPARATOR_NAME.value: CUtilsCompareJsons,
|
||||
CLASSES.CUTILS_STAT_SYSTEM_NAME.value: CUtilsStatSystem,
|
||||
CLASSES.CJSONFILE_NAME.value: CJsonFile,
|
||||
CLASSES.CJSONEXTRACTOR_NAME.value: CJsonExtractor,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
CLASSES.CBOOLEAN_NAME.value: CLASSES.CBOOLEAN_DESC.value,
|
||||
CLASSES.CTEXT_NAME.value: CLASSES.CTEXT_DESC.value,
|
||||
CLASSES.CTEXTML_NAME.value: CLASSES.CTEXTML_DESC.value,
|
||||
CLASSES.CINTEGER_NAME.value: CLASSES.CINTEGER_DESC.value,
|
||||
CLASSES.CFLOAT_NAME.value: CLASSES.CFLOAT_DESC.value,
|
||||
|
||||
CLASSES.CDEBUGGER_CONSOLE_ANY_NAME.value: CLASSES.CDEBUGGER_ANY_DESC.value,
|
||||
CLASSES.CDEBUGGER_CONSOLE_ANY_TO_JSON_NAME.value: CLASSES.CDEBUGGER_CONSOLE_ANY_TO_JSON_DESC.value,
|
||||
|
||||
CLASSES.CLIST_ANY_NAME.value: CLASSES.CLIST_ANY_DESC.value,
|
||||
CLASSES.CLIST_STRING_NAME.value: CLASSES.CLIST_STRING_DESC.value,
|
||||
|
||||
CLASSES.CSWITCH_FROM_ANY_NAME.value: CLASSES.CSWITCH_FROM_ANY_DESC.value,
|
||||
CLASSES.CSWITCH_ANY_NAME.value: CLASSES.CSWITCH_ANY_DESC.value,
|
||||
CLASSES.CSWITCH_LATENT_NAME.value: CLASSES.CSWITCH_LATENT_DESC.value,
|
||||
CLASSES.CSWITCH_CONDITIONING_NAME.value: CLASSES.CSWITCH_CONDITIONING_DESC.value,
|
||||
CLASSES.CSWITCH_IMAGE_NAME.value: CLASSES.CSWITCH_IMAGE_DESC.value,
|
||||
CLASSES.CSWITCH_MASK_NAME.value: CLASSES.CSWITCH_MASK_DESC.value,
|
||||
CLASSES.CSWITCH_STRING_NAME.value: CLASSES.CSWITCH_STRING_DESC.value,
|
||||
|
||||
CLASSES.CPIPE_TO_ANY_NAME.value: CLASSES.CPIPE_TO_ANY_DESC.value,
|
||||
CLASSES.CPIPE_FROM_ANY_NAME.value: CLASSES.CPIPE_FROM_ANY_DESC.value,
|
||||
|
||||
CLASSES.CIMAGE_LOAD_METADATA_NAME.value: CLASSES.CIMAGE_LOAD_METADATA_DESC.value,
|
||||
CLASSES.CIMAGE_GET_RESOLUTION_NAME.value: CLASSES.CIMAGE_GET_RESOLUTION_DESC.value,
|
||||
CLASSES.CIMAGE_PREVIEW_IMAGE_NAME.value: CLASSES.CIMAGE_PREVIEW_IMAGE_DESC.value,
|
||||
CLASSES.CIMAGE_PREVIEW_METADATA_NAME.value: CLASSES.CIMAGE_PREVIEW_METADATA_DESC.value,
|
||||
CLASSES.CIMAGE_SAVE_METADATA_NAME.value: CLASSES.CIMAGE_SAVE_METADATA_DESC.value,
|
||||
|
||||
CLASSES.CMETADATA_EXTRACTOR_NAME.value: CLASSES.CMETADATA_EXTRACTOR_DESC.value,
|
||||
CLASSES.CMETADATA_COMPARATOR_NAME.value: CLASSES.CMETADATA_COMPARATOR_DESC.value,
|
||||
|
||||
CLASSES.CUTILS_JSON_COMPARATOR_NAME.value: CLASSES.CUTILS_JSON_COMPARATOR_DESC.value,
|
||||
CLASSES.CUTILS_STAT_SYSTEM_NAME.value: CLASSES.CUTILS_STAT_SYSTEM_DESC.value,
|
||||
|
||||
CLASSES.CJSONFILE_NAME.value: CLASSES.CJSONFILE_DESC.value,
|
||||
CLASSES.CJSONEXTRACTOR_NAME.value: CLASSES.CJSONEXTRACTOR_DESC.value,
|
||||
}
|
||||
|
||||
|
||||
WEB_DIRECTORY = "./web"
|
||||
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]
|
||||
6
custom_nodes/ComfyUI-Crystools/core/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from .logger import *
|
||||
from .keys import *
|
||||
from .types import *
|
||||
from .config import *
|
||||
from .common import *
|
||||
from .version import *
|
||||
119
custom_nodes/ComfyUI-Crystools/core/common.py
Normal file
@@ -0,0 +1,119 @@
|
||||
import os
|
||||
import json
|
||||
import torch
|
||||
from deepdiff import DeepDiff
|
||||
from ..core import CONFIG, logger
|
||||
|
||||
|
||||
# just a helper function to set the widget values (or clear them)
|
||||
def setWidgetValues(value=None, unique_id=None, extra_pnginfo=None) -> None:
|
||||
if unique_id and extra_pnginfo:
|
||||
workflow = extra_pnginfo["workflow"]
|
||||
node = next((x for x in workflow["nodes"] if str(x["id"]) == unique_id), None)
|
||||
|
||||
if node:
|
||||
node["widgets_values"] = value
|
||||
|
||||
return None
|
||||
|
||||
|
||||
# find difference between two jsons
|
||||
def findJsonStrDiff(json1, json2):
|
||||
msgError = "Could not compare jsons"
|
||||
returnJson = {"error": msgError}
|
||||
try:
|
||||
# TODO review this
|
||||
# dict1 = json.loads(json1)
|
||||
# dict2 = json.loads(json2)
|
||||
|
||||
returnJson = findJsonsDiff(json1, json2)
|
||||
|
||||
returnJson = json.dumps(returnJson, indent=CONFIG["indent"])
|
||||
except Exception as e:
|
||||
logger.warn(f"{msgError}: {e}")
|
||||
|
||||
return returnJson
|
||||
|
||||
|
||||
def findJsonsDiff(json1, json2):
|
||||
msgError = "Could not compare jsons"
|
||||
returnJson = {"error": msgError}
|
||||
|
||||
try:
|
||||
diff = DeepDiff(json1, json2, ignore_order=True, verbose_level=2)
|
||||
|
||||
returnJson = {k: v for k, v in diff.items() if
|
||||
k in ('dictionary_item_added', 'dictionary_item_removed', 'values_changed')}
|
||||
|
||||
# just for print "values_changed" at first
|
||||
returnJson = dict(reversed(returnJson.items()))
|
||||
|
||||
except Exception as e:
|
||||
logger.warn(f"{msgError}: {e}")
|
||||
|
||||
return returnJson
|
||||
|
||||
|
||||
# powered by:
|
||||
# https://github.com/WASasquatch/was-node-suite-comfyui/blob/main/WAS_Node_Suite.py
|
||||
# class: WAS_Samples_Passthrough_Stat_System
|
||||
def get_system_stats():
|
||||
import psutil
|
||||
|
||||
# RAM
|
||||
ram = psutil.virtual_memory()
|
||||
ram_used = ram.used / (1024 ** 3)
|
||||
ram_total = ram.total / (1024 ** 3)
|
||||
ram_stats = f"Used RAM: {ram_used:.2f} GB / Total RAM: {ram_total:.2f} GB"
|
||||
|
||||
# VRAM (with PyTorch)
|
||||
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
||||
vram_used = torch.cuda.memory_allocated(device) / (1024 ** 3)
|
||||
vram_total = torch.cuda.get_device_properties(device).total_memory / (1024 ** 3)
|
||||
vram_stats = f"Used VRAM: {vram_used:.2f} GB / Total VRAM: {vram_total:.2f} GB"
|
||||
|
||||
# Hard Drive Space
|
||||
hard_drive = psutil.disk_usage("/")
|
||||
used_space = hard_drive.used / (1024 ** 3)
|
||||
total_space = hard_drive.total / (1024 ** 3)
|
||||
hard_drive_stats = f"Used Space: {used_space:.2f} GB / Total Space: {total_space:.2f} GB"
|
||||
|
||||
return [ram_stats, vram_stats, hard_drive_stats]
|
||||
|
||||
|
||||
# return x and y resolution of an image (torch tensor)
|
||||
def getResolutionByTensor(image=None) -> dict:
|
||||
res = {"x": 0, "y": 0}
|
||||
|
||||
if image is not None:
|
||||
img = image.movedim(-1, 1)
|
||||
|
||||
res["x"] = img.shape[3]
|
||||
res["y"] = img.shape[2]
|
||||
|
||||
return res
|
||||
|
||||
|
||||
# by https://stackoverflow.com/questions/6080477/how-to-get-the-size-of-tar-gz-in-mb-file-in-python
|
||||
def get_size(path):
|
||||
size = os.path.getsize(path)
|
||||
if size < 1024:
|
||||
return f"{size} bytes"
|
||||
elif size < pow(1024, 2):
|
||||
return f"{round(size / 1024, 2)} KB"
|
||||
elif size < pow(1024, 3):
|
||||
return f"{round(size / (pow(1024, 2)), 2)} MB"
|
||||
elif size < pow(1024, 4):
|
||||
return f"{round(size / (pow(1024, 3)), 2)} GB"
|
||||
|
||||
|
||||
def get_nested_value(data, dotted_key, default=None):
|
||||
keys = dotted_key.split('.')
|
||||
for key in keys:
|
||||
if isinstance(data, str):
|
||||
data = json.loads(data)
|
||||
if isinstance(data, dict) and key in data:
|
||||
data = data[key]
|
||||
else:
|
||||
return default
|
||||
return data
|
||||
7
custom_nodes/ComfyUI-Crystools/core/config.py
Normal file
@@ -0,0 +1,7 @@
|
||||
import os
|
||||
import logging
|
||||
|
||||
CONFIG = {
|
||||
"loglevel": int(os.environ.get("CRYSTOOLS_LOGLEVEL", logging.INFO)),
|
||||
"indent": int(os.environ.get("CRYSTOOLS_INDENT", 2))
|
||||
}
|
||||
29
custom_nodes/ComfyUI-Crystools/core/keys.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class TEXTS(Enum):
|
||||
CUSTOM_NODE_NAME = "Crystools"
|
||||
LOGGER_PREFIX = "Crystools"
|
||||
CONCAT = "concatenated"
|
||||
INACTIVE_MSG = "inactive"
|
||||
INVALID_METADATA_MSG = "Invalid metadata raw"
|
||||
FILE_NOT_FOUND = "File not found!"
|
||||
|
||||
|
||||
class CATEGORY(Enum):
|
||||
TESTING = "_for_testing"
|
||||
MAIN = "crystools 🪛"
|
||||
PRIMITIVE = "/Primitive"
|
||||
DEBUGGER = "/Debugger"
|
||||
LIST = "/List"
|
||||
SWITCH = "/Switch"
|
||||
PIPE = "/Pipe"
|
||||
IMAGE = "/Image"
|
||||
UTILS = "/Utils"
|
||||
METADATA = "/Metadata"
|
||||
|
||||
|
||||
# remember, all keys should be in lowercase!
|
||||
class KEYS(Enum):
|
||||
LIST = "list_string"
|
||||
PREFIX = "prefix"
|
||||
39
custom_nodes/ComfyUI-Crystools/core/logger.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# by https://github.com/Kosinkadink/ComfyUI-Advanced-ControlNet/blob/main/control/logger.py
|
||||
import sys
|
||||
import copy
|
||||
import logging
|
||||
from .keys import TEXTS
|
||||
from .config import CONFIG
|
||||
|
||||
|
||||
class ColoredFormatter(logging.Formatter):
|
||||
COLORS = {
|
||||
"DEBUG": "\033[0;36m", # CYAN
|
||||
"INFO": "\033[0;32m", # GREEN
|
||||
"WARNING": "\033[0;33m", # YELLOW
|
||||
"ERROR": "\033[0;31m", # RED
|
||||
"CRITICAL": "\033[0;37;41m", # WHITE ON RED
|
||||
"RESET": "\033[0m", # RESET COLOR
|
||||
}
|
||||
|
||||
def format(self, record):
|
||||
colored_record = copy.copy(record)
|
||||
levelname = colored_record.levelname
|
||||
seq = self.COLORS.get(levelname, self.COLORS["RESET"])
|
||||
colored_record.levelname = f"{seq}{levelname}{self.COLORS['RESET']}"
|
||||
return super().format(colored_record)
|
||||
|
||||
|
||||
# Create a new logger
|
||||
logger = logging.getLogger(TEXTS.LOGGER_PREFIX.value)
|
||||
logger.propagate = False
|
||||
|
||||
# Add handler if we don't have one.
|
||||
if not logger.handlers:
|
||||
handler = logging.StreamHandler(sys.stdout)
|
||||
handler.setFormatter(ColoredFormatter("[%(name)s %(levelname)s] %(message)s"))
|
||||
logger.addHandler(handler)
|
||||
|
||||
# Configure logger
|
||||
loglevel = CONFIG["loglevel"]
|
||||
logger.setLevel(loglevel)
|
||||
36
custom_nodes/ComfyUI-Crystools/core/types.py
Normal file
@@ -0,0 +1,36 @@
|
||||
import sys
|
||||
|
||||
FLOAT = ("FLOAT", {"default": 1,
|
||||
"min": -sys.float_info.max,
|
||||
"max": sys.float_info.max,
|
||||
"step": 0.01})
|
||||
|
||||
BOOLEAN = ("BOOLEAN", {"default": True})
|
||||
BOOLEAN_FALSE = ("BOOLEAN", {"default": False})
|
||||
|
||||
INT = ("INT", {"default": 1,
|
||||
"min": -sys.maxsize,
|
||||
"max": sys.maxsize,
|
||||
"step": 1})
|
||||
|
||||
STRING = ("STRING", {"default": ""})
|
||||
|
||||
STRING_ML = ("STRING", {"multiline": True, "default": ""})
|
||||
|
||||
STRING_WIDGET = ("STRING", {"forceInput": True})
|
||||
|
||||
JSON_WIDGET = ("JSON", {"forceInput": True})
|
||||
|
||||
METADATA_RAW = ("METADATA_RAW", {"forceInput": True})
|
||||
|
||||
class AnyType(str):
|
||||
"""A special class that is always equal in not equal comparisons. Credit to pythongosssss"""
|
||||
|
||||
def __eq__(self, _) -> bool:
|
||||
return True
|
||||
|
||||
def __ne__(self, __value: object) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
any = AnyType("*")
|
||||
1
custom_nodes/ComfyUI-Crystools/core/version.py
Normal file
@@ -0,0 +1 @@
|
||||
version = "1.27.4"
|
||||
BIN
custom_nodes/ComfyUI-Crystools/docs/crystools-save.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/debugger-show-any.png
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/debugger-show-json.png
Normal file
|
After Width: | Height: | Size: 205 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/debugger-show-metadata.png
Normal file
|
After Width: | Height: | Size: 263 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/image-load.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/image-preview-diff.png
Normal file
|
After Width: | Height: | Size: 273 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/image-preview-metadata.png
Normal file
|
After Width: | Height: | Size: 264 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/image-preview.png
Normal file
|
After Width: | Height: | Size: 113 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/image-resolution.png
Normal file
|
After Width: | Height: | Size: 164 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/image-save.png
Normal file
|
After Width: | Height: | Size: 208 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/jake.gif
Normal file
|
After Width: | Height: | Size: 149 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/list-any.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/list-string.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/menu.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/metadata-comparator-mark.png
Normal file
|
After Width: | Height: | Size: 154 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/metadata-comparator.png
Normal file
|
After Width: | Height: | Size: 149 KiB |
|
After Width: | Height: | Size: 177 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/metadata-extractor.png
Normal file
|
After Width: | Height: | Size: 256 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/monitor-settings.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/monitor.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/monitor1.webp
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/monitor3.webp
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/pipe-0.png
Normal file
|
After Width: | Height: | Size: 299 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/pipe-1.png
Normal file
|
After Width: | Height: | Size: 284 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/pipe-2.png
Normal file
|
After Width: | Height: | Size: 343 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/pipe-3.png
Normal file
|
After Width: | Height: | Size: 187 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/primitives.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/progress-bar.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/screwdriver.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/shortcut.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/switches.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/utils-json-comparator.png
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
custom_nodes/ComfyUI-Crystools/docs/utils-stats.png
Normal file
|
After Width: | Height: | Size: 190 KiB |
3
custom_nodes/ComfyUI-Crystools/general/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .monitor import *
|
||||
from .hdd import *
|
||||
from .gpu import *
|
||||
300
custom_nodes/ComfyUI-Crystools/general/gpu.py
Normal file
@@ -0,0 +1,300 @@
|
||||
import torch
|
||||
import comfy.model_management
|
||||
from ..core import logger
|
||||
import os
|
||||
import platform
|
||||
|
||||
def is_jetson() -> bool:
|
||||
"""
|
||||
Determines if the Python environment is running on a Jetson device by checking the device model
|
||||
information or the platform release.
|
||||
"""
|
||||
PROC_DEVICE_MODEL = ''
|
||||
try:
|
||||
with open('/proc/device-tree/model', 'r') as f:
|
||||
PROC_DEVICE_MODEL = f.read().strip()
|
||||
logger.info(f"Device model: {PROC_DEVICE_MODEL}")
|
||||
return "NVIDIA" in PROC_DEVICE_MODEL
|
||||
except Exception as e:
|
||||
# logger.warning(f"JETSON: Could not read /proc/device-tree/model: {e} (If you're not using Jetson, ignore this warning)")
|
||||
# If /proc/device-tree/model is not available, check platform.release()
|
||||
platform_release = platform.release()
|
||||
logger.info(f"Platform release: {platform_release}")
|
||||
if 'tegra' in platform_release.lower():
|
||||
logger.info("Detected 'tegra' in platform release. Assuming Jetson device.")
|
||||
return True
|
||||
else:
|
||||
logger.info("JETSON: Not detected.")
|
||||
return False
|
||||
|
||||
IS_JETSON = is_jetson()
|
||||
|
||||
class CGPUInfo:
|
||||
"""
|
||||
This class is responsible for getting information from GPU (ONLY).
|
||||
"""
|
||||
cuda = False
|
||||
pynvmlLoaded = False
|
||||
jtopLoaded = False
|
||||
cudaAvailable = False
|
||||
torchDevice = 'cpu'
|
||||
cudaDevice = 'cpu'
|
||||
cudaDevicesFound = 0
|
||||
switchGPU = True
|
||||
switchVRAM = True
|
||||
switchTemperature = True
|
||||
gpus = []
|
||||
gpusUtilization = []
|
||||
gpusVRAM = []
|
||||
gpusTemperature = []
|
||||
|
||||
def __init__(self):
|
||||
if IS_JETSON:
|
||||
# Try to import jtop for Jetson devices
|
||||
try:
|
||||
from jtop import jtop
|
||||
self.jtopInstance = jtop()
|
||||
self.jtopInstance.start()
|
||||
self.jtopLoaded = True
|
||||
logger.info('jtop initialized on Jetson device.')
|
||||
except ImportError as e:
|
||||
logger.error('jtop is not installed. ' + str(e))
|
||||
except Exception as e:
|
||||
logger.error('Could not initialize jtop. ' + str(e))
|
||||
else:
|
||||
# Try to import pynvml for non-Jetson devices
|
||||
try:
|
||||
import pynvml
|
||||
self.pynvml = pynvml
|
||||
self.pynvml.nvmlInit()
|
||||
self.pynvmlLoaded = True
|
||||
logger.info('pynvml (NVIDIA) initialized.')
|
||||
except ImportError as e:
|
||||
logger.error('pynvml is not installed. ' + str(e))
|
||||
except Exception as e:
|
||||
logger.error('Could not init pynvml (NVIDIA). ' + str(e))
|
||||
|
||||
self.anygpuLoaded = self.pynvmlLoaded or self.jtopLoaded
|
||||
|
||||
try:
|
||||
self.torchDevice = comfy.model_management.get_torch_device_name(comfy.model_management.get_torch_device())
|
||||
except Exception as e:
|
||||
logger.error('Could not pick default device. ' + str(e))
|
||||
|
||||
if self.pynvmlLoaded and not self.jtopLoaded and not self.deviceGetCount():
|
||||
logger.warning('No GPU detected, disabling GPU monitoring.')
|
||||
self.anygpuLoaded = False
|
||||
self.pynvmlLoaded = False
|
||||
self.jtopLoaded = False
|
||||
|
||||
if self.anygpuLoaded:
|
||||
if self.deviceGetCount() > 0:
|
||||
self.cudaDevicesFound = self.deviceGetCount()
|
||||
|
||||
logger.info(f"GPU/s:")
|
||||
|
||||
for deviceIndex in range(self.cudaDevicesFound):
|
||||
deviceHandle = self.deviceGetHandleByIndex(deviceIndex)
|
||||
|
||||
gpuName = self.deviceGetName(deviceHandle, deviceIndex)
|
||||
|
||||
logger.info(f"{deviceIndex}) {gpuName}")
|
||||
|
||||
self.gpus.append({
|
||||
'index': deviceIndex,
|
||||
'name': gpuName,
|
||||
})
|
||||
|
||||
# Same index as gpus, with default values
|
||||
self.gpusUtilization.append(True)
|
||||
self.gpusVRAM.append(True)
|
||||
self.gpusTemperature.append(True)
|
||||
|
||||
self.cuda = True
|
||||
logger.info(self.systemGetDriverVersion())
|
||||
else:
|
||||
logger.warning('No GPU with CUDA detected.')
|
||||
else:
|
||||
logger.warning('No GPU monitoring libraries available.')
|
||||
|
||||
self.cudaDevice = 'cpu' if self.torchDevice == 'cpu' else 'cuda'
|
||||
self.cudaAvailable = torch.cuda.is_available()
|
||||
|
||||
if self.cuda and self.cudaAvailable and self.torchDevice == 'cpu':
|
||||
logger.warning('CUDA is available, but torch is using CPU.')
|
||||
|
||||
def getInfo(self):
|
||||
logger.debug('Getting GPUs info...')
|
||||
return self.gpus
|
||||
|
||||
def getStatus(self):
|
||||
gpuUtilization = -1
|
||||
gpuTemperature = -1
|
||||
vramUsed = -1
|
||||
vramTotal = -1
|
||||
vramPercent = -1
|
||||
|
||||
gpuType = ''
|
||||
gpus = []
|
||||
|
||||
if self.cudaDevice == 'cpu':
|
||||
gpuType = 'cpu'
|
||||
gpus.append({
|
||||
'gpu_utilization': -1,
|
||||
'gpu_temperature': -1,
|
||||
'vram_total': -1,
|
||||
'vram_used': -1,
|
||||
'vram_used_percent': -1,
|
||||
})
|
||||
else:
|
||||
gpuType = self.cudaDevice
|
||||
|
||||
if self.anygpuLoaded and self.cuda and self.cudaAvailable:
|
||||
for deviceIndex in range(self.cudaDevicesFound):
|
||||
deviceHandle = self.deviceGetHandleByIndex(deviceIndex)
|
||||
|
||||
gpuUtilization = -1
|
||||
vramPercent = -1
|
||||
vramUsed = -1
|
||||
vramTotal = -1
|
||||
gpuTemperature = -1
|
||||
|
||||
# GPU Utilization
|
||||
if self.switchGPU and self.gpusUtilization[deviceIndex]:
|
||||
try:
|
||||
gpuUtilization = self.deviceGetUtilizationRates(deviceHandle)
|
||||
except Exception as e:
|
||||
logger.error('Could not get GPU utilization. ' + str(e))
|
||||
logger.error('Monitor of GPU is turning off.')
|
||||
self.switchGPU = False
|
||||
|
||||
if self.switchVRAM and self.gpusVRAM[deviceIndex]:
|
||||
try:
|
||||
memory = self.deviceGetMemoryInfo(deviceHandle)
|
||||
vramUsed = memory['used']
|
||||
vramTotal = memory['total']
|
||||
|
||||
# Check if vramTotal is not zero or None
|
||||
if vramTotal and vramTotal != 0:
|
||||
vramPercent = vramUsed / vramTotal * 100
|
||||
except Exception as e:
|
||||
logger.error('Could not get GPU memory info. ' + str(e))
|
||||
self.switchVRAM = False
|
||||
|
||||
# Temperature
|
||||
if self.switchTemperature and self.gpusTemperature[deviceIndex]:
|
||||
try:
|
||||
gpuTemperature = self.deviceGetTemperature(deviceHandle)
|
||||
except Exception as e:
|
||||
logger.error('Could not get GPU temperature. Turning off this feature. ' + str(e))
|
||||
self.switchTemperature = False
|
||||
|
||||
gpus.append({
|
||||
'gpu_utilization': gpuUtilization,
|
||||
'gpu_temperature': gpuTemperature,
|
||||
'vram_total': vramTotal,
|
||||
'vram_used': vramUsed,
|
||||
'vram_used_percent': vramPercent,
|
||||
})
|
||||
|
||||
return {
|
||||
'device_type': gpuType,
|
||||
'gpus': gpus,
|
||||
}
|
||||
|
||||
def deviceGetCount(self):
|
||||
if self.pynvmlLoaded:
|
||||
return self.pynvml.nvmlDeviceGetCount()
|
||||
elif self.jtopLoaded:
|
||||
# For Jetson devices, we assume there's one GPU
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def deviceGetHandleByIndex(self, index):
|
||||
if self.pynvmlLoaded:
|
||||
return self.pynvml.nvmlDeviceGetHandleByIndex(index)
|
||||
elif self.jtopLoaded:
|
||||
return index # On Jetson, index acts as handle
|
||||
else:
|
||||
return 0
|
||||
|
||||
def deviceGetName(self, deviceHandle, deviceIndex):
|
||||
if self.pynvmlLoaded:
|
||||
gpuName = 'Unknown GPU'
|
||||
|
||||
try:
|
||||
gpuName = self.pynvml.nvmlDeviceGetName(deviceHandle)
|
||||
try:
|
||||
gpuName = gpuName.decode('utf-8', errors='ignore')
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
except UnicodeDecodeError as e:
|
||||
gpuName = 'Unknown GPU (decoding error)'
|
||||
logger.error(f"UnicodeDecodeError: {e}")
|
||||
|
||||
return gpuName
|
||||
elif self.jtopLoaded:
|
||||
# Access the GPU name from self.jtopInstance.gpu
|
||||
try:
|
||||
gpu_info = self.jtopInstance.gpu
|
||||
gpu_name = next(iter(gpu_info.keys()))
|
||||
return gpu_name
|
||||
except Exception as e:
|
||||
logger.error('Could not get GPU name. ' + str(e))
|
||||
return 'Unknown GPU'
|
||||
else:
|
||||
return ''
|
||||
|
||||
def systemGetDriverVersion(self):
|
||||
if self.pynvmlLoaded:
|
||||
return f'NVIDIA Driver: {self.pynvml.nvmlSystemGetDriverVersion()}'
|
||||
elif self.jtopLoaded:
|
||||
# No direct method to get driver version from jtop
|
||||
return 'NVIDIA Driver: unknown'
|
||||
else:
|
||||
return 'Driver unknown'
|
||||
|
||||
def deviceGetUtilizationRates(self, deviceHandle):
|
||||
if self.pynvmlLoaded:
|
||||
return self.pynvml.nvmlDeviceGetUtilizationRates(deviceHandle).gpu
|
||||
elif self.jtopLoaded:
|
||||
# GPU utilization from jtop stats
|
||||
try:
|
||||
gpu_util = self.jtopInstance.stats.get('GPU', -1)
|
||||
return gpu_util
|
||||
except Exception as e:
|
||||
logger.error('Could not get GPU utilization. ' + str(e))
|
||||
return -1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def deviceGetMemoryInfo(self, deviceHandle):
|
||||
if self.pynvmlLoaded:
|
||||
mem = self.pynvml.nvmlDeviceGetMemoryInfo(deviceHandle)
|
||||
return {'total': mem.total, 'used': mem.used}
|
||||
elif self.jtopLoaded:
|
||||
mem_data = self.jtopInstance.memory['RAM']
|
||||
total = mem_data['tot']
|
||||
used = mem_data['used']
|
||||
return {'total': total, 'used': used}
|
||||
else:
|
||||
return {'total': 1, 'used': 1}
|
||||
|
||||
def deviceGetTemperature(self, deviceHandle):
|
||||
if self.pynvmlLoaded:
|
||||
return self.pynvml.nvmlDeviceGetTemperature(deviceHandle, self.pynvml.NVML_TEMPERATURE_GPU)
|
||||
elif self.jtopLoaded:
|
||||
try:
|
||||
temperature = self.jtopInstance.stats.get('Temp gpu', -1)
|
||||
return temperature
|
||||
except Exception as e:
|
||||
logger.error('Could not get GPU temperature. ' + str(e))
|
||||
return -1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def close(self):
|
||||
if self.jtopLoaded and self.jtopInstance is not None:
|
||||
self.jtopInstance.close()
|
||||
132
custom_nodes/ComfyUI-Crystools/general/hardware.py
Normal file
@@ -0,0 +1,132 @@
|
||||
import platform
|
||||
import re
|
||||
import cpuinfo
|
||||
from cpuinfo import DataSource
|
||||
import psutil
|
||||
from .gpu import CGPUInfo
|
||||
from .hdd import getDrivesInfo
|
||||
|
||||
from ..core import logger
|
||||
|
||||
|
||||
class CHardwareInfo:
|
||||
"""
|
||||
This is only class to get information from hardware.
|
||||
Specially for share it to other software.
|
||||
"""
|
||||
switchCPU = False
|
||||
switchHDD = False
|
||||
switchRAM = False
|
||||
whichHDD = '/' # breaks linux
|
||||
|
||||
@property
|
||||
def switchGPU(self):
|
||||
return self.GPUInfo.switchGPU
|
||||
@switchGPU.setter
|
||||
def switchGPU(self, value):
|
||||
self.GPUInfo.switchGPU = value
|
||||
|
||||
@property
|
||||
def switchVRAM(self):
|
||||
return self.GPUInfo.switchVRAM
|
||||
@switchVRAM.setter
|
||||
def switchVRAM(self, value):
|
||||
self.GPUInfo.switchVRAM = value
|
||||
|
||||
def __init__(self, switchCPU=False, switchGPU=False, switchHDD=False, switchRAM=False, switchVRAM=False):
|
||||
self.switchCPU = switchCPU
|
||||
self.switchHDD = switchHDD
|
||||
self.switchRAM = switchRAM
|
||||
|
||||
self.print_sys_info()
|
||||
|
||||
self.GPUInfo = CGPUInfo()
|
||||
self.switchGPU = switchGPU
|
||||
self.switchVRAM = switchVRAM
|
||||
|
||||
def print_sys_info(self):
|
||||
brand = None
|
||||
if DataSource.is_windows: # Windows
|
||||
brand = DataSource.winreg_processor_brand().strip()
|
||||
elif DataSource.has_proc_cpuinfo(): # Linux
|
||||
return_code, output = DataSource.cat_proc_cpuinfo()
|
||||
if return_code == 0 and output is not None:
|
||||
for line in output.splitlines():
|
||||
r = re.search(r'model name\s*:\s*(.+)', line)
|
||||
if r:
|
||||
brand = r.group(1)
|
||||
break
|
||||
elif DataSource.has_sysctl(): # macOS
|
||||
return_code, output = DataSource.sysctl_machdep_cpu_hw_cpufrequency()
|
||||
if return_code == 0 and output is not None:
|
||||
for line in output.splitlines():
|
||||
r = re.search(r'machdep\.cpu\.brand_string\s*:\s*(.+)', line)
|
||||
if r:
|
||||
brand = r.group(1)
|
||||
break
|
||||
|
||||
# fallback to use cpuinfo.get_cpu_info()
|
||||
if not brand:
|
||||
brand = cpuinfo.get_cpu_info().get('brand_raw', "Unknown")
|
||||
|
||||
arch_string_raw = 'Arch unknown'
|
||||
|
||||
try:
|
||||
arch_string_raw = DataSource.arch_string_raw
|
||||
except:
|
||||
pass
|
||||
|
||||
specName = 'CPU: ' + brand
|
||||
specArch = 'Arch: ' + arch_string_raw
|
||||
specOs = 'OS: ' + str(platform.system()) + ' ' + str(platform.release())
|
||||
logger.info(f"{specName} - {specArch} - {specOs}")
|
||||
|
||||
def getHDDsInfo(self):
|
||||
return getDrivesInfo()
|
||||
|
||||
def getGPUInfo(self):
|
||||
return self.GPUInfo.getInfo()
|
||||
|
||||
def getStatus(self):
|
||||
cpu = -1
|
||||
ramTotal = -1
|
||||
ramUsed = -1
|
||||
ramUsedPercent = -1
|
||||
hddTotal = -1
|
||||
hddUsed = -1
|
||||
hddUsedPercent = -1
|
||||
|
||||
if self.switchCPU:
|
||||
cpu = psutil.cpu_percent()
|
||||
|
||||
if self.switchRAM:
|
||||
ram = psutil.virtual_memory()
|
||||
ramTotal = ram.total
|
||||
ramUsed = ram.used
|
||||
ramUsedPercent = ram.percent
|
||||
|
||||
if self.switchHDD:
|
||||
try:
|
||||
hdd = psutil.disk_usage(self.whichHDD)
|
||||
hddTotal = hdd.total
|
||||
hddUsed = hdd.used
|
||||
hddUsedPercent = hdd.percent
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting disk usage for {self.whichHDD}: {e}")
|
||||
hddTotal = -1
|
||||
hddUsed = -1
|
||||
hddUsedPercent = -1
|
||||
|
||||
getStatus = self.GPUInfo.getStatus()
|
||||
|
||||
return {
|
||||
'cpu_utilization': cpu,
|
||||
'ram_total': ramTotal,
|
||||
'ram_used': ramUsed,
|
||||
'ram_used_percent': ramUsedPercent,
|
||||
'hdd_total': hddTotal,
|
||||
'hdd_used': hddUsed,
|
||||
'hdd_used_percent': hddUsedPercent,
|
||||
'device_type': getStatus['device_type'],
|
||||
'gpus': getStatus['gpus'],
|
||||
}
|
||||
10
custom_nodes/ComfyUI-Crystools/general/hdd.py
Normal file
@@ -0,0 +1,10 @@
|
||||
import psutil
|
||||
from ..core import logger
|
||||
|
||||
def getDrivesInfo():
|
||||
hdds = []
|
||||
logger.debug('Getting HDDs info...')
|
||||
for partition in psutil.disk_partitions():
|
||||
hdds.append(partition.mountpoint)
|
||||
|
||||
return hdds
|
||||
67
custom_nodes/ComfyUI-Crystools/general/monitor.py
Normal file
@@ -0,0 +1,67 @@
|
||||
import asyncio
|
||||
import server
|
||||
import time
|
||||
import threading
|
||||
from .hardware import CHardwareInfo
|
||||
|
||||
from ..core import logger
|
||||
|
||||
lock = threading.Lock()
|
||||
|
||||
|
||||
class CMonitor:
|
||||
monitorThread = None
|
||||
threadController = threading.Event()
|
||||
rate = 0
|
||||
hardwareInfo = None
|
||||
|
||||
def __init__(self, rate=5, switchCPU=False, switchGPU=False, switchHDD=False, switchRAM=False, switchVRAM=False):
|
||||
self.rate = rate
|
||||
self.hardwareInfo = CHardwareInfo(switchCPU, switchGPU, switchHDD, switchRAM, switchVRAM)
|
||||
|
||||
self.startMonitor()
|
||||
|
||||
async def send_message(self, data) -> None:
|
||||
# I'm not sure if it is ok, but works ¯\_(ツ)_/¯
|
||||
# I tried to use async with send_json, but eventually that don't send the message
|
||||
server.PromptServer.instance.send_sync('crystools.monitor', data)
|
||||
|
||||
def startMonitorLoop(self):
|
||||
# logger.debug('Starting monitor loop...')
|
||||
asyncio.run(self.MonitorLoop())
|
||||
|
||||
async def MonitorLoop(self):
|
||||
while self.rate > 0 and not self.threadController.is_set():
|
||||
data = self.hardwareInfo.getStatus()
|
||||
# logger.debug('data to send' + str(data))
|
||||
await self.send_message(data)
|
||||
await asyncio.sleep(self.rate)
|
||||
|
||||
def startMonitor(self):
|
||||
if self.monitorThread is not None:
|
||||
self.stopMonitor()
|
||||
logger.debug('Restarting monitor...')
|
||||
else:
|
||||
if self.rate == 0:
|
||||
logger.debug('Monitor rate is 0, not starting monitor.')
|
||||
return None
|
||||
|
||||
logger.debug('Starting monitor...')
|
||||
|
||||
self.threadController.clear()
|
||||
|
||||
if self.monitorThread is None or not self.monitorThread.is_alive():
|
||||
lock.acquire()
|
||||
self.monitorThread = threading.Thread(target=self.startMonitorLoop)
|
||||
lock.release()
|
||||
self.monitorThread.daemon = True
|
||||
self.monitorThread.start()
|
||||
|
||||
|
||||
def stopMonitor(self):
|
||||
logger.debug('Stopping monitor...')
|
||||
self.threadController.set()
|
||||
|
||||
|
||||
cmonitor = CMonitor(1, True, True, True, True, True)
|
||||
|
||||
1
custom_nodes/ComfyUI-Crystools/nodes/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# intentionally left blank
|
||||
80
custom_nodes/ComfyUI-Crystools/nodes/_names.py
Normal file
@@ -0,0 +1,80 @@
|
||||
from enum import Enum
|
||||
|
||||
prefix = '🪛 '
|
||||
|
||||
# IMPORTANT DON'T CHANGE THE 'NAME' AND 'TYPE' OF THE ENUMS, IT WILL BREAK THE COMPATIBILITY!
|
||||
# remember: NAME is for search, DESC is for contextual
|
||||
class CLASSES(Enum):
|
||||
CBOOLEAN_NAME = 'Primitive boolean [Crystools]'
|
||||
CBOOLEAN_DESC = prefix + 'Primitive boolean'
|
||||
CTEXT_NAME = 'Primitive string [Crystools]'
|
||||
CTEXT_DESC = prefix + 'Primitive string'
|
||||
CTEXTML_NAME = 'Primitive string multiline [Crystools]'
|
||||
CTEXTML_DESC = prefix + 'Primitive string multiline'
|
||||
CINTEGER_NAME = 'Primitive integer [Crystools]'
|
||||
CINTEGER_DESC = prefix + 'Primitive integer'
|
||||
CFLOAT_NAME = 'Primitive float [Crystools]'
|
||||
CFLOAT_DESC = prefix + 'Primitive float'
|
||||
|
||||
CDEBUGGER_CONSOLE_ANY_NAME = 'Show any [Crystools]'
|
||||
CDEBUGGER_ANY_DESC = prefix + 'Show any value to console/display'
|
||||
CDEBUGGER_CONSOLE_ANY_TO_JSON_NAME = 'Show any to JSON [Crystools]'
|
||||
CDEBUGGER_CONSOLE_ANY_TO_JSON_DESC = prefix + 'Show any to JSON'
|
||||
|
||||
CLIST_ANY_TYPE = 'ListAny'
|
||||
CLIST_ANY_NAME = 'List of any [Crystools]'
|
||||
CLIST_ANY_DESC = prefix + 'List of any'
|
||||
CLIST_STRING_TYPE = 'ListString'
|
||||
CLIST_STRING_NAME = 'List of strings [Crystools]'
|
||||
CLIST_STRING_DESC = prefix + 'List of strings'
|
||||
|
||||
CSWITCH_FROM_ANY_NAME = 'Switch from any [Crystools]'
|
||||
CSWITCH_FROM_ANY_DESC = prefix + 'Switch from any'
|
||||
CSWITCH_ANY_NAME = 'Switch any [Crystools]'
|
||||
CSWITCH_ANY_DESC = prefix + 'Switch any'
|
||||
CSWITCH_STRING_NAME = 'Switch string [Crystools]'
|
||||
CSWITCH_STRING_DESC = prefix + 'Switch string'
|
||||
CSWITCH_CONDITIONING_NAME = 'Switch conditioning [Crystools]'
|
||||
CSWITCH_CONDITIONING_DESC = prefix + 'Switch conditioning'
|
||||
CSWITCH_IMAGE_NAME = 'Switch image [Crystools]'
|
||||
CSWITCH_IMAGE_DESC = prefix + 'Switch image'
|
||||
CSWITCH_MASK_NAME = 'Switch mask [Crystools]'
|
||||
CSWITCH_MASK_DESC = prefix + 'Switch mask'
|
||||
CSWITCH_LATENT_NAME = 'Switch latent [Crystools]'
|
||||
CSWITCH_LATENT_DESC = prefix + 'Switch latent'
|
||||
|
||||
CPIPE_ANY_TYPE = 'CPipeAny'
|
||||
CPIPE_TO_ANY_NAME = 'Pipe to/edit any [Crystools]'
|
||||
CPIPE_TO_ANY_DESC = prefix + 'Pipe to/edit any'
|
||||
CPIPE_FROM_ANY_NAME = 'Pipe from any [Crystools]'
|
||||
CPIPE_FROM_ANY_DESC = prefix + 'Pipe from any'
|
||||
|
||||
CIMAGE_LOAD_METADATA_NAME = 'Load image with metadata [Crystools]'
|
||||
CIMAGE_LOAD_METADATA_DESC = prefix + 'Load image with metadata'
|
||||
CIMAGE_GET_RESOLUTION_NAME = 'Get resolution [Crystools]'
|
||||
CIMAGE_GET_RESOLUTION_DESC = prefix + 'Get resolution'
|
||||
CIMAGE_PREVIEW_IMAGE_NAME = 'Preview from image [Crystools]'
|
||||
CIMAGE_PREVIEW_IMAGE_DESC = prefix + 'Preview from image'
|
||||
CIMAGE_PREVIEW_METADATA_NAME = 'Preview from metadata [Crystools]'
|
||||
CIMAGE_PREVIEW_METADATA_DESC = prefix + 'Preview from metadata'
|
||||
CIMAGE_SAVE_METADATA_NAME = 'Save image with extra metadata [Crystools]'
|
||||
CIMAGE_SAVE_METADATA_DESC = prefix + 'Save image with extra metadata'
|
||||
|
||||
CMETADATA_EXTRACTOR_NAME = 'Metadata extractor [Crystools]'
|
||||
CMETADATA_EXTRACTOR_DESC = prefix + 'Metadata extractor'
|
||||
CMETADATA_COMPARATOR_NAME = 'Metadata comparator [Crystools]'
|
||||
CMETADATA_COMPARATOR_DESC = prefix + 'Metadata comparator'
|
||||
|
||||
CUTILS_JSON_COMPARATOR_NAME = 'JSON comparator [Crystools]'
|
||||
CUTILS_JSON_COMPARATOR_DESC = prefix + 'JSON comparator'
|
||||
CUTILS_STAT_SYSTEM_NAME = 'Stats system [Crystools]'
|
||||
CUTILS_STAT_SYSTEM_DESC = prefix + 'Stats system (powered by WAS)'
|
||||
|
||||
# CPARAMETERS_NAME = 'External parameter from JSON file [Crystools]'
|
||||
# CPARAMETERS_DESC = prefix + 'External parameters from JSON file'
|
||||
|
||||
CJSONFILE_NAME = 'Read JSON file [Crystools]'
|
||||
CJSONFILE_DESC = prefix + 'Read JSON file (BETA)'
|
||||
|
||||
CJSONEXTRACTOR_NAME = 'JSON extractor [Crystools]'
|
||||
CJSONEXTRACTOR_DESC = prefix + 'JSON extractor (BETA)'
|
||||
123
custom_nodes/ComfyUI-Crystools/nodes/debugger.py
Normal file
@@ -0,0 +1,123 @@
|
||||
import json
|
||||
from ..core import CONFIG, CATEGORY, BOOLEAN, BOOLEAN_FALSE, KEYS, TEXTS, STRING, logger, any
|
||||
|
||||
class CConsoleAny:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
},
|
||||
"optional": {
|
||||
"any_value": (any,),
|
||||
"console": BOOLEAN_FALSE,
|
||||
"display": BOOLEAN,
|
||||
KEYS.PREFIX.value: STRING,
|
||||
},
|
||||
"hidden": {
|
||||
# "unique_id": "UNIQUE_ID",
|
||||
# "extra_pnginfo": "EXTRA_PNGINFO",
|
||||
},
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.DEBUGGER.value
|
||||
INPUT_IS_LIST = True
|
||||
|
||||
RETURN_TYPES = ()
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, any_value=None, console=False, display=True, prefix=None):
|
||||
console = console[0]
|
||||
display = display[0]
|
||||
prefix = prefix[0]
|
||||
text = ""
|
||||
textToDisplay = TEXTS.INACTIVE_MSG.value
|
||||
|
||||
if any_value is not None:
|
||||
try:
|
||||
if type(any_value) == list:
|
||||
for item in any_value:
|
||||
try:
|
||||
text += str(item)
|
||||
except Exception as e:
|
||||
text += "source exists, but could not be serialized.\n"
|
||||
logger.warn(e)
|
||||
else:
|
||||
logger.warn("any_value is not a list")
|
||||
|
||||
except Exception:
|
||||
try:
|
||||
text = json.dumps(any_value)[1:-1]
|
||||
except Exception:
|
||||
text = 'source exists, but could not be serialized.'
|
||||
|
||||
logger.debug(f"Show any to console is running...")
|
||||
|
||||
if console:
|
||||
if prefix is not None and prefix != "":
|
||||
print(f"{prefix}: {text}")
|
||||
else:
|
||||
print(text)
|
||||
|
||||
if display:
|
||||
textToDisplay = text
|
||||
|
||||
value = [console, display, prefix, textToDisplay]
|
||||
# setWidgetValues(value, unique_id, extra_pnginfo)
|
||||
|
||||
return {"ui": {"text": value}}
|
||||
|
||||
|
||||
class CConsoleAnyToJson:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
},
|
||||
"optional": {
|
||||
"any_value": (any,),
|
||||
},
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.DEBUGGER.value
|
||||
INPUT_IS_LIST = True
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("string",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, any_value=None):
|
||||
text = TEXTS.INACTIVE_MSG.value
|
||||
|
||||
if any_value is not None and isinstance(any_value, list):
|
||||
item = any_value[0]
|
||||
|
||||
if isinstance(item, dict):
|
||||
try:
|
||||
text = json.dumps(item, indent=CONFIG["indent"])
|
||||
except Exception as e:
|
||||
text = "The input is a dict, but could not be serialized.\n"
|
||||
logger.warn(e)
|
||||
|
||||
elif isinstance(item, list):
|
||||
try:
|
||||
text = json.dumps(item, indent=CONFIG["indent"])
|
||||
except Exception as e:
|
||||
text = "The input is a list, but could not be serialized.\n"
|
||||
logger.warn(e)
|
||||
|
||||
else:
|
||||
text = str(item)
|
||||
|
||||
logger.debug(f"Show any-json to console is running...")
|
||||
|
||||
return {"ui": {"text": [text]}, "result": (text,)}
|
||||
517
custom_nodes/ComfyUI-Crystools/nodes/image.py
Normal file
@@ -0,0 +1,517 @@
|
||||
import fnmatch
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
import json
|
||||
import piexif
|
||||
import hashlib
|
||||
from datetime import datetime
|
||||
import torch
|
||||
import numpy as np
|
||||
from pathlib import Path
|
||||
from PIL import Image, ImageOps
|
||||
from PIL.ExifTags import TAGS, GPSTAGS, IFD
|
||||
from PIL.PngImagePlugin import PngImageFile
|
||||
from PIL.JpegImagePlugin import JpegImageFile
|
||||
from nodes import PreviewImage, SaveImage
|
||||
import folder_paths
|
||||
|
||||
from ..core import CATEGORY, CONFIG, BOOLEAN, METADATA_RAW,TEXTS, setWidgetValues, logger, getResolutionByTensor, get_size
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy"))
|
||||
|
||||
|
||||
class CImagePreviewFromImage(PreviewImage):
|
||||
def __init__(self):
|
||||
self.output_dir = folder_paths.get_temp_directory()
|
||||
self.type = "temp"
|
||||
self.prefix_append = "_" + ''.join(random.choice("abcdefghijklmnopqrstupvxyz") for x in range(5))
|
||||
self.compress_level = 1
|
||||
self.data_cached = None
|
||||
self.data_cached_text = None
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
# if it is required, in next node does not receive any value even the cache!
|
||||
},
|
||||
"optional": {
|
||||
"image": ("IMAGE",),
|
||||
},
|
||||
"hidden": {
|
||||
"prompt": "PROMPT",
|
||||
"extra_pnginfo": "EXTRA_PNGINFO",
|
||||
},
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.IMAGE.value
|
||||
RETURN_TYPES = ("METADATA_RAW",)
|
||||
RETURN_NAMES = ("Metadata RAW",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, image=None, prompt=None, extra_pnginfo=None):
|
||||
text = ""
|
||||
title = ""
|
||||
data = {
|
||||
"result": [''],
|
||||
"ui": {
|
||||
"text": [''],
|
||||
"images": [],
|
||||
}
|
||||
}
|
||||
|
||||
if image is not None:
|
||||
saved = self.save_images(image, "crystools/i", prompt, extra_pnginfo)
|
||||
image = saved["ui"]["images"][0]
|
||||
image_path = Path(self.output_dir).joinpath(image["subfolder"], image["filename"])
|
||||
|
||||
img, promptFromImage, metadata = buildMetadata(image_path)
|
||||
|
||||
images = [image]
|
||||
result = metadata
|
||||
|
||||
data["result"] = [result]
|
||||
data["ui"]["images"] = images
|
||||
|
||||
title = "Source: Image link \n"
|
||||
text += buildPreviewText(metadata)
|
||||
text += f"Current prompt (NO FROM IMAGE!):\n"
|
||||
text += json.dumps(promptFromImage, indent=CONFIG["indent"])
|
||||
|
||||
self.data_cached_text = text
|
||||
self.data_cached = data
|
||||
|
||||
elif image is None and self.data_cached is not None:
|
||||
title = "Source: Image link - CACHED\n"
|
||||
data = self.data_cached
|
||||
text = self.data_cached_text
|
||||
|
||||
else:
|
||||
logger.debug("Source: Empty on CImagePreviewFromImage")
|
||||
text = "Source: Empty"
|
||||
|
||||
data['ui']['text'] = [title + text]
|
||||
return data
|
||||
|
||||
|
||||
class CImagePreviewFromMetadata(PreviewImage):
|
||||
def __init__(self):
|
||||
self.data_cached = None
|
||||
self.data_cached_text = None
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
# if it is required, in next node does not receive any value even the cache!
|
||||
},
|
||||
"optional": {
|
||||
"metadata_raw": METADATA_RAW,
|
||||
},
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.IMAGE.value
|
||||
RETURN_TYPES = ("METADATA_RAW",)
|
||||
RETURN_NAMES = ("Metadata RAW",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, metadata_raw=None):
|
||||
text = ""
|
||||
title = ""
|
||||
data = {
|
||||
"result": [''],
|
||||
"ui": {
|
||||
"text": [''],
|
||||
"images": [],
|
||||
}
|
||||
}
|
||||
|
||||
if metadata_raw is not None and metadata_raw != '':
|
||||
promptFromImage = {}
|
||||
if "prompt" in metadata_raw:
|
||||
promptFromImage = metadata_raw["prompt"]
|
||||
|
||||
title = "Source: Metadata RAW\n"
|
||||
text += buildPreviewText(metadata_raw)
|
||||
text += f"Prompt from image:\n"
|
||||
text += json.dumps(promptFromImage, indent=CONFIG["indent"])
|
||||
|
||||
images = self.resolveImage(metadata_raw["fileinfo"]["filename"])
|
||||
result = metadata_raw
|
||||
|
||||
data["result"] = [result]
|
||||
data["ui"]["images"] = images
|
||||
|
||||
self.data_cached_text = text
|
||||
self.data_cached = data
|
||||
|
||||
elif metadata_raw is None and self.data_cached is not None:
|
||||
title = "Source: Metadata RAW - CACHED\n"
|
||||
data = self.data_cached
|
||||
text = self.data_cached_text
|
||||
|
||||
else:
|
||||
logger.debug("Source: Empty on CImagePreviewFromMetadata")
|
||||
text = "Source: Empty"
|
||||
|
||||
data["ui"]["text"] = [title + text]
|
||||
return data
|
||||
|
||||
def resolveImage(self, filename=None):
|
||||
images = []
|
||||
|
||||
if filename is not None:
|
||||
image_input_folder = os.path.normpath(folder_paths.get_input_directory())
|
||||
image_input_folder_abs = Path(image_input_folder).resolve()
|
||||
|
||||
image_path = os.path.normpath(filename)
|
||||
image_path_abs = Path(image_path).resolve()
|
||||
|
||||
if Path(image_path_abs).is_file() is False:
|
||||
raise Exception(TEXTS.FILE_NOT_FOUND.value)
|
||||
|
||||
try:
|
||||
# get common path, should be input/output/temp folder
|
||||
common = os.path.commonpath([image_input_folder_abs, image_path_abs])
|
||||
|
||||
if common != image_input_folder:
|
||||
raise Exception("Path invalid (should be in the input folder)")
|
||||
|
||||
relative = os.path.normpath(os.path.relpath(image_path_abs, image_input_folder_abs))
|
||||
|
||||
images.append({
|
||||
"filename": Path(relative).name,
|
||||
"subfolder": os.path.dirname(relative),
|
||||
"type": "input"
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.warn(e)
|
||||
|
||||
return images
|
||||
|
||||
|
||||
class CImageGetResolution:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
},
|
||||
"hidden": {
|
||||
"unique_id": "UNIQUE_ID",
|
||||
"extra_pnginfo": "EXTRA_PNGINFO",
|
||||
},
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.IMAGE.value
|
||||
RETURN_TYPES = ("INT", "INT",)
|
||||
RETURN_NAMES = ("width", "height",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, image, extra_pnginfo=None, unique_id=None):
|
||||
res = getResolutionByTensor(image)
|
||||
text = [f"{res['x']}x{res['y']}"]
|
||||
setWidgetValues(text, unique_id, extra_pnginfo)
|
||||
logger.debug(f"Resolution: {text}")
|
||||
return {"ui": {"text": text}, "result": (res["x"], res["y"])}
|
||||
|
||||
|
||||
# subfolders based on: https://github.com/catscandrive/comfyui-imagesubfolders
|
||||
class CImageLoadWithMetadata:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
input_dir = folder_paths.get_input_directory()
|
||||
|
||||
exclude_files = {"Thumbs.db", "*.DS_Store", "desktop.ini", "*.lock" }
|
||||
exclude_folders = {"clipspace", ".*"}
|
||||
|
||||
file_list = []
|
||||
|
||||
for root, dirs, files in os.walk(input_dir, followlinks=True):
|
||||
# Exclude specific folders
|
||||
dirs[:] = [d for d in dirs if not any(fnmatch.fnmatch(d, exclude) for exclude in exclude_folders)]
|
||||
files = [f for f in files if not any(fnmatch.fnmatch(f, exclude) for exclude in exclude_files)]
|
||||
|
||||
|
||||
for file in files:
|
||||
relpath = os.path.relpath(os.path.join(root, file), start=input_dir)
|
||||
# fix for windows
|
||||
relpath = relpath.replace("\\", "/")
|
||||
file_list.append(relpath)
|
||||
|
||||
return {
|
||||
"required": {
|
||||
"image": (sorted(file_list), {"image_upload": True})
|
||||
},
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.IMAGE.value
|
||||
RETURN_TYPES = ("IMAGE", "MASK", "JSON", "METADATA_RAW")
|
||||
RETURN_NAMES = ("image", "mask", "prompt", "Metadata RAW")
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, image):
|
||||
image_path = folder_paths.get_annotated_filepath(image)
|
||||
|
||||
imgF = Image.open(image_path)
|
||||
img, prompt, metadata = buildMetadata(image_path)
|
||||
if imgF.format == 'WEBP':
|
||||
# Use piexif to extract EXIF data from WebP image
|
||||
try:
|
||||
exif_data = piexif.load(image_path)
|
||||
prompt, metadata = self.process_exif_data(exif_data)
|
||||
except ValueError:
|
||||
prompt = {}
|
||||
|
||||
img = ImageOps.exif_transpose(img)
|
||||
image = img.convert("RGB")
|
||||
image = np.array(image).astype(np.float32) / 255.0
|
||||
image = torch.from_numpy(image)[None,]
|
||||
if 'A' in img.getbands():
|
||||
mask = np.array(img.getchannel('A')).astype(np.float32) / 255.0
|
||||
mask = 1. - torch.from_numpy(mask)
|
||||
else:
|
||||
mask = torch.zeros((64, 64), dtype=torch.float32, device="cpu")
|
||||
|
||||
return image, mask.unsqueeze(0), prompt, metadata
|
||||
|
||||
def process_exif_data(self, exif_data):
|
||||
metadata = {}
|
||||
# 检查 '0th' 键下的 271 值,提取 Prompt 信息
|
||||
if '0th' in exif_data and 271 in exif_data['0th']:
|
||||
prompt_data = exif_data['0th'][271].decode('utf-8')
|
||||
# 移除可能的前缀 'Prompt:'
|
||||
prompt_data = prompt_data.replace('Prompt:', '', 1)
|
||||
# 假设 prompt_data 是一个字符串,尝试将其转换为 JSON 对象
|
||||
try:
|
||||
metadata['prompt'] = json.loads(prompt_data)
|
||||
except json.JSONDecodeError:
|
||||
metadata['prompt'] = prompt_data
|
||||
|
||||
# 检查 '0th' 键下的 270 值,提取 Workflow 信息
|
||||
if '0th' in exif_data and 270 in exif_data['0th']:
|
||||
workflow_data = exif_data['0th'][270].decode('utf-8')
|
||||
# 移除可能的前缀 'Workflow:'
|
||||
workflow_data = workflow_data.replace('Workflow:', '', 1)
|
||||
try:
|
||||
# 尝试将字节字符串转换为 JSON 对象
|
||||
metadata['workflow'] = json.loads(workflow_data)
|
||||
except json.JSONDecodeError:
|
||||
# 如果转换失败,则将原始字符串存储在 metadata 中
|
||||
metadata['workflow'] = workflow_data
|
||||
|
||||
metadata.update(exif_data)
|
||||
return metadata
|
||||
|
||||
@classmethod
|
||||
def IS_CHANGED(cls, image):
|
||||
image_path = folder_paths.get_annotated_filepath(image)
|
||||
m = hashlib.sha256()
|
||||
with open(image_path, 'rb') as f:
|
||||
m.update(f.read())
|
||||
return m.digest().hex()
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, image):
|
||||
if not folder_paths.exists_annotated_filepath(image):
|
||||
return "Invalid image file: {}".format(image)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class CImageSaveWithExtraMetadata(SaveImage):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.data_cached = None
|
||||
self.data_cached_text = None
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
# if it is required, in next node does not receive any value even the cache!
|
||||
"image": ("IMAGE",),
|
||||
"filename_prefix": ("STRING", {"default": "ComfyUI"}),
|
||||
"with_workflow": BOOLEAN,
|
||||
},
|
||||
"optional": {
|
||||
"metadata_extra": ("STRING", {"multiline": True, "default": json.dumps({
|
||||
"Title": "Image generated by Crystian",
|
||||
"Description": "More info: https:\/\/www.instagram.com\/crystian.ia",
|
||||
"Author": "crystian.ia",
|
||||
"Software": "ComfyUI",
|
||||
"Category": "StableDiffusion",
|
||||
"Rating": 5,
|
||||
"UserComment": "",
|
||||
"Keywords": [
|
||||
""
|
||||
],
|
||||
"Copyrights": "",
|
||||
}, indent=CONFIG["indent"]).replace("\\/", "/"),
|
||||
}),
|
||||
},
|
||||
"hidden": {
|
||||
"prompt": "PROMPT",
|
||||
"extra_pnginfo": "EXTRA_PNGINFO",
|
||||
},
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.IMAGE.value
|
||||
RETURN_TYPES = ("METADATA_RAW",)
|
||||
RETURN_NAMES = ("Metadata RAW",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, image=None, filename_prefix="ComfyUI", with_workflow=True, metadata_extra=None, prompt=None, extra_pnginfo=None):
|
||||
data = {
|
||||
"result": [''],
|
||||
"ui": {
|
||||
"text": [''],
|
||||
"images": [],
|
||||
}
|
||||
}
|
||||
if image is not None:
|
||||
if with_workflow is True:
|
||||
extra_pnginfo_new = extra_pnginfo.copy()
|
||||
prompt = prompt.copy()
|
||||
else:
|
||||
extra_pnginfo_new = None
|
||||
prompt = None
|
||||
|
||||
if metadata_extra is not None and metadata_extra != 'undefined':
|
||||
try:
|
||||
# metadata_extra = json.loads(f"{{{metadata_extra}}}") // a fix?
|
||||
metadata_extra = json.loads(metadata_extra)
|
||||
except Exception as e:
|
||||
logger.error(f"Error parsing metadata_extra (it will send as string), error: {e}")
|
||||
metadata_extra = {"extra": str(metadata_extra)}
|
||||
|
||||
if isinstance(metadata_extra, dict):
|
||||
for k, v in metadata_extra.items():
|
||||
if extra_pnginfo_new is None:
|
||||
extra_pnginfo_new = {}
|
||||
|
||||
extra_pnginfo_new[k] = v
|
||||
|
||||
saved = super().save_images(image, filename_prefix, prompt, extra_pnginfo_new)
|
||||
|
||||
image = saved["ui"]["images"][0]
|
||||
image_path = Path(self.output_dir).joinpath(image["subfolder"], image["filename"])
|
||||
img, promptFromImage, metadata = buildMetadata(image_path)
|
||||
|
||||
images = [image]
|
||||
result = metadata
|
||||
|
||||
data["result"] = [result]
|
||||
data["ui"]["images"] = images
|
||||
|
||||
else:
|
||||
logger.debug("Source: Empty on CImageSaveWithExtraMetadata")
|
||||
|
||||
return data
|
||||
|
||||
|
||||
|
||||
def buildMetadata(image_path):
|
||||
if Path(image_path).is_file() is False:
|
||||
raise Exception(TEXTS.FILE_NOT_FOUND.value)
|
||||
|
||||
img = Image.open(image_path)
|
||||
|
||||
metadata = {}
|
||||
prompt = {}
|
||||
|
||||
metadata["fileinfo"] = {
|
||||
"filename": Path(image_path).as_posix(),
|
||||
"resolution": f"{img.width}x{img.height}",
|
||||
"date": str(datetime.fromtimestamp(os.path.getmtime(image_path))),
|
||||
"size": str(get_size(image_path)),
|
||||
}
|
||||
|
||||
# only for png files
|
||||
if isinstance(img, PngImageFile):
|
||||
metadataFromImg = img.info
|
||||
|
||||
# for all metadataFromImg convert to string (but not for workflow and prompt!)
|
||||
for k, v in metadataFromImg.items():
|
||||
# from ComfyUI
|
||||
if k == "workflow":
|
||||
try:
|
||||
metadata["workflow"] = json.loads(metadataFromImg["workflow"])
|
||||
except Exception as e:
|
||||
logger.warn(f"Error parsing metadataFromImg 'workflow': {e}")
|
||||
|
||||
# from ComfyUI
|
||||
elif k == "prompt":
|
||||
try:
|
||||
metadata["prompt"] = json.loads(metadataFromImg["prompt"])
|
||||
|
||||
# extract prompt to use on metadataFromImg
|
||||
prompt = metadata["prompt"]
|
||||
except Exception as e:
|
||||
logger.warn(f"Error parsing metadataFromImg 'prompt': {e}")
|
||||
|
||||
else:
|
||||
try:
|
||||
# for all possible metadataFromImg by user
|
||||
metadata[str(k)] = json.loads(v)
|
||||
except Exception as e:
|
||||
logger.debug(f"Error parsing {k} as json, trying as string: {e}")
|
||||
try:
|
||||
metadata[str(k)] = str(v)
|
||||
except Exception as e:
|
||||
logger.debug(f"Error parsing {k} it will be skipped: {e}")
|
||||
|
||||
if isinstance(img, JpegImageFile):
|
||||
exif = img.getexif()
|
||||
|
||||
for k, v in exif.items():
|
||||
tag = TAGS.get(k, k)
|
||||
if v is not None:
|
||||
metadata[str(tag)] = str(v)
|
||||
|
||||
for ifd_id in IFD:
|
||||
try:
|
||||
if ifd_id == IFD.GPSInfo:
|
||||
resolve = GPSTAGS
|
||||
else:
|
||||
resolve = TAGS
|
||||
|
||||
ifd = exif.get_ifd(ifd_id)
|
||||
ifd_name = str(ifd_id.name)
|
||||
metadata[ifd_name] = {}
|
||||
|
||||
for k, v in ifd.items():
|
||||
tag = resolve.get(k, k)
|
||||
metadata[ifd_name][str(tag)] = str(v)
|
||||
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
return img, prompt, metadata
|
||||
|
||||
|
||||
def buildPreviewText(metadata):
|
||||
text = f"File: {metadata['fileinfo']['filename']}\n"
|
||||
text += f"Resolution: {metadata['fileinfo']['resolution']}\n"
|
||||
text += f"Date: {metadata['fileinfo']['date']}\n"
|
||||
text += f"Size: {metadata['fileinfo']['size']}\n"
|
||||
return text
|
||||
149
custom_nodes/ComfyUI-Crystools/nodes/list.py
Normal file
@@ -0,0 +1,149 @@
|
||||
from ..core import STRING, TEXTS, KEYS, CATEGORY, any, logger
|
||||
from ._names import CLASSES
|
||||
|
||||
|
||||
class CListAny:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
},
|
||||
"optional": {
|
||||
"any_1": (any,),
|
||||
"any_2": (any,),
|
||||
"any_3": (any,),
|
||||
"any_4": (any,),
|
||||
"any_5": (any,),
|
||||
"any_6": (any,),
|
||||
"any_7": (any,),
|
||||
"any_8": (any,),
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.LIST.value
|
||||
RETURN_TYPES = (any,),
|
||||
RETURN_NAMES = ("any_list",)
|
||||
OUTPUT_IS_LIST = (True,)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self,
|
||||
any_1=None,
|
||||
any_2=None,
|
||||
any_3=None,
|
||||
any_4=None,
|
||||
any_5=None,
|
||||
any_6=None,
|
||||
any_7=None,
|
||||
any_8=None):
|
||||
|
||||
list_any = []
|
||||
|
||||
if any_1 is not None:
|
||||
try:
|
||||
list_any.append(any_1)
|
||||
except Exception as e:
|
||||
logger.warn(e)
|
||||
if any_2 is not None:
|
||||
try:
|
||||
list_any.append(any_2)
|
||||
except Exception as e:
|
||||
logger.warn(e)
|
||||
if any_3 is not None:
|
||||
try:
|
||||
list_any.append(any_3)
|
||||
except Exception as e:
|
||||
logger.warn(e)
|
||||
if any_4 is not None:
|
||||
try:
|
||||
list_any.append(any_4)
|
||||
except Exception as e:
|
||||
logger.warn(e)
|
||||
if any_5 is not None:
|
||||
try:
|
||||
list_any.append(any_5)
|
||||
except Exception as e:
|
||||
logger.warn(e)
|
||||
if any_6 is not None:
|
||||
try:
|
||||
list_any.append(any_6)
|
||||
except Exception as e:
|
||||
logger.warn(e)
|
||||
if any_7 is not None:
|
||||
try:
|
||||
list_any.append(any_7)
|
||||
except Exception as e:
|
||||
logger.warn(e)
|
||||
if any_8 is not None:
|
||||
try:
|
||||
list_any.append(any_8)
|
||||
except Exception as e:
|
||||
logger.warn(e)
|
||||
|
||||
# yes, double brackets are needed because of the OUTPUT_IS_LIST... ¯\_(ツ)_/¯
|
||||
return [[list_any]]
|
||||
|
||||
|
||||
class CListString:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
},
|
||||
"optional": {
|
||||
"string_1": STRING,
|
||||
"string_2": STRING,
|
||||
"string_3": STRING,
|
||||
"string_4": STRING,
|
||||
"string_5": STRING,
|
||||
"string_6": STRING,
|
||||
"string_7": STRING,
|
||||
"string_8": STRING,
|
||||
"delimiter": ("STRING", {"default": " "}),
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.LIST.value
|
||||
RETURN_TYPES = ("STRING", CLASSES.CLIST_STRING_TYPE.value,)
|
||||
RETURN_NAMES = (TEXTS.CONCAT.value, KEYS.LIST.value)
|
||||
OUTPUT_IS_LIST = (False, True, )
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self,
|
||||
string_1=None,
|
||||
string_2=None,
|
||||
string_3=None,
|
||||
string_4=None,
|
||||
string_5=None,
|
||||
string_6=None,
|
||||
string_7=None,
|
||||
string_8=None,
|
||||
delimiter=""):
|
||||
|
||||
list_str = []
|
||||
|
||||
if string_1 is not None and string_1 != "":
|
||||
list_str.append(string_1)
|
||||
if string_2 is not None and string_2 != "":
|
||||
list_str.append(string_2)
|
||||
if string_3 is not None and string_3 != "":
|
||||
list_str.append(string_3)
|
||||
if string_4 is not None and string_4 != "":
|
||||
list_str.append(string_4)
|
||||
if string_5 is not None and string_5 != "":
|
||||
list_str.append(string_5)
|
||||
if string_6 is not None and string_6 != "":
|
||||
list_str.append(string_6)
|
||||
if string_7 is not None and string_7 != "":
|
||||
list_str.append(string_7)
|
||||
if string_8 is not None and string_8 != "":
|
||||
list_str.append(string_8)
|
||||
|
||||
return delimiter.join(list_str), [list_str]
|
||||
164
custom_nodes/ComfyUI-Crystools/nodes/metadata.py
Normal file
@@ -0,0 +1,164 @@
|
||||
import json
|
||||
import re
|
||||
from ..core import CATEGORY, CONFIG, METADATA_RAW, TEXTS, findJsonsDiff, logger
|
||||
|
||||
|
||||
class CMetadataExtractor:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"metadata_raw": METADATA_RAW,
|
||||
},
|
||||
"optional": {
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.METADATA.value
|
||||
RETURN_TYPES = ("JSON", "JSON", "JSON", "JSON", "STRING", "STRING")
|
||||
RETURN_NAMES = ("prompt", "workflow", "file info", "raw to JSON", "raw to property", "raw to csv")
|
||||
# OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, metadata_raw=None):
|
||||
prompt = {}
|
||||
workflow = {}
|
||||
fileinfo = {}
|
||||
text = ""
|
||||
csv = ""
|
||||
|
||||
if metadata_raw is not None and isinstance(metadata_raw, dict):
|
||||
try:
|
||||
for key, value in metadata_raw.items():
|
||||
|
||||
if isinstance(value, dict):
|
||||
# yes, double json.dumps is needed for jsons
|
||||
value = json.dumps(json.dumps(value))
|
||||
else:
|
||||
value = json.dumps(value)
|
||||
|
||||
text += f"\"{key}\"={value}\n"
|
||||
# remove spaces
|
||||
# value = re.sub(' +', ' ', value)
|
||||
value = re.sub('\n', ' ', value)
|
||||
csv += f'"{key}"\t{value}\n'
|
||||
|
||||
if csv != "":
|
||||
csv = '"key"\t"value"\n' + csv
|
||||
|
||||
except Exception as e:
|
||||
logger.warn(e)
|
||||
|
||||
try:
|
||||
if "prompt" in metadata_raw:
|
||||
prompt = metadata_raw["prompt"]
|
||||
else:
|
||||
raise Exception("Prompt not found in metadata_raw")
|
||||
except Exception as e:
|
||||
logger.warn(e)
|
||||
|
||||
try:
|
||||
if "workflow" in metadata_raw:
|
||||
workflow = metadata_raw["workflow"]
|
||||
else:
|
||||
raise Exception("Workflow not found in metadata_raw")
|
||||
except Exception as e:
|
||||
logger.warn(e)
|
||||
|
||||
try:
|
||||
if "fileinfo" in metadata_raw:
|
||||
fileinfo = metadata_raw["fileinfo"]
|
||||
else:
|
||||
raise Exception("Fileinfo not found in metadata_raw")
|
||||
except Exception as e:
|
||||
logger.warn(e)
|
||||
|
||||
elif metadata_raw is None:
|
||||
logger.debug("metadata_raw is None")
|
||||
else:
|
||||
logger.warn(TEXTS.INVALID_METADATA_MSG.value)
|
||||
|
||||
return (json.dumps(prompt, indent=CONFIG["indent"]),
|
||||
json.dumps(workflow, indent=CONFIG["indent"]),
|
||||
json.dumps(fileinfo, indent=CONFIG["indent"]),
|
||||
json.dumps(metadata_raw, indent=CONFIG["indent"]),
|
||||
text, csv)
|
||||
|
||||
|
||||
class CMetadataCompare:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"metadata_raw_old": METADATA_RAW,
|
||||
"metadata_raw_new": METADATA_RAW,
|
||||
"what": (["Prompt", "Workflow", "Fileinfo"],),
|
||||
},
|
||||
"optional": {
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.METADATA.value
|
||||
RETURN_TYPES = ("JSON",)
|
||||
RETURN_NAMES = ("diff",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, what, metadata_raw_old=None, metadata_raw_new=None):
|
||||
prompt_old = {}
|
||||
workflow_old = {}
|
||||
fileinfo_old = {}
|
||||
prompt_new = {}
|
||||
workflow_new = {}
|
||||
fileinfo_new = {}
|
||||
diff = ""
|
||||
|
||||
if type(metadata_raw_old) == dict and type(metadata_raw_new) == dict:
|
||||
|
||||
if "prompt" in metadata_raw_old:
|
||||
prompt_old = metadata_raw_old["prompt"]
|
||||
else:
|
||||
logger.warn("Prompt not found in metadata_raw_old")
|
||||
|
||||
if "workflow" in metadata_raw_old:
|
||||
workflow_old = metadata_raw_old["workflow"]
|
||||
else:
|
||||
logger.warn("Workflow not found in metadata_raw_old")
|
||||
|
||||
if "fileinfo" in metadata_raw_old:
|
||||
fileinfo_old = metadata_raw_old["fileinfo"]
|
||||
else:
|
||||
logger.warn("Fileinfo not found in metadata_raw_old")
|
||||
|
||||
if "prompt" in metadata_raw_new:
|
||||
prompt_new = metadata_raw_new["prompt"]
|
||||
else:
|
||||
logger.warn("Prompt not found in metadata_raw_new")
|
||||
|
||||
if "workflow" in metadata_raw_new:
|
||||
workflow_new = metadata_raw_new["workflow"]
|
||||
else:
|
||||
logger.warn("Workflow not found in metadata_raw_new")
|
||||
|
||||
if "fileinfo" in metadata_raw_new:
|
||||
fileinfo_new = metadata_raw_new["fileinfo"]
|
||||
else:
|
||||
logger.warn("Fileinfo not found in metadata_raw_new")
|
||||
|
||||
if what == "Prompt":
|
||||
diff = findJsonsDiff(prompt_old, prompt_new)
|
||||
elif what == "Workflow":
|
||||
diff = findJsonsDiff(workflow_old, workflow_new)
|
||||
else:
|
||||
diff = findJsonsDiff(fileinfo_old, fileinfo_new)
|
||||
|
||||
diff = json.dumps(diff, indent=CONFIG["indent"])
|
||||
|
||||
else:
|
||||
invalid_msg = TEXTS.INVALID_METADATA_MSG.value
|
||||
logger.warn(invalid_msg)
|
||||
diff = invalid_msg
|
||||
|
||||
return {"ui": {"text": [diff]}, "result": (diff,)}
|
||||
170
custom_nodes/ComfyUI-Crystools/nodes/parameters.py
Normal file
@@ -0,0 +1,170 @@
|
||||
import json
|
||||
from ..core import CONFIG, any, JSON_WIDGET, CATEGORY, STRING, INT, FLOAT, BOOLEAN, logger, get_nested_value
|
||||
|
||||
# class CParameter:
|
||||
# def __init__(self):
|
||||
# pass
|
||||
#
|
||||
# @classmethod
|
||||
# def INPUT_TYPES(cls):
|
||||
# return {
|
||||
# "required": {
|
||||
# },
|
||||
# "optional": {
|
||||
# "path_to_json": STRING,
|
||||
# "key": STRING,
|
||||
# "default": STRING,
|
||||
# },
|
||||
# }
|
||||
#
|
||||
# CATEGORY = CATEGORY.MAIN.value + CATEGORY.UTILS.value
|
||||
# INPUT_IS_LIST = False
|
||||
#
|
||||
# RETURN_TYPES = (any,)
|
||||
# RETURN_NAMES = ("any",)
|
||||
#
|
||||
# FUNCTION = "execute"
|
||||
#
|
||||
# def execute(self, path_to_json=None, key=True, default=None):
|
||||
# text = default
|
||||
# value = text
|
||||
#
|
||||
# if path_to_json is not None and path_to_json != "":
|
||||
# logger.debug(f"External parameter from: '{path_to_json}'")
|
||||
# try:
|
||||
# with open(path_to_json, 'r') as file:
|
||||
# data = json.load(file)
|
||||
# logger.debug(f"File found, data: '{data}'")
|
||||
#
|
||||
# result = get_value(data, key, default)
|
||||
# text = result["text"]
|
||||
# value = result["value"]
|
||||
#
|
||||
# except Exception as e:
|
||||
# logger.error(e)
|
||||
# text = f"Error reading file: {e}\nReturning default value: '{default}'"
|
||||
# value = default
|
||||
#
|
||||
# return {"ui": {"text": [text]}, "result": [value]}
|
||||
|
||||
class CJsonFile:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
},
|
||||
"optional": {
|
||||
"path_to_json": STRING,
|
||||
},
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.UTILS.value
|
||||
INPUT_IS_LIST = False
|
||||
|
||||
RETURN_TYPES = ("JSON",)
|
||||
RETURN_NAMES = ("json",)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def IS_CHANGED(path_to_json=None):
|
||||
return True
|
||||
|
||||
def execute(self, path_to_json=None):
|
||||
text = ""
|
||||
data = {}
|
||||
|
||||
if path_to_json is not None and path_to_json != "":
|
||||
logger.debug(f"Open json file: '{path_to_json}'")
|
||||
try:
|
||||
with open(path_to_json, 'r') as file:
|
||||
data = json.load(file)
|
||||
text = json.dumps(data, indent=CONFIG["indent"])
|
||||
logger.debug(f"File found, data: '{str(data)}'")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
text = f"Error reading file: {e}"
|
||||
|
||||
return {"ui": {"text": [text]}, "result": [data]}
|
||||
|
||||
class CJsonExtractor:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"json": JSON_WIDGET,
|
||||
},
|
||||
"optional": {
|
||||
"key": STRING,
|
||||
"default": STRING,
|
||||
},
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.UTILS.value
|
||||
INPUT_IS_LIST = False
|
||||
|
||||
RETURN_TYPES = (any, "STRING", "INT", "FLOAT", "BOOLEAN")
|
||||
RETURN_NAMES = ("any", "string", "int", "float", "boolean")
|
||||
|
||||
# OUTPUT_IS_LIST = (False,)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(cls, json=None, key=True, default=None):
|
||||
result = get_value(json, key, default)
|
||||
|
||||
result["any"] = result["value"]
|
||||
try:
|
||||
result["string"] = str(result["value"])
|
||||
except Exception as e:
|
||||
result["string"] = result["value"]
|
||||
|
||||
try:
|
||||
result["int"] = int(result["value"])
|
||||
except Exception as e:
|
||||
result["int"] = result["value"]
|
||||
|
||||
try:
|
||||
result["float"] = float(result["value"])
|
||||
except Exception as e:
|
||||
result["float"] = result["value"]
|
||||
|
||||
try:
|
||||
result["boolean"] = result["value"].lower() == "true"
|
||||
except Exception as e:
|
||||
result["boolean"] = result["value"]
|
||||
|
||||
return {
|
||||
"ui": {"text": [result["text"]]},
|
||||
"result": [
|
||||
result["any"],
|
||||
result["string"],
|
||||
result["int"],
|
||||
result["float"],
|
||||
result["boolean"]
|
||||
]
|
||||
}
|
||||
|
||||
def get_value(data, key, default=None):
|
||||
text = ""
|
||||
val = ""
|
||||
|
||||
if key is not None and key != "":
|
||||
val = get_nested_value(data, key, default)
|
||||
if default != val:
|
||||
text = f"Key found, return value: '{val}'"
|
||||
else:
|
||||
text = f"Key no found, return default value: '{val}'"
|
||||
else:
|
||||
text = f"Key is empty, return default value: '{val}'"
|
||||
|
||||
return {
|
||||
"text": text,
|
||||
"value": val
|
||||
}
|
||||
74
custom_nodes/ComfyUI-Crystools/nodes/pipe.py
Normal file
@@ -0,0 +1,74 @@
|
||||
from ..core import CATEGORY, any
|
||||
from ._names import CLASSES
|
||||
|
||||
|
||||
class CPipeToAny:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {},
|
||||
"optional": {
|
||||
CLASSES.CPIPE_ANY_TYPE.value: (CLASSES.CPIPE_ANY_TYPE.value,),
|
||||
"any_1": (any,),
|
||||
"any_2": (any,),
|
||||
"any_3": (any,),
|
||||
"any_4": (any,),
|
||||
"any_5": (any,),
|
||||
"any_6": (any,),
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.PIPE.value
|
||||
RETURN_TYPES = (CLASSES.CPIPE_ANY_TYPE.value,)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, CPipeAny=None, any_1=None, any_2=None, any_3=None, any_4=None, any_5=None, any_6=None):
|
||||
any_1_original = None
|
||||
any_2_original = None
|
||||
any_3_original = None
|
||||
any_4_original = None
|
||||
any_5_original = None
|
||||
any_6_original = None
|
||||
|
||||
if CPipeAny != None:
|
||||
any_1_original, any_2_original, any_3_original, any_4_original, any_5_original, any_6_original = CPipeAny
|
||||
|
||||
CAnyPipeMod = []
|
||||
|
||||
CAnyPipeMod.append(any_1 if any_1 is not None else any_1_original)
|
||||
CAnyPipeMod.append(any_2 if any_2 is not None else any_2_original)
|
||||
CAnyPipeMod.append(any_3 if any_3 is not None else any_3_original)
|
||||
CAnyPipeMod.append(any_4 if any_4 is not None else any_4_original)
|
||||
CAnyPipeMod.append(any_5 if any_5 is not None else any_5_original)
|
||||
CAnyPipeMod.append(any_6 if any_6 is not None else any_6_original)
|
||||
|
||||
return (CAnyPipeMod,)
|
||||
|
||||
|
||||
class CPipeFromAny:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
CLASSES.CPIPE_ANY_TYPE.value: (CLASSES.CPIPE_ANY_TYPE.value,),
|
||||
},
|
||||
"optional": {
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.PIPE.value
|
||||
RETURN_TYPES = (CLASSES.CPIPE_ANY_TYPE.value, any, any, any, any, any, any,)
|
||||
RETURN_NAMES = (CLASSES.CPIPE_ANY_TYPE.value, "any_1", "any_2", "any_3", "any_4", "any_5", "any_6",)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, CPipeAny=None, ):
|
||||
any_1, any_2, any_3, any_4, any_5, any_6 = CPipeAny
|
||||
return CPipeAny, any_1, any_2, any_3, any_4, any_5, any_6
|
||||
111
custom_nodes/ComfyUI-Crystools/nodes/primitive.py
Normal file
@@ -0,0 +1,111 @@
|
||||
from ..core import BOOLEAN, CATEGORY, STRING, INT, FLOAT, STRING_ML
|
||||
|
||||
|
||||
class CBoolean:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"boolean": BOOLEAN,
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.PRIMITIVE.value
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
RETURN_NAMES = ("boolean",)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, boolean=True):
|
||||
return (boolean,)
|
||||
|
||||
|
||||
class CText:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"string": STRING,
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.PRIMITIVE.value
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("string",)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, string=""):
|
||||
return (string,)
|
||||
|
||||
|
||||
class CTextML:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"string": STRING_ML,
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.PRIMITIVE.value
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("string",)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, string=""):
|
||||
return (string,)
|
||||
|
||||
|
||||
class CInteger:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"int": INT,
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.PRIMITIVE.value
|
||||
RETURN_TYPES = ("INT",)
|
||||
RETURN_NAMES = ("int",)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, int=True):
|
||||
return (int,)
|
||||
|
||||
|
||||
class CFloat:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"float": FLOAT,
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.PRIMITIVE.value
|
||||
RETURN_TYPES = ("FLOAT",)
|
||||
RETURN_NAMES = ("float",)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, float=True):
|
||||
return (float,)
|
||||
225
custom_nodes/ComfyUI-Crystools/nodes/switch.py
Normal file
@@ -0,0 +1,225 @@
|
||||
from ..core import BOOLEAN, STRING, CATEGORY, any, logger
|
||||
|
||||
|
||||
class CSwitchFromAny:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"any": (any, ),
|
||||
"boolean": BOOLEAN,
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.SWITCH.value
|
||||
RETURN_TYPES = (any, any,)
|
||||
RETURN_NAMES = ("on_true", "on_false",)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, any,boolean=True):
|
||||
logger.debug("Any switch: " + str(boolean))
|
||||
|
||||
if boolean:
|
||||
return any, None
|
||||
else:
|
||||
return None, any
|
||||
|
||||
class CSwitchBooleanAny:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"on_true": (any, {"lazy": True}),
|
||||
"on_false": (any, {"lazy": True}),
|
||||
"boolean": BOOLEAN,
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.SWITCH.value
|
||||
RETURN_TYPES = (any,)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def check_lazy_status(self, on_true=None, on_false=None, boolean=True):
|
||||
needed = "on_true" if boolean else "on_false"
|
||||
return [needed]
|
||||
|
||||
def execute(self, on_true, on_false, boolean=True):
|
||||
logger.debug("Any switch: " + str(boolean))
|
||||
|
||||
if boolean:
|
||||
return (on_true,)
|
||||
else:
|
||||
return (on_false,)
|
||||
|
||||
|
||||
class CSwitchBooleanString:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"on_true": ("STRING", {"default": "", "lazy": True}),
|
||||
"on_false": ("STRING", {"default": "", "lazy": True}),
|
||||
"boolean": BOOLEAN,
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.SWITCH.value
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("string",)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def check_lazy_status(self, on_true=None, on_false=None, boolean=True):
|
||||
needed = "on_true" if boolean else "on_false"
|
||||
return [needed]
|
||||
|
||||
def execute(self, on_true, on_false, boolean=True):
|
||||
logger.debug("String switch: " + str(boolean))
|
||||
|
||||
if boolean:
|
||||
return (on_true,)
|
||||
else:
|
||||
return (on_false,)
|
||||
|
||||
|
||||
class CSwitchBooleanConditioning:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"on_true": ("CONDITIONING", {"lazy": True}),
|
||||
"on_false": ("CONDITIONING", {"lazy": True}),
|
||||
"boolean": BOOLEAN,
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.SWITCH.value
|
||||
RETURN_TYPES = ("CONDITIONING",)
|
||||
RETURN_NAMES = ("conditioning",)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def check_lazy_status(self, on_true=None, on_false=None, boolean=True):
|
||||
needed = "on_true" if boolean else "on_false"
|
||||
return [needed]
|
||||
|
||||
def execute(self, on_true, on_false, boolean=True):
|
||||
logger.debug("Conditioning switch: " + str(boolean))
|
||||
|
||||
if boolean:
|
||||
return (on_true,)
|
||||
else:
|
||||
return (on_false,)
|
||||
|
||||
|
||||
class CSwitchBooleanImage:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"on_true": ("IMAGE", {"lazy": True}),
|
||||
"on_false": ("IMAGE", {"lazy": True}),
|
||||
"boolean": BOOLEAN,
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.SWITCH.value
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_NAMES = ("image",)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def check_lazy_status(self, on_true=None, on_false=None, boolean=True):
|
||||
needed = "on_true" if boolean else "on_false"
|
||||
return [needed]
|
||||
|
||||
def execute(self, on_true, on_false, boolean=True):
|
||||
logger.debug("Image switch: " + str(boolean))
|
||||
|
||||
if boolean:
|
||||
return (on_true,)
|
||||
else:
|
||||
return (on_false,)
|
||||
|
||||
|
||||
class CSwitchBooleanLatent:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"on_true": ("LATENT", {"lazy": True}),
|
||||
"on_false": ("LATENT", {"lazy": True}),
|
||||
"boolean": BOOLEAN,
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.SWITCH.value
|
||||
RETURN_TYPES = ("LATENT",)
|
||||
RETURN_NAMES = ("latent",)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def check_lazy_status(self, on_true=None, on_false=None, boolean=True):
|
||||
needed = "on_true" if boolean else "on_false"
|
||||
return [needed]
|
||||
|
||||
def execute(self, on_true, on_false, boolean=True):
|
||||
logger.debug("Latent switch: " + str(boolean))
|
||||
|
||||
if boolean:
|
||||
return (on_true,)
|
||||
else:
|
||||
return (on_false,)
|
||||
|
||||
|
||||
class CSwitchBooleanMask:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"on_true": ("MASK", {"lazy": True}),
|
||||
"on_false": ("MASK", {"lazy": True}),
|
||||
"boolean": BOOLEAN,
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.SWITCH.value
|
||||
RETURN_TYPES = ("MASK",)
|
||||
RETURN_NAMES = ("mask",)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def check_lazy_status(self, on_true=None, on_false=None, boolean=True):
|
||||
needed = "on_true" if boolean else "on_false"
|
||||
return [needed]
|
||||
|
||||
def execute(self, on_true, on_false, boolean=True):
|
||||
logger.debug("Mask switch: " + str(boolean))
|
||||
|
||||
if boolean:
|
||||
return (on_true,)
|
||||
else:
|
||||
return (on_false,)
|
||||
55
custom_nodes/ComfyUI-Crystools/nodes/utils.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from ..core import CATEGORY, JSON_WIDGET, findJsonStrDiff, get_system_stats, logger
|
||||
|
||||
|
||||
class CUtilsCompareJsons:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"json_old": JSON_WIDGET,
|
||||
"json_new": JSON_WIDGET,
|
||||
},
|
||||
"optional": {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.UTILS.value
|
||||
RETURN_TYPES = ("JSON",)
|
||||
RETURN_NAMES = ("json_compared",)
|
||||
OUTPUT_NODE = True
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, json_old, json_new):
|
||||
json = findJsonStrDiff(json_old, json_new)
|
||||
return (str(json),)
|
||||
|
||||
|
||||
# Credits to: https://github.com/WASasquatch/was-node-suite-comfyui for the following node!
|
||||
class CUtilsStatSystem:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"latent": ("LATENT",),
|
||||
}
|
||||
}
|
||||
|
||||
CATEGORY = CATEGORY.MAIN.value + CATEGORY.UTILS.value
|
||||
RETURN_TYPES = ("LATENT",)
|
||||
RETURN_NAMES = ("latent",)
|
||||
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, latent):
|
||||
log = "Samples Passthrough:\n"
|
||||
for stat in get_system_stats():
|
||||
log += stat + "\n"
|
||||
|
||||
logger.debug(log)
|
||||
|
||||
return {"ui": {"text": [log]}, "result": (latent,)}
|
||||
2761
custom_nodes/ComfyUI-Crystools/package-lock.json
generated
Normal file
20
custom_nodes/ComfyUI-Crystools/package.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "crystools-typescript",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "tsc --watch",
|
||||
"tsc": "tsc",
|
||||
"lint": "eslint web --ext ts --report-unused-disable-directives --max-warnings 0",
|
||||
"lint-fix": "eslint web --ext ts --fix",
|
||||
"validate": "npm run tsc && npm run lint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "6.18.1",
|
||||
"@typescript-eslint/parser": "6.18.1",
|
||||
"eslint": "8.56.0",
|
||||
"eslint-plugin-import": "2.29.1",
|
||||
"typescript": "5.3.3"
|
||||
}
|
||||
}
|
||||
21
custom_nodes/ComfyUI-Crystools/pyproject.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
[project]
|
||||
name = "ComfyUI-Crystools"
|
||||
description = "With this suit, you can see the resources monitor, progress bar & time elapsed, metadata and compare between two images, compare between two JSONs, show any value to console/display, pipes, and more!\nThis provides better nodes to load/save images, previews, etc, and see \"hidden\" data without loading a new workflow."
|
||||
version = "1.27.4"
|
||||
license = { file = "LICENSE" }
|
||||
dependencies = ["deepdiff", "torch", "numpy", "Pillow", "pynvml", "py-cpuinfo"]
|
||||
|
||||
classifiers = [
|
||||
"Operating System :: OS Independent",
|
||||
"Environment :: GPU :: NVIDIA CUDA",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Repository = "https://github.com/crystian/ComfyUI-Crystools"
|
||||
Documentation = "https://github.com/crystian/ComfyUI-Crystools/blob/main/README.md"
|
||||
"Bug Tracker" = "https://github.com/crystian/ComfyUI-Crystools/issues"
|
||||
|
||||
[tool.comfy]
|
||||
PublisherId = "crystian"
|
||||
DisplayName = "ComfyUI-Crystools"
|
||||
Icon = "https://raw.githubusercontent.com/crystian/ComfyUI-Crystools/main/docs/screwdriver.png"
|
||||
8
custom_nodes/ComfyUI-Crystools/requirements.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
deepdiff
|
||||
torch
|
||||
numpy
|
||||
Pillow
|
||||
pynvml; platform_machine != 'aarch64'
|
||||
py-cpuinfo
|
||||
piexif
|
||||
jetson-stats; platform_machine == 'aarch64'
|
||||
102
custom_nodes/ComfyUI-Crystools/samples/debugger-any.json
Normal file
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"last_node_id": 4,
|
||||
"last_link_id": 4,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 3,
|
||||
"type": "Show any [Crystools]",
|
||||
"pos": [
|
||||
475,
|
||||
250
|
||||
],
|
||||
"size": {
|
||||
"0": 400,
|
||||
"1": 750
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_value",
|
||||
"type": "*",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Show any [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
false,
|
||||
true,
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"type": "Load image with metadata [Crystools]",
|
||||
"pos": [
|
||||
100,
|
||||
75
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
350
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "prompt",
|
||||
"type": "JSON",
|
||||
"links": [
|
||||
3
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 2
|
||||
},
|
||||
{
|
||||
"name": "Metadata RAW",
|
||||
"type": "METADATA_RAW",
|
||||
"links": [],
|
||||
"shape": 3,
|
||||
"slot_index": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Load image with metadata [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"tests/ComfyUI_00314_20-8-euler.png",
|
||||
"image"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
3,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
0,
|
||||
"*"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
182
custom_nodes/ComfyUI-Crystools/samples/debugger-json.json
Normal file
@@ -0,0 +1,182 @@
|
||||
{
|
||||
"last_node_id": 4,
|
||||
"last_link_id": 4,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 4,
|
||||
"type": "Show any to JSON [Crystools]",
|
||||
"pos": [
|
||||
900,
|
||||
175
|
||||
],
|
||||
"size": {
|
||||
"0": 400,
|
||||
"1": 825
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_value",
|
||||
"type": "*",
|
||||
"link": 4
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "string",
|
||||
"type": "STRING",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Show any to JSON [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "Show any to JSON [Crystools]",
|
||||
"pos": [
|
||||
1350,
|
||||
50
|
||||
],
|
||||
"size": [
|
||||
400,
|
||||
950
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_value",
|
||||
"type": "*",
|
||||
"link": 2
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "string",
|
||||
"type": "STRING",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Show any to JSON [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "Show any [Crystools]",
|
||||
"pos": [
|
||||
475,
|
||||
250
|
||||
],
|
||||
"size": [
|
||||
400,
|
||||
750
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_value",
|
||||
"type": "*",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Show any [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"type": "Load image with metadata [Crystools]",
|
||||
"pos": [
|
||||
100,
|
||||
75
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
350
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "prompt",
|
||||
"type": "JSON",
|
||||
"links": [
|
||||
2,
|
||||
3
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 2
|
||||
},
|
||||
{
|
||||
"name": "Metadata RAW",
|
||||
"type": "METADATA_RAW",
|
||||
"links": [
|
||||
4
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Load image with metadata [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"tests/ComfyUI_00314_20-8-euler.png",
|
||||
"image"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
2,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
3,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
4,
|
||||
1,
|
||||
3,
|
||||
4,
|
||||
0,
|
||||
"*"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
382
custom_nodes/ComfyUI-Crystools/samples/debugger-metadata.json
Normal file
@@ -0,0 +1,382 @@
|
||||
{
|
||||
"last_node_id": 13,
|
||||
"last_link_id": 11,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 7,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
413,
|
||||
389
|
||||
],
|
||||
"size": {
|
||||
"0": 425.27801513671875,
|
||||
"1": 180.6060791015625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 5
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
6
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"text, watermark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
415,
|
||||
186
|
||||
],
|
||||
"size": {
|
||||
"0": 422.84503173828125,
|
||||
"1": 164.31304931640625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
4
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "EmptyLatentImage",
|
||||
"pos": [
|
||||
473,
|
||||
609
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 106
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
2
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyLatentImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
512,
|
||||
512,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
1209,
|
||||
188
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 7
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 8
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
9
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1451,
|
||||
189
|
||||
],
|
||||
"size": [
|
||||
200,
|
||||
275
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 9
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"ComfyUI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
863,
|
||||
186
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
475
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 1
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 4
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 6
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 2
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
7
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
156680208700286,
|
||||
"fixed",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"normal",
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"type": "Show Metadata [Crystools]",
|
||||
"pos": [
|
||||
1225,
|
||||
525
|
||||
],
|
||||
"size": [
|
||||
450,
|
||||
525
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"properties": {}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "CheckpointLoaderSimple",
|
||||
"pos": [
|
||||
26,
|
||||
474
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 98
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
1
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"links": [
|
||||
3,
|
||||
5
|
||||
],
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"links": [
|
||||
8
|
||||
],
|
||||
"slot_index": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CheckpointLoaderSimple"
|
||||
},
|
||||
"widgets_values": [
|
||||
"sd-v1-5-pruned-emaonly.safetensors"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
2,
|
||||
5,
|
||||
0,
|
||||
3,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
3,
|
||||
4,
|
||||
1,
|
||||
6,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
4,
|
||||
6,
|
||||
0,
|
||||
3,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
5,
|
||||
4,
|
||||
1,
|
||||
7,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
6,
|
||||
7,
|
||||
0,
|
||||
3,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
7,
|
||||
3,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
8,
|
||||
4,
|
||||
2,
|
||||
8,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
9,
|
||||
8,
|
||||
0,
|
||||
9,
|
||||
0,
|
||||
"IMAGE"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
59
custom_nodes/ComfyUI-Crystools/samples/image-load.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"last_node_id": 1,
|
||||
"last_link_id": 0,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "Load image with metadata [Crystools]",
|
||||
"pos": [
|
||||
150,
|
||||
200
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
350
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "prompt",
|
||||
"type": "JSON",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "Metadata RAW",
|
||||
"type": "METADATA_RAW",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Load image with metadata [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"tests/ComfyUI_00314_20-8-euler.png",
|
||||
"image"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
373
custom_nodes/ComfyUI-Crystools/samples/image-preview-image.json
Normal file
@@ -0,0 +1,373 @@
|
||||
{
|
||||
"last_node_id": 14,
|
||||
"last_link_id": 12,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 7,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
413,
|
||||
389
|
||||
],
|
||||
"size": {
|
||||
"0": 425.27801513671875,
|
||||
"1": 180.6060791015625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 5
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
6
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"text, watermark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
415,
|
||||
186
|
||||
],
|
||||
"size": {
|
||||
"0": 422.84503173828125,
|
||||
"1": 164.31304931640625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
4
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "EmptyLatentImage",
|
||||
"pos": [
|
||||
473,
|
||||
609
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 106
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
2
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyLatentImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
512,
|
||||
512,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
1209,
|
||||
188
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 7
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 8
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
12
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "CheckpointLoaderSimple",
|
||||
"pos": [
|
||||
26,
|
||||
474
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 98
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
1
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"links": [
|
||||
3,
|
||||
5
|
||||
],
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"links": [
|
||||
8
|
||||
],
|
||||
"slot_index": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CheckpointLoaderSimple"
|
||||
},
|
||||
"widgets_values": [
|
||||
"sd-v1-5-pruned-emaonly.safetensors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
863,
|
||||
186
|
||||
],
|
||||
"size": {
|
||||
"0": 325,
|
||||
"1": 475
|
||||
},
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 1
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 4
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 6
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 2
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
7
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
156680208700286,
|
||||
"fixed",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"normal",
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"type": "Preview from image [Crystools]",
|
||||
"pos": [
|
||||
1525,
|
||||
175
|
||||
],
|
||||
"size": [
|
||||
400,
|
||||
800
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 12
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "Metadata RAW",
|
||||
"type": "METADATA_RAW",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Preview from image [Crystools]"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
2,
|
||||
5,
|
||||
0,
|
||||
3,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
3,
|
||||
4,
|
||||
1,
|
||||
6,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
4,
|
||||
6,
|
||||
0,
|
||||
3,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
5,
|
||||
4,
|
||||
1,
|
||||
7,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
6,
|
||||
7,
|
||||
0,
|
||||
3,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
7,
|
||||
3,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
8,
|
||||
4,
|
||||
2,
|
||||
8,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
12,
|
||||
8,
|
||||
0,
|
||||
14,
|
||||
0,
|
||||
"IMAGE"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
{
|
||||
"last_node_id": 2,
|
||||
"last_link_id": 1,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "Load image with metadata [Crystools]",
|
||||
"pos": [
|
||||
150,
|
||||
200
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
350
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "prompt",
|
||||
"type": "JSON",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "Metadata RAW",
|
||||
"type": "METADATA_RAW",
|
||||
"links": [
|
||||
1
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Load image with metadata [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"tests/ComfyUI_00314_20-8-euler.png",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "Preview from metadata [Crystools]",
|
||||
"pos": [
|
||||
575,
|
||||
200
|
||||
],
|
||||
"size": [
|
||||
425,
|
||||
675
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "metadata_raw",
|
||||
"type": "METADATA_RAW",
|
||||
"link": 1
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "Metadata RAW",
|
||||
"type": "METADATA_RAW",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Preview from metadata [Crystools]"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
1,
|
||||
3,
|
||||
2,
|
||||
0,
|
||||
"METADATA_RAW"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
512
custom_nodes/ComfyUI-Crystools/samples/image-resolution.json
Normal file
@@ -0,0 +1,512 @@
|
||||
{
|
||||
"last_node_id": 13,
|
||||
"last_link_id": 11,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 7,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
413,
|
||||
389
|
||||
],
|
||||
"size": {
|
||||
"0": 425.27801513671875,
|
||||
"1": 180.6060791015625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 5
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
6
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"text, watermark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
415,
|
||||
186
|
||||
],
|
||||
"size": {
|
||||
"0": 422.84503173828125,
|
||||
"1": 164.31304931640625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
4
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "EmptyLatentImage",
|
||||
"pos": [
|
||||
473,
|
||||
609
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 106
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
2
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyLatentImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
512,
|
||||
512,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "CheckpointLoaderSimple",
|
||||
"pos": [
|
||||
26,
|
||||
474
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 98
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
1
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"links": [
|
||||
3,
|
||||
5
|
||||
],
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"links": [
|
||||
8
|
||||
],
|
||||
"slot_index": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CheckpointLoaderSimple"
|
||||
},
|
||||
"widgets_values": [
|
||||
"SD1.5\\3d\\disneyPixarCartoon_v10.safetensors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
863,
|
||||
186
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
475
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 1
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 4
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 6
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 2
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
7
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
156680208700286,
|
||||
"fixed",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"normal",
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
1209,
|
||||
188
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 7
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 8
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
9,
|
||||
10
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1475,
|
||||
250
|
||||
],
|
||||
"size": [
|
||||
200,
|
||||
275
|
||||
],
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 9
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"ComfyUI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"type": "Get resolution [Crystools]",
|
||||
"pos": [
|
||||
1475,
|
||||
100
|
||||
],
|
||||
"size": {
|
||||
"0": 200,
|
||||
"1": 100
|
||||
},
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 10
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "width",
|
||||
"type": "INT",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "height",
|
||||
"type": "INT",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Get resolution [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"type": "Load image with metadata [Crystools]",
|
||||
"pos": [
|
||||
1350,
|
||||
625
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
350
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
11
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "prompt",
|
||||
"type": "JSON",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "Metadata RAW",
|
||||
"type": "METADATA_RAW",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Load image with metadata [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"tests/ComfyUI_00314_20-8-euler.png",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"type": "Get resolution [Crystools]",
|
||||
"pos": [
|
||||
1725,
|
||||
625
|
||||
],
|
||||
"size": {
|
||||
"0": 200,
|
||||
"1": 100
|
||||
},
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 11
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "width",
|
||||
"type": "INT",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "height",
|
||||
"type": "INT",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Get resolution [Crystools]"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
2,
|
||||
5,
|
||||
0,
|
||||
3,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
3,
|
||||
4,
|
||||
1,
|
||||
6,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
4,
|
||||
6,
|
||||
0,
|
||||
3,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
5,
|
||||
4,
|
||||
1,
|
||||
7,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
6,
|
||||
7,
|
||||
0,
|
||||
3,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
7,
|
||||
3,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
8,
|
||||
4,
|
||||
2,
|
||||
8,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
9,
|
||||
8,
|
||||
0,
|
||||
9,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
10,
|
||||
8,
|
||||
0,
|
||||
10,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
11,
|
||||
12,
|
||||
0,
|
||||
13,
|
||||
0,
|
||||
"IMAGE"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
422
custom_nodes/ComfyUI-Crystools/samples/image-save.json
Normal file
@@ -0,0 +1,422 @@
|
||||
{
|
||||
"last_node_id": 11,
|
||||
"last_link_id": 11,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 7,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
413,
|
||||
389
|
||||
],
|
||||
"size": {
|
||||
"0": 425.27801513671875,
|
||||
"1": 180.6060791015625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 5
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
6
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"text, watermark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
415,
|
||||
186
|
||||
],
|
||||
"size": {
|
||||
"0": 422.84503173828125,
|
||||
"1": 164.31304931640625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
4
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "EmptyLatentImage",
|
||||
"pos": [
|
||||
473,
|
||||
609
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 106
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
2
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyLatentImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
512,
|
||||
512,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
863,
|
||||
186
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
475
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 1
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 4
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 6
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 2
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
7
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
156680208700286,
|
||||
"fixed",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"normal",
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "CheckpointLoaderSimple",
|
||||
"pos": [
|
||||
26,
|
||||
474
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 98
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
1
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"links": [
|
||||
3,
|
||||
5
|
||||
],
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"links": [
|
||||
8
|
||||
],
|
||||
"slot_index": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CheckpointLoaderSimple"
|
||||
},
|
||||
"widgets_values": [
|
||||
"SD1.5\\anime\\chilloutmix_NiPrunedFp32Fix.safetensors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
1209,
|
||||
188
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 7
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 8
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
10
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"type": "Save image with extra metadata [Crystools]",
|
||||
"pos": [
|
||||
1450,
|
||||
200
|
||||
],
|
||||
"size": [
|
||||
425,
|
||||
550
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 10
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "Metadata RAW",
|
||||
"type": "METADATA_RAW",
|
||||
"links": [
|
||||
11
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Save image with extra metadata [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"ComfyUI",
|
||||
false,
|
||||
"{\n \"Title\": \"Image generated by Crystian\",\n \"Description\": \"More info: https:\\/\\/www.instagram.com\\/crystian.ia\",\n \"Author\": \"crystian.ia\",\n \"Software\": \"ComfyUI\",\n \"Category\": \"StableDiffusion\",\n \"Rating\": 5,\n \"UserComment\": \"\",\n \"Keywords\": [\n \"\"\n ],\n \"Copyrights\": \"\"\n}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"type": "Show any to JSON [Crystools]",
|
||||
"pos": [
|
||||
1925,
|
||||
200
|
||||
],
|
||||
"size": [
|
||||
425,
|
||||
300
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_value",
|
||||
"type": "*",
|
||||
"link": 11
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "string",
|
||||
"type": "STRING",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Show any to JSON [Crystools]"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
2,
|
||||
5,
|
||||
0,
|
||||
3,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
3,
|
||||
4,
|
||||
1,
|
||||
6,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
4,
|
||||
6,
|
||||
0,
|
||||
3,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
5,
|
||||
4,
|
||||
1,
|
||||
7,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
6,
|
||||
7,
|
||||
0,
|
||||
3,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
7,
|
||||
3,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
8,
|
||||
4,
|
||||
2,
|
||||
8,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
10,
|
||||
8,
|
||||
0,
|
||||
10,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
11,
|
||||
10,
|
||||
0,
|
||||
11,
|
||||
0,
|
||||
"*"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
375
custom_nodes/ComfyUI-Crystools/samples/list-any.json
Normal file
@@ -0,0 +1,375 @@
|
||||
{
|
||||
"last_node_id": 15,
|
||||
"last_link_id": 13,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 10,
|
||||
"type": "Primitive integer [Crystools]",
|
||||
"pos": [
|
||||
175,
|
||||
525
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 58
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "int",
|
||||
"type": "INT",
|
||||
"links": [
|
||||
9
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Primitive integer [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"type": "Primitive float [Crystools]",
|
||||
"pos": [
|
||||
175,
|
||||
625
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 58
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "float",
|
||||
"type": "FLOAT",
|
||||
"links": [
|
||||
10
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Primitive float [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "Primitive string multiline [Crystools]",
|
||||
"pos": [
|
||||
90,
|
||||
275
|
||||
],
|
||||
"size": {
|
||||
"0": 400,
|
||||
"1": 200
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "string",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
8
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Primitive string multiline [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"sample\nmultiline"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"type": "Primitive string [Crystools]",
|
||||
"pos": [
|
||||
240,
|
||||
175
|
||||
],
|
||||
"size": {
|
||||
"0": 250,
|
||||
"1": 58
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "string",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
6
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Primitive string [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"sample"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"type": "Load image with metadata [Crystools]",
|
||||
"pos": [
|
||||
165,
|
||||
750
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
350
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
11
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "prompt",
|
||||
"type": "JSON",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "Metadata RAW",
|
||||
"type": "METADATA_RAW",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Load image with metadata [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"tests/ComfyUI_00314_20-8-euler.png",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "List of any [Crystools]",
|
||||
"pos": [
|
||||
600,
|
||||
325
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 166
|
||||
},
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_1",
|
||||
"type": "*",
|
||||
"link": 5
|
||||
},
|
||||
{
|
||||
"name": "any_2",
|
||||
"type": "*",
|
||||
"link": 6
|
||||
},
|
||||
{
|
||||
"name": "any_3",
|
||||
"type": "*",
|
||||
"link": 8
|
||||
},
|
||||
{
|
||||
"name": "any_4",
|
||||
"type": "*",
|
||||
"link": 9
|
||||
},
|
||||
{
|
||||
"name": "any_5",
|
||||
"type": "*",
|
||||
"link": 10
|
||||
},
|
||||
{
|
||||
"name": "any_6",
|
||||
"type": "*",
|
||||
"link": 11
|
||||
},
|
||||
{
|
||||
"name": "any_7",
|
||||
"type": "*",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "any_8",
|
||||
"type": "*",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "any_list",
|
||||
"type": "COMBO",
|
||||
"links": [
|
||||
12
|
||||
],
|
||||
"shape": 6,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "List of any [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"type": "Show any [Crystools]",
|
||||
"pos": [
|
||||
850,
|
||||
325
|
||||
],
|
||||
"size": [
|
||||
575,
|
||||
625
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_value",
|
||||
"type": "*",
|
||||
"link": 12
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Show any [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "Primitive boolean [Crystools]",
|
||||
"pos": [
|
||||
175,
|
||||
75
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 58
|
||||
},
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "boolean",
|
||||
"type": "BOOLEAN",
|
||||
"links": [
|
||||
5
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Primitive boolean [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
true
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
5,
|
||||
8,
|
||||
0,
|
||||
7,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
6,
|
||||
12,
|
||||
0,
|
||||
7,
|
||||
1,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
8,
|
||||
9,
|
||||
0,
|
||||
7,
|
||||
2,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
9,
|
||||
10,
|
||||
0,
|
||||
7,
|
||||
3,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
10,
|
||||
11,
|
||||
0,
|
||||
7,
|
||||
4,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
11,
|
||||
14,
|
||||
0,
|
||||
7,
|
||||
5,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
12,
|
||||
7,
|
||||
0,
|
||||
15,
|
||||
0,
|
||||
"*"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
177
custom_nodes/ComfyUI-Crystools/samples/list-strings.json
Normal file
@@ -0,0 +1,177 @@
|
||||
{
|
||||
"last_node_id": 6,
|
||||
"last_link_id": 4,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 3,
|
||||
"type": "Primitive string [Crystools]",
|
||||
"pos": [
|
||||
50,
|
||||
100
|
||||
],
|
||||
"size": {
|
||||
"0": 250,
|
||||
"1": 58
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "string",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
2
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Primitive string [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"folder2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "List of strings [Crystools]",
|
||||
"pos": [
|
||||
350,
|
||||
100
|
||||
],
|
||||
"size": {
|
||||
"0": 325,
|
||||
"1": 275
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "string_2",
|
||||
"type": "STRING",
|
||||
"link": 2,
|
||||
"widget": {
|
||||
"name": "string_2"
|
||||
}
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "concatenated",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
4
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "list_string",
|
||||
"type": "ListString",
|
||||
"links": [
|
||||
3
|
||||
],
|
||||
"shape": 6,
|
||||
"slot_index": 1
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "List of strings [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"folder1",
|
||||
"",
|
||||
"folder3",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"/"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "Show any [Crystools]",
|
||||
"pos": [
|
||||
775,
|
||||
100
|
||||
],
|
||||
"size": {
|
||||
"0": 375,
|
||||
"1": 150
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_value",
|
||||
"type": "*",
|
||||
"link": 4
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Show any [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "Show any [Crystools]",
|
||||
"pos": [
|
||||
775,
|
||||
325
|
||||
],
|
||||
"size": {
|
||||
"0": 375,
|
||||
"1": 150
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_value",
|
||||
"type": "*",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Show any [Crystools]"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
2,
|
||||
3,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
"STRING"
|
||||
],
|
||||
[
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
5,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
4,
|
||||
2,
|
||||
0,
|
||||
6,
|
||||
0,
|
||||
"*"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
168
custom_nodes/ComfyUI-Crystools/samples/metadata-comparator.json
Normal file
@@ -0,0 +1,168 @@
|
||||
{
|
||||
"last_node_id": 10,
|
||||
"last_link_id": 9,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "Load image with metadata [Crystools]",
|
||||
"pos": [
|
||||
100,
|
||||
75
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
350
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "prompt",
|
||||
"type": "JSON",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "Metadata RAW",
|
||||
"type": "METADATA_RAW",
|
||||
"links": [
|
||||
8
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Load image with metadata [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"tests/ComfyUI_00314_20-8-euler.png",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "Load image with metadata [Crystools]",
|
||||
"pos": [
|
||||
100,
|
||||
500
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
350
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "prompt",
|
||||
"type": "JSON",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "Metadata RAW",
|
||||
"type": "METADATA_RAW",
|
||||
"links": [
|
||||
9
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Load image with metadata [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"tests/ComfyUI_00315_21-81-heun.png",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"type": "Metadata comparator [Crystools]",
|
||||
"pos": [
|
||||
550,
|
||||
100
|
||||
],
|
||||
"size": [
|
||||
375,
|
||||
750
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "metadata_raw_old",
|
||||
"type": "METADATA_RAW",
|
||||
"link": 8
|
||||
},
|
||||
{
|
||||
"name": "metadata_raw_new",
|
||||
"type": "METADATA_RAW",
|
||||
"link": 9
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "diff",
|
||||
"type": "JSON",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Metadata comparator [Crystools]"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
8,
|
||||
1,
|
||||
3,
|
||||
10,
|
||||
0,
|
||||
"METADATA_RAW"
|
||||
],
|
||||
[
|
||||
9,
|
||||
9,
|
||||
3,
|
||||
10,
|
||||
1,
|
||||
"METADATA_RAW"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
350
custom_nodes/ComfyUI-Crystools/samples/metadata-extractor.json
Normal file
@@ -0,0 +1,350 @@
|
||||
{
|
||||
"last_node_id": 8,
|
||||
"last_link_id": 7,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 5,
|
||||
"type": "Show any [Crystools]",
|
||||
"pos": [
|
||||
1100,
|
||||
575
|
||||
],
|
||||
"size": [
|
||||
475,
|
||||
225
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_value",
|
||||
"type": "*",
|
||||
"link": 4
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Show any [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "Show any [Crystools]",
|
||||
"pos": [
|
||||
1100,
|
||||
50
|
||||
],
|
||||
"size": [
|
||||
475,
|
||||
450
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_value",
|
||||
"type": "*",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Show any [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "Show any [Crystools]",
|
||||
"pos": [
|
||||
100,
|
||||
900
|
||||
],
|
||||
"size": [
|
||||
450,
|
||||
375
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_value",
|
||||
"type": "*",
|
||||
"link": 7
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Show any [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"type": "Load image with metadata [Crystools]",
|
||||
"pos": [
|
||||
100,
|
||||
75
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
350
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "prompt",
|
||||
"type": "JSON",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "Metadata RAW",
|
||||
"type": "METADATA_RAW",
|
||||
"links": [
|
||||
1
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Load image with metadata [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"tests/ComfyUI_00314_20-8-euler.png",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "Metadata extractor [Crystools]",
|
||||
"pos": [
|
||||
125,
|
||||
625
|
||||
],
|
||||
"size": {
|
||||
"0": 355.20001220703125,
|
||||
"1": 126
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "metadata_raw",
|
||||
"type": "METADATA_RAW",
|
||||
"link": 1
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "prompt",
|
||||
"type": "JSON",
|
||||
"links": [
|
||||
2
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "workflow",
|
||||
"type": "JSON",
|
||||
"links": [
|
||||
3
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "file info",
|
||||
"type": "JSON",
|
||||
"links": [
|
||||
4
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 2
|
||||
},
|
||||
{
|
||||
"name": "raw to JSON",
|
||||
"type": "JSON",
|
||||
"links": [
|
||||
5
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 3
|
||||
},
|
||||
{
|
||||
"name": "raw to property",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
6
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 4
|
||||
},
|
||||
{
|
||||
"name": "raw to csv",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
7
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 5
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Metadata extractor [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "Show any [Crystools]",
|
||||
"pos": [
|
||||
1100,
|
||||
900
|
||||
],
|
||||
"size": [
|
||||
475,
|
||||
375
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_value",
|
||||
"type": "*",
|
||||
"link": 5
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Show any [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "Show any [Crystools]",
|
||||
"pos": [
|
||||
600,
|
||||
900
|
||||
],
|
||||
"size": [
|
||||
450,
|
||||
375
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_value",
|
||||
"type": "*",
|
||||
"link": 6
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Show any [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "Show any [Crystools]",
|
||||
"pos": [
|
||||
625,
|
||||
50
|
||||
],
|
||||
"size": [
|
||||
425,
|
||||
450
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_value",
|
||||
"type": "*",
|
||||
"link": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Show any [Crystools]"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
1,
|
||||
3,
|
||||
2,
|
||||
0,
|
||||
"METADATA_RAW"
|
||||
],
|
||||
[
|
||||
2,
|
||||
2,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
4,
|
||||
2,
|
||||
2,
|
||||
5,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
5,
|
||||
2,
|
||||
3,
|
||||
6,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
6,
|
||||
2,
|
||||
4,
|
||||
7,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
7,
|
||||
2,
|
||||
5,
|
||||
8,
|
||||
0,
|
||||
"*"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
564
custom_nodes/ComfyUI-Crystools/samples/pipe-1.json
Normal file
@@ -0,0 +1,564 @@
|
||||
{
|
||||
"last_node_id": 15,
|
||||
"last_link_id": 29,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 3,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
1350,
|
||||
125
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
475
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 17
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 26
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 25
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 24
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
7
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
156680208700286,
|
||||
"fixed",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"normal",
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
1400,
|
||||
675
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 7
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 27
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
9
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1400,
|
||||
800
|
||||
],
|
||||
"size": [
|
||||
200,
|
||||
275
|
||||
],
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 9
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"ComfyUI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
75,
|
||||
525
|
||||
],
|
||||
"size": {
|
||||
"0": 425.27801513671875,
|
||||
"1": 180.6060791015625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 5
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
22
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"text, watermark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"type": "Pipe from any [Crystools]",
|
||||
"pos": [
|
||||
975,
|
||||
200
|
||||
],
|
||||
"size": {
|
||||
"0": 216.59999084472656,
|
||||
"1": 146
|
||||
},
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "CPipeAny",
|
||||
"type": "CPipeAny",
|
||||
"link": 12
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CPipeAny",
|
||||
"type": "CPipeAny",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "any_1",
|
||||
"type": "*",
|
||||
"links": [
|
||||
17
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "any_2",
|
||||
"type": "*",
|
||||
"links": [
|
||||
27
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 2
|
||||
},
|
||||
{
|
||||
"name": "any_3",
|
||||
"type": "*",
|
||||
"links": [
|
||||
26
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 3
|
||||
},
|
||||
{
|
||||
"name": "any_4",
|
||||
"type": "*",
|
||||
"links": [
|
||||
25
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 4
|
||||
},
|
||||
{
|
||||
"name": "any_5",
|
||||
"type": "*",
|
||||
"links": [
|
||||
24
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 5
|
||||
},
|
||||
{
|
||||
"name": "any_6",
|
||||
"type": "*",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Pipe from any [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
75,
|
||||
275
|
||||
],
|
||||
"size": {
|
||||
"0": 422.84503173828125,
|
||||
"1": 164.31304931640625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
29
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "CheckpointLoaderSimple",
|
||||
"pos": [
|
||||
175,
|
||||
100
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 98
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
13
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"links": [
|
||||
3,
|
||||
5
|
||||
],
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"links": [
|
||||
28
|
||||
],
|
||||
"slot_index": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CheckpointLoaderSimple"
|
||||
},
|
||||
"widgets_values": [
|
||||
"SD1.5\\3d\\disneyPixarCartoon_v10.safetensors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "EmptyLatentImage",
|
||||
"pos": [
|
||||
175,
|
||||
775
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 106
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
21
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyLatentImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
512,
|
||||
512,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"type": "Pipe to/edit any [Crystools]",
|
||||
"pos": [
|
||||
625,
|
||||
200
|
||||
],
|
||||
"size": {
|
||||
"0": 216.59999084472656,
|
||||
"1": 146
|
||||
},
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "CPipeAny",
|
||||
"type": "CPipeAny",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "any_1",
|
||||
"type": "*",
|
||||
"link": 13
|
||||
},
|
||||
{
|
||||
"name": "any_2",
|
||||
"type": "*",
|
||||
"link": 28
|
||||
},
|
||||
{
|
||||
"name": "any_3",
|
||||
"type": "*",
|
||||
"link": 29
|
||||
},
|
||||
{
|
||||
"name": "any_4",
|
||||
"type": "*",
|
||||
"link": 22
|
||||
},
|
||||
{
|
||||
"name": "any_5",
|
||||
"type": "*",
|
||||
"link": 21
|
||||
},
|
||||
{
|
||||
"name": "any_6",
|
||||
"type": "*",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CPipeAny",
|
||||
"type": "CPipeAny",
|
||||
"links": [
|
||||
12
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Pipe to/edit any [Crystools]"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
3,
|
||||
4,
|
||||
1,
|
||||
6,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
5,
|
||||
4,
|
||||
1,
|
||||
7,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
7,
|
||||
3,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
9,
|
||||
8,
|
||||
0,
|
||||
9,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
12,
|
||||
14,
|
||||
0,
|
||||
15,
|
||||
0,
|
||||
"CPipeAny"
|
||||
],
|
||||
[
|
||||
13,
|
||||
4,
|
||||
0,
|
||||
14,
|
||||
1,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
17,
|
||||
15,
|
||||
1,
|
||||
3,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
21,
|
||||
5,
|
||||
0,
|
||||
14,
|
||||
5,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
22,
|
||||
7,
|
||||
0,
|
||||
14,
|
||||
4,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
24,
|
||||
15,
|
||||
5,
|
||||
3,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
25,
|
||||
15,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
26,
|
||||
15,
|
||||
3,
|
||||
3,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
27,
|
||||
15,
|
||||
2,
|
||||
8,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
28,
|
||||
4,
|
||||
2,
|
||||
14,
|
||||
2,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
29,
|
||||
6,
|
||||
0,
|
||||
14,
|
||||
3,
|
||||
"*"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
849
custom_nodes/ComfyUI-Crystools/samples/pipe-2.json
Normal file
@@ -0,0 +1,849 @@
|
||||
{
|
||||
"last_node_id": 19,
|
||||
"last_link_id": 37,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 3,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
1350,
|
||||
125
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
475
|
||||
],
|
||||
"flags": {},
|
||||
"order": 10,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 17
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 26
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 25
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 24
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
7
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
156680208700286,
|
||||
"fixed",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"normal",
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
1400,
|
||||
675
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 11,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 7
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 27
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
9
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1400,
|
||||
800
|
||||
],
|
||||
"size": [
|
||||
200,
|
||||
275
|
||||
],
|
||||
"flags": {},
|
||||
"order": 12,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 9
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"ComfyUI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
75,
|
||||
525
|
||||
],
|
||||
"size": {
|
||||
"0": 425.27801513671875,
|
||||
"1": 180.6060791015625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 5
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
22
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"text, watermark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"type": "Pipe from any [Crystools]",
|
||||
"pos": [
|
||||
975,
|
||||
200
|
||||
],
|
||||
"size": {
|
||||
"0": 216.59999084472656,
|
||||
"1": 146
|
||||
},
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "CPipeAny",
|
||||
"type": "CPipeAny",
|
||||
"link": 32
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CPipeAny",
|
||||
"type": "CPipeAny",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "any_1",
|
||||
"type": "*",
|
||||
"links": [
|
||||
17
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "any_2",
|
||||
"type": "*",
|
||||
"links": [
|
||||
27
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 2
|
||||
},
|
||||
{
|
||||
"name": "any_3",
|
||||
"type": "*",
|
||||
"links": [
|
||||
26
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 3
|
||||
},
|
||||
{
|
||||
"name": "any_4",
|
||||
"type": "*",
|
||||
"links": [
|
||||
25
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 4
|
||||
},
|
||||
{
|
||||
"name": "any_5",
|
||||
"type": "*",
|
||||
"links": [
|
||||
24
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 5
|
||||
},
|
||||
{
|
||||
"name": "any_6",
|
||||
"type": "*",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Pipe from any [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
75,
|
||||
275
|
||||
],
|
||||
"size": {
|
||||
"0": 422.84503173828125,
|
||||
"1": 164.31304931640625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
29
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "EmptyLatentImage",
|
||||
"pos": [
|
||||
175,
|
||||
775
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 106
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
21
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyLatentImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
512,
|
||||
512,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"type": "Pipe to/edit any [Crystools]",
|
||||
"pos": [
|
||||
625,
|
||||
200
|
||||
],
|
||||
"size": {
|
||||
"0": 216.59999084472656,
|
||||
"1": 146
|
||||
},
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "CPipeAny",
|
||||
"type": "CPipeAny",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "any_1",
|
||||
"type": "*",
|
||||
"link": 13
|
||||
},
|
||||
{
|
||||
"name": "any_2",
|
||||
"type": "*",
|
||||
"link": 28
|
||||
},
|
||||
{
|
||||
"name": "any_3",
|
||||
"type": "*",
|
||||
"link": 29
|
||||
},
|
||||
{
|
||||
"name": "any_4",
|
||||
"type": "*",
|
||||
"link": 22
|
||||
},
|
||||
{
|
||||
"name": "any_5",
|
||||
"type": "*",
|
||||
"link": 21
|
||||
},
|
||||
{
|
||||
"name": "any_6",
|
||||
"type": "*",
|
||||
"link": 33
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CPipeAny",
|
||||
"type": "CPipeAny",
|
||||
"links": [
|
||||
30
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Pipe to/edit any [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"type": "Pipe to/edit any [Crystools]",
|
||||
"pos": [
|
||||
950,
|
||||
475
|
||||
],
|
||||
"size": {
|
||||
"0": 216.59999084472656,
|
||||
"1": 146
|
||||
},
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "CPipeAny",
|
||||
"type": "CPipeAny",
|
||||
"link": 31
|
||||
},
|
||||
{
|
||||
"name": "any_1",
|
||||
"type": "*",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "any_2",
|
||||
"type": "*",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "any_3",
|
||||
"type": "*",
|
||||
"link": 37
|
||||
},
|
||||
{
|
||||
"name": "any_4",
|
||||
"type": "*",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "any_5",
|
||||
"type": "*",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "any_6",
|
||||
"type": "*",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CPipeAny",
|
||||
"type": "CPipeAny",
|
||||
"links": [
|
||||
32
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Pipe to/edit any [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "CheckpointLoaderSimple",
|
||||
"pos": [
|
||||
175,
|
||||
100
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 98
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
13
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"links": [
|
||||
3,
|
||||
5,
|
||||
33
|
||||
],
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"links": [
|
||||
28
|
||||
],
|
||||
"slot_index": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CheckpointLoaderSimple"
|
||||
},
|
||||
"widgets_values": [
|
||||
"SD1.5\\3d\\disneyPixarCartoon_v10.safetensors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"type": "Pipe from any [Crystools]",
|
||||
"pos": [
|
||||
650,
|
||||
475
|
||||
],
|
||||
"size": {
|
||||
"0": 216.59999084472656,
|
||||
"1": 146
|
||||
},
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "CPipeAny",
|
||||
"type": "CPipeAny",
|
||||
"link": 30
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CPipeAny",
|
||||
"type": "CPipeAny",
|
||||
"links": [
|
||||
31
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "any_1",
|
||||
"type": "*",
|
||||
"links": [],
|
||||
"shape": 3,
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "any_2",
|
||||
"type": "*",
|
||||
"links": [],
|
||||
"shape": 3,
|
||||
"slot_index": 2
|
||||
},
|
||||
{
|
||||
"name": "any_3",
|
||||
"type": "*",
|
||||
"links": [
|
||||
35
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 3
|
||||
},
|
||||
{
|
||||
"name": "any_4",
|
||||
"type": "*",
|
||||
"links": [],
|
||||
"shape": 3,
|
||||
"slot_index": 4
|
||||
},
|
||||
{
|
||||
"name": "any_5",
|
||||
"type": "*",
|
||||
"links": [],
|
||||
"shape": 3,
|
||||
"slot_index": 5
|
||||
},
|
||||
{
|
||||
"name": "any_6",
|
||||
"type": "*",
|
||||
"links": [
|
||||
34
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 6
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Pipe from any [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"type": "ConditioningCombine",
|
||||
"pos": [
|
||||
925,
|
||||
750
|
||||
],
|
||||
"size": {
|
||||
"0": 342.5999755859375,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "conditioning_1",
|
||||
"type": "CONDITIONING",
|
||||
"link": 35
|
||||
},
|
||||
{
|
||||
"name": "conditioning_2",
|
||||
"type": "CONDITIONING",
|
||||
"link": 36
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
37
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "ConditioningCombine"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
650,
|
||||
775
|
||||
],
|
||||
"size": [
|
||||
200,
|
||||
75.99999237060547
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 34
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
36
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"at night"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
3,
|
||||
4,
|
||||
1,
|
||||
6,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
5,
|
||||
4,
|
||||
1,
|
||||
7,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
7,
|
||||
3,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
9,
|
||||
8,
|
||||
0,
|
||||
9,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
13,
|
||||
4,
|
||||
0,
|
||||
14,
|
||||
1,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
17,
|
||||
15,
|
||||
1,
|
||||
3,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
21,
|
||||
5,
|
||||
0,
|
||||
14,
|
||||
5,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
22,
|
||||
7,
|
||||
0,
|
||||
14,
|
||||
4,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
24,
|
||||
15,
|
||||
5,
|
||||
3,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
25,
|
||||
15,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
26,
|
||||
15,
|
||||
3,
|
||||
3,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
27,
|
||||
15,
|
||||
2,
|
||||
8,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
28,
|
||||
4,
|
||||
2,
|
||||
14,
|
||||
2,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
29,
|
||||
6,
|
||||
0,
|
||||
14,
|
||||
3,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
30,
|
||||
14,
|
||||
0,
|
||||
17,
|
||||
0,
|
||||
"CPipeAny"
|
||||
],
|
||||
[
|
||||
31,
|
||||
17,
|
||||
0,
|
||||
16,
|
||||
0,
|
||||
"CPipeAny"
|
||||
],
|
||||
[
|
||||
32,
|
||||
16,
|
||||
0,
|
||||
15,
|
||||
0,
|
||||
"CPipeAny"
|
||||
],
|
||||
[
|
||||
33,
|
||||
4,
|
||||
1,
|
||||
14,
|
||||
6,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
34,
|
||||
17,
|
||||
6,
|
||||
18,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
35,
|
||||
17,
|
||||
3,
|
||||
19,
|
||||
0,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
36,
|
||||
18,
|
||||
0,
|
||||
19,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
37,
|
||||
19,
|
||||
0,
|
||||
16,
|
||||
3,
|
||||
"*"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
496
custom_nodes/ComfyUI-Crystools/samples/switch.json
Normal file
@@ -0,0 +1,496 @@
|
||||
{
|
||||
"last_node_id": 12,
|
||||
"last_link_id": 16,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 7,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
425,
|
||||
525
|
||||
],
|
||||
"size": {
|
||||
"0": 425.27801513671875,
|
||||
"1": 180.6060791015625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 5
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
6
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"text, watermark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "EmptyLatentImage",
|
||||
"pos": [
|
||||
475,
|
||||
750
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 106
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
2
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyLatentImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
512,
|
||||
512,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
1675,
|
||||
325
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 7
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 8
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
9
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1900,
|
||||
325
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 275
|
||||
},
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 9
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"ComfyUI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "CheckpointLoaderSimple",
|
||||
"pos": [
|
||||
50,
|
||||
625
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 98
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
1
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"links": [
|
||||
3,
|
||||
5,
|
||||
14
|
||||
],
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"links": [
|
||||
8
|
||||
],
|
||||
"slot_index": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CheckpointLoaderSimple"
|
||||
},
|
||||
"widgets_values": [
|
||||
"SD1.5\\3d\\disneyPixarCartoon_v10.safetensors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
1325,
|
||||
325
|
||||
],
|
||||
"size": {
|
||||
"0": 325,
|
||||
"1": 475
|
||||
},
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 1
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 13
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 6
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 2
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
7
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
156680208700286,
|
||||
"fixed",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"normal",
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
425,
|
||||
325
|
||||
],
|
||||
"size": {
|
||||
"0": 422.84503173828125,
|
||||
"1": 164.31304931640625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
16
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
425,
|
||||
100
|
||||
],
|
||||
"size": {
|
||||
"0": 422.84503173828125,
|
||||
"1": 164.31304931640625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 14
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
15
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"beautiful scenery nature glass bottle landscape, in the bottle should be a cat (seen the camera:1.2), purple galaxy bottle,"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"type": "Switch conditioning [Crystools]",
|
||||
"pos": [
|
||||
950,
|
||||
200
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 78
|
||||
},
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "on_true",
|
||||
"type": "CONDITIONING",
|
||||
"link": 15
|
||||
},
|
||||
{
|
||||
"name": "on_false",
|
||||
"type": "CONDITIONING",
|
||||
"link": 16
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "conditioning",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
13
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Switch conditioning [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"type": "Note",
|
||||
"pos": [
|
||||
950,
|
||||
75
|
||||
],
|
||||
"size": [
|
||||
300,
|
||||
52
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"properties": {
|
||||
"text": ""
|
||||
},
|
||||
"widgets_values": [
|
||||
"change the switch to select a prompt"
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#653"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
2,
|
||||
5,
|
||||
0,
|
||||
3,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
3,
|
||||
4,
|
||||
1,
|
||||
6,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
5,
|
||||
4,
|
||||
1,
|
||||
7,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
6,
|
||||
7,
|
||||
0,
|
||||
3,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
7,
|
||||
3,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
8,
|
||||
4,
|
||||
2,
|
||||
8,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
9,
|
||||
8,
|
||||
0,
|
||||
9,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
13,
|
||||
11,
|
||||
0,
|
||||
3,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
14,
|
||||
4,
|
||||
1,
|
||||
10,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
15,
|
||||
10,
|
||||
0,
|
||||
11,
|
||||
0,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
16,
|
||||
6,
|
||||
0,
|
||||
11,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
{
|
||||
"last_node_id": 4,
|
||||
"last_link_id": 3,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "Load image with metadata [Crystools]",
|
||||
"pos": [
|
||||
200,
|
||||
250
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
350
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "prompt",
|
||||
"type": "JSON",
|
||||
"links": [
|
||||
1
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 2
|
||||
},
|
||||
{
|
||||
"name": "Metadata RAW",
|
||||
"type": "METADATA_RAW",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Load image with metadata [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"tests/ComfyUI_00314_20-8-euler.png",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "Load image with metadata [Crystools]",
|
||||
"pos": [
|
||||
200,
|
||||
700
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
350
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "prompt",
|
||||
"type": "JSON",
|
||||
"links": [
|
||||
2
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 2
|
||||
},
|
||||
{
|
||||
"name": "Metadata RAW",
|
||||
"type": "METADATA_RAW",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Load image with metadata [Crystools]"
|
||||
},
|
||||
"widgets_values": [
|
||||
"tests/ComfyUI_00315_21-81-heun.png",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "Json comparator [Crystools]",
|
||||
"pos": [
|
||||
650,
|
||||
275
|
||||
],
|
||||
"size": {
|
||||
"0": 279.5999755859375,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "json_old",
|
||||
"type": "JSON",
|
||||
"link": 1
|
||||
},
|
||||
{
|
||||
"name": "json_new",
|
||||
"type": "JSON",
|
||||
"link": 2
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "json_compared",
|
||||
"type": "JSON",
|
||||
"links": [
|
||||
3
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Json comparator [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "Show any to JSON [Crystools]",
|
||||
"pos": [
|
||||
650,
|
||||
450
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
350
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "any_value",
|
||||
"type": "*",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "string",
|
||||
"type": "STRING",
|
||||
"links": null,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Show any to JSON [Crystools]"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
0,
|
||||
"JSON"
|
||||
],
|
||||
[
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
3,
|
||||
1,
|
||||
"JSON"
|
||||
],
|
||||
[
|
||||
3,
|
||||
3,
|
||||
0,
|
||||
4,
|
||||
0,
|
||||
"*"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
410
custom_nodes/ComfyUI-Crystools/samples/utils-stats.json
Normal file
@@ -0,0 +1,410 @@
|
||||
{
|
||||
"last_node_id": 10,
|
||||
"last_link_id": 11,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 7,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
413,
|
||||
389
|
||||
],
|
||||
"size": {
|
||||
"0": 425.27801513671875,
|
||||
"1": 180.6060791015625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 5
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
6
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"text, watermark"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
415,
|
||||
186
|
||||
],
|
||||
"size": {
|
||||
"0": 422.84503173828125,
|
||||
"1": 164.31304931640625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
4
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "EmptyLatentImage",
|
||||
"pos": [
|
||||
473,
|
||||
609
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 106
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
2
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyLatentImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
512,
|
||||
512,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
1675,
|
||||
300
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 11
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 8
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
9
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "CheckpointLoaderSimple",
|
||||
"pos": [
|
||||
26,
|
||||
474
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 98
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
1
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"links": [
|
||||
3,
|
||||
5
|
||||
],
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"links": [
|
||||
8
|
||||
],
|
||||
"slot_index": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CheckpointLoaderSimple"
|
||||
},
|
||||
"widgets_values": [
|
||||
"SD1.5\\3d\\disneyPixarCartoon_v10.safetensors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
863,
|
||||
186
|
||||
],
|
||||
"size": [
|
||||
325,
|
||||
475
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 1
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 4
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 6
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 2
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
10
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
156680208700286,
|
||||
"fixed",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"normal",
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"type": "Stats system [Crystools]",
|
||||
"pos": [
|
||||
1275,
|
||||
175
|
||||
],
|
||||
"size": [
|
||||
350,
|
||||
125
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "latent",
|
||||
"type": "LATENT",
|
||||
"link": 10
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "latent",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
11
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Stats system [Crystools]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1925,
|
||||
300
|
||||
],
|
||||
"size": [
|
||||
200,
|
||||
275
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 9
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"ComfyUI"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
2,
|
||||
5,
|
||||
0,
|
||||
3,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
3,
|
||||
4,
|
||||
1,
|
||||
6,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
4,
|
||||
6,
|
||||
0,
|
||||
3,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
5,
|
||||
4,
|
||||
1,
|
||||
7,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
6,
|
||||
7,
|
||||
0,
|
||||
3,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
8,
|
||||
4,
|
||||
2,
|
||||
8,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
9,
|
||||
8,
|
||||
0,
|
||||
9,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
10,
|
||||
3,
|
||||
0,
|
||||
10,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
11,
|
||||
10,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"LATENT"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
1
custom_nodes/ComfyUI-Crystools/server/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .monitor import *
|
||||
125
custom_nodes/ComfyUI-Crystools/server/monitor.py
Normal file
@@ -0,0 +1,125 @@
|
||||
from server import PromptServer
|
||||
from aiohttp import web
|
||||
from ..core import logger
|
||||
from ..general import cmonitor
|
||||
|
||||
@PromptServer.instance.routes.patch("/crystools/monitor")
|
||||
async def newSettings(request):
|
||||
try:
|
||||
settings = await request.json()
|
||||
# print(settings)
|
||||
|
||||
if 'rate' in settings is not None:
|
||||
rate = settings['rate']
|
||||
if type(rate) is not int and type(rate) is not float:
|
||||
raise Exception('Rate must be an number.')
|
||||
|
||||
if cmonitor.rate == 0 and rate > 0:
|
||||
cmonitor.rate = rate
|
||||
cmonitor.startMonitor()
|
||||
else:
|
||||
cmonitor.rate = rate
|
||||
|
||||
|
||||
if 'switchCPU' in settings is not None:
|
||||
switchCPU = settings['switchCPU']
|
||||
if type(switchCPU) is not bool:
|
||||
raise Exception('switchCPU must be an boolean.')
|
||||
|
||||
cmonitor.hardwareInfo.switchCPU = switchCPU
|
||||
|
||||
if 'switchHDD' in settings is not None:
|
||||
switchHDD = settings['switchHDD']
|
||||
if type(switchHDD) is not bool:
|
||||
raise Exception('switchHDD must be an boolean.')
|
||||
|
||||
cmonitor.hardwareInfo.switchHDD = switchHDD
|
||||
|
||||
if 'switchRAM' in settings is not None:
|
||||
switchRAM = settings['switchRAM']
|
||||
if type(switchRAM) is not bool:
|
||||
raise Exception('switchRAM must be an boolean.')
|
||||
|
||||
cmonitor.hardwareInfo.switchRAM = switchRAM
|
||||
|
||||
if 'whichHDD' in settings is not None:
|
||||
whichHDD = settings['whichHDD']
|
||||
if type(whichHDD) is not str:
|
||||
raise Exception('whichHDD must be an string.')
|
||||
|
||||
cmonitor.hardwareInfo.whichHDD = whichHDD
|
||||
|
||||
|
||||
return web.Response(status=200)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
return web.Response(status=400, text=str(e))
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/crystools/monitor/switch")
|
||||
async def monitorSwitch(request):
|
||||
try:
|
||||
switch = await request.json()
|
||||
|
||||
if 'monitor' in switch is not None:
|
||||
monitor = switch['monitor']
|
||||
if type(monitor) is not bool:
|
||||
raise Exception('monitor must be an boolean.')
|
||||
|
||||
if monitor:
|
||||
cmonitor.startMonitor()
|
||||
else:
|
||||
cmonitor.stopMonitor()
|
||||
|
||||
return web.Response(status=200)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
return web.Response(status=400, text=str(e))
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/crystools/monitor/HDD")
|
||||
def getHDDs(request):
|
||||
try:
|
||||
return web.json_response(cmonitor.hardwareInfo.getHDDsInfo())
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
return web.Response(status=400, text=str(e))
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/crystools/monitor/GPU")
|
||||
def getGPUs(request):
|
||||
try:
|
||||
gpuInfo = cmonitor.hardwareInfo.getGPUInfo()
|
||||
return web.json_response(gpuInfo)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
return web.Response(status=400, text=str(e))
|
||||
|
||||
|
||||
@PromptServer.instance.routes.patch("/crystools/monitor/GPU/{index}")
|
||||
async def getGPUs(request):
|
||||
try:
|
||||
index = request.match_info["index"]
|
||||
settings = await request.json()
|
||||
if 'utilization' in settings is not None:
|
||||
if type(settings['utilization']) is not bool:
|
||||
raise Exception('utilization must be an boolean.')
|
||||
|
||||
cmonitor.hardwareInfo.GPUInfo.gpusUtilization[int(index)] = settings['utilization']
|
||||
|
||||
if 'vram' in settings is not None:
|
||||
if type(settings['vram']) is not bool:
|
||||
raise Exception('vram must be an boolean.')
|
||||
|
||||
cmonitor.hardwareInfo.GPUInfo.gpusVRAM[int(index)] = settings['vram']
|
||||
|
||||
if 'temperature' in settings is not None:
|
||||
if type(settings['temperature']) is not bool:
|
||||
raise Exception('temperature must be an boolean.')
|
||||
|
||||
cmonitor.hardwareInfo.GPUInfo.gpusTemperature[int(index)] = settings['temperature']
|
||||
|
||||
return web.Response(status=200)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
return web.Response(status=400, text=str(e))
|
||||
67
custom_nodes/ComfyUI-Crystools/tsconfig.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2020",
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"typeRoots": [
|
||||
// "./web/ts/typings",
|
||||
],
|
||||
// "rootDir": "../",
|
||||
"baseUrl": "../../web",
|
||||
// "baseUrl": "./",
|
||||
"paths": {
|
||||
// "/scripts/*": ["../../web/scripts/*"], // works
|
||||
},
|
||||
"rootDirs": [
|
||||
"../../web",
|
||||
// "web"
|
||||
],
|
||||
"preserveSymlinks": true,
|
||||
"checkJs": false,
|
||||
"allowJs": true,
|
||||
// if set this, it makes folders in the output folder...
|
||||
// "outDir": "web/dist",
|
||||
"declaration": true,
|
||||
// "declarationDir": "./web/dist/types",
|
||||
|
||||
"strict": true,
|
||||
"alwaysStrict": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"strictBindCallApply": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitOverride": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": false,
|
||||
"strictPropertyInitialization": false,
|
||||
"exactOptionalPropertyTypes": false,
|
||||
|
||||
"noResolve": false,
|
||||
"moduleResolution": "Bundler",
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"useUnknownInCatchVariables": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"allowUnusedLabels": true,
|
||||
"allowSyntheticDefaultImports": false,
|
||||
"useDefineForClassFields": true,
|
||||
"allowImportingTsExtensions": false,
|
||||
"isolatedModules": true,
|
||||
"removeComments": true,
|
||||
"noEmit": false
|
||||
},
|
||||
"include": [
|
||||
// "./custom_nodes/comfyui-crystools/web/*.ts",
|
||||
// "../../../web/*.ts",
|
||||
// "../../web/*.ts",
|
||||
"web/*.ts",
|
||||
// "web/types.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
1
custom_nodes/ComfyUI-Crystools/version
Normal file
@@ -0,0 +1 @@
|
||||
1.27.4
|
||||
5
custom_nodes/ComfyUI-Crystools/web/comfy/index.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export type * from './scripts.js';
|
||||
export * from './scripts.js';
|
||||
export type { ComfyApp } from './typings/comfy.js';
|
||||
export * from './liteGraph.js';
|
||||
export type * from './liteGraph.js';
|
||||
2
custom_nodes/ComfyUI-Crystools/web/comfy/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './scripts.js';
|
||||
export * from './liteGraph.js';
|
||||
5
custom_nodes/ComfyUI-Crystools/web/comfy/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export type * from './scripts.js';
|
||||
export * from './scripts.js';
|
||||
export type { ComfyApp } from './typings/comfy.js';
|
||||
export * from './liteGraph.js';
|
||||
export type * from './liteGraph.js';
|
||||
19
custom_nodes/ComfyUI-Crystools/web/comfy/liteGraph.d.ts
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
export type * from './liteGraph.types.js';
|
||||
import type { IWidget as IWidgetOld, LGraphNode as TypeGraphNode, TypeLiteGraph } from './liteGraph.types.js';
|
||||
declare const LGraphNode: typeof TypeGraphNode;
|
||||
export interface IWidget extends IWidgetOld {
|
||||
onRemove?: () => void;
|
||||
serializeValue?: () => Promise<void>;
|
||||
}
|
||||
export declare class TLGraphNode extends LGraphNode {
|
||||
static category: string;
|
||||
static shape: number;
|
||||
static color: string;
|
||||
static bgcolor: string;
|
||||
static collapsable: boolean;
|
||||
isVirtualNode?: boolean;
|
||||
widgets_values?: any[];
|
||||
name?: string;
|
||||
prototype: TLGraphNode;
|
||||
}
|
||||
export declare const LiteGraph: TypeLiteGraph;
|
||||
30
custom_nodes/ComfyUI-Crystools/web/comfy/liteGraph.js
Normal file
@@ -0,0 +1,30 @@
|
||||
export class TLGraphNode extends LGraphNode {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
Object.defineProperty(this, "isVirtualNode", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "widgets_values", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "name", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "prototype", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
}
|
||||
}
|
||||
export const LiteGraph = window.LiteGraph;
|
||||
32
custom_nodes/ComfyUI-Crystools/web/comfy/liteGraph.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
// / <reference path="/types/litegraph.d.ts" />
|
||||
// A LOTS OF PATCHES FOR LITEGRAPH TYPES ¯\_(ツ)_/¯
|
||||
export type * from './liteGraph.types.js';
|
||||
|
||||
import type { IWidget as IWidgetOld, LGraphNode as TypeGraphNode, TypeLiteGraph } from './liteGraph.types.js';
|
||||
|
||||
declare const LGraphNode: typeof TypeGraphNode; // just for get the type
|
||||
|
||||
export interface IWidget extends IWidgetOld {
|
||||
onRemove?: () => void;
|
||||
serializeValue?: () => Promise<void>;
|
||||
}
|
||||
|
||||
export class TLGraphNode extends LGraphNode {
|
||||
// on discovery...
|
||||
static category: string;
|
||||
static shape: number;
|
||||
static color: string;
|
||||
static bgcolor: string;
|
||||
static collapsable: boolean;
|
||||
|
||||
// widgets?: IWidget[];
|
||||
isVirtualNode?: boolean;
|
||||
// override onResize?: (size: [number, number]) => void;
|
||||
widgets_values?: any[];
|
||||
name?: string;
|
||||
|
||||
prototype: TLGraphNode; // yes itself
|
||||
}
|
||||
|
||||
// from globals
|
||||
export const LiteGraph: TypeLiteGraph = (window as any).LiteGraph;
|
||||
19
custom_nodes/ComfyUI-Crystools/web/comfy/liteGraph.types.d.ts
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// A LOTS OF PATCHES FOR LITEGRAPH TYPES ¯\_(ツ)_/¯
|
||||
import { LGraph } from './typings/litegraph.js';
|
||||
|
||||
export type * from './typings/litegraph.js';
|
||||
|
||||
export declare type TypeLiteGraph = typeof LiteGraph & {
|
||||
graph: LGraph;
|
||||
};
|
||||
|
||||
// export declare type ComfyApi = typeof api;
|
||||
export declare type ComfyNode = any;
|
||||
|
||||
// I prefer not use global, but if I change of opinion:
|
||||
// / <reference path="./types.ts" />
|
||||
// import { LGraphNode as TLGraphNode, LiteGraph as TLiteGraph } from '/types/litegraph';
|
||||
// export declare const LGraphNode: typeof TLGraphNode;
|
||||
// declare global {
|
||||
// const LGraphNode: LGraphNode;
|
||||
// }
|
||||
5
custom_nodes/ComfyUI-Crystools/web/comfy/scripts.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export { ComfyWidgets } from '../../../scripts/widgets.js';
|
||||
export { app } from '../../../scripts/app.js';
|
||||
export { api } from '../../../scripts/api.js';
|
||||
export * as utils from '../../../scripts/utils.js';
|
||||
export { ComfyButtonGroup } from '../../../scripts/ui/components/buttonGroup.js';
|
||||
5
custom_nodes/ComfyUI-Crystools/web/comfy/scripts.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export { ComfyWidgets } from '../../../scripts/widgets.js';
|
||||
export { app } from '../../../scripts/app.js';
|
||||
export { api } from '../../../scripts/api.js';
|
||||
export * as utils from '../../../scripts/utils.js';
|
||||
export { ComfyButtonGroup } from '../../../scripts/ui/components/buttonGroup.js';
|
||||
10
custom_nodes/ComfyUI-Crystools/web/comfy/scripts.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
// @ts-expect-error I could not find a way to make this work
|
||||
export { ComfyWidgets } from '../../../scripts/widgets.js';
|
||||
// @ts-expect-error I could not find a way to make this work
|
||||
export { app } from '../../../scripts/app.js';
|
||||
// @ts-expect-error I could not find a way to make this work
|
||||
export { api } from '../../../scripts/api.js';
|
||||
// @ts-expect-error I could not find a way to make this work
|
||||
export * as utils from '../../../scripts/utils.js';
|
||||
// @ts-expect-error I could not find a way to make this work
|
||||
export { ComfyButtonGroup } from '../../../scripts/ui/components/buttonGroup.js';
|
||||
@@ -0,0 +1,5 @@
|
||||
COPIED FROM rgthree
|
||||
|
||||
The typings in node_modules or in ComfyUI's web/ directory were not that well covered. These typings are hacked together with some of the inconsistencies I found.
|
||||
|
||||
To be honest, I have no idea why I needed a bizarre workaround for litegraph's types. Usually the '/// <reference>' comment should have picked up the types, but it wasn't having it. ¯\_(ツ)_/¯
|
||||
227
custom_nodes/ComfyUI-Crystools/web/comfy/typings/comfy.d.ts
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
import type { LGraphGroup as TLGraphGroup, LGraphNode as TLGraphNode, IWidget, SerializedLGraphNode, LGraph as TLGraph, LGraphCanvas as TLGraphCanvas, LiteGraph as TLiteGraph } from "./litegraph.js";
|
||||
import type {Constructor, SerializedGraph} from './index.js';
|
||||
|
||||
declare global {
|
||||
const LiteGraph: typeof TLiteGraph;
|
||||
const LGraph: typeof TLGraph;
|
||||
const LGraphNode: typeof TLGraphNode;
|
||||
const LGraphCanvas: typeof TLGraphCanvas;
|
||||
const LGraphGroup: typeof TLGraphGroup;
|
||||
}
|
||||
|
||||
// @rgthree: Types on ComfyApp as needed.
|
||||
export interface ComfyApp {
|
||||
extensions: ComfyExtension[];
|
||||
async queuePrompt(number?: number, batchCount = 1): Promise<void>;
|
||||
graph: TLGraph;
|
||||
canvas: TLGraphCanvas;
|
||||
clean() : void;
|
||||
registerExtension(extension: ComfyExtension): void;
|
||||
getPreviewFormatParam(): string;
|
||||
getRandParam(): string;
|
||||
loadApiJson(apiData: {}, fileName: string): void;
|
||||
async graphToPrompt(graph?: TLGraph, clean?: boolean): Promise<void>;
|
||||
// workflow: ComfyWorkflowInstance ???
|
||||
async loadGraphData(graphData: {}, clean?: boolean, restore_view?: boolean, workflow?: any|null): Promise<void>
|
||||
ui: {
|
||||
settings: {
|
||||
addSetting(config: {id: string, name: string, type: () => HTMLElement}) : void;
|
||||
}
|
||||
}
|
||||
// Just marking as any for now.
|
||||
menu?: any;
|
||||
}
|
||||
|
||||
export interface ComfyWidget extends IWidget {
|
||||
// https://github.com/comfyanonymous/ComfyUI/issues/2193 Changes from SerializedLGraphNode to
|
||||
// LGraphNode...
|
||||
serializeValue(nodeType: TLGraphNode, index: number): Promise<TValue>;
|
||||
afterQueued(): void;
|
||||
inputEl?: HTMLTextAreaElement;
|
||||
width: number;
|
||||
}
|
||||
|
||||
export interface ComfyGraphNode extends TLGraphNode {
|
||||
getExtraMenuOptions: (node: TLGraphNode, options: ContextMenuItem[]) => void;
|
||||
onExecuted(message: any): void;
|
||||
}
|
||||
|
||||
export interface ComfyNode extends TLGraphNode {
|
||||
comfyClass: string;
|
||||
}
|
||||
|
||||
// @rgthree
|
||||
export interface ComfyNodeConstructor extends Constructor<ComfyNode> {
|
||||
static title: string;
|
||||
static type?: string;
|
||||
static comfyClass: string;
|
||||
}
|
||||
|
||||
export type NodeMode = 0|1|2|3|4|undefined;
|
||||
|
||||
|
||||
export interface ComfyExtension {
|
||||
/**
|
||||
* The name of the extension
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Allows any initialisation, e.g. loading resources. Called after the canvas is created but before nodes are added
|
||||
* @param app The ComfyUI app instance
|
||||
*/
|
||||
init?(app: ComfyApp): Promise<void>;
|
||||
/**
|
||||
* Allows any additonal setup, called after the application is fully set up and running
|
||||
* @param app The ComfyUI app instance
|
||||
*/
|
||||
setup?(app: ComfyApp): Promise<void>;
|
||||
/**
|
||||
* Called before nodes are registered with the graph
|
||||
* @param defs The collection of node definitions, add custom ones or edit existing ones
|
||||
* @param app The ComfyUI app instance
|
||||
*/
|
||||
addCustomNodeDefs?(defs: Record<string, ComfyObjectInfo>, app: ComfyApp): Promise<void>;
|
||||
/**
|
||||
* Allows the extension to add custom widgets
|
||||
* @param app The ComfyUI app instance
|
||||
* @returns An array of {[widget name]: widget data}
|
||||
*/
|
||||
getCustomWidgets?(
|
||||
app: ComfyApp
|
||||
): Promise<
|
||||
Record<string, (node, inputName, inputData, app) => { widget?: IWidget; minWidth?: number; minHeight?: number }>
|
||||
>;
|
||||
/**
|
||||
* Allows the extension to add additional handling to the node before it is registered with LGraph
|
||||
* @rgthree changed nodeType from `typeof LGraphNode` to `ComfyNodeConstructor`
|
||||
* @param nodeType The node class (not an instance)
|
||||
* @param nodeData The original node object info config object
|
||||
* @param app The ComfyUI app instance
|
||||
*/
|
||||
beforeRegisterNodeDef?(nodeType: ComfyNodeConstructor, nodeData: ComfyObjectInfo, app: ComfyApp): Promise<void>;
|
||||
/**
|
||||
* Allows the extension to register additional nodes with LGraph after standard nodes are added
|
||||
* @param app The ComfyUI app instance
|
||||
*/
|
||||
// @rgthree - add void for non async
|
||||
registerCustomNodes?(app: ComfyApp): void|Promise<void>;
|
||||
/**
|
||||
* Allows the extension to modify a node that has been reloaded onto the graph.
|
||||
* If you break something in the backend and want to patch workflows in the frontend
|
||||
* This is the place to do this
|
||||
* @param node The node that has been loaded
|
||||
* @param app The ComfyUI app instance
|
||||
*/
|
||||
loadedGraphNode?(node: TLGraphNode, app: ComfyApp);
|
||||
/**
|
||||
* Allows the extension to run code after the constructor of the node
|
||||
* @param node The node that has been created
|
||||
* @param app The ComfyUI app instance
|
||||
*/
|
||||
nodeCreated?(node: TLGraphNode, app: ComfyApp);
|
||||
}
|
||||
|
||||
export type ComfyObjectInfo = {
|
||||
name: string;
|
||||
display_name?: string;
|
||||
description?: string;
|
||||
category: string;
|
||||
input?: {
|
||||
required?: Record<string, ComfyObjectInfoConfig>;
|
||||
optional?: Record<string, ComfyObjectInfoConfig>;
|
||||
hidden?: Record<string, ComfyObjectInfoConfig>;
|
||||
};
|
||||
output?: string[];
|
||||
output_name: string[];
|
||||
// @rgthree
|
||||
output_node?: boolean;
|
||||
};
|
||||
|
||||
export type ComfyObjectInfoConfig = [string | any[]] | [string | any[], any];
|
||||
|
||||
// @rgthree
|
||||
type ComfyApiInputLink = [
|
||||
/** The id string of the connected node. */
|
||||
string,
|
||||
/** The output index. */
|
||||
number,
|
||||
]
|
||||
|
||||
// @rgthree
|
||||
export type ComfyApiFormatNode = {
|
||||
"inputs": {
|
||||
[input_name: string]: string|number|boolean|ComfyApiInputLink,
|
||||
},
|
||||
"class_type": string,
|
||||
"_meta": {
|
||||
"title": string,
|
||||
}
|
||||
}
|
||||
|
||||
// @rgthree
|
||||
export type ComfyApiFormat = {
|
||||
[node_id: string]: ComfyApiFormatNode
|
||||
}
|
||||
|
||||
// @rgthree
|
||||
export type ComfyApiPrompt = {
|
||||
workflow: SerializedGraph,
|
||||
output: ComfyApiFormat,
|
||||
}
|
||||
|
||||
// @rgthree
|
||||
export type ComfyApiEventDetailStatus = {
|
||||
exec_info: {
|
||||
queue_remaining: number;
|
||||
};
|
||||
};
|
||||
|
||||
// @rgthree
|
||||
export type ComfyApiEventDetailExecutionStart = {
|
||||
prompt_id: string;
|
||||
};
|
||||
|
||||
// @rgthree
|
||||
export type ComfyApiEventDetailExecuting = null | string;
|
||||
|
||||
// @rgthree
|
||||
export type ComfyApiEventDetailProgress = {
|
||||
node: string;
|
||||
prompt_id: string;
|
||||
max: number;
|
||||
value: number;
|
||||
};
|
||||
|
||||
// @rgthree
|
||||
export type ComfyApiEventDetailExecuted = {
|
||||
node: string;
|
||||
prompt_id: string;
|
||||
output: any;
|
||||
};
|
||||
|
||||
// @rgthree
|
||||
export type ComfyApiEventDetailCached = {
|
||||
nodes: string[];
|
||||
prompt_id: string;
|
||||
};
|
||||
|
||||
// @rgthree
|
||||
export type ComfyApiEventDetailExecuted = {
|
||||
prompt_id: string;
|
||||
node: string;
|
||||
output: any;
|
||||
};
|
||||
|
||||
// @rgthree
|
||||
export type ComfyApiEventDetailError = {
|
||||
prompt_id: string;
|
||||
exception_type: string;
|
||||
exception_message: string;
|
||||
node_id: string;
|
||||
node_type: string;
|
||||
node_id: string;
|
||||
traceback: string;
|
||||
executed: any[];
|
||||
current_inputs: {[key: string]: (number[]|string[])};
|
||||
current_outputs: {[key: string]: (number[]|string[])};
|
||||
}
|
||||
55
custom_nodes/ComfyUI-Crystools/web/comfy/typings/index.d.ts
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
import { LGraph } from "./litegraph.js";
|
||||
|
||||
export type Constructor<T> = new(...args: any[]) => T;
|
||||
|
||||
export type SerializedLink = [
|
||||
number, // this.id,
|
||||
number, // this.origin_id,
|
||||
number, // this.origin_slot,
|
||||
number, // this.target_id,
|
||||
number, // this.target_slot,
|
||||
string, // this.type
|
||||
];
|
||||
|
||||
export interface SerializedNodeInput {
|
||||
name: string;
|
||||
type: string;
|
||||
link: number;
|
||||
}
|
||||
export interface SerializedNodeOutput {
|
||||
name: string;
|
||||
type: string;
|
||||
link: number;
|
||||
slot_index: number;
|
||||
links: number[];
|
||||
}
|
||||
export interface SerializedNode {
|
||||
id: number;
|
||||
inputs: SerializedNodeInput[];
|
||||
outputs: SerializedNodeOutput[];
|
||||
mode: number;
|
||||
order: number;
|
||||
pos: [number, number];
|
||||
properties: any;
|
||||
size: [number, number];
|
||||
type: string;
|
||||
widgets_values: Array<number | string>;
|
||||
}
|
||||
|
||||
export interface SerializedGraph {
|
||||
config: any;
|
||||
extra: any;
|
||||
groups: any;
|
||||
last_link_id: number;
|
||||
last_node_id: number;
|
||||
links: SerializedLink[];
|
||||
nodes: SerializedNode[];
|
||||
}
|
||||
|
||||
export interface BadLinksData<T = SerializedGraph|LGraph> {
|
||||
hasBadLinks: boolean;
|
||||
fixed: boolean;
|
||||
graph: T;
|
||||
patched: number;
|
||||
deleted: number;
|
||||
}
|
||||
1750
custom_nodes/ComfyUI-Crystools/web/comfy/typings/litegraph.d.ts
vendored
Normal file
4
custom_nodes/ComfyUI-Crystools/web/common.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import type { TLGraphNode } from './comfy/index.js';
|
||||
import { ComfyApp } from './comfy/index.js';
|
||||
export declare const commonPrefix = "\uD83E\uDE9B";
|
||||
export declare function displayContext(nodeType: TLGraphNode, appFromArg: ComfyApp, index?: number, serialize_widgets?: boolean, isVirtualNode?: boolean): void;
|
||||