Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bfc47d0d53 | ||
|
|
b837f38422 | ||
|
|
5e3c8cbc44 |
@@ -8,17 +8,19 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- "pyproject.toml"
|
- "pyproject.toml"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish-node:
|
publish-node:
|
||||||
name: Publish Custom Node to registry
|
name: Publish Custom Node to registry
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
# if this is a forked repository. Skipping the workflow.
|
if: ${{ github.repository_owner == 'acorderob' }}
|
||||||
if: github.event.repository.fork == false
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Publish Custom Node
|
- name: Publish Custom Node
|
||||||
uses: Comfy-Org/publish-node-action@main
|
uses: Comfy-Org/publish-node-action@v1
|
||||||
with:
|
with:
|
||||||
## Add your own personal access token to your Github Repository secrets and reference it here.
|
## Add your own personal access token to your Github Repository secrets and reference it here.
|
||||||
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
|
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
* **seed**: Connect here the seed used. By default it is -1 (random).
|
* **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.
|
* **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.
|
* **neg_prompt**: Connect here the negative prompt text, or fill it as a widget.
|
||||||
|
* **wc_wildcards_input**: Wildcards definitions (in yaml or json format). Direct input added to the ones found in the wildcards folders. Allows wildcards to be included in the workflow.
|
||||||
|
|
||||||
Other common settings (see [below](#common-settings)) also appear as inputs or widgets.
|
Other common settings (see [below](#common-settings)) also appear as inputs or widgets.
|
||||||
|
|
||||||
@@ -40,6 +41,7 @@ With this prompt: `__quality__, 1girl, ${head:__eyes__, __hair__, __expression__
|
|||||||
|
|
||||||
The default value defines strings for *Pony* and *Illustrious* models.
|
The default value defines strings for *Pony* and *Illustrious* models.
|
||||||
* **Apply in img2img**: check if you want to do the processing in img2img processes (*does not apply to the ComfyUI node*).
|
* **Apply in img2img**: check if you want to do the processing in img2img processes (*does not apply to the ComfyUI node*).
|
||||||
|
* **Add original prompts to metadata**: adds original prompts to the metadata if they have changed (*does not apply to the ComfyUI node*).
|
||||||
|
|
||||||
### Wildcard settings
|
### Wildcard settings
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import logging
|
|||||||
import math
|
import math
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
import time
|
import time
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
@@ -9,11 +10,12 @@ from enum import Enum
|
|||||||
from typing import Any, Callable, Optional
|
from typing import Any, Callable, Optional
|
||||||
|
|
||||||
import lark
|
import lark
|
||||||
import lark.parsers
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from ppp_logging import DEBUG_LEVEL
|
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||||
from ppp_wildcards import PPPWildcard, PPPWildcards
|
|
||||||
|
from ppp_logging import DEBUG_LEVEL # pylint: disable=import-error
|
||||||
|
from ppp_wildcards import PPPWildcard, PPPWildcards # pylint: disable=import-error
|
||||||
|
|
||||||
|
|
||||||
class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-instance-attributes
|
class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-instance-attributes
|
||||||
@@ -119,7 +121,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
|||||||
self.wil_keep_choices_order = options.get("keep_choices_order", False)
|
self.wil_keep_choices_order = options.get("keep_choices_order", False)
|
||||||
self.wil_choice_separator = options.get("choice_separator", self.DEFAULT_CHOICE_SEPARATOR)
|
self.wil_choice_separator = options.get("choice_separator", self.DEFAULT_CHOICE_SEPARATOR)
|
||||||
self.wil_ifwildcards = self.IFWILDCARDS_CHOICES(
|
self.wil_ifwildcards = self.IFWILDCARDS_CHOICES(
|
||||||
options.get("if_wildcards", self.IFWILDCARDS_CHOICES.ignore.value)
|
options.get("if_wildcards", self.IFWILDCARDS_CHOICES.stop.value)
|
||||||
)
|
)
|
||||||
# Send to negative options
|
# Send to negative options
|
||||||
self.stn_ignore_repeats = options.get("stn_ignore_repeats", True)
|
self.stn_ignore_repeats = options.get("stn_ignore_repeats", True)
|
||||||
@@ -220,6 +222,11 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
|||||||
for model_name, model_type_and_substrings in self.variants_definitions.items()
|
for model_name, model_type_and_substrings in self.variants_definitions.items()
|
||||||
if model_name not in self.SUPPORTED_MODELS
|
if model_name not in self.SUPPORTED_MODELS
|
||||||
}
|
}
|
||||||
|
is_models_true = [k for k, v in is_models.items() if v]
|
||||||
|
if len(is_models_true) > 1:
|
||||||
|
self.logger.warning(
|
||||||
|
f"Multiple model variants detected at the same time in the filename!: {', '.join(is_models_true)}"
|
||||||
|
)
|
||||||
self.system_variables.update({"_is_" + x: y for x, y in is_models.items()})
|
self.system_variables.update({"_is_" + x: y for x, y in is_models.items()})
|
||||||
for x in sdchecks.keys():
|
for x in sdchecks.keys():
|
||||||
if x != "":
|
if x != "":
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ from collections import OrderedDict
|
|||||||
from logging import Logger
|
from logging import Logger
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
from ppp_logging import DEBUG_LEVEL
|
from ppp_logging import DEBUG_LEVEL # pylint: disable=import-error
|
||||||
|
|
||||||
|
|
||||||
class PPPLRUCache:
|
class PPPLRUCache:
|
||||||
|
|||||||
+37
-57
@@ -1,5 +1,3 @@
|
|||||||
# pylint: disable=missing-module-docstring, missing-class-docstring, missing-function-docstring, invalid-name
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# pylint: disable=import-error
|
# pylint: disable=import-error
|
||||||
@@ -48,8 +46,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"multiline": True,
|
"multiline": True,
|
||||||
"default": "",
|
"default": "",
|
||||||
"dynamicPrompts": False,
|
"dynamicPrompts": False,
|
||||||
"defaultInput": True,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"neg_prompt": (
|
"neg_prompt": (
|
||||||
@@ -58,8 +54,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"multiline": True,
|
"multiline": True,
|
||||||
"default": "",
|
"default": "",
|
||||||
"dynamicPrompts": False,
|
"dynamicPrompts": False,
|
||||||
"defaultInput": True,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -77,16 +71,13 @@ class PromptPostProcessorComfyUINode:
|
|||||||
{
|
{
|
||||||
"default": "",
|
"default": "",
|
||||||
"placeholder": "full path of the model",
|
"placeholder": "full path of the model",
|
||||||
"defaultInput": True,
|
"dynamicPrompts": False,
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"seed": (
|
"seed": (
|
||||||
"INT",
|
"INT",
|
||||||
{
|
{
|
||||||
"default": -1,
|
"default": -1,
|
||||||
"defaultInput": True,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"debug_level": (
|
"debug_level": (
|
||||||
@@ -94,8 +85,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
{
|
{
|
||||||
"default": DEBUG_LEVEL.minimal.value,
|
"default": DEBUG_LEVEL.minimal.value,
|
||||||
"tooltip": "Debug level",
|
"tooltip": "Debug level",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"variants_definitions": (
|
"variants_definitions": (
|
||||||
@@ -105,8 +94,7 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"multiline": True,
|
"multiline": True,
|
||||||
"placeholder": "",
|
"placeholder": "",
|
||||||
"tooltip": "Definitions for variant models to be recognized based on strings found in the full filename. Format for each line is: 'name(kind)=comma separated list of substrings (case insensitive)' with kind being one of the base model types or not specified",
|
"tooltip": "Definitions for variant models to be recognized based on strings found in the full filename. Format for each line is: 'name(kind)=comma separated list of substrings (case insensitive)' with kind being one of the base model types or not specified",
|
||||||
"defaultInput": False,
|
"dynamicPrompts": False,
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"wc_process_wildcards": (
|
"wc_process_wildcards": (
|
||||||
@@ -116,8 +104,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"tooltip": "Process wildcards in the prompt",
|
"tooltip": "Process wildcards in the prompt",
|
||||||
"label_on": "Yes",
|
"label_on": "Yes",
|
||||||
"label_off": "No",
|
"label_off": "No",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"wc_wildcards_folders": (
|
"wc_wildcards_folders": (
|
||||||
@@ -125,17 +111,24 @@ class PromptPostProcessorComfyUINode:
|
|||||||
{
|
{
|
||||||
"default": "",
|
"default": "",
|
||||||
"tooltip": "Comma separated list of wildcards folders",
|
"tooltip": "Comma separated list of wildcards folders",
|
||||||
"defaultInput": False,
|
"dynamicPrompts": False,
|
||||||
"forceInput": False,
|
},
|
||||||
|
),
|
||||||
|
"wc_wildcards_input": (
|
||||||
|
"STRING",
|
||||||
|
{
|
||||||
|
"default": "",
|
||||||
|
"multiline": True,
|
||||||
|
"placeholder": "wildcards definitions",
|
||||||
|
"tooltip": "Wildcards definitions in yaml/json format",
|
||||||
|
"dynamicPrompts": False,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"wc_if_wildcards": (
|
"wc_if_wildcards": (
|
||||||
[e.value for e in PromptPostProcessor.IFWILDCARDS_CHOICES],
|
[e.value for e in PromptPostProcessor.IFWILDCARDS_CHOICES],
|
||||||
{
|
{
|
||||||
"default": PromptPostProcessor.IFWILDCARDS_CHOICES.ignore.value,
|
"default": PromptPostProcessor.IFWILDCARDS_CHOICES.stop.value,
|
||||||
"tooltip": "How to handle invalid wildcards in the prompt",
|
"tooltip": "How to handle invalid wildcards in the prompt",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"wc_choice_separator": (
|
"wc_choice_separator": (
|
||||||
@@ -143,8 +136,7 @@ class PromptPostProcessorComfyUINode:
|
|||||||
{
|
{
|
||||||
"default": PromptPostProcessor.DEFAULT_CHOICE_SEPARATOR,
|
"default": PromptPostProcessor.DEFAULT_CHOICE_SEPARATOR,
|
||||||
"tooltip": "Default separator for selected choices",
|
"tooltip": "Default separator for selected choices",
|
||||||
"defaultInput": False,
|
"dynamicPrompts": False,
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"wc_keep_choices_order": (
|
"wc_keep_choices_order": (
|
||||||
@@ -154,8 +146,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"tooltip": "Keep the order of the choices in the prompt",
|
"tooltip": "Keep the order of the choices in the prompt",
|
||||||
"label_on": "Yes",
|
"label_on": "Yes",
|
||||||
"label_off": "No",
|
"label_off": "No",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"stn_separator": (
|
"stn_separator": (
|
||||||
@@ -163,8 +153,7 @@ class PromptPostProcessorComfyUINode:
|
|||||||
{
|
{
|
||||||
"default": PromptPostProcessor.DEFAULT_STN_SEPARATOR,
|
"default": PromptPostProcessor.DEFAULT_STN_SEPARATOR,
|
||||||
"tooltip": "Separator for the content added to the negative prompt",
|
"tooltip": "Separator for the content added to the negative prompt",
|
||||||
"defaultInput": False,
|
"dynamicPrompts": False,
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"stn_ignore_repeats": (
|
"stn_ignore_repeats": (
|
||||||
@@ -174,8 +163,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"tooltip": "Ignore repeated content added to the negative prompt",
|
"tooltip": "Ignore repeated content added to the negative prompt",
|
||||||
"label_on": "Yes",
|
"label_on": "Yes",
|
||||||
"label_off": "No",
|
"label_off": "No",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"cleanup_extra_spaces": (
|
"cleanup_extra_spaces": (
|
||||||
@@ -185,8 +172,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"tooltip": "Remove extra spaces",
|
"tooltip": "Remove extra spaces",
|
||||||
"label_on": "Yes",
|
"label_on": "Yes",
|
||||||
"label_off": "No",
|
"label_off": "No",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"cleanup_empty_constructs": (
|
"cleanup_empty_constructs": (
|
||||||
@@ -196,8 +181,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"tooltip": "Remove empty constructs",
|
"tooltip": "Remove empty constructs",
|
||||||
"label_on": "Yes",
|
"label_on": "Yes",
|
||||||
"label_off": "No",
|
"label_off": "No",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"cleanup_extra_separators": (
|
"cleanup_extra_separators": (
|
||||||
@@ -207,8 +190,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"tooltip": "Remove extra separators",
|
"tooltip": "Remove extra separators",
|
||||||
"label_on": "Yes",
|
"label_on": "Yes",
|
||||||
"label_off": "No",
|
"label_off": "No",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"cleanup_extra_separators2": (
|
"cleanup_extra_separators2": (
|
||||||
@@ -218,8 +199,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"tooltip": "Remove extra separators (additional cases)",
|
"tooltip": "Remove extra separators (additional cases)",
|
||||||
"label_on": "Yes",
|
"label_on": "Yes",
|
||||||
"label_off": "No",
|
"label_off": "No",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"cleanup_breaks": (
|
"cleanup_breaks": (
|
||||||
@@ -229,8 +208,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"tooltip": "Cleanup around BREAKs",
|
"tooltip": "Cleanup around BREAKs",
|
||||||
"label_on": "Yes",
|
"label_on": "Yes",
|
||||||
"label_off": "No",
|
"label_off": "No",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"cleanup_breaks_eol": (
|
"cleanup_breaks_eol": (
|
||||||
@@ -240,8 +217,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"tooltip": "Set BREAKs in their own line",
|
"tooltip": "Set BREAKs in their own line",
|
||||||
"label_on": "Yes",
|
"label_on": "Yes",
|
||||||
"label_off": "No",
|
"label_off": "No",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"cleanup_ands": (
|
"cleanup_ands": (
|
||||||
@@ -251,8 +226,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"tooltip": "Cleanup around ANDs",
|
"tooltip": "Cleanup around ANDs",
|
||||||
"label_on": "Yes",
|
"label_on": "Yes",
|
||||||
"label_off": "No",
|
"label_off": "No",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"cleanup_ands_eol": (
|
"cleanup_ands_eol": (
|
||||||
@@ -262,8 +235,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"tooltip": "Set ANDs in their own line",
|
"tooltip": "Set ANDs in their own line",
|
||||||
"label_on": "Yes",
|
"label_on": "Yes",
|
||||||
"label_off": "No",
|
"label_off": "No",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"cleanup_extranetwork_tags": (
|
"cleanup_extranetwork_tags": (
|
||||||
@@ -273,8 +244,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"tooltip": "Clean up around extra network tags",
|
"tooltip": "Clean up around extra network tags",
|
||||||
"label_on": "Yes",
|
"label_on": "Yes",
|
||||||
"label_off": "No",
|
"label_off": "No",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"cleanup_merge_attention": (
|
"cleanup_merge_attention": (
|
||||||
@@ -284,8 +253,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"tooltip": "Merge nested attention constructs",
|
"tooltip": "Merge nested attention constructs",
|
||||||
"label_on": "Yes",
|
"label_on": "Yes",
|
||||||
"label_off": "No",
|
"label_off": "No",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
"remove_extranetwork_tags": (
|
"remove_extranetwork_tags": (
|
||||||
@@ -295,8 +262,6 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"tooltip": "Remove extra network tags",
|
"tooltip": "Remove extra network tags",
|
||||||
"label_on": "Yes",
|
"label_on": "Yes",
|
||||||
"label_off": "No",
|
"label_off": "No",
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -342,6 +307,7 @@ class PromptPostProcessorComfyUINode:
|
|||||||
variants_definitions,
|
variants_definitions,
|
||||||
wc_process_wildcards,
|
wc_process_wildcards,
|
||||||
wc_wildcards_folders,
|
wc_wildcards_folders,
|
||||||
|
wc_wildcards_input,
|
||||||
wc_if_wildcards,
|
wc_if_wildcards,
|
||||||
wc_choice_separator,
|
wc_choice_separator,
|
||||||
wc_keep_choices_order,
|
wc_keep_choices_order,
|
||||||
@@ -372,6 +338,7 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"variants_definitions": variants_definitions,
|
"variants_definitions": variants_definitions,
|
||||||
"process_wildcards": wc_process_wildcards,
|
"process_wildcards": wc_process_wildcards,
|
||||||
"wildcards_folders": wc_wildcards_folders,
|
"wildcards_folders": wc_wildcards_folders,
|
||||||
|
"wildcards_input": wc_wildcards_input,
|
||||||
"if_wildcards": wc_if_wildcards,
|
"if_wildcards": wc_if_wildcards,
|
||||||
"choice_separator": wc_choice_separator,
|
"choice_separator": wc_choice_separator,
|
||||||
"keep_choices_order": wc_keep_choices_order,
|
"keep_choices_order": wc_keep_choices_order,
|
||||||
@@ -403,6 +370,7 @@ class PromptPostProcessorComfyUINode:
|
|||||||
variants_definitions,
|
variants_definitions,
|
||||||
wc_process_wildcards,
|
wc_process_wildcards,
|
||||||
wc_wildcards_folders,
|
wc_wildcards_folders,
|
||||||
|
wc_wildcards_input,
|
||||||
wc_if_wildcards,
|
wc_if_wildcards,
|
||||||
wc_choice_separator,
|
wc_choice_separator,
|
||||||
wc_keep_choices_order,
|
wc_keep_choices_order,
|
||||||
@@ -427,13 +395,14 @@ class PromptPostProcessorComfyUINode:
|
|||||||
self.logger.warning("Model class is not provided. System variables might not be properly set.")
|
self.logger.warning("Model class is not provided. System variables might not be properly set.")
|
||||||
if modelname == "":
|
if modelname == "":
|
||||||
self.logger.warning("Modelname is not provided. System variables will not be properly set.")
|
self.logger.warning("Modelname is not provided. System variables will not be properly set.")
|
||||||
|
# model class values in ComfyUI\comfy\supported_models.py
|
||||||
env_info = {
|
env_info = {
|
||||||
"app": "comfyui",
|
"app": "comfyui",
|
||||||
"models_path": folder_paths.models_dir,
|
"models_path": folder_paths.models_dir,
|
||||||
"model_filename": modelname or "", # path is relative to checkpoints folder
|
"model_filename": modelname or "", # path is relative to checkpoints folder
|
||||||
"model_class": modelclass,
|
"model_class": modelclass,
|
||||||
"is_sd1": modelclass in ("SD15", "SD15_instructpix2pix"),
|
"is_sd1": modelclass in ("SD15", "SD15_instructpix2pix"),
|
||||||
"is_sd2": modelclass in ("SD20", "SD21UnclipL", "SD21UnclipH"),
|
"is_sd2": modelclass in ("SD20", "SD21UnclipL", "SD21UnclipH", "LotusD"),
|
||||||
"is_sdxl": (
|
"is_sdxl": (
|
||||||
modelclass in ("SDXL", "SDXLRefiner", "SDXL_instructpix2pix", "Segmind_Vega", "KOALA_700M", "KOALA_1B")
|
modelclass in ("SDXL", "SDXLRefiner", "SDXL_instructpix2pix", "Segmind_Vega", "KOALA_700M", "KOALA_1B")
|
||||||
),
|
),
|
||||||
@@ -441,9 +410,18 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"is_sd3": modelclass in ("SD3",),
|
"is_sd3": modelclass in ("SD3",),
|
||||||
"is_flux": modelclass in ("Flux", "FluxInpaint", "FluxSchnell"),
|
"is_flux": modelclass in ("Flux", "FluxInpaint", "FluxSchnell"),
|
||||||
"is_auraflow": modelclass in ("AuraFlow",),
|
"is_auraflow": modelclass in ("AuraFlow",),
|
||||||
|
"is_pixart": modelclass in ("PixArtAlpha", "PixArtSigma"),
|
||||||
|
"is_lumina2": modelclass in ("Lumina2",),
|
||||||
|
"is_ltxv": modelclass in ("LTXV",),
|
||||||
|
"is_cosmos": modelclass in ("CosmosT2V", "CosmosI2V"),
|
||||||
|
"is_genmomochi": modelclass in ("GenmoMochi",),
|
||||||
|
"is_hunyuan": modelclass in ("HunyuanDiT", "HunyuanDiT1"),
|
||||||
|
"is_hunyuanvideo": modelclass in ("HunyuanVideo", "HunyuanVideoI2V", "HunyuanVideoSkyreelsI2V"),
|
||||||
|
"is_hunyuan3d": modelclass in ("Hunyuan3Dv2", "Hunyuan3Dv2mini"),
|
||||||
|
"is_wanvideo": modelclass in ("WAN21_T2V", "WAN21_I2V", "WAN21_FunControl2V"),
|
||||||
|
"is_hidream": modelclass in ("HiDream",),
|
||||||
}
|
}
|
||||||
# Also supported: SVD_img2vid, SVD3D_u, SVD3_p, Stable_Zero123, SD_X4Upscaler,
|
# Also supported: SVD_img2vid, SVD3D_u, SVD3_p, Stable_Zero123, SD_X4Upscaler, Stable_Cascade_C, Stable_Cascade_B, StableAudio
|
||||||
# Stable_Cascade_C, Stable_Cascade_B, StableAudio, HunyuanDiT, HunyuanDiT1, GenmoMochi, LTXV
|
|
||||||
|
|
||||||
if wc_wildcards_folders == "":
|
if wc_wildcards_folders == "":
|
||||||
wc_wildcards_folders = ",".join(folder_paths.get_folder_paths("wildcards") or [])
|
wc_wildcards_folders = ",".join(folder_paths.get_folder_paths("wildcards") or [])
|
||||||
@@ -477,7 +455,11 @@ class PromptPostProcessorComfyUINode:
|
|||||||
"cleanup_merge_attention": cleanup_merge_attention,
|
"cleanup_merge_attention": cleanup_merge_attention,
|
||||||
"remove_extranetwork_tags": remove_extranetwork_tags,
|
"remove_extranetwork_tags": remove_extranetwork_tags,
|
||||||
}
|
}
|
||||||
self.wildcards_obj.refresh_wildcards(debug_level, wildcards_folders if options["process_wildcards"] else None)
|
self.wildcards_obj.refresh_wildcards(
|
||||||
|
debug_level,
|
||||||
|
wildcards_folders if options["process_wildcards"] else None,
|
||||||
|
wc_wildcards_input,
|
||||||
|
)
|
||||||
ppp = PromptPostProcessor(
|
ppp = PromptPostProcessor(
|
||||||
self.logger, self.interrupt, env_info, options, self.grammar_content, self.wildcards_obj
|
self.logger, self.interrupt, env_info, options, self.grammar_content, self.wildcards_obj
|
||||||
)
|
)
|
||||||
@@ -519,8 +501,6 @@ class PromptPostProcessorSelectVariableComfyUINode:
|
|||||||
"multiline": False,
|
"multiline": False,
|
||||||
"default": "",
|
"default": "",
|
||||||
"dynamicPrompts": False,
|
"dynamicPrompts": False,
|
||||||
"defaultInput": False,
|
|
||||||
"forceInput": False,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
+59
-29
@@ -1,11 +1,10 @@
|
|||||||
import fnmatch
|
import fnmatch
|
||||||
import os
|
import os
|
||||||
import json
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
import logging
|
import logging
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from ppp_logging import DEBUG_LEVEL
|
from ppp_logging import DEBUG_LEVEL # pylint: disable=import-error
|
||||||
|
|
||||||
|
|
||||||
def deep_freeze(obj):
|
def deep_freeze(obj):
|
||||||
@@ -20,12 +19,11 @@ def deep_freeze(obj):
|
|||||||
"""
|
"""
|
||||||
if isinstance(obj, dict):
|
if isinstance(obj, dict):
|
||||||
return tuple((k, deep_freeze(v)) for k, v in sorted(obj.items()))
|
return tuple((k, deep_freeze(v)) for k, v in sorted(obj.items()))
|
||||||
elif isinstance(obj, list):
|
if isinstance(obj, list):
|
||||||
return tuple(deep_freeze(i) for i in obj)
|
return tuple(deep_freeze(i) for i in obj)
|
||||||
elif isinstance(obj, set):
|
if isinstance(obj, set):
|
||||||
return tuple(deep_freeze(i) for i in sorted(obj))
|
return tuple(deep_freeze(i) for i in sorted(obj))
|
||||||
else:
|
return obj
|
||||||
return obj
|
|
||||||
|
|
||||||
|
|
||||||
class PPPWildcard:
|
class PPPWildcard:
|
||||||
@@ -70,6 +68,7 @@ class PPPWildcards:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
DEFAULT_WILDCARDS_FOLDER = "wildcards"
|
DEFAULT_WILDCARDS_FOLDER = "wildcards"
|
||||||
|
LOCALINPUT_FILENAME = "#INPUT"
|
||||||
|
|
||||||
def __init__(self, logger):
|
def __init__(self, logger):
|
||||||
self.__logger: logging.Logger = logger
|
self.__logger: logging.Logger = logger
|
||||||
@@ -84,31 +83,38 @@ class PPPWildcards:
|
|||||||
def __sizeof__(self):
|
def __sizeof__(self):
|
||||||
return self.wildcards.__sizeof__() + self.__wildcards_folders.__sizeof__() + self.__wildcard_files.__sizeof__()
|
return self.wildcards.__sizeof__() + self.__wildcards_folders.__sizeof__() + self.__wildcard_files.__sizeof__()
|
||||||
|
|
||||||
def refresh_wildcards(self, debug_level: DEBUG_LEVEL, wildcards_folders: Optional[list[str]]):
|
def refresh_wildcards(
|
||||||
|
self, debug_level: DEBUG_LEVEL, wildcards_folders: Optional[list[str]], wildcards_input: str = None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Initialize the wildcards.
|
Initialize the wildcards.
|
||||||
"""
|
"""
|
||||||
self.__debug_level = debug_level
|
self.__debug_level = debug_level
|
||||||
self.__wildcards_folders = wildcards_folders
|
self.__wildcards_folders = wildcards_folders or []
|
||||||
if wildcards_folders is not None:
|
# if self.debug_level != DEBUG_LEVEL.none:
|
||||||
# if self.debug_level != DEBUG_LEVEL.none:
|
# self.logger.info("Refreshing wildcards...")
|
||||||
# self.logger.info("Initializing wildcards...")
|
# t1 = time.time()
|
||||||
# t1 = time.time()
|
for fullpath in list(self.__wildcard_files.keys()):
|
||||||
for fullpath in list(self.__wildcard_files.keys()):
|
if fullpath != self.LOCALINPUT_FILENAME:
|
||||||
path = os.path.dirname(fullpath)
|
path = os.path.dirname(fullpath)
|
||||||
if not os.path.exists(fullpath) or not any(
|
if not os.path.exists(fullpath) or not any(
|
||||||
os.path.commonpath([path, folder]) == folder for folder in self.__wildcards_folders
|
os.path.commonpath([path, folder]) == folder for folder in self.__wildcards_folders
|
||||||
):
|
):
|
||||||
self.__remove_wildcards_from_file(fullpath)
|
self.__remove_wildcards_from_path(fullpath)
|
||||||
for f in self.__wildcards_folders:
|
elif wildcards_input is None:
|
||||||
self.__get_wildcards_in_directory(f, f)
|
self.__remove_wildcards_from_path(fullpath)
|
||||||
# t2 = time.time()
|
if wildcards_folders is not None or wildcards_input is not None:
|
||||||
# if self.debug_level != DEBUG_LEVEL.none:
|
if wildcards_folders is not None:
|
||||||
# self.logger.info(f"Wildcards init time: {t2 - t1:.3f} seconds")
|
for f in self.__wildcards_folders:
|
||||||
|
self.__get_wildcards_in_directory(f, f)
|
||||||
|
if wildcards_input is not None:
|
||||||
|
self.__get_wildcards_in_input(wildcards_input)
|
||||||
else:
|
else:
|
||||||
self.__wildcards_folders = []
|
|
||||||
self.wildcards = {}
|
self.wildcards = {}
|
||||||
self.__wildcard_files = {}
|
self.__wildcard_files = {}
|
||||||
|
# t2 = time.time()
|
||||||
|
# if self.debug_level != DEBUG_LEVEL.none:
|
||||||
|
# self.logger.info(f"Wildcards refresh time: {t2 - t1:.3f} seconds")
|
||||||
|
|
||||||
def get_wildcards(self, key: str) -> list[PPPWildcard]:
|
def get_wildcards(self, key: str) -> list[PPPWildcard]:
|
||||||
"""
|
"""
|
||||||
@@ -161,7 +167,7 @@ class PPPWildcards:
|
|||||||
return None
|
return None
|
||||||
return current_dict
|
return current_dict
|
||||||
|
|
||||||
def __remove_wildcards_from_file(self, full_path: str, debug=True):
|
def __remove_wildcards_from_path(self, full_path: str, debug=True):
|
||||||
"""
|
"""
|
||||||
Clear all wildcards in a file.
|
Clear all wildcards in a file.
|
||||||
|
|
||||||
@@ -169,9 +175,12 @@ class PPPWildcards:
|
|||||||
full_path (str): The path to the file.
|
full_path (str): The path to the file.
|
||||||
debug (bool): Whether to print debug messages or not.
|
debug (bool): Whether to print debug messages or not.
|
||||||
"""
|
"""
|
||||||
last_modified_cached = self.__wildcard_files.get(full_path, None)
|
last_modified_cached = self.__wildcard_files.get(full_path, None) # a time or a hash
|
||||||
if debug and last_modified_cached is not None and self.__debug_level != DEBUG_LEVEL.none:
|
if debug and last_modified_cached is not None and self.__debug_level != DEBUG_LEVEL.none:
|
||||||
self.__logger.debug(f"Removing wildcards from file: {full_path}")
|
if full_path == self.LOCALINPUT_FILENAME:
|
||||||
|
self.__logger.debug("Removing wildcards from input")
|
||||||
|
else:
|
||||||
|
self.__logger.debug(f"Removing wildcards from file: {full_path}")
|
||||||
if full_path in self.__wildcard_files.keys():
|
if full_path in self.__wildcard_files.keys():
|
||||||
del self.__wildcard_files[full_path]
|
del self.__wildcard_files[full_path]
|
||||||
for key in list(self.wildcards.keys()):
|
for key in list(self.wildcards.keys()):
|
||||||
@@ -194,7 +203,7 @@ class PPPWildcards:
|
|||||||
_, extension = os.path.splitext(filename)
|
_, extension = os.path.splitext(filename)
|
||||||
if extension not in (".txt", ".json", ".yaml", ".yml"):
|
if extension not in (".txt", ".json", ".yaml", ".yml"):
|
||||||
return
|
return
|
||||||
self.__remove_wildcards_from_file(full_path, False)
|
self.__remove_wildcards_from_path(full_path, False)
|
||||||
if last_modified_cached is not None and self.__debug_level != DEBUG_LEVEL.none:
|
if last_modified_cached is not None and self.__debug_level != DEBUG_LEVEL.none:
|
||||||
self.__logger.debug(f"Updating wildcards from file: {full_path}")
|
self.__logger.debug(f"Updating wildcards from file: {full_path}")
|
||||||
if extension == ".txt":
|
if extension == ".txt":
|
||||||
@@ -203,6 +212,31 @@ class PPPWildcards:
|
|||||||
self.__get_wildcards_in_structured_file(full_path, base)
|
self.__get_wildcards_in_structured_file(full_path, base)
|
||||||
self.__wildcard_files[full_path] = last_modified
|
self.__wildcard_files[full_path] = last_modified
|
||||||
|
|
||||||
|
def __get_wildcards_in_input(self, wildcards_input: str):
|
||||||
|
"""
|
||||||
|
Get all wildcards in the string.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
wildcards_input (str): The input string containing wildcards in json or yaml format.
|
||||||
|
"""
|
||||||
|
new_h = hash(wildcards_input)
|
||||||
|
h = self.__wildcard_files.get(self.LOCALINPUT_FILENAME, None)
|
||||||
|
if h == new_h:
|
||||||
|
return
|
||||||
|
self.__remove_wildcards_from_path(self.LOCALINPUT_FILENAME, False)
|
||||||
|
if h is not None and self.__debug_level != DEBUG_LEVEL.none:
|
||||||
|
self.__logger.debug("Updating wildcards from input")
|
||||||
|
wildcards_input = wildcards_input.strip()
|
||||||
|
if wildcards_input != "":
|
||||||
|
try:
|
||||||
|
content = yaml.safe_load(wildcards_input)
|
||||||
|
except yaml.YAMLError as e:
|
||||||
|
self.__logger.warning(f"Invalid format for input wildcards: {e}")
|
||||||
|
return
|
||||||
|
if content is not None:
|
||||||
|
self.__add_wildcard(content, self.LOCALINPUT_FILENAME, [self.LOCALINPUT_FILENAME])
|
||||||
|
self.__wildcard_files[self.LOCALINPUT_FILENAME] = new_h
|
||||||
|
|
||||||
def is_dict_choices_options(self, d: dict) -> bool:
|
def is_dict_choices_options(self, d: dict) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if a dictionary is a valid choices options dictionary.
|
Check if a dictionary is a valid choices options dictionary.
|
||||||
@@ -374,12 +408,8 @@ class PPPWildcards:
|
|||||||
"""
|
"""
|
||||||
external_key: str = os.path.relpath(os.path.splitext(full_path)[0], base)
|
external_key: str = os.path.relpath(os.path.splitext(full_path)[0], base)
|
||||||
external_key_parts = external_key.split(os.sep)
|
external_key_parts = external_key.split(os.sep)
|
||||||
_, extension = os.path.splitext(full_path)
|
|
||||||
with open(full_path, "r", encoding="utf-8") as file:
|
with open(full_path, "r", encoding="utf-8") as file:
|
||||||
if extension == ".json":
|
content = yaml.safe_load(file)
|
||||||
content = json.loads(file.read())
|
|
||||||
else:
|
|
||||||
content = yaml.safe_load(file)
|
|
||||||
self.__add_wildcard(content, full_path, external_key_parts)
|
self.__add_wildcard(content, full_path, external_key_parts)
|
||||||
|
|
||||||
def __get_wildcards_in_text_file(self, full_path, base):
|
def __get_wildcards_in_text_file(self, full_path, base):
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "sd-webui-prompt-postprocessor"
|
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."
|
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.9.0"
|
version = "2.10.0"
|
||||||
license = { file = "LICENSE.txt" }
|
license = { file = "LICENSE.txt" }
|
||||||
dependencies = ["lark", "numpy", "pyyaml"]
|
dependencies = ["lark", "numpy", "pyyaml"]
|
||||||
|
|
||||||
|
|||||||
+63
-31
@@ -6,18 +6,17 @@ import os
|
|||||||
import time
|
import time
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
sys.path.append(os.path.join(sys.path[0], ".."))
|
sys.path.append(os.path.join(os.path.realpath(__file__), "..")) # base path for the extension
|
||||||
|
|
||||||
|
from modules import scripts, shared, script_callbacks # pylint: disable=import-error
|
||||||
from modules import scripts, shared, script_callbacks
|
from modules.processing import StableDiffusionProcessing # pylint: disable=import-error
|
||||||
from modules.processing import StableDiffusionProcessing
|
from modules.shared import opts # pylint: disable=import-error
|
||||||
from modules.shared import opts
|
from modules.paths import models_path # pylint: disable=import-error
|
||||||
from modules.paths import models_path
|
import gradio as gr # pylint: disable=import-error
|
||||||
import gradio as gr
|
from ppp import PromptPostProcessor # pylint: disable=import-error
|
||||||
from ppp import PromptPostProcessor
|
from ppp_logging import DEBUG_LEVEL, PromptPostProcessorLogFactory # pylint: disable=import-error
|
||||||
from ppp_logging import DEBUG_LEVEL, PromptPostProcessorLogFactory
|
from ppp_cache import PPPLRUCache # pylint: disable=import-error
|
||||||
from ppp_cache import PPPLRUCache
|
from ppp_wildcards import PPPWildcards # pylint: disable=import-error
|
||||||
from ppp_wildcards import PPPWildcards
|
|
||||||
|
|
||||||
|
|
||||||
class PromptPostProcessorA1111Script(scripts.Script):
|
class PromptPostProcessorA1111Script(scripts.Script):
|
||||||
@@ -82,7 +81,7 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
|||||||
"""
|
"""
|
||||||
return PromptPostProcessor.NAME
|
return PromptPostProcessor.NAME
|
||||||
|
|
||||||
def show(self, is_img2img):
|
def show(self, is_img2img): # pylint: disable=unused-argument
|
||||||
"""
|
"""
|
||||||
Determines whether the script should be shown based on the kind of processing.
|
Determines whether the script should be shown based on the kind of processing.
|
||||||
|
|
||||||
@@ -94,7 +93,7 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
|||||||
"""
|
"""
|
||||||
return scripts.AlwaysVisible
|
return scripts.AlwaysVisible
|
||||||
|
|
||||||
def ui(self, is_img2img):
|
def ui(self, is_img2img): # pylint: disable=unused-argument
|
||||||
with gr.Accordion(PromptPostProcessor.NAME, open=False):
|
with gr.Accordion(PromptPostProcessor.NAME, open=False):
|
||||||
force_equal_seeds = gr.Checkbox(
|
force_equal_seeds = gr.Checkbox(
|
||||||
label="Force equal seeds",
|
label="Force equal seeds",
|
||||||
@@ -171,6 +170,7 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
|||||||
is_i2i = bool(init_images[0])
|
is_i2i = bool(init_images[0])
|
||||||
self.ppp_debug_level = DEBUG_LEVEL(getattr(opts, "ppp_gen_debug_level", DEBUG_LEVEL.none.value))
|
self.ppp_debug_level = DEBUG_LEVEL(getattr(opts, "ppp_gen_debug_level", DEBUG_LEVEL.none.value))
|
||||||
do_i2i = getattr(opts, "ppp_gen_doi2i", False)
|
do_i2i = getattr(opts, "ppp_gen_doi2i", False)
|
||||||
|
add_prompts = getattr(opts, "ppp_gen_addpromptstometadata", True)
|
||||||
if is_i2i and not do_i2i:
|
if is_i2i and not do_i2i:
|
||||||
if self.ppp_debug_level != DEBUG_LEVEL.none:
|
if self.ppp_debug_level != DEBUG_LEVEL.none:
|
||||||
self.ppp_logger.info("Not processing the prompt for i2i")
|
self.ppp_logger.info("Not processing the prompt for i2i")
|
||||||
@@ -226,6 +226,16 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
|||||||
"is_sd3": False, # Stable Diffusion 3
|
"is_sd3": False, # Stable Diffusion 3
|
||||||
"is_flux": False, # Flux
|
"is_flux": False, # Flux
|
||||||
"is_auraflow": False, # AuraFlow
|
"is_auraflow": False, # AuraFlow
|
||||||
|
"is_pixart": False, # PixArt
|
||||||
|
"is_lumina2": False, # Lumina2
|
||||||
|
"is_ltxv": False, # LTXV
|
||||||
|
"is_cosmos": False, # Cosmos
|
||||||
|
"is_genmomochi": False, # GenmoMochi
|
||||||
|
"is_hunyuan": False, # Hunyuan
|
||||||
|
"is_hunyuanvideo": False, # HunyuanVideo
|
||||||
|
"is_hunyuan3d": False, # Hunyuan3D
|
||||||
|
"is_wanvideo": False, # WanVideo
|
||||||
|
"is_hidream": False, # HiDream
|
||||||
}
|
}
|
||||||
if app == "sdnext":
|
if app == "sdnext":
|
||||||
# cannot differentiate SD1 and SD2, we set True to both
|
# cannot differentiate SD1 and SD2, we set True to both
|
||||||
@@ -283,7 +293,7 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
|||||||
opts, "ppp_gen_variantsdefinitions", PromptPostProcessor.DEFAULT_VARIANTS_DEFINITIONS
|
opts, "ppp_gen_variantsdefinitions", PromptPostProcessor.DEFAULT_VARIANTS_DEFINITIONS
|
||||||
),
|
),
|
||||||
"process_wildcards": getattr(opts, "ppp_wil_processwildcards", True),
|
"process_wildcards": getattr(opts, "ppp_wil_processwildcards", True),
|
||||||
"if_wildcards": getattr(opts, "ppp_wil_ifwildcards", PromptPostProcessor.IFWILDCARDS_CHOICES.ignore.value),
|
"if_wildcards": getattr(opts, "ppp_wil_ifwildcards", PromptPostProcessor.IFWILDCARDS_CHOICES.stop.value),
|
||||||
"choice_separator": getattr(opts, "ppp_wil_choice_separator", PromptPostProcessor.DEFAULT_CHOICE_SEPARATOR),
|
"choice_separator": getattr(opts, "ppp_wil_choice_separator", PromptPostProcessor.DEFAULT_CHOICE_SEPARATOR),
|
||||||
"keep_choices_order": getattr(opts, "ppp_wil_keep_choices_order", False),
|
"keep_choices_order": getattr(opts, "ppp_wil_keep_choices_order", False),
|
||||||
"stn_separator": getattr(opts, "ppp_stn_separator", PromptPostProcessor.DEFAULT_STN_SEPARATOR),
|
"stn_separator": getattr(opts, "ppp_stn_separator", PromptPostProcessor.DEFAULT_STN_SEPARATOR),
|
||||||
@@ -349,12 +359,6 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
|||||||
rpr: list[str] = getattr(p, "all_prompts", None)
|
rpr: list[str] = getattr(p, "all_prompts", None)
|
||||||
rnr: list[str] = getattr(p, "all_negative_prompts", None)
|
rnr: list[str] = getattr(p, "all_negative_prompts", None)
|
||||||
if rpr is not None and rnr is not None:
|
if rpr is not None and rnr is not None:
|
||||||
extra_params.update(
|
|
||||||
{
|
|
||||||
"PPP original prompts": rpr.copy(),
|
|
||||||
"PPP original negative prompts": rnr.copy(),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
prompts_list += [
|
prompts_list += [
|
||||||
("regular", seed, prompt, negative_prompt)
|
("regular", seed, prompt, negative_prompt)
|
||||||
for seed, prompt, negative_prompt in zip(calculated_seeds, rpr, rnr)
|
for seed, prompt, negative_prompt in zip(calculated_seeds, rpr, rnr)
|
||||||
@@ -364,23 +368,12 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
|||||||
rph: list[str] = getattr(p, "all_hr_prompts", None)
|
rph: list[str] = getattr(p, "all_hr_prompts", None)
|
||||||
rnh: list[str] = getattr(p, "all_hr_negative_prompts", None)
|
rnh: list[str] = getattr(p, "all_hr_negative_prompts", None)
|
||||||
if rph is not None and rnh is not None:
|
if rph is not None and rnh is not None:
|
||||||
extra_params.update(
|
|
||||||
{
|
|
||||||
"PPP original HR prompts": rph.copy(),
|
|
||||||
"PPP original HR negative prompts": rnh.copy(),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
prompts_list += [
|
prompts_list += [
|
||||||
("hiresfix", seed, prompt, negative_prompt)
|
("hiresfix", seed, prompt, negative_prompt)
|
||||||
for seed, prompt, negative_prompt in zip(calculated_seeds, rph, rnh)
|
for seed, prompt, negative_prompt in zip(calculated_seeds, rph, rnh)
|
||||||
if (seed, prompt, negative_prompt) not in prompts_list
|
if (seed, prompt, negative_prompt) not in prompts_list
|
||||||
]
|
]
|
||||||
|
|
||||||
# fill extra generation parameters only if not already present
|
|
||||||
for k, v in extra_params.items():
|
|
||||||
if p.extra_generation_params.get(k) is None:
|
|
||||||
p.extra_generation_params[k] = v
|
|
||||||
|
|
||||||
# processes prompts
|
# processes prompts
|
||||||
for i, (prompttype, seed, prompt, negative_prompt) in enumerate(prompts_list):
|
for i, (prompttype, seed, prompt, negative_prompt) in enumerate(prompts_list):
|
||||||
if self.ppp_debug_level != DEBUG_LEVEL.none:
|
if self.ppp_debug_level != DEBUG_LEVEL.none:
|
||||||
@@ -395,17 +388,48 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
|||||||
|
|
||||||
# updates the prompts
|
# updates the prompts
|
||||||
if rpr is not None and rnr is not None:
|
if rpr is not None and rnr is not None:
|
||||||
|
rpr_changes = False
|
||||||
|
rnr_changes = False
|
||||||
|
rpr_copy = rpr.copy()
|
||||||
|
rnr_copy = rnr.copy()
|
||||||
for i, (seed, prompt, negative_prompt) in enumerate(zip(calculated_seeds, rpr, rnr)):
|
for i, (seed, prompt, negative_prompt) in enumerate(zip(calculated_seeds, rpr, rnr)):
|
||||||
found = self.lru_cache.get((seed, hash(self.wildcards_obj), prompt, negative_prompt))
|
found = self.lru_cache.get((seed, hash(self.wildcards_obj), prompt, negative_prompt))
|
||||||
if found is not None:
|
if found is not None:
|
||||||
|
if rpr[i].strip() != found[0].strip():
|
||||||
|
rpr_changes = True
|
||||||
|
if rnr[i].strip() != found[1].strip():
|
||||||
|
rnr_changes = True
|
||||||
rpr[i] = found[0]
|
rpr[i] = found[0]
|
||||||
rnr[i] = found[1]
|
rnr[i] = found[1]
|
||||||
|
if add_prompts:
|
||||||
|
if rpr_changes:
|
||||||
|
extra_params["PPP original prompts"] = rpr_copy
|
||||||
|
if rnr_changes:
|
||||||
|
extra_params["PPP original negative prompts"] = rnr_copy
|
||||||
if rph is not None and rnh is not None:
|
if rph is not None and rnh is not None:
|
||||||
|
rph_changes = False
|
||||||
|
rnh_changes = False
|
||||||
|
rph_copy = rph.copy()
|
||||||
|
rnh_copy = rnh.copy()
|
||||||
for i, (seed, prompt, negative_prompt) in enumerate(zip(calculated_seeds, rph, rnh)):
|
for i, (seed, prompt, negative_prompt) in enumerate(zip(calculated_seeds, rph, rnh)):
|
||||||
found = self.lru_cache.get((seed, hash(self.wildcards_obj), prompt, negative_prompt))
|
found = self.lru_cache.get((seed, hash(self.wildcards_obj), prompt, negative_prompt))
|
||||||
if found is not None:
|
if found is not None:
|
||||||
|
if rph[i].strip() != found[0].strip():
|
||||||
|
rph_changes = True
|
||||||
|
if rnh[i].strip() != found[1].strip():
|
||||||
|
rnh_changes = True
|
||||||
rph[i] = found[0]
|
rph[i] = found[0]
|
||||||
rnh[i] = found[1]
|
rnh[i] = found[1]
|
||||||
|
if add_prompts:
|
||||||
|
if rph_changes:
|
||||||
|
extra_params["PPP original HR prompts"] = rph_copy
|
||||||
|
if rnh_changes:
|
||||||
|
extra_params["PPP original HR negative prompts"] = rnh_copy
|
||||||
|
|
||||||
|
# fill extra generation parameters only if not already present
|
||||||
|
for k, v in extra_params.items():
|
||||||
|
if p.extra_generation_params.get(k) is None:
|
||||||
|
p.extra_generation_params[k] = v
|
||||||
|
|
||||||
t2 = time.time()
|
t2 = time.time()
|
||||||
if self.ppp_debug_level != DEBUG_LEVEL.none:
|
if self.ppp_debug_level != DEBUG_LEVEL.none:
|
||||||
@@ -500,6 +524,14 @@ def on_ui_settings():
|
|||||||
section=section,
|
section=section,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
shared.opts.add_option(
|
||||||
|
key="ppp_gen_addpromptstometadata",
|
||||||
|
info=shared.OptionInfo(
|
||||||
|
True,
|
||||||
|
label="Add original prompts to metadata (if they change)",
|
||||||
|
section=section,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
# wildcard settings
|
# wildcard settings
|
||||||
shared.opts.add_option(
|
shared.opts.add_option(
|
||||||
|
|||||||
+48
-27
@@ -4,12 +4,11 @@ import unittest
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from ppp_wildcards import PPPWildcards
|
sys.path.append(os.path.join(os.path.realpath(__file__), "..")) # base path for the extension
|
||||||
|
|
||||||
sys.path.append(os.path.join(sys.path[0], ".."))
|
from ppp_wildcards import PPPWildcards # pylint: disable=import-error
|
||||||
|
from ppp import PromptPostProcessor # pylint: disable=import-error
|
||||||
from ppp import PromptPostProcessor
|
from ppp_logging import DEBUG_LEVEL, PromptPostProcessorLogFactory # pylint: disable=import-error
|
||||||
from ppp_logging import DEBUG_LEVEL, PromptPostProcessorLogFactory
|
|
||||||
|
|
||||||
|
|
||||||
PromptPair = namedtuple("PromptPair", ["prompt", "negative_prompt"], defaults=["", ""])
|
PromptPair = namedtuple("PromptPair", ["prompt", "negative_prompt"], defaults=["", ""])
|
||||||
@@ -69,6 +68,13 @@ class TestPromptPostProcessor(unittest.TestCase):
|
|||||||
os.path.abspath(os.path.join(os.path.dirname(__file__), "wildcards")),
|
os.path.abspath(os.path.join(os.path.dirname(__file__), "wildcards")),
|
||||||
os.path.abspath(os.path.join(os.path.dirname(__file__), "wildcards2")),
|
os.path.abspath(os.path.join(os.path.dirname(__file__), "wildcards2")),
|
||||||
],
|
],
|
||||||
|
"""
|
||||||
|
yaml_input:
|
||||||
|
wildcardI:
|
||||||
|
- choice1
|
||||||
|
- choice2
|
||||||
|
- choice3
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
grammar_filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../grammar.lark")
|
grammar_filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../grammar.lark")
|
||||||
with open(grammar_filename, "r", encoding="utf-8") as file:
|
with open(grammar_filename, "r", encoding="utf-8") as file:
|
||||||
@@ -355,7 +361,8 @@ class TestPromptPostProcessor(unittest.TestCase):
|
|||||||
def test_cmd_if_nested(self): # nested if command
|
def test_cmd_if_nested(self): # nested if command
|
||||||
self.__process(
|
self.__process(
|
||||||
PromptPair(
|
PromptPair(
|
||||||
"this is <ppp:if _sd eq 'sd1'>SD1<ppp:else><ppp:if _is_pony>PONY<ppp:else>SD2<ppp:/if><ppp:/if><ppp:if _is_sdxl_no_pony>NOPONY<ppp:/if><ppp:if _is_pure_sdxl>NOPONY<ppp:/if>", ""
|
"this is <ppp:if _sd eq 'sd1'>SD1<ppp:else><ppp:if _is_pony>PONY<ppp:else>SD2<ppp:/if><ppp:/if><ppp:if _is_sdxl_no_pony>NOPONY<ppp:/if><ppp:if _is_pure_sdxl>NOPONY<ppp:/if>",
|
||||||
|
"",
|
||||||
),
|
),
|
||||||
PromptPair("this is PONY", ""),
|
PromptPair("this is PONY", ""),
|
||||||
ppp=PromptPostProcessor(
|
ppp=PromptPostProcessor(
|
||||||
@@ -394,13 +401,19 @@ class TestPromptPostProcessor(unittest.TestCase):
|
|||||||
|
|
||||||
def test_cmd_set_if_complex_conditions_1(self): # complex conditions (or)
|
def test_cmd_set_if_complex_conditions_1(self): # complex conditions (or)
|
||||||
self.__process(
|
self.__process(
|
||||||
PromptPair("<ppp:set v1>true<ppp:/set><ppp:set v2>false<ppp:/set>this test is <ppp:if v1 or v2>OK<ppp:else>not OK<ppp:/if>", ""),
|
PromptPair(
|
||||||
|
"<ppp:set v1>true<ppp:/set><ppp:set v2>false<ppp:/set>this test is <ppp:if v1 or v2>OK<ppp:else>not OK<ppp:/if>",
|
||||||
|
"",
|
||||||
|
),
|
||||||
PromptPair("this test is OK", ""),
|
PromptPair("this test is OK", ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_cmd_set_if_complex_conditions_2(self): # complex conditions (and)
|
def test_cmd_set_if_complex_conditions_2(self): # complex conditions (and)
|
||||||
self.__process(
|
self.__process(
|
||||||
PromptPair("<ppp:set v1>true<ppp:/set><ppp:set v2>true<ppp:/set>this test is <ppp:if v1 and v2>OK<ppp:else>not OK<ppp:/if>", ""),
|
PromptPair(
|
||||||
|
"<ppp:set v1>true<ppp:/set><ppp:set v2>true<ppp:/set>this test is <ppp:if v1 and v2>OK<ppp:else>not OK<ppp:/if>",
|
||||||
|
"",
|
||||||
|
),
|
||||||
PromptPair("this test is OK", ""),
|
PromptPair("this test is OK", ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -412,25 +425,37 @@ class TestPromptPostProcessor(unittest.TestCase):
|
|||||||
|
|
||||||
def test_cmd_set_if_complex_conditions_4(self): # complex conditions (not, precedence)
|
def test_cmd_set_if_complex_conditions_4(self): # complex conditions (not, precedence)
|
||||||
self.__process(
|
self.__process(
|
||||||
PromptPair("<ppp:set v1>true<ppp:/set><ppp:set v2>false<ppp:/set>this test is <ppp:if not (v1 and v2)>OK<ppp:else>not OK<ppp:/if>", ""),
|
PromptPair(
|
||||||
|
"<ppp:set v1>true<ppp:/set><ppp:set v2>false<ppp:/set>this test is <ppp:if not (v1 and v2)>OK<ppp:else>not OK<ppp:/if>",
|
||||||
|
"",
|
||||||
|
),
|
||||||
PromptPair("this test is OK", ""),
|
PromptPair("this test is OK", ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_cmd_set_if_complex_conditions_5(self): # complex conditions (not, precedence, comparison)
|
def test_cmd_set_if_complex_conditions_5(self): # complex conditions (not, precedence, comparison)
|
||||||
self.__process(
|
self.__process(
|
||||||
PromptPair("<ppp:set v1>1<ppp:/set><ppp:set v2>false<ppp:/set>this test is <ppp:if not(v1 eq '1' and v2)>OK<ppp:else>not OK<ppp:/if>", ""),
|
PromptPair(
|
||||||
|
"<ppp:set v1>1<ppp:/set><ppp:set v2>false<ppp:/set>this test is <ppp:if not(v1 eq '1' and v2)>OK<ppp:else>not OK<ppp:/if>",
|
||||||
|
"",
|
||||||
|
),
|
||||||
PromptPair("this test is OK", ""),
|
PromptPair("this test is OK", ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_cmd_set_if_complex_conditions_6(self): # complex conditions
|
def test_cmd_set_if_complex_conditions_6(self): # complex conditions
|
||||||
self.__process(
|
self.__process(
|
||||||
PromptPair("<ppp:set v1>1<ppp:/set><ppp:set v2>2<ppp:/set><ppp:set v3>3<ppp:/set>this test is <ppp:if v1 eq '1' and v2 eq '2' and v3 eq '3'>OK<ppp:else>not OK<ppp:/if>", ""),
|
PromptPair(
|
||||||
|
"<ppp:set v1>1<ppp:/set><ppp:set v2>2<ppp:/set><ppp:set v3>3<ppp:/set>this test is <ppp:if v1 eq '1' and v2 eq '2' and v3 eq '3'>OK<ppp:else>not OK<ppp:/if>",
|
||||||
|
"",
|
||||||
|
),
|
||||||
PromptPair("this test is OK", ""),
|
PromptPair("this test is OK", ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_cmd_set_if_complex_conditions_7(self): # complex conditions
|
def test_cmd_set_if_complex_conditions_7(self): # complex conditions
|
||||||
self.__process(
|
self.__process(
|
||||||
PromptPair("<ppp:set v1>1<ppp:/set><ppp:set v2>2<ppp:/set><ppp:set v3>3<ppp:/set>this test is <ppp:if v1 eq '1' and v2 not eq '2' or v3 eq '3'>OK<ppp:else>not OK<ppp:/if>", ""),
|
PromptPair(
|
||||||
|
"<ppp:set v1>1<ppp:/set><ppp:set v2>2<ppp:/set><ppp:set v3>3<ppp:/set>this test is <ppp:if v1 eq '1' and v2 not eq '2' or v3 eq '3'>OK<ppp:else>not OK<ppp:/if>",
|
||||||
|
"",
|
||||||
|
),
|
||||||
PromptPair("this test is OK", ""),
|
PromptPair("this test is OK", ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -916,11 +941,21 @@ class TestPromptPostProcessor(unittest.TestCase):
|
|||||||
ppp=self.__nocupppp,
|
ppp=self.__nocupppp,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_wc_wildcard_input(self): # simple yaml wildcard input
|
||||||
|
self.__process(
|
||||||
|
PromptPair("the choices are: __yaml_input/wildcardI__", ""),
|
||||||
|
PromptPair("the choices are: choice2", ""),
|
||||||
|
ppp=self.__nocupppp,
|
||||||
|
)
|
||||||
|
|
||||||
# Model variants tests
|
# Model variants tests
|
||||||
|
|
||||||
def test_variants(self):
|
def test_variants(self):
|
||||||
self.__process(
|
self.__process(
|
||||||
PromptPair("<ppp:if _is_test1>test1<ppp:/if><ppp:if _is_test2>test2<ppp:/if><ppp:if _is_test3>test3<ppp:/if><ppp:if _is_test4>test4<ppp:/if>", ""),
|
PromptPair(
|
||||||
|
"<ppp:if _is_test1>test1<ppp:/if><ppp:if _is_test2>test2<ppp:/if><ppp:if _is_test3>test3<ppp:/if><ppp:if _is_test4>test4<ppp:/if>",
|
||||||
|
"",
|
||||||
|
),
|
||||||
PromptPair("test1test2", ""),
|
PromptPair("test1test2", ""),
|
||||||
ppp=PromptPostProcessor(
|
ppp=PromptPostProcessor(
|
||||||
self.__ppp_logger,
|
self.__ppp_logger,
|
||||||
@@ -947,7 +982,6 @@ class TestPromptPostProcessor(unittest.TestCase):
|
|||||||
ppp=self.__comfyuippp,
|
ppp=self.__comfyuippp,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# def test_mix(self):
|
# def test_mix(self):
|
||||||
# self.__process(
|
# self.__process(
|
||||||
# PromptPair(
|
# PromptPair(
|
||||||
@@ -961,19 +995,6 @@ class TestPromptPostProcessor(unittest.TestCase):
|
|||||||
# ppp=self.__nocupppp,
|
# ppp=self.__nocupppp,
|
||||||
# )
|
# )
|
||||||
|
|
||||||
# def test_real(self):
|
|
||||||
# self.__wildcards_obj.refresh_wildcards(
|
|
||||||
# DEBUG_LEVEL.full,
|
|
||||||
# ["D:\\AI\\SD\\_configuraciones\\acb-wildcards\\wildcards"],
|
|
||||||
# )
|
|
||||||
# self.__process(
|
|
||||||
# PromptPair(
|
|
||||||
# "${separator=()}, __quality/high__ __misc/sep__, photograph of a __character__",
|
|
||||||
# "__negatives/ng_generic__",
|
|
||||||
# ),
|
|
||||||
# PromptPair("", ""),
|
|
||||||
# )
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user