Compare commits

..
Author SHA1 Message Date
Dijkstra a95cba4e3b doc: last fix 2024-04-09 22:18:14 +02:00
Dijkstra 40f09582e2 doc: added View info in readme 2024-04-09 22:17:08 +02:00
Dijkstra 6635d30566 doc: updated readme 2024-04-09 22:11:55 +02:00
dijkstra 5cf49c9565 Merge pull request #19 from idrirap/issue14
feat: added pyssss's lora view info
2024-04-09 21:24:05 +02:00
Dijkstra 1e8ed1e16f feat: added pyssss's lora view info 2024-04-09 21:09:44 +02:00
dijkstra 64113afd7f Merge pull request #18 from idrirap/issue16
feat: added lora name to output
2024-04-09 18:16:19 +02:00
Dijkstra 2bd6769b78 fix: now can use the output lora_name as an input for override_lora_name 2024-04-09 18:11:46 +02:00
Dijkstra 96a69f7cbe feat: added lora name to output 2024-04-09 17:05:22 +02:00
dijkstra 9d8b79844f Merge pull request #13 from idrirap/issue12
fix: broken preview when using both enable preview and override_lora_name
2024-03-14 23:26:17 +01:00
Dijkstra f3815b7ce4 fix: broken preview when using both enable preview and override_lora_name 2024-03-14 23:23:35 +01:00
dijkstra d5641ba745 Merge pull request #11 from deipfei/json-error-change
don't delete loras_tags.json on JSONDecodeError
2024-03-08 21:21:03 +01:00
Dustin Pfeiffer 5b5eaf3a81 don't delete loras_tags.json on JSONDecodeError 2024-02-23 15:28:01 -08:00
dijkstra 517b8a8a12 Merge pull request #9 from idrirap/issue8
feat: added tags only node. Added node to load lora names as string. …
2023-12-12 18:58:03 +01:00
Dijkstra 0be7528f10 feat: added tags only node. Added node to load lora names as string. Added the ability to override lora name from dropdown menu. + fixed bad parameters for strenght_model 2023-12-12 18:51:00 +01:00
dijkstra b63862f2e3 Merge pull request #7 from idrirap/fix_civitai_initial_search
fix: tags were never pulled from civitai the first time they were req…
2023-11-20 18:12:13 +01:00
Dijkstra 8ed3d36eaf fix: tags were never pulled from civitai the first time they were requested 2023-11-20 18:11:23 +01:00
dijkstra 8af8cce210 Merge pull request #5 from idrirap/fix_cache_stacker
fix: bug where lora_stack input get stacked with the lora_stack output exponentially
2023-11-17 18:36:32 +01:00
Dijkstra d7530a3326 fix: bug where lora_stack input get stacked with the lora_stack output exponentially 2023-11-17 18:33:28 +01:00
Dijkstra 05de5959e1 Merge branch 'main' of github.com:idrirap/ComfyUI-Lora-Auto-Trigger-Words into main 2023-11-01 18:49:28 +01:00
dijkstra 049fd1eb71 Merge pull request #3 from idrirap/dev/fix_issue2
Dev/fix issue2
2023-11-01 18:45:53 +01:00
13 changed files with 226 additions and 65 deletions
+70 -21
View File
@@ -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.
![image](./images/main.png) ![image](./images/main.png)
#### Nodes ### Nodes
- LoraLoader (Vanilla or Advanced) #### LoraLoader (Vanilla and Advanced)
- LoraLoaderStacked (Vanilla or Avanced). The stacked lora input is optional. ![image](./images/LoraLoader.png)
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).
![image](./images/LoraLoaderStacked.png)
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
![image](./images/LoraTagsOnly.png)
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
![image](./images/TagsFormater.png)
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
![image](./images/TagsSelector.png)
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
![image](./images/LoraListNames.png)
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
![image](./images/ViewInfo.png)
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
![image](./images/loaderAdvanced.png) ![image](./images/loaderAdvanced.png)
@@ -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
+2 -1
View File
@@ -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"]
Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

+81 -28
View File
@@ -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",
} }
+27 -7
View File
@@ -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",
} }
+10 -8
View File
@@ -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
+36
View File
@@ -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);
};
}
});