Version 0.1.0

This commit is contained in:
Adi Eyal
2023-07-30 21:31:49 +02:00
parent 0a570798fa
commit 83db0a9834
24 changed files with 2888 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
*.pyc
__pycache__
+20
View File
@@ -0,0 +1,20 @@
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.259
hooks:
- id: ruff
args:
- --fix
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: end-of-file-fixer
exclude: ^collections/.*
- id: trailing-whitespace
exclude: ^collections/.*
- repo: https://github.com/psf/black
rev: 23.1.0
hooks:
- id: black
args:
- --quiet
+72
View File
@@ -0,0 +1,72 @@
# ComfyUI-DynamicPrompts Custom Nodes
<img src="images/example.png"/>
ComfyUI-DynamicPrompts is a custom nodes library that integrates into your existing ComfyUI Library. It provides nodes that enable the use of [Dynamic Prompts](https://github.com/adieyal/dynamicprompts) in your ComfyUI. The nodes provided in this library are:
1. [Random Prompts](link_to_doc) - Implements standard wildcard mode for random sampling of variants and wildcards.
2. [Combinatorial Prompts](https://github.com/adieyal/sd-dynamic-prompts/blob/main/docs/SYNTAX.md#combinatorial-sampler) - Iterates through every possible combination of random values in a prompt.
3. [I'm Feeling Lucky](https://github.com/adieyal/dynamicprompts#im-feeling-lucky) - Uses the given prompt to download a related prompt from Lexica.art.
4. [Magic Prompt](https://github.com/adieyal/dynamicprompts#magic-prompt) - Employs a neural network to add relevant modifiers to your prompt.
5. [Jinja2 Templates](https://github.com/adieyal/dynamicprompts#jinja2-templates) - Allows you to write prompts using Jinja2 templates.
Nodes can be found in the Dynamic Prompts menu:
<img src="images/menu.png"/>
## Useful Links
* [Dynamic Prompts Home](https://github.com/adieyal/dynamicprompts)
* [Dynamic Prompts Syntax](https://github.com/adieyal/sd-dynamic-prompts/blob/main/docs/SYNTAX.md)
* [Dynamic Prompts Extension for Auto1111](https://github.com/adieyal/sd-dynamic-prompts)
* [Tutorial](https://github.com/adieyal/sd-dynamic-prompts/blob/main/docs/tutorial.md)
* [Online Resources](https://github.com/adieyal/sd-dynamic-prompts/blob/main/docs/resources.md)
## Installation
Follow the steps below to install the ComfyUI-DynamicPrompts Library:
1. Clone the repository:
```
git clone https://github.com/adieyal/comfyui-dynamicprompts ComfyUI/custom_nodes/
```
2. Install the required Python packages:
```
python -m pip install -r ComfyUI/custom_nodes/requirements.txt
```
3. Copy the dp.js file to the ComfyUI web extensions directory:
```
cp ComfyUI/custom_nodes/comfyui-dynamicprompts/web-extensions/dp.js ComfyUI/web/extensions
```
4. `mkdir ComfyUI/wildcards`
5. (Optional) download a wildcard collection and copy it into this new wildcards folder.
6. Restart your ComfyUI.
7. Example workflows can be found in `ComfyUI/custom_nodes/comfyui-dynamicprompts/example_workflows`.
## Wildcards
ComfyUI-DynamicPrompts supports wildcard files in `.txt`, .`json` and .`yaml` ([example format](https://github.com/adieyal/sd-dynamic-prompts/blob/main/collections/publicprompts.yaml)) . This library looks for a wildcards folder either in `ComfyUI/wildcards` or `ComfyUI/custom_nodes/comfyui-dynamicprompts/wildcards`.
There are many pre-built wildcards collections available. Here are a few to get you started:
* [SD Dynamic Prompts built-in](https://github.com/adieyal/sd-dynamic-prompts/tree/main/collections)
* [Civitai wildcard packs](https://github.com/adieyal/sd-dynamic-prompts/blob/main/docs/resources.md#wildcard-packs)
## Node Outputs
All nodes in this library produce a String output that can typically be passed into Clip Text Encode Prompts. Both positive and negative nodes are supported.
Please note, since ComfyUI is inherently stateless, some nodes might have a slightly unexpected behavior:
- The Combinatorial Prompt generation iterates through all possible values in a cycle. For example, A `{red|green|blue}` ball will generate the following sequence:
- A red ball
- A green ball
- A blue ball
- A red ball
- ...
- The I'm Feeling Lucky, Magic Prompt, and Jinja2 nodes have an optional auto refresh parameter. If set to `True`, a new prompt is generated for every iteration. However, if set to `False`, a prompt will be downloaded once and used for subsequent generations.
## Roadmap
1. This is a quick and dirty release with some known limitations such as non-configurable random seeds, inability to select the MagicPrompt model, and absence of several other configuration features.
2. Currently, the only way to view the generated prompt is through console output. A future release will introduce nodes to display the generate prompt on screen and to write it to a file.
3. It is not currently possible to chain generators, this functionality will be added in future releases.
5. The installation script will be automated in the future for ease of use.
+5
View File
@@ -0,0 +1,5 @@
from comfy_dynamicprompts.nodes import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
__version__ = "0.1.0"
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
+433
View File
@@ -0,0 +1,433 @@
{
"last_node_id": 11,
"last_link_id": 11,
"nodes": [
{
"id": 4,
"type": "CheckpointLoaderSimple",
"pos": [
-117,
491
],
"size": {
"0": 315,
"1": 98
},
"flags": {},
"order": 0,
"mode": 0,
"outputs": [
{
"name": "MODEL",
"type": "MODEL",
"links": [
1
],
"slot_index": 0
},
{
"name": "CLIP",
"type": "CLIP",
"links": [
3,
5
],
"slot_index": 1
},
{
"name": "VAE",
"type": "VAE",
"links": [
8
],
"slot_index": 2
}
],
"properties": {
"Node name for S&R": "CheckpointLoaderSimple"
},
"widgets_values": [
"v1-5-pruned-emaonly.ckpt"
]
},
{
"id": 3,
"type": "KSampler",
"pos": [
749,
186
],
"size": {
"0": 315,
"1": 262
},
"flags": {
"collapsed": true
},
"order": 5,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "MODEL",
"link": 1
},
{
"name": "positive",
"type": "CONDITIONING",
"link": 4
},
{
"name": "negative",
"type": "CONDITIONING",
"link": 6
},
{
"name": "latent_image",
"type": "LATENT",
"link": 2
}
],
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [
7
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
649510431673174,
"randomize",
20,
8,
"euler",
"normal",
1
]
},
{
"id": 8,
"type": "VAEDecode",
"pos": [
974,
183
],
"size": {
"0": 210,
"1": 46
},
"flags": {
"collapsed": true
},
"order": 6,
"mode": 0,
"inputs": [
{
"name": "samples",
"type": "LATENT",
"link": 7
},
{
"name": "vae",
"type": "VAE",
"link": 8
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
9
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "VAEDecode"
}
},
{
"id": 7,
"type": "CLIPTextEncode",
"pos": [
503,
538
],
"size": {
"0": 425.27801513671875,
"1": 180.6060791015625
},
"flags": {
"collapsed": true
},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "clip",
"type": "CLIP",
"link": 5
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
6
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"text, watermark"
]
},
{
"id": 5,
"type": "EmptyLatentImage",
"pos": [
388,
191
],
"size": {
"0": 315,
"1": 106
},
"flags": {
"collapsed": true
},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [
2
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "EmptyLatentImage"
},
"widgets_values": [
512,
512,
1
]
},
{
"id": 9,
"type": "SaveImage",
"pos": [
1212,
154
],
"size": {
"0": 210,
"1": 270
},
"flags": {},
"order": 7,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 9
}
],
"properties": {},
"widgets_values": [
"ComfyUI"
]
},
{
"id": 6,
"type": "CLIPTextEncode",
"pos": [
406,
56
],
"size": {
"0": 422.84503173828125,
"1": 164.31304931640625
},
"flags": {
"collapsed": true
},
"order": 4,
"mode": 0,
"inputs": [
{
"name": "clip",
"type": "CLIP",
"link": 3
},
{
"name": "text",
"type": "STRING",
"link": 11,
"widget": {
"name": "text",
"config": [
"STRING",
{
"multiline": true
}
]
}
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
4
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
]
},
{
"id": 11,
"type": "DPCombinatorialGenerator",
"pos": [
-245,
28
],
"size": {
"0": 400,
"1": 200
},
"flags": {},
"order": 2,
"mode": 0,
"outputs": [
{
"name": "STRING",
"type": "STRING",
"links": [
11
],
"shape": 3,
"slot_index": 0
}
],
"title": "DP - Combinatorial",
"properties": {
"Node name for S&R": "DPCombinatorialGenerator"
},
"widgets_values": [
"A {red|green|blue} ball by __artists/Photography/by_country/georgia__"
],
"color": "#2a363b",
"bgcolor": "#3f5159"
}
],
"links": [
[
1,
4,
0,
3,
0,
"MODEL"
],
[
2,
5,
0,
3,
3,
"LATENT"
],
[
3,
4,
1,
6,
0,
"CLIP"
],
[
4,
6,
0,
3,
1,
"CONDITIONING"
],
[
5,
4,
1,
7,
0,
"CLIP"
],
[
6,
7,
0,
3,
2,
"CONDITIONING"
],
[
7,
3,
0,
8,
0,
"LATENT"
],
[
8,
4,
2,
8,
1,
"VAE"
],
[
9,
8,
0,
9,
0,
"IMAGE"
],
[
11,
11,
0,
6,
1,
"STRING"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
}
+434
View File
@@ -0,0 +1,434 @@
{
"last_node_id": 12,
"last_link_id": 12,
"nodes": [
{
"id": 4,
"type": "CheckpointLoaderSimple",
"pos": [
-117,
491
],
"size": {
"0": 315,
"1": 98
},
"flags": {},
"order": 0,
"mode": 0,
"outputs": [
{
"name": "MODEL",
"type": "MODEL",
"links": [
1
],
"slot_index": 0
},
{
"name": "CLIP",
"type": "CLIP",
"links": [
3,
5
],
"slot_index": 1
},
{
"name": "VAE",
"type": "VAE",
"links": [
8
],
"slot_index": 2
}
],
"properties": {
"Node name for S&R": "CheckpointLoaderSimple"
},
"widgets_values": [
"v1-5-pruned-emaonly.ckpt"
]
},
{
"id": 3,
"type": "KSampler",
"pos": [
749,
186
],
"size": {
"0": 315,
"1": 262
},
"flags": {
"collapsed": true
},
"order": 5,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "MODEL",
"link": 1
},
{
"name": "positive",
"type": "CONDITIONING",
"link": 4
},
{
"name": "negative",
"type": "CONDITIONING",
"link": 6
},
{
"name": "latent_image",
"type": "LATENT",
"link": 2
}
],
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [
7
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
921027108188161,
"randomize",
20,
8,
"euler",
"normal",
1
]
},
{
"id": 8,
"type": "VAEDecode",
"pos": [
974,
183
],
"size": {
"0": 210,
"1": 46
},
"flags": {
"collapsed": true
},
"order": 6,
"mode": 0,
"inputs": [
{
"name": "samples",
"type": "LATENT",
"link": 7
},
{
"name": "vae",
"type": "VAE",
"link": 8
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
9
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "VAEDecode"
}
},
{
"id": 7,
"type": "CLIPTextEncode",
"pos": [
503,
538
],
"size": {
"0": 425.27801513671875,
"1": 180.6060791015625
},
"flags": {
"collapsed": true
},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "clip",
"type": "CLIP",
"link": 5
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
6
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"text, watermark"
]
},
{
"id": 5,
"type": "EmptyLatentImage",
"pos": [
388,
191
],
"size": {
"0": 315,
"1": 106
},
"flags": {
"collapsed": true
},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [
2
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "EmptyLatentImage"
},
"widgets_values": [
512,
512,
1
]
},
{
"id": 9,
"type": "SaveImage",
"pos": [
1212,
154
],
"size": {
"0": 210,
"1": 270
},
"flags": {},
"order": 7,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 9
}
],
"properties": {},
"widgets_values": [
"ComfyUI"
]
},
{
"id": 6,
"type": "CLIPTextEncode",
"pos": [
364,
77
],
"size": {
"0": 422.84503173828125,
"1": 164.31304931640625
},
"flags": {
"collapsed": true
},
"order": 4,
"mode": 0,
"inputs": [
{
"name": "clip",
"type": "CLIP",
"link": 3
},
{
"name": "text",
"type": "STRING",
"link": 12,
"widget": {
"name": "text",
"config": [
"STRING",
{
"multiline": true
}
]
}
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
4
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
]
},
{
"id": 12,
"type": "DPFeelingLucky",
"pos": [
-193,
50
],
"size": {
"0": 400,
"1": 200
},
"flags": {},
"order": 2,
"mode": 0,
"outputs": [
{
"name": "STRING",
"type": "STRING",
"links": [
12
],
"shape": 3,
"slot_index": 0
}
],
"title": "I'm Feeling Lucky",
"properties": {
"Node name for S&R": "DPFeelingLucky"
},
"widgets_values": [
"A mech warrior",
"Yes"
],
"color": "#2a363b",
"bgcolor": "#3f5159"
}
],
"links": [
[
1,
4,
0,
3,
0,
"MODEL"
],
[
2,
5,
0,
3,
3,
"LATENT"
],
[
3,
4,
1,
6,
0,
"CLIP"
],
[
4,
6,
0,
3,
1,
"CONDITIONING"
],
[
5,
4,
1,
7,
0,
"CLIP"
],
[
6,
7,
0,
3,
2,
"CONDITIONING"
],
[
7,
3,
0,
8,
0,
"LATENT"
],
[
8,
4,
2,
8,
1,
"VAE"
],
[
9,
8,
0,
9,
0,
"IMAGE"
],
[
12,
12,
0,
6,
1,
"STRING"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
}
+433
View File
@@ -0,0 +1,433 @@
{
"last_node_id": 15,
"last_link_id": 14,
"nodes": [
{
"id": 4,
"type": "CheckpointLoaderSimple",
"pos": [
-117,
491
],
"size": {
"0": 315,
"1": 98
},
"flags": {},
"order": 0,
"mode": 0,
"outputs": [
{
"name": "MODEL",
"type": "MODEL",
"links": [
1
],
"slot_index": 0
},
{
"name": "CLIP",
"type": "CLIP",
"links": [
3,
5
],
"slot_index": 1
},
{
"name": "VAE",
"type": "VAE",
"links": [
8
],
"slot_index": 2
}
],
"properties": {
"Node name for S&R": "CheckpointLoaderSimple"
},
"widgets_values": [
"v1-5-pruned-emaonly.ckpt"
]
},
{
"id": 3,
"type": "KSampler",
"pos": [
749,
186
],
"size": {
"0": 315,
"1": 262
},
"flags": {
"collapsed": true
},
"order": 5,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "MODEL",
"link": 1
},
{
"name": "positive",
"type": "CONDITIONING",
"link": 4
},
{
"name": "negative",
"type": "CONDITIONING",
"link": 6
},
{
"name": "latent_image",
"type": "LATENT",
"link": 2
}
],
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [
7
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
692806126811304,
"randomize",
20,
8,
"euler",
"normal",
1
]
},
{
"id": 8,
"type": "VAEDecode",
"pos": [
974,
183
],
"size": {
"0": 210,
"1": 46
},
"flags": {
"collapsed": true
},
"order": 6,
"mode": 0,
"inputs": [
{
"name": "samples",
"type": "LATENT",
"link": 7
},
{
"name": "vae",
"type": "VAE",
"link": 8
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
9
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "VAEDecode"
}
},
{
"id": 7,
"type": "CLIPTextEncode",
"pos": [
503,
538
],
"size": {
"0": 425.27801513671875,
"1": 180.6060791015625
},
"flags": {
"collapsed": true
},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "clip",
"type": "CLIP",
"link": 5
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
6
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"text, watermark"
]
},
{
"id": 5,
"type": "EmptyLatentImage",
"pos": [
388,
191
],
"size": {
"0": 315,
"1": 106
},
"flags": {
"collapsed": true
},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [
2
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "EmptyLatentImage"
},
"widgets_values": [
512,
512,
1
]
},
{
"id": 9,
"type": "SaveImage",
"pos": [
1212,
154
],
"size": {
"0": 210,
"1": 270
},
"flags": {},
"order": 7,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 9
}
],
"properties": {},
"widgets_values": [
"ComfyUI"
]
},
{
"id": 6,
"type": "CLIPTextEncode",
"pos": [
364,
77
],
"size": {
"0": 422.84503173828125,
"1": 164.31304931640625
},
"flags": {
"collapsed": true
},
"order": 4,
"mode": 0,
"inputs": [
{
"name": "clip",
"type": "CLIP",
"link": 3
},
{
"name": "text",
"type": "STRING",
"link": 14,
"widget": {
"name": "text",
"config": [
"STRING",
{
"multiline": true
}
]
}
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
4
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
]
},
{
"id": 15,
"type": "DPJinja",
"pos": [
-209,
50
],
"size": {
"0": 400,
"1": 200
},
"flags": {},
"order": 2,
"mode": 0,
"outputs": [
{
"name": "STRING",
"type": "STRING",
"links": [
14
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "DPJinja"
},
"widgets_values": [
"{{ choice('red', 'blue', 'green') }} ball",
"Yes"
],
"color": "#2a363b",
"bgcolor": "#3f5159"
}
],
"links": [
[
1,
4,
0,
3,
0,
"MODEL"
],
[
2,
5,
0,
3,
3,
"LATENT"
],
[
3,
4,
1,
6,
0,
"CLIP"
],
[
4,
6,
0,
3,
1,
"CONDITIONING"
],
[
5,
4,
1,
7,
0,
"CLIP"
],
[
6,
7,
0,
3,
2,
"CONDITIONING"
],
[
7,
3,
0,
8,
0,
"LATENT"
],
[
8,
4,
2,
8,
1,
"VAE"
],
[
9,
8,
0,
9,
0,
"IMAGE"
],
[
14,
15,
0,
6,
1,
"STRING"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
}
+433
View File
@@ -0,0 +1,433 @@
{
"last_node_id": 14,
"last_link_id": 13,
"nodes": [
{
"id": 4,
"type": "CheckpointLoaderSimple",
"pos": [
-117,
491
],
"size": {
"0": 315,
"1": 98
},
"flags": {},
"order": 0,
"mode": 0,
"outputs": [
{
"name": "MODEL",
"type": "MODEL",
"links": [
1
],
"slot_index": 0
},
{
"name": "CLIP",
"type": "CLIP",
"links": [
3,
5
],
"slot_index": 1
},
{
"name": "VAE",
"type": "VAE",
"links": [
8
],
"slot_index": 2
}
],
"properties": {
"Node name for S&R": "CheckpointLoaderSimple"
},
"widgets_values": [
"v1-5-pruned-emaonly.ckpt"
]
},
{
"id": 3,
"type": "KSampler",
"pos": [
749,
186
],
"size": {
"0": 315,
"1": 262
},
"flags": {
"collapsed": true
},
"order": 5,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "MODEL",
"link": 1
},
{
"name": "positive",
"type": "CONDITIONING",
"link": 4
},
{
"name": "negative",
"type": "CONDITIONING",
"link": 6
},
{
"name": "latent_image",
"type": "LATENT",
"link": 2
}
],
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [
7
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
338617970807747,
"randomize",
20,
8,
"euler",
"normal",
1
]
},
{
"id": 8,
"type": "VAEDecode",
"pos": [
974,
183
],
"size": {
"0": 210,
"1": 46
},
"flags": {
"collapsed": true
},
"order": 6,
"mode": 0,
"inputs": [
{
"name": "samples",
"type": "LATENT",
"link": 7
},
{
"name": "vae",
"type": "VAE",
"link": 8
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
9
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "VAEDecode"
}
},
{
"id": 7,
"type": "CLIPTextEncode",
"pos": [
503,
538
],
"size": {
"0": 425.27801513671875,
"1": 180.6060791015625
},
"flags": {
"collapsed": true
},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "clip",
"type": "CLIP",
"link": 5
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
6
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"text, watermark"
]
},
{
"id": 5,
"type": "EmptyLatentImage",
"pos": [
388,
191
],
"size": {
"0": 315,
"1": 106
},
"flags": {
"collapsed": true
},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [
2
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "EmptyLatentImage"
},
"widgets_values": [
512,
512,
1
]
},
{
"id": 9,
"type": "SaveImage",
"pos": [
1212,
154
],
"size": {
"0": 210,
"1": 270
},
"flags": {},
"order": 7,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 9
}
],
"properties": {},
"widgets_values": [
"ComfyUI"
]
},
{
"id": 6,
"type": "CLIPTextEncode",
"pos": [
364,
77
],
"size": {
"0": 422.84503173828125,
"1": 164.31304931640625
},
"flags": {
"collapsed": true
},
"order": 4,
"mode": 0,
"inputs": [
{
"name": "clip",
"type": "CLIP",
"link": 3
},
{
"name": "text",
"type": "STRING",
"link": 13,
"widget": {
"name": "text",
"config": [
"STRING",
{
"multiline": true
}
]
}
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
4
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
]
},
{
"id": 14,
"type": "DPMagicPrompt",
"pos": [
-271,
51
],
"size": {
"0": 400,
"1": 200
},
"flags": {},
"order": 2,
"mode": 0,
"outputs": [
{
"name": "STRING",
"type": "STRING",
"links": [
13
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "DPMagicPrompt"
},
"widgets_values": [
"A mech warrior",
"Yes"
],
"color": "#2a363b",
"bgcolor": "#3f5159"
}
],
"links": [
[
1,
4,
0,
3,
0,
"MODEL"
],
[
2,
5,
0,
3,
3,
"LATENT"
],
[
3,
4,
1,
6,
0,
"CLIP"
],
[
4,
6,
0,
3,
1,
"CONDITIONING"
],
[
5,
4,
1,
7,
0,
"CLIP"
],
[
6,
7,
0,
3,
2,
"CONDITIONING"
],
[
7,
3,
0,
8,
0,
"LATENT"
],
[
8,
4,
2,
8,
1,
"VAE"
],
[
9,
8,
0,
9,
0,
"IMAGE"
],
[
13,
14,
0,
6,
1,
"STRING"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
}
+433
View File
@@ -0,0 +1,433 @@
{
"last_node_id": 10,
"last_link_id": 10,
"nodes": [
{
"id": 4,
"type": "CheckpointLoaderSimple",
"pos": [
-117,
491
],
"size": {
"0": 315,
"1": 98
},
"flags": {},
"order": 2,
"mode": 0,
"outputs": [
{
"name": "MODEL",
"type": "MODEL",
"links": [
1
],
"slot_index": 0
},
{
"name": "CLIP",
"type": "CLIP",
"links": [
3,
5
],
"slot_index": 1
},
{
"name": "VAE",
"type": "VAE",
"links": [
8
],
"slot_index": 2
}
],
"properties": {
"Node name for S&R": "CheckpointLoaderSimple"
},
"widgets_values": [
"v1-5-pruned-emaonly.ckpt"
]
},
{
"id": 6,
"type": "CLIPTextEncode",
"pos": [
406,
56
],
"size": {
"0": 422.84503173828125,
"1": 164.31304931640625
},
"flags": {
"collapsed": true
},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "clip",
"type": "CLIP",
"link": 3
},
{
"name": "text",
"type": "STRING",
"link": 10,
"widget": {
"name": "text",
"config": [
"STRING",
{
"multiline": true
}
]
}
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
4
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
]
},
{
"id": 3,
"type": "KSampler",
"pos": [
749,
186
],
"size": {
"0": 315,
"1": 262
},
"flags": {
"collapsed": true
},
"order": 5,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "MODEL",
"link": 1
},
{
"name": "positive",
"type": "CONDITIONING",
"link": 4
},
{
"name": "negative",
"type": "CONDITIONING",
"link": 6
},
{
"name": "latent_image",
"type": "LATENT",
"link": 2
}
],
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [
7
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
714776232058319,
"randomize",
20,
8,
"euler",
"normal",
1
]
},
{
"id": 8,
"type": "VAEDecode",
"pos": [
974,
183
],
"size": {
"0": 210,
"1": 46
},
"flags": {
"collapsed": true
},
"order": 6,
"mode": 0,
"inputs": [
{
"name": "samples",
"type": "LATENT",
"link": 7
},
{
"name": "vae",
"type": "VAE",
"link": 8
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
9
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "VAEDecode"
}
},
{
"id": 7,
"type": "CLIPTextEncode",
"pos": [
503,
538
],
"size": {
"0": 425.27801513671875,
"1": 180.6060791015625
},
"flags": {
"collapsed": true
},
"order": 4,
"mode": 0,
"inputs": [
{
"name": "clip",
"type": "CLIP",
"link": 5
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
6
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"text, watermark"
]
},
{
"id": 10,
"type": "DPRandomGenerator",
"pos": [
-130,
30
],
"size": {
"0": 400,
"1": 200
},
"flags": {},
"order": 0,
"mode": 0,
"outputs": [
{
"name": "STRING",
"type": "STRING",
"links": [
10
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "DPRandomGenerator"
},
"widgets_values": [
"A {red|green|blue} ball by __artists/Photography/by_country/georgia__"
],
"color": "#2a363b",
"bgcolor": "#3f5159",
"shape": 4
},
{
"id": 5,
"type": "EmptyLatentImage",
"pos": [
388,
191
],
"size": {
"0": 315,
"1": 106
},
"flags": {
"collapsed": true
},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [
2
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "EmptyLatentImage"
},
"widgets_values": [
512,
512,
1
]
},
{
"id": 9,
"type": "SaveImage",
"pos": [
1212,
154
],
"size": {
"0": 210,
"1": 270
},
"flags": {},
"order": 7,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 9
}
],
"properties": {},
"widgets_values": [
"ComfyUI"
]
}
],
"links": [
[
1,
4,
0,
3,
0,
"MODEL"
],
[
2,
5,
0,
3,
3,
"LATENT"
],
[
3,
4,
1,
6,
0,
"CLIP"
],
[
4,
6,
0,
3,
1,
"CONDITIONING"
],
[
5,
4,
1,
7,
0,
"CLIP"
],
[
6,
7,
0,
3,
2,
"CONDITIONING"
],
[
7,
3,
0,
8,
0,
"LATENT"
],
[
8,
4,
2,
8,
1,
"VAE"
],
[
9,
8,
0,
9,
0,
"IMAGE"
],
[
10,
10,
0,
6,
1,
"STRING"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
}
+367
View File
@@ -0,0 +1,367 @@
{
"last_node_id": 10,
"last_link_id": 11,
"nodes": [
{
"id": 8,
"type": "VAEDecode",
"pos": [
1209,
188
],
"size": {
"0": 210,
"1": 46
},
"flags": {},
"order": 5,
"mode": 0,
"inputs": [
{
"name": "samples",
"type": "LATENT",
"link": 7
},
{
"name": "vae",
"type": "VAE",
"link": 8
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
9
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "VAEDecode"
}
},
{
"id": 5,
"type": "EmptyLatentImage",
"pos": [
439,
743
],
"size": {
"0": 315,
"1": 106
},
"flags": {},
"order": 0,
"mode": 0,
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [
2
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "EmptyLatentImage"
},
"widgets_values": [
512,
512,
1
]
},
{
"id": 7,
"type": "CLIPTextEncode",
"pos": [
179,
431
],
"size": {
"0": 425.27801513671875,
"1": 180.6060791015625
},
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "clip",
"type": "CLIP",
"link": 5
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
6
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"text, watermark"
]
},
{
"id": 3,
"type": "KSampler",
"pos": [
871,
197
],
"size": {
"0": 315,
"1": 262
},
"flags": {},
"order": 4,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "MODEL",
"link": 1
},
{
"name": "positive",
"type": "CONDITIONING",
"link": 11
},
{
"name": "negative",
"type": "CONDITIONING",
"link": 6
},
{
"name": "latent_image",
"type": "LATENT",
"link": 2
}
],
"outputs": [
{
"name": "LATENT",
"type": "LATENT",
"links": [
7
],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
122610977253400,
"randomize",
20,
8,
"euler",
"normal",
1
]
},
{
"id": 9,
"type": "SaveImage",
"pos": [
1451,
189
],
"size": {
"0": 210,
"1": 270
},
"flags": {},
"order": 6,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 9
}
],
"properties": {},
"widgets_values": [
"ComfyUI"
]
},
{
"id": 4,
"type": "CheckpointLoaderSimple",
"pos": [
-385,
105
],
"size": {
"0": 315,
"1": 98
},
"flags": {},
"order": 1,
"mode": 0,
"outputs": [
{
"name": "MODEL",
"type": "MODEL",
"links": [
1
],
"slot_index": 0
},
{
"name": "CLIP",
"type": "CLIP",
"links": [
5,
10
],
"slot_index": 1
},
{
"name": "VAE",
"type": "VAE",
"links": [
8
],
"slot_index": 2
}
],
"properties": {
"Node name for S&R": "CheckpointLoaderSimple"
},
"widgets_values": [
"realisticVisionV40_v40VAE.safetensors"
]
},
{
"id": 10,
"type": "DynamicPrompts",
"pos": [
182,
-92
],
"size": {
"0": 400,
"1": 200
},
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "clip",
"type": "CLIP",
"link": 10
}
],
"outputs": [
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
11
],
"shape": 3,
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "DynamicPrompts"
},
"widgets_values": [
"A {red|green|blue} ball"
]
}
],
"links": [
[
1,
4,
0,
3,
0,
"MODEL"
],
[
2,
5,
0,
3,
3,
"LATENT"
],
[
5,
4,
1,
7,
0,
"CLIP"
],
[
6,
7,
0,
3,
2,
"CONDITIONING"
],
[
7,
3,
0,
8,
0,
"LATENT"
],
[
8,
4,
2,
8,
1,
"VAE"
],
[
9,
8,
0,
9,
0,
"IMAGE"
],
[
10,
4,
1,
10,
0,
"CLIP"
],
[
11,
10,
0,
3,
1,
"CONDITIONING"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 0.4
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 816 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

+24
View File
@@ -0,0 +1,24 @@
from comfy_dynamicprompts.nodes.combinatorial import DPCombinatorialGenerator
from comfy_dynamicprompts.nodes.feeling_lucky import DPFeelingLucky
from comfy_dynamicprompts.nodes.jinja import DPJinja
from comfy_dynamicprompts.nodes.magicprompt import DPMagicPrompt
from comfy_dynamicprompts.nodes.random import DPRandomGenerator
NODE_CLASS_MAPPINGS = {
"DPRandomGenerator": DPRandomGenerator,
"DPCombinatorialGenerator": DPCombinatorialGenerator,
"DPFeelingLucky": DPFeelingLucky,
"DPJinja": DPJinja,
"DPMagicPrompt": DPMagicPrompt,
}
# A dictionary that contains the friendly/humanly readable titles for the nodes
NODE_DISPLAY_NAME_MAPPINGS = {
"DPRandomGenerator": "Random Prompts",
"DPCombinatorialGenerator": "Combinatorial Prompts",
"DPFeelingLucky": "I'm Feeling Lucky",
"DPJinja": "Jinja2 Templates",
"DPMagicPrompt": "Magic Prompt",
}
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
+13
View File
@@ -0,0 +1,13 @@
from dynamicprompts.commands.base import SamplingMethod
from dynamicprompts.sampling_context import SamplingContext
from dynamicprompts.wildcards import WildcardManager
from comfy_dynamicprompts.nodes.sampler import DPAbstractSamplerNode
class DPCombinatorialGenerator(DPAbstractSamplerNode):
def _get_context(self, wildcard_manager: WildcardManager):
self._context = SamplingContext(
wildcard_manager=wildcard_manager,
default_sampling_method=SamplingMethod.COMBINATORIAL,
)
+11
View File
@@ -0,0 +1,11 @@
from dynamicprompts.generators import FeelingLuckyGenerator, RandomPromptGenerator
from comfy_dynamicprompts.nodes.generator import DPGeneratorNode
class DPFeelingLucky(DPGeneratorNode):
def generate_prompt(self, text) -> str:
prompt_generator = FeelingLuckyGenerator(generator=RandomPromptGenerator())
all_prompts = prompt_generator.generate(text, 1) or [""]
return all_prompts[0]
+32
View File
@@ -0,0 +1,32 @@
from abc import ABC, abstractmethod
class DPGeneratorNode(ABC):
RETURN_TYPES = ("STRING",)
FUNCTION = "get_prompt"
CATEGORY = "Dynamic Prompts"
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text": ("PROMPT", {"multiline": True}),
"autorefresh": (["Yes", "No"],),
},
}
@classmethod
def IS_CHANGED(cls, text, autorefresh):
# Force re-evaluation of the node
if autorefresh == "Yes":
return float("NaN")
def get_prompt(self, text: str, autorefresh: str) -> tuple[str]:
prompt = self.generate_prompt(text)
print(f"Prompt: {prompt}")
return (prompt,)
@abstractmethod
def generate_prompt(self, text: str) -> str:
...
+11
View File
@@ -0,0 +1,11 @@
from dynamicprompts.generators import JinjaGenerator
from comfy_dynamicprompts.nodes.generator import DPGeneratorNode
class DPJinja(DPGeneratorNode):
def generate_prompt(self, text):
prompt_generator = JinjaGenerator()
all_prompts = prompt_generator.generate(text, 1) or [""]
return all_prompts[0]
+14
View File
@@ -0,0 +1,14 @@
from dynamicprompts.generators import RandomPromptGenerator
from dynamicprompts.generators.magicprompt import MagicPromptGenerator
from comfy_dynamicprompts.nodes.generator import DPGeneratorNode
class DPMagicPrompt(DPGeneratorNode):
def generate_prompt(self, text):
prompt_generator = MagicPromptGenerator(
prompt_generator=RandomPromptGenerator(),
)
all_prompts = prompt_generator.generate(text, 1) or [""]
return all_prompts[0]
+18
View File
@@ -0,0 +1,18 @@
class OutputString:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"string": ("STRING", {}),
},
}
RETURN_TYPES = ()
FUNCTION = "output_string"
OUTPUT_NODE = True
CATEGORY = "utils"
def output_string(self, string):
return {"ui": {"string": string}}
+13
View File
@@ -0,0 +1,13 @@
from dynamicprompts.commands.base import SamplingMethod
from dynamicprompts.sampling_context import SamplingContext
from dynamicprompts.wildcards import WildcardManager
from comfy_dynamicprompts.nodes.sampler import DPAbstractSamplerNode
class DPRandomGenerator(DPAbstractSamplerNode):
def _get_context(self, wildcard_manager: WildcardManager):
self._context = SamplingContext(
wildcard_manager=wildcard_manager,
default_sampling_method=SamplingMethod.RANDOM,
)
+84
View File
@@ -0,0 +1,84 @@
import logging
from abc import ABC, abstractmethod
from pathlib import Path
from dynamicprompts.wildcards import WildcardManager
logger = logging.getLogger(__name__)
class DPAbstractSamplerNode(ABC):
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text": ("PROMPT", {"dynamicPrompts": False, "multiline": True}),
},
}
@classmethod
def IS_CHANGED(cls, text):
# Force re-evaluation of the node
return float("NaN")
RETURN_TYPES = ("STRING",)
FUNCTION = "get_prompt"
CATEGORY = "Dynamic Prompts"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
wildcards_folder = self._find_wildcards_folder()
self._wildcard_manager = WildcardManager(path=wildcards_folder)
self._sampling_context = self._get_context(self._wildcard_manager)
self._current_prompt = None
def _find_wildcards_folder(self):
wildcards_folder = Path("wildcards")
if wildcards_folder.exists():
return wildcards_folder
wildcards_folder = Path(__file__).parent / "wildcards"
if wildcards_folder.exists():
return wildcards_folder
return None
def _get_next_prompt(self):
"""
Get the next prompt from the prompts generator.
"""
try:
return next(self._prompts)
except StopIteration:
self._prompts = self._context.sample_prompts(self._current_prompt)
try:
return next(self._prompts)
except StopIteration:
logger.exception("No more prompts to generate!")
return ""
def get_prompt(self, text: str) -> str:
"""
Using the sampling context, generate a new prompt.
"""
if text.strip() == "":
return ("",)
if self._current_prompt != text:
self._current_prompt = text
self._prompts = self._context.sample_prompts(self._current_prompt)
if self._prompts is None:
logger.exception("Prompts is None!")
return ("",)
new_prompt = self._get_next_prompt()
logger.info(f"New prompt: {new_prompt}")
logger.info(f"Prompt: {new_prompt}")
print(f"Prompt: {new_prompt}")
return (new_prompt,)
@abstractmethod
def _get_context(self, wildcard_manager: WildcardManager = None):
...
+18
View File
@@ -0,0 +1,18 @@
[tool.ruff]
target-version = "py310"
select = [
"B",
"C",
"COM",
"E",
"F",
"I",
"UP",
]
ignore = [
"C901", # Complexity
"E501", # Line length
]
unfixable = [
"B007", # Loop control variable not used within the loop body
]
+1
View File
@@ -0,0 +1 @@
dynamicprompts
+17
View File
@@ -0,0 +1,17 @@
import {app} from "../scripts/app.js";
import {ComfyWidgets} from "../scripts/widgets.js";
// It is currently not possible to disable the built-in dynamic prompts-like syntax in ComfyUI.
// Until that is fixed, this extension is used to disable it.
const id = "DP.PromptWidget";
app.registerExtension({
name: id,
addCustomNodeDefs(node_defs) {
ComfyWidgets["PROMPT"] = function(node, inputName, inputData, app) {
let stringWidget = ComfyWidgets["STRING"](node, inputName, inputData, app);
stringWidget.widget.dynamicPrompts = false;
return stringWidget;
}
}
});