diff --git a/README.md b/README.md index 539d21e..d1e0d18 100644 --- a/README.md +++ b/README.md @@ -146,4 +146,8 @@ Many of the nodes require these paths to be in your extra_model_paths.yaml (with > -# Example Workflows \ No newline at end of file +# Example Workflows +## Lora Tester +Note: Uses [ImagesGrid](https://github.com/LEv145/images-grid-comfy-plugin) for making the actual grid from the image output. + +![Lora Tester](./imgs/lora_tester_workflow.png) \ No newline at end of file diff --git a/characters.json b/characters.json index 6c0445c..8f7978e 100644 --- a/characters.json +++ b/characters.json @@ -140,7 +140,7 @@ "prompt": "black hair, large breasts, long hair, ponytail, red eyes, very long hair, feathered wings, red halo" }, { - "name": "Asuna (SAO)", + "name": "Yuuki Asuna (SAO)", "associated_string": "asuna \\(sao\\), sword art online", "prompt": "braid, brown eyes, brown hair, french braid, large breasts, long hair, short ponytail, very long hair" }, @@ -205,7 +205,7 @@ "prompt": "blonde hair, forehead mark, large breasts, long hair, parted bangs, brown eyes, mature female, hair intakes" }, { - "name": "Asuna (Blue Archive)", + "name": "Ichinose Asuna (Blue Archive)", "associated_string": "asuna \\(blue archive\\), asuna \\(bunny\\) (blue archive), blue archive", "prompt": "blue eyes, blue ribbon, hair ribbon, large breasts, light brown hair, very long hair, ribbon" }, @@ -242,6 +242,31 @@ { "name": "Shishiro Botan (Hololive)", "associated_string": "shishiro botan, hololive", - "prompt": "black hair, blue eyes, hair between eyes, medium breasts, long hair, multicolored hair, red hair, twintails, uneven twintails, virtual youtuber, white hair" + "prompt": "grey eyes, grey hair, hair between eyes, large breasts, long hair, virtual youtuber, animal ear piercing, animal ears, lion ears, lion girl" + }, + { + "name": "Takane Lui (Hololive)", + "associated_string": "takane lui, hololive", + "prompt": "hair between eyes, large breasts, pink hair, virtual youtuber, thigh gap, head wings, hair wings" + }, + { + "name": "Shirakami Fubuki (Hololive)", + "associated_string": "shirakami fubuki, hololive", + "prompt": "ahoge, animal ears, aqua eyes, braid, hair between eyes, large breasts, side braid, virtual youtuber, white hair, fox girl, fox ears" + }, + { + "name": "Nekomata Okayu (Hololive)", + "associated_string": "nekomata okayu, hololive", + "prompt": "ahoge, animal ears, crossed bangs, large breasts, medium hair, pink hair, purple eyes, virtual youtuber" + }, + { + "name": "Irys (Hololive)", + "associated_string": "irys \\(hololive\\), hololive, hololive english", + "prompt": "blue eyes, heterochromia, horns, medium breasts, long hair, pointy ears, purple eyes, red hair, very long hair, virtual youtuber" + }, + { + "name": "Ninomae Ina'nis (Hololive)", + "associated_string": "ninomae ina'nis, hololive, hololive english", + "prompt": "blue eyes, blunt bangs, long hair, mole, mole under eye, multicolored hair, orange hair, pointy ears, purple hair, small breasts, very long hair, virtual youtuber" } ] diff --git a/imgs/find_res.png b/imgs/find_res.png index 78818e6..cfc5adc 100644 Binary files a/imgs/find_res.png and b/imgs/find_res.png differ diff --git a/imgs/lora_tester_workflow.png b/imgs/lora_tester_workflow.png new file mode 100644 index 0000000..ce78ce9 Binary files /dev/null and b/imgs/lora_tester_workflow.png differ diff --git a/src/load_lora_character.py b/src/load_lora_character.py index 21629fd..2817de3 100644 --- a/src/load_lora_character.py +++ b/src/load_lora_character.py @@ -61,11 +61,20 @@ class LoadLoraCharacterNode: character_name = None cleaned_character = self.clean_string(character) + min_character_distance = float('inf') + for char in character_data: - cleaned_associated_string = self.clean_string(char['associated_string']) - if cleaned_associated_string == cleaned_character: - character_name = char['name'] - break + cleaned_character_lower = cleaned_character.lower().split() + if any(word in char['name'].lower() for word in cleaned_character_lower): + cleaned_associated_string = self.clean_string(char['associated_string']) + distance = self.levenshtein_distance(cleaned_associated_string, cleaned_character) + + if distance < min_character_distance: + print_sn0w(f"Distance: {distance} Name: {char['name']}") + min_character_distance = distance + character_name = char['name'] + if distance <= 2: + break if character_name: lora_loader = LoraLoader() @@ -117,6 +126,6 @@ class LoadLoraCharacterNode: print_sn0w(lora_path) model, clip = lora_loader.load_lora(model, clip, lora_path, lora_strength, lora_strength) else: - print_sn0w("No matching Lora found for the character.") + print_sn0w(f"No matching Lora found for the character {character_name}.") return model, clip \ No newline at end of file diff --git a/src/lora_selector.py b/src/lora_selector.py index 07c9adb..a77dfc6 100644 --- a/src/lora_selector.py +++ b/src/lora_selector.py @@ -1,5 +1,4 @@ import folder_paths -import json class LoraSelectorNode: @classmethod diff --git a/workflows/lora_tester_example.json b/workflows/lora_tester_example.json new file mode 100644 index 0000000..a839b82 --- /dev/null +++ b/workflows/lora_tester_example.json @@ -0,0 +1,749 @@ +{ + "last_node_id": 441, + "last_link_id": 997, + "nodes": [ + { + "id": 54, + "type": "UpscaleModelLoader", + "pos": [ + -762.3588212890626, + 528.9573682128906 + ], + "size": { + "0": 315, + "1": 58 + }, + "flags": {}, + "order": 0, + "mode": 0, + "outputs": [ + { + "name": "UPSCALE_MODEL", + "type": "UPSCALE_MODEL", + "links": [ + 968 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "UpscaleModelLoader" + }, + "widgets_values": [ + "RealESRGAN_x4plus.pth" + ] + }, + { + "id": 432, + "type": "Lora Tester XL", + "pos": [ + -420, + 380 + ], + "size": [ + 320, + 610 + ], + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 994 + }, + { + "name": "clip", + "type": "CLIP", + "link": 995 + }, + { + "name": "vae", + "type": "VAE", + "link": 976 + }, + { + "name": "upscale_model", + "type": "UPSCALE_MODEL", + "link": 968 + }, + { + "name": "lora_info", + "type": "STRING", + "link": 988, + "widget": { + "name": "lora_info" + } + }, + { + "name": "width", + "type": "INT", + "link": 984, + "widget": { + "name": "width" + } + }, + { + "name": "height", + "type": "INT", + "link": 985, + "widget": { + "name": "height" + } + } + ], + "outputs": [ + { + "name": "IMAGES", + "type": "IMAGE", + "links": [ + 975, + 978 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "Lora Tester XL" + }, + "widgets_values": [ + 1038150464022680, + "randomize", + 25, + 8.5, + 768, + 0, + "euler_ancestral", + "normal", + "1girl, black necktie, black pants, blonde hair, collared shirt, cross-shaped pupils, double v, hair between eyes, horns, jacket, long hair, looking at viewer, necktie, orange eyes, pants, parted lips, red background, red horns, red jacket, sharp teeth, shirt, shirt partially tucked in, shirt tucked in, simple background, sleeves past wrists, smile, solo, symbol-shaped pupils, teeth, v, white shirt, ", + "(lowres, multiple views, futanari, bad anatomy, bad hands, missing fingers, extra digit, text, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts:1.15), (signature, watermark, username, gumroad username, patreon username, artist name:1.1), multiple views, error, blurry", + 1, + "", + false + ] + }, + { + "id": 403, + "type": "ImagesGridByColumns", + "pos": [ + -70, + 380 + ], + "size": { + "0": 320, + "1": 100 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 975 + }, + { + "name": "annotation", + "type": "GRID_ANNOTATION", + "link": 880 + }, + { + "name": "max_columns", + "type": "INT", + "link": 989, + "widget": { + "name": "max_columns" + } + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 882 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "ImagesGridByColumns" + }, + "widgets_values": [ + 0, + 1 + ] + }, + { + "id": 402, + "type": "GridAnnotation", + "pos": [ + -70, + 530 + ], + "size": [ + 320, + 180 + ], + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "column_texts", + "type": "STRING", + "link": 990, + "widget": { + "name": "column_texts" + } + }, + { + "name": "font_size", + "type": "INT", + "link": 979, + "widget": { + "name": "font_size" + } + } + ], + "outputs": [ + { + "name": "GRID_ANNOTATION", + "type": "GRID_ANNOTATION", + "links": [ + 880 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "GridAnnotation" + }, + "widgets_values": [ + "", + "", + 50 + ] + }, + { + "id": 438, + "type": "Find SDXL Resolution", + "pos": [ + -660, + 1040 + ], + "size": { + "0": 210, + "1": 130 + }, + "flags": {}, + "order": 1, + "mode": 0, + "outputs": [ + { + "name": "WIDTH", + "type": "INT", + "links": [ + 984 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "HEIGHT", + "type": "INT", + "links": [ + 985 + ], + "shape": 3, + "slot_index": 1 + } + ], + "properties": { + "Node name for S&R": "Find SDXL Resolution" + }, + "widgets_values": [ + 768, + 1152, + false + ] + }, + { + "id": 4, + "type": "CheckpointLoaderSimple", + "pos": [ + -760.8242044214777, + 385.1089789797194 + ], + "size": { + "0": 315, + "1": 98 + }, + "flags": {}, + "order": 2, + "mode": 0, + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 992 + ], + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 993 + ], + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [ + 976 + ], + "slot_index": 2 + } + ], + "properties": { + "Node name for S&R": "CheckpointLoaderSimple" + }, + "widgets_values": [ + "animagineXLV3_v30.safetensors" + ] + }, + { + "id": 439, + "type": "Lora Selector", + "pos": [ + -760, + 810 + ], + "size": { + "0": 315, + "1": 174 + }, + "flags": {}, + "order": 3, + "mode": 0, + "outputs": [ + { + "name": "LORA_INFO", + "type": "STRING", + "links": [ + 988, + 990, + 991 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "TOTAL_LORAS", + "type": "INT", + "links": [ + 989 + ], + "shape": 3, + "slot_index": 1 + } + ], + "properties": { + "Node name for S&R": "Lora Selector" + }, + "widgets_values": [ + "Training\\Kaba_Yuuji_XL\\model\\Kaba_Yuuji_XL-000002.safetensors", + 1, + 8, + 4, + true + ] + }, + { + "id": 433, + "type": "Get Font Size", + "pos": [ + -420, + 1040 + ], + "size": { + "0": 320, + "1": 54 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 978 + }, + { + "name": "lora_info", + "type": "STRING", + "link": 991, + "widget": { + "name": "lora_info" + } + } + ], + "outputs": [ + { + "name": "FONT_SIZE", + "type": "INT", + "links": [ + 979 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "Get Font Size" + }, + "widgets_values": [ + "" + ] + }, + { + "id": 440, + "type": "Load Lora Character", + "pos": [ + -760, + 630 + ], + "size": [ + 310, + 130 + ], + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 992 + }, + { + "name": "clip", + "type": "CLIP", + "link": 993 + }, + { + "name": "character", + "type": "STRING", + "link": 997, + "widget": { + "name": "character" + } + }, + { + "name": "xl", + "type": "BOOLEAN", + "link": 996, + "widget": { + "name": "xl" + } + } + ], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 994 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 995 + ], + "shape": 3, + "slot_index": 1 + } + ], + "properties": { + "Node name for S&R": "Load Lora Character" + }, + "widgets_values": [ + "power ", + true, + 0.8 + ] + }, + { + "id": 441, + "type": "Character Selector", + "pos": [ + -1100, + 660 + ], + "size": { + "0": 315, + "1": 170 + }, + "flags": {}, + "order": 4, + "mode": 0, + "outputs": [ + { + "name": "CHARACTER STRING", + "type": "STRING", + "links": [ + 997 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "CHARACTER PROMPT", + "type": "STRING", + "links": null, + "shape": 3 + }, + { + "name": "XL", + "type": "BOOLEAN", + "links": [ + 996 + ], + "shape": 3, + "slot_index": 2 + } + ], + "properties": { + "Node name for S&R": "Character Selector" + }, + "widgets_values": [ + "Power (Chainsaw Man)", + 1, + false, + true + ] + }, + { + "id": 404, + "type": "PreviewImage", + "pos": [ + -70, + 750 + ], + "size": [ + 990, + 350 + ], + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 882 + } + ], + "properties": { + "Node name for S&R": "PreviewImage" + } + } + ], + "links": [ + [ + 880, + 402, + 0, + 403, + 1, + "GRID_ANNOTATION" + ], + [ + 882, + 403, + 0, + 404, + 0, + "IMAGE" + ], + [ + 968, + 54, + 0, + 432, + 3, + "UPSCALE_MODEL" + ], + [ + 975, + 432, + 0, + 403, + 0, + "IMAGE" + ], + [ + 976, + 4, + 2, + 432, + 2, + "VAE" + ], + [ + 978, + 432, + 0, + 433, + 0, + "IMAGE" + ], + [ + 979, + 433, + 0, + 402, + 1, + "INT" + ], + [ + 984, + 438, + 0, + 432, + 5, + "INT" + ], + [ + 985, + 438, + 1, + 432, + 6, + "INT" + ], + [ + 988, + 439, + 0, + 432, + 4, + "STRING" + ], + [ + 989, + 439, + 1, + 403, + 2, + "INT" + ], + [ + 990, + 439, + 0, + 402, + 0, + "STRING" + ], + [ + 991, + 439, + 0, + 433, + 1, + "STRING" + ], + [ + 992, + 4, + 0, + 440, + 0, + "MODEL" + ], + [ + 993, + 4, + 1, + 440, + 1, + "CLIP" + ], + [ + 994, + 440, + 0, + 432, + 0, + "MODEL" + ], + [ + 995, + 440, + 1, + 432, + 1, + "CLIP" + ], + [ + 996, + 441, + 2, + 440, + 3, + "BOOLEAN" + ], + [ + 997, + 441, + 0, + 440, + 2, + "STRING" + ] + ], + "groups": [ + { + "title": "Txt2img", + "bounding": [ + -429, + 307, + 342, + 802 + ], + "color": "#3f789e", + "font_size": 24, + "locked": false + }, + { + "title": "Loading", + "bounding": [ + -770, + 309, + 330, + 695 + ], + "color": "#b06634", + "font_size": 24, + "locked": false + } + ], + "config": {}, + "extra": { + "groupNodes": {} + }, + "version": 0.4 +} \ No newline at end of file