Skip to content

Commit

Permalink
* Added pyproject.toml to publish to ComfyUI registry.
Browse files Browse the repository at this point in the history
* ComfyUI: optional modelname and model, and allowed sending a classname string instead of a model (#12)
  • Loading branch information
acorderob committed Oct 5, 2024
1 parent 830bd4f commit 0b03e17
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 33 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,14 @@ This should still work as intended, and the only negative point i see is the unn

## Configuration

### ComfyUI specific inputs

* **model**: Connect here the MODEL or a string with the model class name used by ComfyUI. Needed for the model kind system variables.
* **modelname**: Name of the model. Needed for the model name system variables and detection of pony (this also requieres for the model to be SDXL).
* **seed**: Connect here the seed used. By default it is -1 (random).
* **pos_prompt**: Connect here the prompt text, or fill it as a widget.
* **neg_prompt**: Connect here the negative prompt text, or fill it as a widget.

### General settings

* **Debug level**: what to write to the console. Note: in SD.Next debug messages only show if you launch it with the --debug argument.
Expand Down
2 changes: 1 addition & 1 deletion ppp.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
"""

NAME = "Prompt Post-Processor"
VERSION = (2, 6, 0)
VERSION = (2, 7, 0)

class IFWILDCARDS_CHOICES(Enum):
ignore = "ignore"
Expand Down
133 changes: 101 additions & 32 deletions ppp_comfyui.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,30 +28,26 @@ def __init__(self):
self.grammar_content = file.read()
self.wildcards_obj = PPPWildcards(lf.log)

class SmartType(str):
def __ne__(self, other):
if self == "*" or other == "*":
return False
selfset = set(self.split(","))
otherset = set(other.split(","))
return not otherset.issubset(selfset)

@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"model": (
"MODEL",
{
"forceInput": True,
},
),
"modelname": (
"STRING",
{
"default": "",
"forceInput": True,
},
),
"pos_prompt": (
"STRING",
{
"multiline": True,
"default": "",
"dynamicPrompts": False,
"forceInput": True,
"defaultInput": True,
"forceInput": False,
},
),
"neg_prompt": (
Expand All @@ -60,15 +56,34 @@ def INPUT_TYPES(cls):
"multiline": True,
"default": "",
"dynamicPrompts": False,
"forceInput": True,
"defaultInput": True,
"forceInput": False,
},
),
},
"optional": {
"model": (
cls.SmartType("MODEL,STRING"),
{
"default": "",
"placeholder": "internal model class name",
"forceInput": True,
},
),
"modelname": (
"STRING",
{
"default": "",
"placeholder": "full path of the model",
"defaultInput": True,
"forceInput": False,
},
),
"seed": (
"INT",
{
"default": -1,
"defaultInput": True,
"forceInput": False,
},
),
Expand All @@ -77,6 +92,8 @@ def INPUT_TYPES(cls):
{
"default": DEBUG_LEVEL.minimal.value,
"tooltip": "Debug level",
"defaultInput": False,
"forceInput": False,
},
),
"pony_substrings": (
Expand All @@ -85,6 +102,8 @@ def INPUT_TYPES(cls):
"default": PromptPostProcessor.DEFAULT_PONY_SUBSTRINGS,
"placeholder": "comma separated list",
"tooltip": "Comma separated list of substrings to look for in the modelname to determine if the model is a pony model",
"defaultInput": False,
"forceInput": False,
},
),
"wc_process_wildcards": (
Expand All @@ -94,27 +113,35 @@ def INPUT_TYPES(cls):
"tooltip": "Process wildcards in the prompt",
"label_on": "Yes",
"label_off": "No",
"defaultInput": False,
"forceInput": False,
},
),
"wc_wildcards_folders": (
"STRING",
{
"default": "",
"tooltip": "Comma separated list of wildcards folders",
"defaultInput": False,
"forceInput": False,
},
),
"wc_if_wildcards": (
[e.value for e in PromptPostProcessor.IFWILDCARDS_CHOICES],
{
"default": PromptPostProcessor.IFWILDCARDS_CHOICES.ignore.value,
"tooltip": "How to handle invalid wildcards in the prompt",
"defaultInput": False,
"forceInput": False,
},
),
"wc_choice_separator": (
"STRING",
{
"default": PromptPostProcessor.DEFAULT_CHOICE_SEPARATOR,
"tooltip": "Default separator for selected choices",
"defaultInput": False,
"forceInput": False,
},
),
"wc_keep_choices_order": (
Expand All @@ -124,13 +151,17 @@ def INPUT_TYPES(cls):
"tooltip": "Keep the order of the choices in the prompt",
"label_on": "Yes",
"label_off": "No",
"defaultInput": False,
"forceInput": False,
},
),
"stn_separator": (
"STRING",
{
"default": PromptPostProcessor.DEFAULT_STN_SEPARATOR,
"tooltip": "Separator for the content added to the negative prompt",
"defaultInput": False,
"forceInput": False,
},
),
"stn_ignore_repeats": (
Expand All @@ -140,6 +171,8 @@ def INPUT_TYPES(cls):
"tooltip": "Ignore repeated content added to the negative prompt",
"label_on": "Yes",
"label_off": "No",
"defaultInput": False,
"forceInput": False,
},
),
"cleanup_extra_spaces": (
Expand All @@ -149,6 +182,8 @@ def INPUT_TYPES(cls):
"tooltip": "Remove extra spaces",
"label_on": "Yes",
"label_off": "No",
"defaultInput": False,
"forceInput": False,
},
),
"cleanup_empty_constructs": (
Expand All @@ -158,6 +193,8 @@ def INPUT_TYPES(cls):
"tooltip": "Remove empty constructs",
"label_on": "Yes",
"label_off": "No",
"defaultInput": False,
"forceInput": False,
},
),
"cleanup_extra_separators": (
Expand All @@ -167,6 +204,8 @@ def INPUT_TYPES(cls):
"tooltip": "Remove extra separators",
"label_on": "Yes",
"label_off": "No",
"defaultInput": False,
"forceInput": False,
},
),
"cleanup_extra_separators2": (
Expand All @@ -176,6 +215,8 @@ def INPUT_TYPES(cls):
"tooltip": "Remove extra separators (additional cases)",
"label_on": "Yes",
"label_off": "No",
"defaultInput": False,
"forceInput": False,
},
),
"cleanup_breaks": (
Expand All @@ -185,6 +226,8 @@ def INPUT_TYPES(cls):
"tooltip": "Cleanup around BREAKs",
"label_on": "Yes",
"label_off": "No",
"defaultInput": False,
"forceInput": False,
},
),
"cleanup_breaks_eol": (
Expand All @@ -194,6 +237,8 @@ def INPUT_TYPES(cls):
"tooltip": "Set BREAKs in their own line",
"label_on": "Yes",
"label_off": "No",
"defaultInput": False,
"forceInput": False,
},
),
"cleanup_ands": (
Expand All @@ -203,6 +248,8 @@ def INPUT_TYPES(cls):
"tooltip": "Cleanup around ANDs",
"label_on": "Yes",
"label_off": "No",
"defaultInput": False,
"forceInput": False,
},
),
"cleanup_ands_eol": (
Expand All @@ -212,6 +259,8 @@ def INPUT_TYPES(cls):
"tooltip": "Set ANDs in their own line",
"label_on": "Yes",
"label_off": "No",
"defaultInput": False,
"forceInput": False,
},
),
"cleanup_extranetwork_tags": (
Expand All @@ -221,6 +270,8 @@ def INPUT_TYPES(cls):
"tooltip": "Clean up around extra network tags",
"label_on": "Yes",
"label_off": "No",
"defaultInput": False,
"forceInput": False,
},
),
"cleanup_merge_attention": (
Expand All @@ -230,6 +281,8 @@ def INPUT_TYPES(cls):
"tooltip": "Merge nested attention constructs",
"label_on": "Yes",
"label_off": "No",
"defaultInput": False,
"forceInput": False,
},
),
"remove_extranetwork_tags": (
Expand All @@ -239,11 +292,26 @@ def INPUT_TYPES(cls):
"tooltip": "Remove extra network tags",
"label_on": "Yes",
"label_off": "No",
"defaultInput": False,
"forceInput": False,
},
),
},
}

@classmethod
def VALIDATE_INPUTS(cls, input_types: dict[str, str]):
it = cls.INPUT_TYPES()
expected = {
k: cls.SmartType("COMBO,STRING") if isinstance(v[0], list) else v[0] # we allow string for combos
for k, v in {**it["required"], **it["optional"]}.items()
}
for input_name, input_type in input_types.items():
t = expected[input_name]
if input_type != t:
return f"Invalid type for input '{input_name}': {input_type} (expected {t})"
return True

RETURN_TYPES = (
"STRING",
"STRING",
Expand Down Expand Up @@ -286,7 +354,7 @@ def IS_CHANGED(
cleanup_merge_attention,
remove_extranetwork_tags,
):
new_run = {
new_run = { # everything except debug_level
"model": model,
"modelname": modelname,
"pos_prompt": pos_prompt,
Expand Down Expand Up @@ -343,26 +411,27 @@ def process(
cleanup_merge_attention,
remove_extranetwork_tags,
):
modelclass = (
model.model.model_config.__class__.__name__ if model is not None and not isinstance(model, str) else model
) or ""
if modelclass == "":
self.logger.warning("Model class is not provided. System variables might not be properly set.")
if modelname == "":
self.logger.warning("Modelname is not provided. System variables will not be properly set.")
env_info = {
"app": "comfyui",
"models_path": folder_paths.models_dir,
"model_filename": modelname, # path is relative to checkpoints folder
"model_class": model.model.model_config.__class__.__name__,
"is_sd1": model.model.model_config.__class__.__name__ in ("SD15", "SD15_instructpix2pix"),
"is_sd2": model.model.model_config.__class__.__name__ in ("SD20", "SD21UnclipL", "SD21UnclipH"),
"is_sdxl": model.model.model_config.__class__.__name__
in (
"SDXL",
"SDXLRefiner",
"SDXL_instructpix2pix",
"Segmind_Vega",
"KOALA_700M",
"KOALA_1B",
"model_filename": modelname or "", # path is relative to checkpoints folder
"model_class": modelclass,
"is_sd1": modelclass in ("SD15", "SD15_instructpix2pix"),
"is_sd2": modelclass in ("SD20", "SD21UnclipL", "SD21UnclipH"),
"is_sdxl": (
modelclass in ("SDXL", "SDXLRefiner", "SDXL_instructpix2pix", "Segmind_Vega", "KOALA_700M", "KOALA_1B")
),
"is_ssd": model.model.model_config.__class__.__name__ in ("SSD1B"),
"is_sd3": model.model.model_config.__class__.__name__ in ("SD3"),
"is_flux": model.model.model_config.__class__.__name__ in ("Flux"),
"is_auraflow": model.model.model_config.__class__.__name__ in ("AuraFlow"),
"is_ssd": modelclass in ("SSD1B",),
"is_sd3": modelclass in ("SD3",),
"is_flux": modelclass in ("Flux",),
"is_auraflow": modelclass in ("AuraFlow",),
}
# SVD_img2vid, SVD3D_u, SVD3_p, Stable_Zero123, SD_X4Upscaler,
# Stable_Cascade_C, Stable_Cascade_B, StableAudio
Expand Down
15 changes: 15 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[project]
name = "sd-webui-prompt-postprocessor"
description = "Stable Diffusion WebUI & ComfyUI extension to post-process the prompt, including sending content from the prompt to the negative prompt and wildcards."
version = "2.7.0"
license = {file = "LICENSE.txt"}
dependencies = ["lark"]

[project.urls]
Repository = "https://github.com/acorderob/sd-webui-prompt-postprocessor"
# Used by Comfy Registry https://comfyregistry.org

[tool.comfy]
PublisherId = "acorderob"
DisplayName = "sd-webui-prompt-postprocessor"
Icon = ""

0 comments on commit 0b03e17

Please sign in to comment.