From 58bf09cddb1c0710e1616d194299c3bd4f19bf55 Mon Sep 17 00:00:00 2001 From: 80sVectorz <66908776+80sVectorz@users.noreply.github.com> Date: Fri, 8 Dec 2023 19:43:51 +0100 Subject: [PATCH] Created new "collection primitives" system --- README.md | 12 ++++ __init__.py | 39 ++++++++++++- collection_primitives.py | 33 +++++++++++ .../collection_primitives_readme.md | 57 +++++++++++++++++++ .../samplers_and_schedulers.json | 34 +++++++++++ 5 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 collection_primitives.py create mode 100644 collection_primitives/collection_primitives_readme.md create mode 100644 collection_primitives/samplers_and_schedulers.json diff --git a/README.md b/README.md index 9a8f03c..d958096 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,18 @@ Here's an example of the original [Sytan's SDXL 1.0 Workflow](https://github.com ![Example](https://github.com/80sVectorz/ComfyUI-Static-Primitives/blob/main/images/Original.png?raw=true) ![Example](https://github.com/80sVectorz/ComfyUI-Static-Primitives/blob/main/images/CleanedUpExample.png?raw=true) +## Collection primitives + +Aside from the basic types included in this extension there's also a +collection type system. +This system allows users to add custom collection types. +There are 2 included by default: +- samplers +- schedulers + +More info about how you can add your own collection primitives can be found +[here](https://github.com/80sVectorz/ComfyUI-Static-Primitives/blob/main/collection_primitives/collection_primitives_readme.md). + # Rambling I decided to install ComfyUI but got really discouraged by the wire spaghetti. diff --git a/__init__.py b/__init__.py index 164de62..3a244df 100644 --- a/__init__.py +++ b/__init__.py @@ -1,6 +1,8 @@ from .static_primitives import * +from .collection_primitives import * import os, shutil import folder_paths +import json module_js_directory = os.path.join(os.path.dirname(os.path.realpath(__file__)), "js") application_root_directory = os.path.dirname(folder_paths.__file__) @@ -8,17 +10,52 @@ application_web_extensions_directory = os.path.join(application_root_directory, shutil.copytree(module_js_directory, application_web_extensions_directory, dirs_exist_ok=True) +collection_primitives_definitions_directory = os.path.join(os.path.dirname(os.path.realpath(__file__)), "collection_primitives") + +definition_files = [f for f in os.listdir(collection_primitives_definitions_directory) if f.endswith('.json')] +collection_primitives_classes = {} +collection_primitives_node_class_mappings = {} +collection_primitives_node_display_name_mappings = {} + +duplicate_counter = {} + +for file in definition_files: + with open(os.path.join(collection_primitives_definitions_directory, file), 'r') as f: + data = json.load(f) + for key in data.keys(): + duplicate_counter[key]=0 + if key in collection_primitives_classes.keys(): + duplicate_counter[key]+=1 + continue + if type(data[key]) is not list or len(data[key]) == 0 or type(data[key][0]) is not str: + print(f"ComfyUI-Static-Primitives:\n !!Found invalid collection primitive definition with key: {key} skipping!!") + continue + + new_class = CollectionPrimitiveFactory(key, data[key]) + collection_primitives_classes[key] = new_class + collection_primitives_node_class_mappings[f"{key}StaticCollectionPrimitive"] = new_class + collection_primitives_node_display_name_mappings[f"{key}StaticCollectionPrimitive"] = f"Collection Primitive ({key})" + +for key, duplicates in duplicate_counter.items(): + if duplicates > 0: + print(f"ComfyUI-Static-Primitives:\n !!Found {duplicates+1} definitions using the same key: {key} skipping all!!") + collection_primitives_classes.remove(key) + collection_primitives_node_class_mappings.remove(f"{key}StaticCollectionPrimitive") + collection_primitives_node_display_name_mappings.remove(f"{key}StaticCollectionPrimitive") + + NODE_CLASS_MAPPINGS = { "StringStaticPrimitive": StringStaticPrimitive, "StringMlStaticPrimitive": StringMlStaticPrimitive, "IntStaticPrimitive": IntStaticPrimitive, "FloatStaticPrimitive": FloatStaticPrimitive, } +NODE_CLASS_MAPPINGS.update(collection_primitives_node_class_mappings) -# A dictionary that contains the friendly/humanly readable titles for the nodes NODE_DISPLAY_NAME_MAPPINGS = { "StringStaticPrimitive": "Primitive (STRING)", "StringMlStaticPrimitive": "Primitive (STRING MULTI-LINE)", "IntStaticPrimitive": "Primitive (INT)", "FloatStaticPrimitive": "Primitive (FLOAT)", } +NODE_DISPLAY_NAME_MAPPINGS.update(collection_primitives_node_display_name_mappings) diff --git a/collection_primitives.py b/collection_primitives.py new file mode 100644 index 0000000..a82472a --- /dev/null +++ b/collection_primitives.py @@ -0,0 +1,33 @@ + +class BaseCollectionPrimitive: + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(s): + return { + "required": { + f"Input_{s.COLLECTION_TYPE}": (s.RETURN_TYPES[0],), + }, + } + + COLLECTION_TYPE = None + + RETURN_TYPES = ([],) + INPUT_FIELD_CONFIG_ID = None + + FUNCTION = "output" + + CATEGORY = "primitives" + + def output(self, **kwargs): + return (kwargs[f"Input_{self.COLLECTION_TYPE}"],) + +def CollectionPrimitiveFactory(key,collection): + def __init__(self, **kwargs): + BaseCollectionPrimitive.__init__(self) + + new_class = type(f"{key}StaticCollectionPrimitive", (BaseCollectionPrimitive,),{"__init__": __init__}) + new_class.COLLECTION_TYPE = key + new_class.RETURN_TYPES = (collection,) + return new_class \ No newline at end of file diff --git a/collection_primitives/collection_primitives_readme.md b/collection_primitives/collection_primitives_readme.md new file mode 100644 index 0000000..1db931f --- /dev/null +++ b/collection_primitives/collection_primitives_readme.md @@ -0,0 +1,57 @@ +# Adding custom collection primitives + +Adding your own collection primitives is quite simple. +Each group of collection primitives is defined in a `.json` file. +These files should be placed in this directory: +`ComfyUI-Static-Primitives/collection_primitives/` + +## Collection primitive definition structure + +Let's look at an example. +```json +{ + "scheduler": [ + "normal", + "karras", + "exponential", + "sgm_uniform", + "simple", + "ddim_uniform" + ], + "sampler" : [ + "euler", + "euler_ancestral", + "heun", + "heunpp2", + "dpm_2", + "dpm_2_ancestral", + "lms", + "dpm_fast", + "dpm_adaptive", + "dpmpp_2s_ancestral", + "dpmpp_sde", + "dpmpp_sde_gpu", + "dpmpp_2m", + "dpmpp_2m_sde", + "dpmpp_2m_sde_gpu", + "dpmpp_3m_sde", + "dpmpp_3m_sde_gpu", + "ddpm", + "lcm", + "ddim", + "uni_pc", + "uni_pc_bh2" + ] +} +``` +This is the contents of the by default included file +`samplers_and_schedulers.json`. +You can see two key value pairs scheduler and sampler. +The key will be used for the display name of their respective nodes. + +The value of each key is a list of strings. +These directly translate to the options for the node's dropdown. + +*NOTE*: +It is important to avoid having duplicate keys across files. +If any duplicate keys are found while loading, all definitions with that key will be ignored \ No newline at end of file diff --git a/collection_primitives/samplers_and_schedulers.json b/collection_primitives/samplers_and_schedulers.json new file mode 100644 index 0000000..1e32fc9 --- /dev/null +++ b/collection_primitives/samplers_and_schedulers.json @@ -0,0 +1,34 @@ +{ + "scheduler": [ + "normal", + "karras", + "exponential", + "sgm_uniform", + "simple", + "ddim_uniform" + ], + "sampler" : [ + "euler", + "euler_ancestral", + "heun", + "heunpp2", + "dpm_2", + "dpm_2_ancestral", + "lms", + "dpm_fast", + "dpm_adaptive", + "dpmpp_2s_ancestral", + "dpmpp_sde", + "dpmpp_sde_gpu", + "dpmpp_2m", + "dpmpp_2m_sde", + "dpmpp_2m_sde_gpu", + "dpmpp_3m_sde", + "dpmpp_3m_sde_gpu", + "ddpm", + "lcm", + "ddim", + "uni_pc", + "uni_pc_bh2" + ] +} \ No newline at end of file