Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a95cba4e3b | ||
|
|
40f09582e2 | ||
|
|
6635d30566 | ||
|
|
5cf49c9565 | ||
|
|
1e8ed1e16f | ||
|
|
64113afd7f | ||
|
|
2bd6769b78 | ||
|
|
96a69f7cbe | ||
|
|
9d8b79844f | ||
|
|
f3815b7ce4 | ||
|
|
d5641ba745 | ||
|
|
5b5eaf3a81 | ||
|
|
517b8a8a12 | ||
|
|
0be7528f10 | ||
|
|
b63862f2e3 | ||
|
|
8ed3d36eaf | ||
|
|
8af8cce210 | ||
|
|
d7530a3326 | ||
|
|
05de5959e1 | ||
|
|
049fd1eb71 |
@@ -2,37 +2,81 @@
|
|||||||
|
|
||||||
This project is a fork of https://github.com/Extraltodeus/LoadLoraWithTags
|
This project is a fork of https://github.com/Extraltodeus/LoadLoraWithTags
|
||||||
The aim of these custom nodes is to get an _easy_ access to the tags used to trigger a lora.
|
The aim of these custom nodes is to get an _easy_ access to the tags used to trigger a lora.
|
||||||
This project is compatible with Stacked Loras from https://github.com/LucianoCirino/efficiency-nodes-comfyui/releases
|
This project is compatible with Stacked Loras from https://github.com/jags111/efficiency-nodes-comfyui
|
||||||
I talk about **lora**, but works with **lycoris** too.
|
When I talk about **lora**, I also mean **lycoris** too.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
Some of this project nodes depends on https://github.com/pythongosssss/ComfyUI-Custom-Scripts :
|
Some of this project nodes depends on https://github.com/pythongosssss/ComfyUI-Custom-Scripts :
|
||||||
- LoraLoaderAdvanced
|
- LoraLoaderAdvanced
|
||||||
- LoraLoaderStackedAdvanced
|
- LoraLoaderStackedAdvanced
|
||||||
They get their vanilla equivalents.
|
- `View info...`
|
||||||
|
|
||||||
|
They get their vanilla equivalents with less features
|
||||||
|
|
||||||
Overall, Custom-Scripts is recommended to be able to know the content of the tag lists with the node `showText`
|
Overall, Custom-Scripts is recommended to be able to know the content of the tag lists with the node `showText`
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
### Main nodes
|
|
||||||
#### Vanilla vs Advanced
|
#### Vanilla vs Advanced
|
||||||
Vanilla refers to nodes that have no lora preview from the menu, nor the lora list. But the features provided are the same.
|
> Vanilla refers to nodes that have no lora preview from the menu, nor the lora list. But the features provided are the same.
|
||||||
|
|
||||||

|

|
||||||
#### Nodes
|
### Nodes
|
||||||
- LoraLoader (Vanilla or Advanced)
|
#### LoraLoader (Vanilla and Advanced)
|
||||||
- LoraLoaderStacked (Vanilla or Avanced). The stacked lora input is optional.
|

|
||||||
Allow to load a lora, either the normal way, or the efficiency-nodes way.
|
INPUT
|
||||||
These loaders have two custom outputs:
|
- `override_lora_name` (optional): Used to ignore the field `lora_name` and use the name passed. Should use [LoraListNames](#loralistnames) or the `lora_name` output.
|
||||||
- civitai_tags_list: a python list of the tags related to this lora on civitai
|
|
||||||
- meta_tags_list: a python list of the tags used for training the lora embeded in it (if any)
|
FIELDS
|
||||||
This outputs needs to be filtered by two othere nodes:
|
- `force_fetch`: Force the civitai fetching of data even if there is already something saved
|
||||||
- TagsFormater: Helper to show the available tag and their indexes
|
- `enable_preview`: Toggle on/off the saved lora preview if any (only in advanced)
|
||||||
- tagsSelector: allow to filter tags and apply a weight to it.
|
- `append_lora_if_empty`: Add the name of the lora to the list of tags if the list is empty
|
||||||
- TagSelector contains four parameters. First the selector (see Filtering next)
|
|
||||||
- The weight `(tag:weight)`
|
OUTPUT
|
||||||
- The boolean `ensure_comma`. To properly append comma if a prefix or suffix is added.
|
- `civitai_tags_list`: a python list of the tags related to this lora on civitai
|
||||||
- The boolean `append_loraname_if_empty` which will add the name of the lora in the list of outputs if they are empty.
|
- `meta_tags_list`: a python list of the tags used for training the lora embeded in it (if any)
|
||||||
#### Filtering
|
- `lora_name`: the name of the current selected lora
|
||||||
|
#### LoraLoaderStacked (Vanilla and Avanced).
|
||||||
|

|
||||||
|
INPUT
|
||||||
|
- `lora_stack` (optional): another stack of lora.
|
||||||
|
- `override_lora_name` (optional): Used to ignore the field `lora_name` and use the name passed. Should use [LoraListNames](#loralistnames) or the `lora_name` output.
|
||||||
|
|
||||||
|
FIELDS
|
||||||
|
- `force_fetch`: Force the civitai fetching of data even if there is already something saved
|
||||||
|
- `enable_preview`: Toggle on/off the saved lora preview if any (only in advanced)
|
||||||
|
- `append_lora_if_empty`: Add the name of the lora to the list of tags if the list is empty
|
||||||
|
|
||||||
|
OUTPUT
|
||||||
|
- `civitai_tags_list`: a python list of the tags related to this lora on civitai
|
||||||
|
- `meta_tags_list`: a python list of the tags used for training the lora embeded in it (if any)
|
||||||
|
- `lora_name`: the name of the current selected lora
|
||||||
|
#### LoraTagsOnly
|
||||||
|

|
||||||
|
To get the tags without using the lora.
|
||||||
|
- `override_lora_name` (optional): Used to ignore the field `lora_name` and use the name passed. Should use [LoraListNames](#loralistnames) or the `lora_name` output.
|
||||||
|
|
||||||
|
OUTPUT
|
||||||
|
- `civitai_tags_list`: a python list of the tags related to this lora on civitai
|
||||||
|
- `meta_tags_list`: a python list of the tags used for training the lora embeded in it (if any)
|
||||||
|
- `lora_name`: the name of the current selected lora
|
||||||
|
|
||||||
|
#### TagsFormater
|
||||||
|

|
||||||
|
Helper to show the available tag and their indexes. Tags are sorted by training frequence. The more a tag was used, the higher in the list it is. Works for both `civitai_tags_list` and `meta_tags_list`
|
||||||
|
|
||||||
|
#### TagsSelector
|
||||||
|

|
||||||
|
Allow to filter tags and apply a weight to it.
|
||||||
|
TagSelector contains four parameters.
|
||||||
|
- `selector` (see the [Filtering](#filtering) section next)
|
||||||
|
- `weight`: to format the tag like `(tag:weight)`. Default set to 1 without the weight like `tag`.
|
||||||
|
- `ensure_comma`. To properly append comma if a prefix or suffix is added.
|
||||||
|
|
||||||
|
#### LoraListNames
|
||||||
|

|
||||||
|
List all the existing lora names. It is used as an input for `override_lora_name`
|
||||||
|
|
||||||
|
### Filtering
|
||||||
The format is simple. It's the same as python list index, but can select multiple index or ranges of indexes separated by comas.
|
The format is simple. It's the same as python list index, but can select multiple index or ranges of indexes separated by comas.
|
||||||
`Ex: 0, 3, 5:8, -8:`
|
`Ex: 0, 3, 5:8, -8:`
|
||||||
- Select a specific list of indexes: `0, 2, 3, 15`...
|
- Select a specific list of indexes: `0, 2, 3, 15`...
|
||||||
@@ -42,6 +86,11 @@ The format is simple. It's the same as python list index, but can select multipl
|
|||||||
- You can use negative indexes. Like `-1` to select the last tag
|
- You can use negative indexes. Like `-1` to select the last tag
|
||||||
- By default `:` selects everything
|
- By default `:` selects everything
|
||||||
|
|
||||||
|
### View Info
|
||||||
|

|
||||||
|
Pythongossss's [View Info...](https://github.com/pythongosssss/ComfyUI-Custom-Scripts?tab=readme-ov-file#checkpointloraembedding-info) feature from ComfyUI-Custom-Scripts
|
||||||
|
|
||||||
|
### Examples
|
||||||
#### Example of normal workflow
|
#### Example of normal workflow
|
||||||

|

|
||||||
|
|
||||||
@@ -55,5 +104,5 @@ Lora Stack can also be chained together to load multiple loras into an efficient
|
|||||||
|
|
||||||
### Side nodes I made and kept here
|
### Side nodes I made and kept here
|
||||||
- FusionText: takes two text input and join them together
|
- FusionText: takes two text input and join them together
|
||||||
- Randomizer: takes two couples text+lorastack and return randomly one them
|
- Randomizer: takes two couples text+lorastack and return randomly one of them
|
||||||
- TextInputBasic: just a text input with two additional input for text chaining
|
- TextInputBasic: just a text input with two additional input for text chaining
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ from .nodes_utils import NODE_CLASS_MAPPINGS as nu_NCM
|
|||||||
|
|
||||||
NODE_CLASS_MAPPINGS = dict(na_NCM, **nu_NCM)
|
NODE_CLASS_MAPPINGS = dict(na_NCM, **nu_NCM)
|
||||||
#NODE_DISPLAY_NAME_MAPPINGS = dict(na_NDNM, **nu_NDNM)
|
#NODE_DISPLAY_NAME_MAPPINGS = dict(na_NDNM, **nu_NDNM)
|
||||||
__all__ = ["NODE_CLASS_MAPPINGS"]#, "NODE_DISPLAY_NAME_MAPPINGS"]
|
WEB_DIRECTORY = "./web"
|
||||||
|
__all__ = ["NODE_CLASS_MAPPINGS", "WEB_DIRECTORY"]#, "NODE_DISPLAY_NAME_MAPPINGS"]
|
||||||
|
|||||||
|
After Width: | Height: | Size: 158 KiB |
|
After Width: | Height: | Size: 404 KiB |
|
After Width: | Height: | Size: 316 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 233 KiB |
|
After Width: | Height: | Size: 262 KiB |
|
After Width: | Height: | Size: 24 KiB |
@@ -16,19 +16,24 @@ class LoraLoaderVanilla:
|
|||||||
"model": ("MODEL",),
|
"model": ("MODEL",),
|
||||||
"clip": ("CLIP", ),
|
"clip": ("CLIP", ),
|
||||||
"lora_name": (LORA_LIST, ),
|
"lora_name": (LORA_LIST, ),
|
||||||
"strength_model": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1}),
|
"strength_model": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
||||||
"strength_clip": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1}),
|
"strength_clip": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
||||||
"force_fetch": ("BOOLEAN", {"default": False}),
|
"force_fetch": ("BOOLEAN", {"default": False}),
|
||||||
"append_loraname_if_empty": ("BOOLEAN", {"default": False}),
|
"append_loraname_if_empty": ("BOOLEAN", {"default": False}),
|
||||||
|
},
|
||||||
|
"optional": {
|
||||||
|
"override_lora_name":("STRING", {"forceInput": True}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("MODEL", "CLIP", "LIST", "LIST")
|
RETURN_TYPES = ("MODEL", "CLIP", "LIST", "LIST", "STRING")
|
||||||
RETURN_NAMES = ("MODEL", "CLIP", "civitai_tags_list", "meta_tags_list")
|
RETURN_NAMES = ("MODEL", "CLIP", "civitai_tags_list", "meta_tags_list", "lora_name")
|
||||||
FUNCTION = "load_lora"
|
FUNCTION = "load_lora"
|
||||||
CATEGORY = "autotrigger"
|
CATEGORY = "autotrigger"
|
||||||
|
|
||||||
def load_lora(self, model, clip, lora_name, strength_model, strength_clip, force_fetch, append_loraname_if_empty):
|
def load_lora(self, model, clip, lora_name, strength_model, strength_clip, force_fetch, append_loraname_if_empty, override_lora_name=""):
|
||||||
|
if override_lora_name != "":
|
||||||
|
lora_name = override_lora_name
|
||||||
meta_tags_list = sort_tags_by_frequency(get_metadata(lora_name, "loras"))
|
meta_tags_list = sort_tags_by_frequency(get_metadata(lora_name, "loras"))
|
||||||
civitai_tags_list = load_and_save_tags(lora_name, force_fetch)
|
civitai_tags_list = load_and_save_tags(lora_name, force_fetch)
|
||||||
|
|
||||||
@@ -51,7 +56,7 @@ class LoraLoaderVanilla:
|
|||||||
|
|
||||||
model_lora, clip_lora = load_lora_for_models(model, clip, lora, strength_model, strength_clip)
|
model_lora, clip_lora = load_lora_for_models(model, clip, lora, strength_model, strength_clip)
|
||||||
|
|
||||||
return (model_lora, clip_lora, civitai_tags_list, meta_tags_list)
|
return (model_lora, clip_lora, civitai_tags_list, meta_tags_list, lora_name)
|
||||||
|
|
||||||
class LoraLoaderStackedVanilla:
|
class LoraLoaderStackedVanilla:
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -66,16 +71,19 @@ class LoraLoaderStackedVanilla:
|
|||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
"lora_stack": ("LORA_STACK", ),
|
"lora_stack": ("LORA_STACK", ),
|
||||||
|
"override_lora_name":("STRING", {"forceInput": True}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("LIST", "LIST", "LORA_STACK",)
|
RETURN_TYPES = ("LIST", "LIST", "LORA_STACK", "STRING")
|
||||||
RETURN_NAMES = ("civitai_tags_list", "meta_tags_list", "LORA_STACK",)
|
RETURN_NAMES = ("civitai_tags_list", "meta_tags_list", "LORA_STACK", "lora_name")
|
||||||
FUNCTION = "set_stack"
|
FUNCTION = "set_stack"
|
||||||
#OUTPUT_NODE = False
|
#OUTPUT_NODE = False
|
||||||
CATEGORY = "autotrigger"
|
CATEGORY = "autotrigger"
|
||||||
|
|
||||||
def set_stack(self, lora_name, lora_weight, force_fetch, append_loraname_if_empty, lora_stack=None):
|
def set_stack(self, lora_name, lora_weight, force_fetch, append_loraname_if_empty, lora_stack=None, override_lora_name=""):
|
||||||
|
if override_lora_name != "":
|
||||||
|
lora_name = override_lora_name
|
||||||
civitai_tags_list = load_and_save_tags(lora_name, force_fetch)
|
civitai_tags_list = load_and_save_tags(lora_name, force_fetch)
|
||||||
|
|
||||||
meta_tags = get_metadata(lora_name, "loras")
|
meta_tags = get_metadata(lora_name, "loras")
|
||||||
@@ -84,12 +92,11 @@ class LoraLoaderStackedVanilla:
|
|||||||
civitai_tags_list = append_lora_name_if_empty(civitai_tags_list, lora_name, append_loraname_if_empty)
|
civitai_tags_list = append_lora_name_if_empty(civitai_tags_list, lora_name, append_loraname_if_empty)
|
||||||
meta_tags_list = append_lora_name_if_empty(meta_tags_list, lora_name, append_loraname_if_empty)
|
meta_tags_list = append_lora_name_if_empty(meta_tags_list, lora_name, append_loraname_if_empty)
|
||||||
|
|
||||||
|
loras = [(lora_name,lora_weight,lora_weight,)]
|
||||||
if lora_stack is not None:
|
if lora_stack is not None:
|
||||||
lora_stack.append((lora_name,lora_weight,lora_weight,))
|
loras.extend(lora_stack)
|
||||||
else:
|
|
||||||
lora_stack = [(lora_name,lora_weight,lora_weight,)]
|
|
||||||
|
|
||||||
return (civitai_tags_list, meta_tags_list, lora_stack)
|
return (civitai_tags_list, meta_tags_list, loras, lora_name)
|
||||||
|
|
||||||
class LoraLoaderAdvanced:
|
class LoraLoaderAdvanced:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -104,20 +111,28 @@ class LoraLoaderAdvanced:
|
|||||||
"model": ("MODEL",),
|
"model": ("MODEL",),
|
||||||
"clip": ("CLIP", ),
|
"clip": ("CLIP", ),
|
||||||
"lora_name": (LORA_LIST, ),
|
"lora_name": (LORA_LIST, ),
|
||||||
"strength_model": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1}),
|
"strength_model": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
||||||
"strength_clip": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1}),
|
"strength_clip": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
||||||
"force_fetch": ("BOOLEAN", {"default": False}),
|
"force_fetch": ("BOOLEAN", {"default": False}),
|
||||||
"enable_preview": ("BOOLEAN", {"default": False}),
|
"enable_preview": ("BOOLEAN", {"default": False}),
|
||||||
"append_loraname_if_empty": ("BOOLEAN", {"default": False}),
|
"append_loraname_if_empty": ("BOOLEAN", {"default": False}),
|
||||||
|
},
|
||||||
|
"optional": {
|
||||||
|
"override_lora_name":("STRING", {"forceInput": True}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("MODEL", "CLIP", "LIST", "LIST")
|
RETURN_TYPES = ("MODEL", "CLIP", "LIST", "LIST", "STRING")
|
||||||
RETURN_NAMES = ("MODEL", "CLIP", "civitai_tags_list", "meta_tags_list")
|
RETURN_NAMES = ("MODEL", "CLIP", "civitai_tags_list", "meta_tags_list", "lora_name")
|
||||||
FUNCTION = "load_lora"
|
FUNCTION = "load_lora"
|
||||||
CATEGORY = "autotrigger"
|
CATEGORY = "autotrigger"
|
||||||
|
|
||||||
def load_lora(self, model, clip, lora_name, strength_model, strength_clip, force_fetch, enable_preview, append_loraname_if_empty):
|
def load_lora(self, model, clip, lora_name, strength_model, strength_clip, force_fetch, enable_preview, append_loraname_if_empty, override_lora_name=""):
|
||||||
|
if override_lora_name != "":
|
||||||
|
has_preview, prev = get_preview_path(override_lora_name, "loras")
|
||||||
|
prev = f"loras/{prev}" if has_preview else None
|
||||||
|
lora_name = {"content": override_lora_name, "image": prev, "type": "loras"}
|
||||||
|
|
||||||
meta_tags_list = sort_tags_by_frequency(get_metadata(lora_name["content"], "loras"))
|
meta_tags_list = sort_tags_by_frequency(get_metadata(lora_name["content"], "loras"))
|
||||||
civitai_tags_list = load_and_save_tags(lora_name["content"], force_fetch)
|
civitai_tags_list = load_and_save_tags(lora_name["content"], force_fetch)
|
||||||
|
|
||||||
@@ -147,10 +162,10 @@ class LoraLoaderAdvanced:
|
|||||||
"subfolder": "lora_preview",
|
"subfolder": "lora_preview",
|
||||||
"type": "temp"
|
"type": "temp"
|
||||||
}
|
}
|
||||||
return {"ui": {"images": [preview_output]}, "result": (model_lora, clip_lora, civitai_tags_list, meta_tags_list)}
|
return {"ui": {"images": [preview_output]}, "result": (model_lora, clip_lora, civitai_tags_list, meta_tags_list, lora_name["content"])}
|
||||||
|
|
||||||
|
|
||||||
return (model_lora, clip_lora, civitai_tags_list, meta_tags_list)
|
return (model_lora, clip_lora, civitai_tags_list, meta_tags_list, lora_name["content"])
|
||||||
|
|
||||||
class LoraLoaderStackedAdvanced:
|
class LoraLoaderStackedAdvanced:
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -167,16 +182,22 @@ class LoraLoaderStackedAdvanced:
|
|||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
"lora_stack": ("LORA_STACK", ),
|
"lora_stack": ("LORA_STACK", ),
|
||||||
|
"override_lora_name":("STRING", {"forceInput": True}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("LIST", "LIST", "LORA_STACK",)
|
RETURN_TYPES = ("LIST", "LIST", "LORA_STACK", "STRING")
|
||||||
RETURN_NAMES = ("civitai_tags_list", "meta_tags_list", "LORA_STACK",)
|
RETURN_NAMES = ("civitai_tags_list", "meta_tags_list", "LORA_STACK", "lora_name")
|
||||||
FUNCTION = "set_stack"
|
FUNCTION = "set_stack"
|
||||||
#OUTPUT_NODE = False
|
#OUTPUT_NODE = False
|
||||||
CATEGORY = "autotrigger"
|
CATEGORY = "autotrigger"
|
||||||
|
|
||||||
def set_stack(self, lora_name, lora_weight, force_fetch, enable_preview, append_loraname_if_empty, lora_stack=None):
|
def set_stack(self, lora_name, lora_weight, force_fetch, enable_preview, append_loraname_if_empty, lora_stack=None, override_lora_name=""):
|
||||||
|
if override_lora_name != "":
|
||||||
|
has_preview, prev = get_preview_path(override_lora_name, "loras")
|
||||||
|
prev = f"loras/{prev}" if has_preview else None
|
||||||
|
lora_name = {"content": override_lora_name, "image": prev, "type": "loras"}
|
||||||
|
|
||||||
civitai_tags_list = load_and_save_tags(lora_name["content"], force_fetch)
|
civitai_tags_list = load_and_save_tags(lora_name["content"], force_fetch)
|
||||||
|
|
||||||
meta_tags = get_metadata(lora_name["content"], "loras")
|
meta_tags = get_metadata(lora_name["content"], "loras")
|
||||||
@@ -185,10 +206,9 @@ class LoraLoaderStackedAdvanced:
|
|||||||
civitai_tags_list = append_lora_name_if_empty(civitai_tags_list, lora_name["content"], append_loraname_if_empty)
|
civitai_tags_list = append_lora_name_if_empty(civitai_tags_list, lora_name["content"], append_loraname_if_empty)
|
||||||
meta_tags_list = append_lora_name_if_empty(meta_tags_list, lora_name["content"], append_loraname_if_empty)
|
meta_tags_list = append_lora_name_if_empty(meta_tags_list, lora_name["content"], append_loraname_if_empty)
|
||||||
|
|
||||||
|
loras = [(lora_name["content"],lora_weight,lora_weight,)]
|
||||||
if lora_stack is not None:
|
if lora_stack is not None:
|
||||||
lora_stack.append((lora_name["content"],lora_weight,lora_weight,))
|
loras.extend(lora_stack)
|
||||||
else:
|
|
||||||
lora_stack = [(lora_name["content"],lora_weight,lora_weight,)]
|
|
||||||
|
|
||||||
if enable_preview:
|
if enable_preview:
|
||||||
_, preview = copy_preview_to_temp(lora_name["image"])
|
_, preview = copy_preview_to_temp(lora_name["image"])
|
||||||
@@ -198,9 +218,40 @@ class LoraLoaderStackedAdvanced:
|
|||||||
"subfolder": "lora_preview",
|
"subfolder": "lora_preview",
|
||||||
"type": "temp"
|
"type": "temp"
|
||||||
}
|
}
|
||||||
return {"ui": {"images": [preview_output]}, "result": (civitai_tags_list, meta_tags_list, lora_stack)}
|
return {"ui": {"images": [preview_output]}, "result": (civitai_tags_list, meta_tags_list, loras, lora_name["content"])}
|
||||||
|
|
||||||
return {"result": (civitai_tags_list, meta_tags_list, lora_stack)}
|
return {"result": (civitai_tags_list, meta_tags_list, loras, lora_name["content"])}
|
||||||
|
|
||||||
|
class LoraTagsOnly:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
LORA_LIST = sorted(folder_paths.get_filename_list("loras"), key=str.lower)
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"lora_name": (LORA_LIST,),
|
||||||
|
"force_fetch": ("BOOLEAN", {"default": False}),
|
||||||
|
"append_loraname_if_empty": ("BOOLEAN", {"default": False}),
|
||||||
|
},
|
||||||
|
"optional": {
|
||||||
|
"override_lora_name":("STRING", {"forceInput": True}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = ("LIST", "LIST")
|
||||||
|
RETURN_NAMES = ("civitai_tags_list", "meta_tags_list")
|
||||||
|
FUNCTION = "ask_lora"
|
||||||
|
CATEGORY = "autotrigger"
|
||||||
|
|
||||||
|
def ask_lora(self, lora_name, force_fetch, append_loraname_if_empty, override_lora_name=""):
|
||||||
|
if override_lora_name != "":
|
||||||
|
lora_name = override_lora_name
|
||||||
|
meta_tags_list = sort_tags_by_frequency(get_metadata(lora_name, "loras"))
|
||||||
|
civitai_tags_list = load_and_save_tags(lora_name, force_fetch)
|
||||||
|
|
||||||
|
meta_tags_list = append_lora_name_if_empty(meta_tags_list, lora_name, append_loraname_if_empty)
|
||||||
|
civitai_tags_list = append_lora_name_if_empty(civitai_tags_list, lora_name, append_loraname_if_empty)
|
||||||
|
|
||||||
|
return (civitai_tags_list, meta_tags_list)
|
||||||
|
|
||||||
|
|
||||||
# A dictionary that contains all nodes you want to export with their names
|
# A dictionary that contains all nodes you want to export with their names
|
||||||
@@ -210,6 +261,7 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
"LoraLoaderStackedVanilla": LoraLoaderStackedVanilla,
|
"LoraLoaderStackedVanilla": LoraLoaderStackedVanilla,
|
||||||
"LoraLoaderAdvanced": LoraLoaderAdvanced,
|
"LoraLoaderAdvanced": LoraLoaderAdvanced,
|
||||||
"LoraLoaderStackedAdvanced": LoraLoaderStackedAdvanced,
|
"LoraLoaderStackedAdvanced": LoraLoaderStackedAdvanced,
|
||||||
|
"LoraTagsOnly": LoraTagsOnly,
|
||||||
}
|
}
|
||||||
|
|
||||||
# A dictionary that contains the friendly/humanly readable titles for the nodes
|
# A dictionary that contains the friendly/humanly readable titles for the nodes
|
||||||
@@ -218,4 +270,5 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
|||||||
"LoraLoaderStackedVanilla": "LoraLoaderStackedVanilla",
|
"LoraLoaderStackedVanilla": "LoraLoaderStackedVanilla",
|
||||||
"LoraLoaderAdvanced": "LoraLoaderAdvanced",
|
"LoraLoaderAdvanced": "LoraLoaderAdvanced",
|
||||||
"LoraLoaderStackedAdvanced": "LoraLoaderStackedAdvanced",
|
"LoraLoaderStackedAdvanced": "LoraLoaderStackedAdvanced",
|
||||||
|
"LoraTagsOnly": "LoraTagsOnly",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import random
|
|
||||||
|
|
||||||
from .utils import *
|
from .utils import *
|
||||||
|
|
||||||
class FusionText:
|
class FusionText:
|
||||||
@@ -20,11 +18,13 @@ class Randomizer:
|
|||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"text_1":("STRING", {"forceInput": True}),
|
"text_1":("STRING", {"forceInput": True}),
|
||||||
"lora_1":("LORA_STACK", ),
|
|
||||||
"text_2":("STRING", {"forceInput": True} ),
|
"text_2":("STRING", {"forceInput": True} ),
|
||||||
"lora_2":("LORA_STACK", ),
|
|
||||||
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||||
},
|
},
|
||||||
|
"optional": {
|
||||||
|
"lora_1":("LORA_STACK", ),
|
||||||
|
"lora_2":("LORA_STACK", ),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("STRING", "LORA_STACK")
|
RETURN_TYPES = ("STRING", "LORA_STACK")
|
||||||
@@ -35,9 +35,8 @@ class Randomizer:
|
|||||||
|
|
||||||
CATEGORY = "autotrigger"
|
CATEGORY = "autotrigger"
|
||||||
|
|
||||||
def randomize(self, text_1, lora_1, text_2, lora_2, seed):
|
def randomize(self, text_1, text_2, seed, lora_1=[], lora_2=[]):
|
||||||
random.seed(seed)
|
if seed %2 == 0:
|
||||||
if random.random() < .5:
|
|
||||||
return (text_1, lora_1)
|
return (text_1, lora_1)
|
||||||
return (text_2, lora_2)
|
return (text_2, lora_2)
|
||||||
|
|
||||||
@@ -121,6 +120,25 @@ class TagsFormater:
|
|||||||
|
|
||||||
return (output,)
|
return (output,)
|
||||||
|
|
||||||
|
class LoraListNames:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
LORA_LIST = sorted(folder_paths.get_filename_list("loras"), key=str.lower)
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"lora_name": (LORA_LIST,),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = ("STRING",)
|
||||||
|
RETURN_NAMES = ("lora_name",)
|
||||||
|
FUNCTION = "output_selected"
|
||||||
|
CATEGORY = "autotrigger"
|
||||||
|
|
||||||
|
def output_selected(self, lora_name):
|
||||||
|
name = lora_name
|
||||||
|
return (name,)
|
||||||
|
|
||||||
# A dictionary that contains all nodes you want to export with their names
|
# A dictionary that contains all nodes you want to export with their names
|
||||||
# NOTE: names should be globally unique
|
# NOTE: names should be globally unique
|
||||||
NODE_CLASS_MAPPINGS = {
|
NODE_CLASS_MAPPINGS = {
|
||||||
@@ -129,6 +147,7 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
"TextInputBasic": TextInputBasic,
|
"TextInputBasic": TextInputBasic,
|
||||||
"TagsSelector": TagsSelector,
|
"TagsSelector": TagsSelector,
|
||||||
"TagsFormater": TagsFormater,
|
"TagsFormater": TagsFormater,
|
||||||
|
"LoraListNames": LoraListNames,
|
||||||
}
|
}
|
||||||
|
|
||||||
# A dictionary that contains the friendly/humanly readable titles for the nodes
|
# A dictionary that contains the friendly/humanly readable titles for the nodes
|
||||||
@@ -138,4 +157,5 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
|||||||
"TextInputBasic": "TextInputBasic",
|
"TextInputBasic": "TextInputBasic",
|
||||||
"TagsSelector": "TagsSelector",
|
"TagsSelector": "TagsSelector",
|
||||||
"TagsFormater": "TagsFormater",
|
"TagsFormater": "TagsFormater",
|
||||||
|
"LoraListNames": "LoraListNames",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ def copy_preview_to_temp(file_name):
|
|||||||
lora_less = "/".join(file_name.split("/")[1:])
|
lora_less = "/".join(file_name.split("/")[1:])
|
||||||
|
|
||||||
file_path = folder_paths.get_full_path("loras", lora_less)
|
file_path = folder_paths.get_full_path("loras", lora_less)
|
||||||
|
if file_path is None:
|
||||||
|
return None, None
|
||||||
|
|
||||||
temp_path = folder_paths.get_temp_directory()
|
temp_path = folder_paths.get_temp_directory()
|
||||||
preview_path = os.path.join(temp_path, "lora_preview")
|
preview_path = os.path.join(temp_path, "lora_preview")
|
||||||
@@ -66,7 +68,7 @@ def load_json_from_file(file_path):
|
|||||||
return None
|
return None
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
print(f"Error decoding JSON in file: {file_path}")
|
print(f"Error decoding JSON in file: {file_path}")
|
||||||
return None
|
raise
|
||||||
|
|
||||||
def save_dict_to_json(data_dict, file_path):
|
def save_dict_to_json(data_dict, file_path):
|
||||||
try:
|
try:
|
||||||
@@ -103,21 +105,21 @@ def load_and_save_tags(lora_name, force_fetch):
|
|||||||
output_tags_list = []
|
output_tags_list = []
|
||||||
|
|
||||||
lora_path = folder_paths.get_full_path("loras", lora_name)
|
lora_path = folder_paths.get_full_path("loras", lora_name)
|
||||||
if lora_tags is None or force_fetch: # search on civitai only if no local cache or forced
|
if lora_tags is None or force_fetch or output_tags is None: # search on civitai only if no local cache or forced
|
||||||
print("calculating lora hash")
|
print("[Lora-Auto-Trigger] calculating lora hash")
|
||||||
LORAsha256 = calculate_sha256(lora_path)
|
LORAsha256 = calculate_sha256(lora_path)
|
||||||
print("requesting infos")
|
print("[Lora-Auto-Trigger] requesting infos")
|
||||||
model_info = get_model_version_info(LORAsha256)
|
model_info = get_model_version_info(LORAsha256)
|
||||||
if model_info is not None:
|
if model_info is not None:
|
||||||
if "trainedWords" in model_info:
|
if "trainedWords" in model_info:
|
||||||
print("tags found!")
|
print("[Lora-Auto-Trigger] tags found!")
|
||||||
if lora_tags is None:
|
if lora_tags is None:
|
||||||
lora_tags = {}
|
lora_tags = {}
|
||||||
lora_tags[lora_name] = model_info["trainedWords"]
|
lora_tags[lora_name] = model_info["trainedWords"]
|
||||||
save_dict_to_json(lora_tags,json_tags_path)
|
save_dict_to_json(lora_tags, json_tags_path)
|
||||||
output_tags_list = model_info["trainedWords"]
|
output_tags_list = model_info["trainedWords"]
|
||||||
else:
|
else:
|
||||||
print("No informations found.")
|
print("[Lora-Auto-Trigger] No informations found.")
|
||||||
if lora_tags is None:
|
if lora_tags is None:
|
||||||
lora_tags = {}
|
lora_tags = {}
|
||||||
lora_tags[lora_name] = []
|
lora_tags[lora_name] = []
|
||||||
@@ -219,4 +221,4 @@ def append_lora_name_if_empty(tags_list, lora_path, enabled):
|
|||||||
filename = os.path.basename(filename)
|
filename = os.path.basename(filename)
|
||||||
|
|
||||||
tags_list.append(filename)
|
tags_list.append(filename)
|
||||||
return tags_list
|
return tags_list
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { app } from "../../../scripts/app.js";
|
||||||
|
import { LoraInfoDialog } from "../../ComfyUI-Custom-Scripts/js/modelInfo.js";
|
||||||
|
|
||||||
|
const infoHandlers = {
|
||||||
|
"LoraLoaderVanilla":true,
|
||||||
|
"LoraLoaderStackedVanilla":true,
|
||||||
|
"LoraLoaderAdvanced":true,
|
||||||
|
"LoraLoaderStackedAdvanced":true
|
||||||
|
}
|
||||||
|
|
||||||
|
app.registerExtension({
|
||||||
|
name: "autotrigger.LoraInfo",
|
||||||
|
beforeRegisterNodeDef(nodeType) {
|
||||||
|
if (! infoHandlers[nodeType.comfyClass]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const getExtraMenuOptions = nodeType.prototype.getExtraMenuOptions;
|
||||||
|
nodeType.prototype.getExtraMenuOptions = function (_, options) {
|
||||||
|
let value = this.widgets[0].value;
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (value.content) {
|
||||||
|
value = value.content;
|
||||||
|
}
|
||||||
|
options.unshift({
|
||||||
|
content: "View info...",
|
||||||
|
callback: async () => {
|
||||||
|
new LoraInfoDialog(value).show("loras", value);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return getExtraMenuOptions?.apply(this, arguments);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||