Skip to content

Commit c03339a

Browse files
committed
* Better processing of interruptions using an exception.
* New option on_warning to stop on invalid content. * New option cleanup_extra_separators_include_eol to choose whether to also remove adjacent EOLs when removing extra separators or not. Default is not to do it. In previous versions it was forced. * Refactoring of the cleanup method. * Only simplify attention modifiers when the merge attention option is set. * A1111: avoid logging about HR prompts and avoid saving them in extra metadata when not different. * A1111: consider options and environment info in the caching of results. * Some refactorings.
1 parent bfc47d0 commit c03339a

File tree

11 files changed

+528
-349
lines changed

11 files changed

+528
-349
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
.vscode/**/*
44
!.vscode/settings.json
55
!.vscode/launch.json
6+
7+
tests/tests_local.py

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
The Prompt PostProcessor (PPP), formerly known as "sd-webui-sendtonegative", is an extension designed to process the prompt, possibly after other extensions have modified it. This extension is compatible with:
44

5+
* [ComfyUI](https://github.com/comfyanonymous/ComfyUI)
56
* [AUTOMATIC1111 Stable Diffusion WebUI](https://github.com/AUTOMATIC1111/stable-diffusion-webui)
67
* [Forge](https://github.com/lllyasviel/stable-diffusion-webui-forge)
78
* [reForge](https://github.com/Panchovix/stable-diffusion-webui-reForge)
89
* [SD.Next](https://github.com/vladmandic/automatic)
910
* ...and probably other forks
10-
* [ComfyUI](https://github.com/comfyanonymous/ComfyUI)
1111

1212
Currently this extension has these functions:
1313

docs/CONFIG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ With this prompt: `__quality__, 1girl, ${head:__eyes__, __hair__, __expression__
3333
### General settings
3434

3535
* **Debug level**: what to write to the console. Note: in *SD.Next* debug messages only show if you launch it with the `--debug` argument.
36+
* **What to do on invalid content warnings?**: warn on the console or stop the generation.
3637
* **Model variant definitions**: definitions for model variants to be recognized based on strings found in the full filename.
3738

3839
The format for each line is (with *kind* being one of the base model identifiers or not defined):
@@ -65,6 +66,7 @@ With this prompt: `__quality__, 1girl, ${head:__eyes__, __hair__, __expression__
6566
* **Remove empty constructs**: removes attention/scheduling/alternation constructs when they are invalid.
6667
* **Remove extra separators**: removes unnecessary separators. This applies to the configured separator and regular commas.
6768
* **Remove additional extra separators**: removes unnecessary separators at start or end of lines. This applies to the configured separator and regular commas.
69+
* **The extra separators options also remove EOLs**: in the previous two options it also removes EOLs attached to the separators.
6870
* **Clean up around BREAKs**: removes consecutive BREAKs and unnecessary commas and space around them.
6971
* **Use EOL instead of Space before BREAKs**: add a newline before BREAKs.
7072
* **Clean up around ANDs**: removes consecutive ANDs and unnecessary commas and space around them.

ppp.py

Lines changed: 132 additions & 80 deletions
Large diffs are not rendered by default.

ppp_comfyui.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,13 @@ def INPUT_TYPES(cls):
8787
"tooltip": "Debug level",
8888
},
8989
),
90+
"on_warnings": (
91+
[e.value for e in PromptPostProcessor.ONWARNING_CHOICES],
92+
{
93+
"default": PromptPostProcessor.ONWARNING_CHOICES.warn.value,
94+
"tooltip": "How to handle invalid content warnings",
95+
},
96+
),
9097
"variants_definitions": (
9198
"STRING",
9299
{
@@ -201,6 +208,15 @@ def INPUT_TYPES(cls):
201208
"label_off": "No",
202209
},
203210
),
211+
"cleanup_extra_separators_include_eol": (
212+
"BOOLEAN",
213+
{
214+
"default": False,
215+
"tooltip": "Extra separators options also remove EOLs",
216+
"label_on": "Yes",
217+
"label_off": "No",
218+
},
219+
),
204220
"cleanup_breaks": (
205221
"BOOLEAN",
206222
{
@@ -304,6 +320,7 @@ def IS_CHANGED(
304320
neg_prompt,
305321
seed,
306322
debug_level, # pylint: disable=unused-argument
323+
on_warnings,
307324
variants_definitions,
308325
wc_process_wildcards,
309326
wc_wildcards_folders,
@@ -317,6 +334,7 @@ def IS_CHANGED(
317334
cleanup_empty_constructs,
318335
cleanup_extra_separators,
319336
cleanup_extra_separators2,
337+
cleanup_extra_separators_include_eol,
320338
cleanup_breaks,
321339
cleanup_breaks_eol,
322340
cleanup_ands,
@@ -335,6 +353,7 @@ def IS_CHANGED(
335353
"pos_prompt": pos_prompt,
336354
"neg_prompt": neg_prompt,
337355
"seed": seed,
356+
"on_warnings": on_warnings,
338357
"variants_definitions": variants_definitions,
339358
"process_wildcards": wc_process_wildcards,
340359
"wildcards_folders": wc_wildcards_folders,
@@ -348,6 +367,7 @@ def IS_CHANGED(
348367
"cleanup_empty_constructs": cleanup_empty_constructs,
349368
"cleanup_extra_separators": cleanup_extra_separators,
350369
"cleanup_extra_separators2": cleanup_extra_separators2,
370+
"cleanup_extra_separators_include_eol": cleanup_extra_separators_include_eol,
351371
"cleanup_breaks": cleanup_breaks,
352372
"cleanup_breaks_eol": cleanup_breaks_eol,
353373
"cleanup_ands": cleanup_ands,
@@ -367,6 +387,7 @@ def process(
367387
neg_prompt,
368388
seed,
369389
debug_level,
390+
on_warnings,
370391
variants_definitions,
371392
wc_process_wildcards,
372393
wc_wildcards_folders,
@@ -380,6 +401,7 @@ def process(
380401
cleanup_empty_constructs,
381402
cleanup_extra_separators,
382403
cleanup_extra_separators2,
404+
cleanup_extra_separators_include_eol,
383405
cleanup_breaks,
384406
cleanup_breaks_eol,
385407
cleanup_ands,
@@ -436,6 +458,7 @@ def process(
436458
raise ValueError("Invalid variants_definitions format")
437459
options = {
438460
"debug_level": debug_level,
461+
"on_warnings": on_warnings,
439462
"variants_definitions": variants_definitions,
440463
"process_wildcards": wc_process_wildcards,
441464
"if_wildcards": wc_if_wildcards,
@@ -447,6 +470,7 @@ def process(
447470
"cleanup_empty_constructs": cleanup_empty_constructs,
448471
"cleanup_extra_separators": cleanup_extra_separators,
449472
"cleanup_extra_separators2": cleanup_extra_separators2,
473+
"cleanup_extra_separators_include_eol": cleanup_extra_separators_include_eol,
450474
"cleanup_breaks": cleanup_breaks,
451475
"cleanup_breaks_eol": cleanup_breaks_eol,
452476
"cleanup_ands": cleanup_ands,

ppp_wildcards.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ def refresh_wildcards(
9191
"""
9292
self.__debug_level = debug_level
9393
self.__wildcards_folders = wildcards_folders or []
94-
# if self.debug_level != DEBUG_LEVEL.none:
95-
# self.logger.info("Refreshing wildcards...")
94+
# if self.__debug_level != DEBUG_LEVEL.none:
95+
# self.__logger.info("Refreshing wildcards...")
9696
# t1 = time.time()
9797
for fullpath in list(self.__wildcard_files.keys()):
9898
if fullpath != self.LOCALINPUT_FILENAME:
@@ -113,8 +113,8 @@ def refresh_wildcards(
113113
self.wildcards = {}
114114
self.__wildcard_files = {}
115115
# t2 = time.time()
116-
# if self.debug_level != DEBUG_LEVEL.none:
117-
# self.logger.info(f"Wildcards refresh time: {t2 - t1:.3f} seconds")
116+
# if self.__debug_level != DEBUG_LEVEL.none:
117+
# self.__logger.info(f"Wildcards refresh time: {t2 - t1:.3f} seconds")
118118

119119
def get_wildcards(self, key: str) -> list[PPPWildcard]:
120120
"""

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "sd-webui-prompt-postprocessor"
33
description = "Stable Diffusion WebUI & ComfyUI extension to post-process the prompt, including sending content from the prompt to the negative prompt and wildcards."
4-
version = "2.10.0"
4+
version = "2.11.0"
55
license = { file = "LICENSE.txt" }
66
dependencies = ["lark", "numpy", "pyyaml"]
77

scripts/ppp_script.py

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
import sys
55
import os
66
import time
7+
from pathlib import Path
78
import numpy as np
89

9-
sys.path.append(os.path.join(os.path.realpath(__file__), "..")) # base path for the extension
10+
sys.path.append(str(Path(__file__).parent)) # base path for the extension
1011

1112
from modules import scripts, shared, script_callbacks # pylint: disable=import-error
1213
from modules.processing import StableDiffusionProcessing # pylint: disable=import-error
@@ -279,6 +280,7 @@ def process(
279280
env_info["is_sd3"] = getattr(p.sd_model, "is_sd3", False)
280281
env_info["is_flux"] = False
281282
env_info["is_auraflow"] = False
283+
hash_envinfo = hash(tuple(sorted(env_info.items())))
282284
wc_wildcards_folders = getattr(opts, "ppp_wil_wildcardsfolders", "")
283285
if wc_wildcards_folders == "":
284286
wc_wildcards_folders = os.getenv("WILDCARD_DIR", PPPWildcards.DEFAULT_WILDCARDS_FOLDER)
@@ -289,6 +291,7 @@ def process(
289291
]
290292
options = {
291293
"debug_level": getattr(opts, "ppp_gen_debug_level", DEBUG_LEVEL.none.value),
294+
"on_warning": getattr(opts, "ppp_gen_onwarning", PromptPostProcessor.ONWARNING_CHOICES.warn.value),
292295
"variants_definitions": getattr(
293296
opts, "ppp_gen_variantsdefinitions", PromptPostProcessor.DEFAULT_VARIANTS_DEFINITIONS
294297
),
@@ -302,6 +305,7 @@ def process(
302305
"cleanup_empty_constructs": getattr(opts, "ppp_cup_emptyconstructs", True),
303306
"cleanup_extra_separators": getattr(opts, "ppp_cup_extraseparators", True),
304307
"cleanup_extra_separators2": getattr(opts, "ppp_cup_extraseparators2", True),
308+
"cleanup_extra_separators_include_eol": getattr(opts, "ppp_cup_extraseparators_include_eol", True),
305309
"cleanup_breaks": getattr(opts, "ppp_cup_breaks", True),
306310
"cleanup_breaks_eol": getattr(opts, "ppp_cup_breaks_eol", False),
307311
"cleanup_ands": getattr(opts, "ppp_cup_ands", True),
@@ -310,6 +314,7 @@ def process(
310314
"cleanup_merge_attention": getattr(opts, "ppp_cup_mergeattention", True),
311315
"remove_extranetwork_tags": getattr(opts, "ppp_rem_removeextranetworktags", False),
312316
}
317+
hash_options = hash(tuple(sorted(options.items())))
313318
self.wildcards_obj.refresh_wildcards(
314319
self.ppp_debug_level, wildcards_folders if options["process_wildcards"] else None
315320
)
@@ -367,7 +372,7 @@ def process(
367372
# make it compatible with A1111 hires fix
368373
rph: list[str] = getattr(p, "all_hr_prompts", None)
369374
rnh: list[str] = getattr(p, "all_hr_negative_prompts", None)
370-
if rph is not None and rnh is not None:
375+
if rph is not None and rnh is not None and (rph != rpr or rnh != rnr):
371376
prompts_list += [
372377
("hiresfix", seed, prompt, negative_prompt)
373378
for seed, prompt, negative_prompt in zip(calculated_seeds, rph, rnh)
@@ -378,22 +383,35 @@ def process(
378383
for i, (prompttype, seed, prompt, negative_prompt) in enumerate(prompts_list):
379384
if self.ppp_debug_level != DEBUG_LEVEL.none:
380385
self.ppp_logger.info(f"processing prompts[{i+1}] ({prompttype})")
381-
if self.lru_cache.get((seed, hash(self.wildcards_obj), prompt, negative_prompt)) is None:
386+
if (
387+
self.lru_cache.get(
388+
(hash_envinfo, hash_options, seed, hash(self.wildcards_obj), prompt, negative_prompt)
389+
)
390+
is None
391+
):
382392
posp, negp, _ = ppp.process_prompt(prompt, negative_prompt, seed)
383-
self.lru_cache.put((seed, hash(self.wildcards_obj), prompt, negative_prompt), (posp, negp))
393+
self.lru_cache.put(
394+
(hash_envinfo, hash_options, seed, hash(self.wildcards_obj), prompt, negative_prompt), (posp, negp)
395+
)
384396
# adds also the result so i2i doesn't process it unnecessarily
385-
self.lru_cache.put((seed, hash(self.wildcards_obj), posp, negp), (posp, negp))
397+
self.lru_cache.put(
398+
(hash_envinfo, hash_options, seed, hash(self.wildcards_obj), posp, negp), (posp, negp)
399+
)
386400
elif self.ppp_debug_level != DEBUG_LEVEL.none:
387401
self.ppp_logger.info("result already in cache")
388402

389403
# updates the prompts
404+
rpr_copy = None
405+
rnr_copy = None
390406
if rpr is not None and rnr is not None:
391407
rpr_changes = False
392408
rnr_changes = False
393409
rpr_copy = rpr.copy()
394410
rnr_copy = rnr.copy()
395411
for i, (seed, prompt, negative_prompt) in enumerate(zip(calculated_seeds, rpr, rnr)):
396-
found = self.lru_cache.get((seed, hash(self.wildcards_obj), prompt, negative_prompt))
412+
found = self.lru_cache.get(
413+
(hash_envinfo, hash_options, seed, hash(self.wildcards_obj), prompt, negative_prompt)
414+
)
397415
if found is not None:
398416
if rpr[i].strip() != found[0].strip():
399417
rpr_changes = True
@@ -412,11 +430,13 @@ def process(
412430
rph_copy = rph.copy()
413431
rnh_copy = rnh.copy()
414432
for i, (seed, prompt, negative_prompt) in enumerate(zip(calculated_seeds, rph, rnh)):
415-
found = self.lru_cache.get((seed, hash(self.wildcards_obj), prompt, negative_prompt))
433+
found = self.lru_cache.get(
434+
(hash_envinfo, hash_options, seed, hash(self.wildcards_obj), prompt, negative_prompt)
435+
)
416436
if found is not None:
417-
if rph[i].strip() != found[0].strip():
437+
if rph[i].strip() != found[0].strip() and (not rpr_copy or rph[i].strip() != rpr_copy[i].strip()):
418438
rph_changes = True
419-
if rnh[i].strip() != found[1].strip():
439+
if rnh[i].strip() != found[1].strip() and (not rnr_copy or rnh[i].strip() != rnr_copy[i].strip()):
420440
rnh_changes = True
421441
rph[i] = found[0]
422442
rnh[i] = found[1]
@@ -502,6 +522,21 @@ def new_html_title(title):
502522
section=section,
503523
),
504524
)
525+
shared.opts.add_option(
526+
key="ppp_gen_onwarning",
527+
info=shared.OptionInfo(
528+
default=PromptPostProcessor.ONWARNING_CHOICES.warn.value,
529+
label="What to do on invalid content warnings?",
530+
component=gr.Radio,
531+
component_args={
532+
"choices": (
533+
("Show warning in console", PromptPostProcessor.ONWARNING_CHOICES.warn.value),
534+
("Stop the generation", PromptPostProcessor.ONWARNING_CHOICES.stop.value),
535+
)
536+
},
537+
section=section,
538+
),
539+
)
505540
shared.opts.add_option(
506541
key="ppp_gen_variantsdefinitions",
507542
info=shared.OptionInfo(
@@ -656,6 +691,14 @@ def new_html_title(title):
656691
section=section,
657692
),
658693
)
694+
shared.opts.add_option(
695+
key="ppp_cup_extraseparators_include_eol",
696+
info=shared.OptionInfo(
697+
False,
698+
label="The extra separators options also remove EOLs",
699+
section=section,
700+
),
701+
)
659702
shared.opts.add_option(
660703
key="ppp_cup_breaks",
661704
info=shared.OptionInfo(

tests/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)