Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c18075e9f | ||
|
|
e0ec5dee30 | ||
|
|
c09e56b21f | ||
|
|
763152c041 | ||
|
|
c85b302a61 | ||
|
|
6484968fbe | ||
|
|
9a212d13e7 | ||
|
|
b02bea5480 | ||
|
|
8c4b7941a6 | ||
|
|
070751dbf1 | ||
|
|
41f6277830 | ||
|
|
03ddfbfe66 | ||
|
|
885a1c8371 | ||
|
|
8656b2ebaf | ||
|
|
c3759e7b30 | ||
|
|
236e230515 | ||
|
|
23ef04b1cb | ||
|
|
a95cba4e3b | ||
|
|
40f09582e2 | ||
|
|
6635d30566 | ||
|
|
5cf49c9565 |
@@ -0,0 +1,21 @@
|
|||||||
|
name: Publish to Comfy registry
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "pyproject.toml"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish-node:
|
||||||
|
name: Publish Custom Node to registry
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Publish Custom Node
|
||||||
|
uses: Comfy-Org/publish-node-action@main
|
||||||
|
with:
|
||||||
|
## Add your own personal access token to your Github Repository secrets and reference it here.
|
||||||
|
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
|
||||||
@@ -2,37 +2,88 @@
|
|||||||
|
|
||||||
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
|
### Lora Trigger Words
|
||||||
|
Lora trigger words are imported from two sources :
|
||||||
|
- Civitai api (only for civitai models)
|
||||||
|
|
||||||
|

|
||||||
|
- Model training metadata (when available)
|
||||||
|
|
||||||
#### 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 +93,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 +111,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
|
||||||
|
|||||||
|
After Width: | Height: | Size: 29 KiB |
|
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 |
@@ -14,7 +14,6 @@ class LoraLoaderVanilla:
|
|||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"model": ("MODEL",),
|
"model": ("MODEL",),
|
||||||
"clip": ("CLIP", ),
|
|
||||||
"lora_name": (LORA_LIST, ),
|
"lora_name": (LORA_LIST, ),
|
||||||
"strength_model": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
"strength_model": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
||||||
"strength_clip": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
"strength_clip": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
||||||
@@ -22,6 +21,7 @@ class LoraLoaderVanilla:
|
|||||||
"append_loraname_if_empty": ("BOOLEAN", {"default": False}),
|
"append_loraname_if_empty": ("BOOLEAN", {"default": False}),
|
||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
|
"clip": ("CLIP", ),
|
||||||
"override_lora_name":("STRING", {"forceInput": True}),
|
"override_lora_name":("STRING", {"forceInput": True}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,9 @@ class LoraLoaderVanilla:
|
|||||||
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, override_lora_name=""):
|
def load_lora(self, model, lora_name, strength_model, strength_clip, force_fetch, append_loraname_if_empty, clip=None, override_lora_name=""):
|
||||||
|
if clip is None:
|
||||||
|
strength_clip=0
|
||||||
if override_lora_name != "":
|
if override_lora_name != "":
|
||||||
lora_name = 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"))
|
||||||
@@ -109,7 +111,6 @@ class LoraLoaderAdvanced:
|
|||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"model": ("MODEL",),
|
"model": ("MODEL",),
|
||||||
"clip": ("CLIP", ),
|
|
||||||
"lora_name": (LORA_LIST, ),
|
"lora_name": (LORA_LIST, ),
|
||||||
"strength_model": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
"strength_model": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
||||||
"strength_clip": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
"strength_clip": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
|
||||||
@@ -118,6 +119,7 @@ class LoraLoaderAdvanced:
|
|||||||
"append_loraname_if_empty": ("BOOLEAN", {"default": False}),
|
"append_loraname_if_empty": ("BOOLEAN", {"default": False}),
|
||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
|
"clip": ("CLIP", ),
|
||||||
"override_lora_name":("STRING", {"forceInput": True}),
|
"override_lora_name":("STRING", {"forceInput": True}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,7 +129,9 @@ class LoraLoaderAdvanced:
|
|||||||
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, override_lora_name=""):
|
def load_lora(self, model, lora_name, strength_model, strength_clip, force_fetch, enable_preview, append_loraname_if_empty, clip=None, override_lora_name=""):
|
||||||
|
if clip is None:
|
||||||
|
strength_clip=0
|
||||||
if override_lora_name != "":
|
if override_lora_name != "":
|
||||||
has_preview, prev = get_preview_path(override_lora_name, "loras")
|
has_preview, prev = get_preview_path(override_lora_name, "loras")
|
||||||
prev = f"loras/{prev}" if has_preview else None
|
prev = f"loras/{prev}" if has_preview else None
|
||||||
@@ -253,7 +257,6 @@ class LoraTagsOnly:
|
|||||||
|
|
||||||
return (civitai_tags_list, meta_tags_list)
|
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
|
||||||
# NOTE: names should be globally unique
|
# NOTE: names should be globally unique
|
||||||
NODE_CLASS_MAPPINGS = {
|
NODE_CLASS_MAPPINGS = {
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[project]
|
||||||
|
name = "comfyui-lora-auto-trigger-words"
|
||||||
|
description = "The aim of these custom nodes is to get an easy access to the tags used to trigger a lora / lycoris. Extract the tags from civitai or from the safetensors metadatas when available."
|
||||||
|
version = "1.0.4"
|
||||||
|
license = "MIT"
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Repository = "https://github.com/idrirap/ComfyUI-Lora-Auto-Trigger-Words"
|
||||||
|
# Used by Comfy Registry https://comfyregistry.org
|
||||||
|
|
||||||
|
[tool.comfy]
|
||||||
|
PublisherId = "dijkstra"
|
||||||
|
DisplayName = "ComfyUI-Lora-Auto-Trigger-Words"
|
||||||
|
Icon = ""
|
||||||
@@ -15,11 +15,14 @@ def get_preview_path(name, type):
|
|||||||
|
|
||||||
file_path_no_ext = os.path.splitext(file_path)[0]
|
file_path_no_ext = os.path.splitext(file_path)[0]
|
||||||
item_image=None
|
item_image=None
|
||||||
for ext in ["png", "jpg", "jpeg", "preview.png"]:
|
for ext in ["png", "jpg", "jpeg", "gif"]:
|
||||||
has_image = os.path.isfile(file_path_no_ext + "." + ext)
|
if item_image is not None:
|
||||||
if has_image:
|
|
||||||
item_image = f"{file_name}.{ext}"
|
|
||||||
break
|
break
|
||||||
|
for ext2 in ["", ".preview"]:
|
||||||
|
has_image = os.path.isfile(file_path_no_ext + ext2 + "." + ext)
|
||||||
|
if has_image:
|
||||||
|
item_image = f"{file_name}{ext2}.{ext}"
|
||||||
|
break
|
||||||
|
|
||||||
return has_image, item_image
|
return has_image, item_image
|
||||||
|
|
||||||
@@ -80,8 +83,11 @@ def save_dict_to_json(data_dict, file_path):
|
|||||||
|
|
||||||
def get_model_version_info(hash_value):
|
def get_model_version_info(hash_value):
|
||||||
api_url = f"https://civitai.com/api/v1/model-versions/by-hash/{hash_value}"
|
api_url = f"https://civitai.com/api/v1/model-versions/by-hash/{hash_value}"
|
||||||
response = requests.get(api_url)
|
try:
|
||||||
|
response = requests.get(api_url)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[Lora-Auto-Trigger] {e}")
|
||||||
|
return None
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
return response.json()
|
return response.json()
|
||||||
else:
|
else:
|
||||||
|
|||||||