diff --git a/examples/sd3.json b/examples/sd3.json new file mode 100644 index 0000000..348be72 --- /dev/null +++ b/examples/sd3.json @@ -0,0 +1,746 @@ +{ + "last_node_id": 277, + "last_link_id": 606, + "nodes": [ + { + "id": 266, + "type": "Note", + "pos": [ + -2352, + 576 + ], + "size": { + "0": 308.061279296875, + "1": 102.86902618408203 + }, + "flags": {}, + "order": 0, + "mode": 0, + "properties": { + "text": "" + }, + "widgets_values": [ + "Resolution should be around 1 megapixel and width/height must be multiple of 64" + ], + "color": "#432", + "bgcolor": "#653" + }, + { + "id": 135, + "type": "EmptySD3LatentImage", + "pos": [ + -2352, + 438 + ], + "size": { + "0": 315, + "1": 106 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 593 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "EmptySD3LatentImage" + }, + "widgets_values": [ + 1024, + 1024, + 1 + ] + }, + { + "id": 71, + "type": "CLIPTextEncode", + "pos": [ + -1869.2871546875003, + 560.071803930664 + ], + "size": { + "0": 380.4615783691406, + "1": 102.07693481445312 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 601 + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 93, + 580 + ], + "shape": 3, + "slot_index": 0 + } + ], + "title": "CLIP Text Encode (Negative Prompt)", + "properties": { + "Node name for S&R": "CLIPTextEncode" + }, + "widgets_values": [ + "bad quality, poor quality, disfigured, jpg, bad anatomy, missing limbs, missing fingers" + ], + "color": "#322", + "bgcolor": "#533" + }, + { + "id": 272, + "type": "PrimitiveNode", + "pos": [ + -2342, + 278 + ], + "size": { + "0": 210, + "1": 82 + }, + "flags": {}, + "order": 2, + "mode": 0, + "outputs": [ + { + "name": "INT", + "type": "INT", + "links": [ + 597 + ], + "slot_index": 0, + "widget": { + "name": "seed" + } + } + ], + "title": "Seed", + "properties": { + "Run widget replace on values": false + }, + "widgets_values": [ + 0, + "fixed" + ] + }, + { + "id": 6, + "type": "CLIPTextEncode", + "pos": [ + -1876, + 284 + ], + "size": { + "0": 389.06927490234375, + "1": 207.84902954101562 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 600 + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 595 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "CLIPTextEncode" + }, + "widgets_values": [ + "Chibi figure of a wizard girl with a big wand. She wears a wizard's hat and a blue robe. The wand is based on a clock. A magic circle is deployed on the underside." + ], + "color": "#232", + "bgcolor": "#353" + }, + { + "id": 252, + "type": "CheckpointLoaderSimple", + "pos": [ + -2355.546164772728, + 16.90906663374463 + ], + "size": [ + 404.13517457201715, + 98 + ], + "flags": {}, + "order": 3, + "mode": 0, + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 565 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 600, + 601 + ], + "shape": 3, + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [ + 557 + ], + "shape": 3, + "slot_index": 2 + } + ], + "properties": { + "Node name for S&R": "CheckpointLoaderSimple" + }, + "widgets_values": [ + "sd3_medium_incl_clips_t5xxlfp8.safetensors" + ] + }, + { + "id": 13, + "type": "ModelSamplingSD3", + "pos": [ + -1774, + 12 + ], + "size": { + "0": 315, + "1": 58 + }, + "flags": { + "collapsed": false + }, + "order": 4, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 565 + } + ], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 591 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "ModelSamplingSD3" + }, + "widgets_values": [ + 3 + ] + }, + { + "id": 67, + "type": "ConditioningZeroOut", + "pos": [ + -1405, + 392 + ], + "size": { + "0": 211.60000610351562, + "1": 26 + }, + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 580 + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 90 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "ConditioningZeroOut" + } + }, + { + "id": 70, + "type": "ConditioningSetTimestepRange", + "pos": [ + -1108, + 549 + ], + "size": { + "0": 317.4000244140625, + "1": 82 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 93, + "slot_index": 0 + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 92 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "ConditioningSetTimestepRange" + }, + "widgets_values": [ + 0, + 0.1 + ] + }, + { + "id": 68, + "type": "ConditioningSetTimestepRange", + "pos": [ + -1111, + 391 + ], + "size": { + "0": 317.4000244140625, + "1": 82 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 90 + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 91 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "ConditioningSetTimestepRange" + }, + "widgets_values": [ + 0.1, + 1 + ] + }, + { + "id": 69, + "type": "ConditioningCombine", + "pos": [ + -734, + 450 + ], + "size": { + "0": 228.39999389648438, + "1": 46 + }, + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "conditioning_1", + "type": "CONDITIONING", + "link": 91 + }, + { + "name": "conditioning_2", + "type": "CONDITIONING", + "link": 92 + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 592 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "ConditioningCombine" + } + }, + { + "id": 271, + "type": "KSampler", + "pos": [ + -420, + 116 + ], + "size": { + "0": 301.5874938964844, + "1": 234 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 591 + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 595 + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 592 + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 593 + }, + { + "name": "seed", + "type": "INT", + "link": 597, + "widget": { + "name": "seed" + }, + "slot_index": 4 + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 596 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "KSampler" + }, + "widgets_values": [ + 0, + "fixed", + 28, + 4.5, + "dpmpp_2m", + "sgm_uniform", + 1 + ] + }, + { + "id": 231, + "type": "VAEDecode", + "pos": [ + -30, + 28 + ], + "size": { + "0": 210, + "1": 46 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 596 + }, + { + "name": "vae", + "type": "VAE", + "link": 557 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 606 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "VAEDecode" + } + }, + { + "id": 277, + "type": "SaveImageWithMetaData", + "pos": [ + 271, + 29 + ], + "size": { + "0": 315, + "1": 438 + }, + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 606 + } + ], + "properties": { + "Node name for S&R": "SaveImageWithMetaData" + }, + "widgets_values": [ + "SD3", + "Farthest", + 0, + "png", + true, + 100, + false, + true + ] + } + ], + "links": [ + [ + 90, + 67, + 0, + 68, + 0, + "CONDITIONING" + ], + [ + 91, + 68, + 0, + 69, + 0, + "CONDITIONING" + ], + [ + 92, + 70, + 0, + 69, + 1, + "CONDITIONING" + ], + [ + 93, + 71, + 0, + 70, + 0, + "CONDITIONING" + ], + [ + 557, + 252, + 2, + 231, + 1, + "VAE" + ], + [ + 565, + 252, + 0, + 13, + 0, + "MODEL" + ], + [ + 580, + 71, + 0, + 67, + 0, + "CONDITIONING" + ], + [ + 591, + 13, + 0, + 271, + 0, + "MODEL" + ], + [ + 592, + 69, + 0, + 271, + 2, + "CONDITIONING" + ], + [ + 593, + 135, + 0, + 271, + 3, + "LATENT" + ], + [ + 595, + 6, + 0, + 271, + 1, + "CONDITIONING" + ], + [ + 596, + 271, + 0, + 231, + 0, + "LATENT" + ], + [ + 597, + 272, + 0, + 271, + 4, + "INT" + ], + [ + 600, + 252, + 1, + 6, + 0, + "CLIP" + ], + [ + 601, + 252, + 1, + 71, + 0, + "CLIP" + ], + [ + 606, + 231, + 0, + 277, + 0, + "IMAGE" + ] + ], + "groups": [ + { + "title": "Load Models", + "bounding": [ + -2407, + -85, + 521, + 245 + ], + "color": "#3f789e", + "font_size": 24, + "locked": false + }, + { + "title": "Input", + "bounding": [ + -2409, + 181, + 972, + 523 + ], + "color": "#3f789e", + "font_size": 24, + "locked": false + } + ], + "config": {}, + "extra": { + "ds": { + "scale": 1.3310000000000004, + "offset": [ + 252.86689786068672, + 111.40230534343857 + ] + } + }, + "version": 0.4 +} diff --git a/examples/sd3.png b/examples/sd3.png new file mode 100644 index 0000000..50d60db Binary files /dev/null and b/examples/sd3.png differ diff --git a/py/defs/formatters.py b/py/defs/formatters.py index 0c86031..074e2b8 100644 --- a/py/defs/formatters.py +++ b/py/defs/formatters.py @@ -78,7 +78,8 @@ def _extract_embedding_names(text, input_data): for word in to_tokenize: # if we find an embedding, deal with the embedding if ( - word.startswith(tokenizer.embedding_identifier) + hasattr(tokenizer, "embedding_identifier") + and word.startswith(tokenizer.embedding_identifier) and tokenizer.embedding_directory is not None ): embedding_name = word[len(tokenizer.embedding_identifier) :].strip("\n") diff --git a/py/defs/validators.py b/py/defs/validators.py index 2d5d151..746abda 100644 --- a/py/defs/validators.py +++ b/py/defs/validators.py @@ -1,21 +1,33 @@ +from collections import deque + from .samplers import SAMPLERS def is_positive_prompt(node_id, obj, prompt, extra_data, outputs, input_data_all): - positive_node_id_list = {} - for nid, node in prompt.items(): - for sampler_type, field_map in SAMPLERS.items(): - if node["class_type"] == sampler_type: - positive_node_id = node["inputs"][field_map["positive"]][0] - positive_node_id_list[nid] = positive_node_id - return node_id in positive_node_id_list.values() + return node_id in _get_node_id_list(prompt, "positive") def is_negative_prompt(node_id, obj, prompt, extra_data, outputs, input_data_all): - negative_node_id_list = {} + return node_id in _get_node_id_list(prompt, "negative") + + +def _get_node_id_list(prompt, field_name): + node_id_list = {} for nid, node in prompt.items(): for sampler_type, field_map in SAMPLERS.items(): if node["class_type"] == sampler_type: - negative_node_id = node["inputs"][field_map["negative"]][0] - negative_node_id_list[nid] = negative_node_id - return node_id in negative_node_id_list.values() + # There are nodes between "KSampler" and "CLIP Text Encode" in the SD3 workflow + d = deque() + d.append(node["inputs"][field_map[field_name]][0]) + while len(d) > 0: + nid2 = d.popleft() + class_type = prompt[nid2]["class_type"] + if class_type == "CLIPTextEncode": + node_id_list[nid] = nid2 + break + inputs = prompt[nid2]["inputs"] + for k, v in inputs.items(): + if isinstance(v, list): + d.append(v[0]) + + return node_id_list.values()