* Selection of prompt parser based on heuristics to improve parsing time on simpler cases.
* Improved timing logging. * Refactor application support handling. * Enhanced regex patterns in `ppp.py` for wildcard and choice detection to ensure proper escaping. * Included icon source files.
This commit is contained in:
+2
-2
@@ -46,9 +46,9 @@ With this prompt: `__quality__, 1girl, ${head:__eyes__, __hair__, __expression__
|
||||
|
||||
### Wildcard settings
|
||||
|
||||
* **Process wildcards**: you can choose to process them with this extension or use a different one.
|
||||
* **Process wildcards**: you can choose to process wildcards and choices with this extension or use a different one.
|
||||
* **Wildcards folders**: you can enter multiple folders separated by commas. In *ComfyUI* you can leave it empty and add a `wildcards` entry in the **extra_model_paths.yaml** file.
|
||||
* **What to do with remaining wildcards?**: select what do you want to do with any found wildcards.
|
||||
* **What to do with remaining wildcards?**: select what do you want to do with any found wildcards/choices (when process wildcards is off or after the processing).
|
||||
* **Ignore**: do not try to detect wildcards.
|
||||
* **Remove**: detect wildcards and remove them.
|
||||
* **Add visible warning**: detect wildcards and add a warning text to the prompt, that hopefully produces a noticeable generation.
|
||||
|
||||
+41
-8
@@ -27,15 +27,48 @@ promptcomp.4: promptcomppart ( [ ":" numpar ] ( /\bAND\b/ promptcomppart [ ":" n
|
||||
promptcomppart: content
|
||||
|
||||
// simple prompts
|
||||
?content.2: ( old_content | new_content | plain | specialchars )*
|
||||
?inside_content.2: ( new_content | plain | specialchars )*
|
||||
?content_choice.2: ( old_content | new_content | plain_choice | specialchars_choice )*
|
||||
?content_var.2: ( old_content | new_content | plain_var | specialchars_var )*
|
||||
?content_negtag.2: ( old_content | new_content_negtag | plain | specialchars_negtag )*
|
||||
?content_alternate.2: ( old_content | new_content | plain_alternate | specialchars_alternate )*
|
||||
|
||||
?old_content.2: ( attention | scheduled | alternate | extranetworktag )+
|
||||
?new_content.3: ( variableset | variableuse | commandstn | commandstni | commandset | commandecho | commandif | wildcard | choices )+
|
||||
?new_content_negtag.3: ( variableset | variableuse | commandset | commandecho | commandif | wildcard | choices )+
|
||||
//#if ALLOW_NEW_CONTENT
|
||||
?content.2: ( old_content | new_content | plain | specialchars )*
|
||||
?inside_content.2: ( new_content | plain | specialchars )*
|
||||
?content_choice.2: ( old_content | new_content | plain_choice | specialchars_choice )*
|
||||
?content_var.2: ( old_content | new_content | plain_var | specialchars_var )*
|
||||
?content_negtag.2: ( old_content | new_content_negtag | plain | specialchars_negtag )*
|
||||
?content_alternate.2: ( old_content | new_content | plain_alternate | specialchars_alternate )*
|
||||
//#if ALLOW_WILDCARDS ALLOW_CHOICES ALLOW_COMMVARS
|
||||
?new_content.3: ( variableset | variableuse | commandstn | commandstni | commandset | commandecho | commandif | wildcard | choices )+
|
||||
?new_content_negtag.3: ( variableset | variableuse | commandset | commandecho | commandif | wildcard | choices )+
|
||||
//#elif ALLOW_WILDCARDS !ALLOW_CHOICES ALLOW_COMMVARS
|
||||
?new_content.3: ( variableset | variableuse | commandstn | commandstni | commandset | commandecho | commandif | wildcard )+
|
||||
?new_content_negtag.3: ( variableset | variableuse | commandset | commandecho | commandif | wildcard )+
|
||||
//#elif !ALLOW_WILDCARDS ALLOW_CHOICES ALLOW_COMMVARS
|
||||
?new_content.3: ( variableset | variableuse | commandstn | commandstni | commandset | commandecho | commandif | choices )+
|
||||
?new_content_negtag.3: ( variableset | variableuse | commandset | commandecho | commandif | choices )+
|
||||
//#elif ALLOW_WILDCARDS ALLOW_CHOICES !ALLOW_COMMVARS
|
||||
?new_content.3: ( wildcard | choices )+
|
||||
?new_content_negtag.3: ( wildcard | choices )+
|
||||
//#elif ALLOW_WILDCARDS !ALLOW_CHOICES !ALLOW_COMMVARS
|
||||
?new_content.3: ( wildcard )+
|
||||
?new_content_negtag.3: ( wildcard )+
|
||||
//#elif !ALLOW_WILDCARDS ALLOW_CHOICES !ALLOW_COMMVARS
|
||||
?new_content.3: ( choices )+
|
||||
?new_content_negtag.3: ( choices )+
|
||||
//#elif !ALLOW_WILDCARDS !ALLOW_CHOICES ALLOW_COMMVARS
|
||||
?new_content.3: ( variableset | variableuse | commandstn | commandstni | commandset | commandecho | commandif )+
|
||||
?new_content_negtag.3: ( variableset | variableuse | commandset | commandecho | commandif )+
|
||||
//#else
|
||||
?new_content.3: ( variableset | variableuse | commandstn | commandstni | commandset | commandecho | commandif | wildcard | choices )+
|
||||
?new_content_negtag.3: ( variableset | variableuse | commandset | commandecho | commandif | wildcard | choices )+
|
||||
//#endif
|
||||
//#else
|
||||
?content.2: ( old_content | plain | specialchars )*
|
||||
?inside_content.2: ( plain | specialchars )*
|
||||
?content_choice.2: ( old_content | plain_choice | specialchars_choice )*
|
||||
?content_var.2: ( old_content | plain_var | specialchars_var )*
|
||||
?content_negtag.2: ( old_content | plain | specialchars_negtag )*
|
||||
?content_alternate.2: ( old_content | plain_alternate | specialchars_alternate )*
|
||||
//#endif
|
||||
|
||||
// attention modifiers
|
||||
attention: ( "(" content [ ":" numpar ] ")" ) | ( "[" content "]" )
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 20 KiB |
@@ -11,6 +11,7 @@ from typing import Any, Callable, Optional
|
||||
import lark
|
||||
import numpy as np
|
||||
|
||||
from ppp_hosts import SUPPORTED_APPS # pylint: disable=import-error
|
||||
from ppp_logging import DEBUG_LEVEL # pylint: disable=import-error
|
||||
from ppp_wildcards import PPPWildcard, PPPWildcards # pylint: disable=import-error
|
||||
|
||||
@@ -165,27 +166,124 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
grammar_filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), "grammar.lark")
|
||||
with open(grammar_filename, "r", encoding="utf-8") as file:
|
||||
grammar_content = file.read()
|
||||
self.parser_complete = lark.Lark(
|
||||
grammar_content,
|
||||
|
||||
# Preprocess grammar content for conditional compilation
|
||||
self.parser_full_only_old = lark.Lark(
|
||||
self.__preprocess_grammar(
|
||||
grammar_content,
|
||||
{
|
||||
"ALLOW_NEW_CONTENT": False,
|
||||
"ALLOW_WILDCARDS": False,
|
||||
"ALLOW_CHOICES": False,
|
||||
"ALLOW_COMMVARS": False,
|
||||
},
|
||||
),
|
||||
propagate_positions=True,
|
||||
)
|
||||
self.parser_choice = lark.Lark(
|
||||
grammar_content_full = self.__preprocess_grammar(
|
||||
grammar_content,
|
||||
{
|
||||
"ALLOW_NEW_CONTENT": True,
|
||||
"ALLOW_WILDCARDS": True,
|
||||
"ALLOW_CHOICES": True,
|
||||
"ALLOW_COMMVARS": True,
|
||||
},
|
||||
)
|
||||
self.parser_complete_full = lark.Lark(
|
||||
grammar_content_full,
|
||||
propagate_positions=True,
|
||||
)
|
||||
self.parser_complete_wc_ch = lark.Lark(
|
||||
self.__preprocess_grammar(
|
||||
grammar_content,
|
||||
{
|
||||
"ALLOW_NEW_CONTENT": True,
|
||||
"ALLOW_WILDCARDS": True,
|
||||
"ALLOW_CHOICES": True,
|
||||
"ALLOW_COMMVARS": False,
|
||||
},
|
||||
),
|
||||
propagate_positions=True,
|
||||
)
|
||||
self.parser_complete_wc_cv = lark.Lark(
|
||||
self.__preprocess_grammar(
|
||||
grammar_content,
|
||||
{
|
||||
"ALLOW_NEW_CONTENT": True,
|
||||
"ALLOW_WILDCARDS": True,
|
||||
"ALLOW_CHOICES": False,
|
||||
"ALLOW_COMMVARS": True,
|
||||
},
|
||||
),
|
||||
propagate_positions=True,
|
||||
)
|
||||
self.parser_complete_ch_cv = lark.Lark(
|
||||
self.__preprocess_grammar(
|
||||
grammar_content,
|
||||
{
|
||||
"ALLOW_NEW_CONTENT": True,
|
||||
"ALLOW_WILDCARDS": False,
|
||||
"ALLOW_CHOICES": True,
|
||||
"ALLOW_COMMVARS": True,
|
||||
},
|
||||
),
|
||||
propagate_positions=True,
|
||||
)
|
||||
self.parser_complete_wc = lark.Lark(
|
||||
self.__preprocess_grammar(
|
||||
grammar_content,
|
||||
{
|
||||
"ALLOW_NEW_CONTENT": True,
|
||||
"ALLOW_WILDCARDS": True,
|
||||
"ALLOW_CHOICES": False,
|
||||
"ALLOW_COMMVARS": False,
|
||||
},
|
||||
),
|
||||
propagate_positions=True,
|
||||
)
|
||||
self.parser_complete_ch = lark.Lark(
|
||||
self.__preprocess_grammar(
|
||||
grammar_content,
|
||||
{
|
||||
"ALLOW_NEW_CONTENT": True,
|
||||
"ALLOW_WILDCARDS": False,
|
||||
"ALLOW_CHOICES": True,
|
||||
"ALLOW_COMMVARS": False,
|
||||
},
|
||||
),
|
||||
propagate_positions=True,
|
||||
)
|
||||
self.parser_complete_cv = lark.Lark(
|
||||
self.__preprocess_grammar(
|
||||
grammar_content,
|
||||
{
|
||||
"ALLOW_NEW_CONTENT": True,
|
||||
"ALLOW_WILDCARDS": False,
|
||||
"ALLOW_CHOICES": False,
|
||||
"ALLOW_COMMVARS": True,
|
||||
},
|
||||
),
|
||||
propagate_positions=True,
|
||||
)
|
||||
|
||||
# Partial parsers for wildcards and choices
|
||||
self.parser_choice = lark.Lark(
|
||||
grammar_content_full,
|
||||
propagate_positions=True,
|
||||
start="choice",
|
||||
)
|
||||
self.parser_choicesoptions = lark.Lark(
|
||||
grammar_content,
|
||||
grammar_content_full,
|
||||
propagate_positions=True,
|
||||
start="choicesoptions",
|
||||
)
|
||||
self.parser_condition = lark.Lark(
|
||||
grammar_content,
|
||||
grammar_content_full,
|
||||
propagate_positions=True,
|
||||
start="condition",
|
||||
)
|
||||
self.parser_choicevalue = lark.Lark(
|
||||
grammar_content,
|
||||
grammar_content_full,
|
||||
propagate_positions=True,
|
||||
start="choicevalue",
|
||||
)
|
||||
@@ -193,6 +291,87 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
self.user_variables = {}
|
||||
self.echoed_variables = {}
|
||||
|
||||
def __preprocess_grammar(self, grammar_content: str, options: dict[str, bool]) -> str:
|
||||
"""
|
||||
Preprocesses the grammar content to handle conditional compilation directives.
|
||||
|
||||
Args:
|
||||
grammar_content (str): The raw grammar content.
|
||||
options (dict[str,bool]): Options for preprocessing.
|
||||
|
||||
Returns:
|
||||
str: The preprocessed grammar content.
|
||||
"""
|
||||
lines = grammar_content.split("\n")
|
||||
result_lines = []
|
||||
skip_current_block = []
|
||||
all_blocks_skipped = []
|
||||
|
||||
def evaluate_conditions(conditions: list[str]) -> bool:
|
||||
"""
|
||||
Evaluates the conditions based on the provided options. Allows for negation with '!' prefix.
|
||||
|
||||
Args:
|
||||
conditions (list[str]): List of conditions to evaluate.
|
||||
|
||||
Returns:
|
||||
bool: True if all conditions are met, False otherwise.
|
||||
"""
|
||||
r = True
|
||||
for condition in conditions:
|
||||
if condition.startswith("!"):
|
||||
r = r and not options.get(condition[1:], False)
|
||||
else:
|
||||
r = r and options.get(condition, True)
|
||||
return r
|
||||
|
||||
for line in lines:
|
||||
stripped_line = line.strip()
|
||||
if stripped_line.startswith("//#if"):
|
||||
# Extract condition from the #if directive
|
||||
conditions = stripped_line[5:].strip().split(" ")
|
||||
# Evaluate the conditions
|
||||
skip_current_block.append(not evaluate_conditions(conditions))
|
||||
all_blocks_skipped.append(skip_current_block[-1])
|
||||
continue
|
||||
if stripped_line.startswith("//#elif"):
|
||||
if not skip_current_block:
|
||||
self.logger.warning("Unmatched //#elif directive found in grammar content.")
|
||||
elif all_blocks_skipped[-1]:
|
||||
# Extract condition from the #elif directive
|
||||
conditions = stripped_line[7:].strip().split(" ")
|
||||
# Evaluate the conditions
|
||||
skip_current_block[-1] = not evaluate_conditions(conditions)
|
||||
if not skip_current_block[-1]:
|
||||
all_blocks_skipped[-1] = False
|
||||
else:
|
||||
skip_current_block[-1] = True
|
||||
continue
|
||||
if stripped_line.startswith("//#else"):
|
||||
if not skip_current_block:
|
||||
self.logger.warning("Unmatched //#else directive found in grammar content.")
|
||||
elif all_blocks_skipped[-1]:
|
||||
skip_current_block[-1] = False
|
||||
else:
|
||||
skip_current_block[-1] = True
|
||||
continue
|
||||
if stripped_line.startswith("//#endif"):
|
||||
if not skip_current_block:
|
||||
self.logger.warning("Unmatched //#endif directive found in grammar content.")
|
||||
else:
|
||||
skip_current_block.pop()
|
||||
all_blocks_skipped.pop()
|
||||
continue
|
||||
# Include the line if we're not skipping any current block
|
||||
if not any(skip_current_block):
|
||||
result_lines.append(stripped_line)
|
||||
# Check for unclosed blocks at the end
|
||||
if skip_current_block:
|
||||
self.logger.warning(
|
||||
f"Found {len(skip_current_block)} unclosed conditional directive(s) at the end of the file"
|
||||
)
|
||||
return "\n".join(result_lines)
|
||||
|
||||
def interrupt(self):
|
||||
if self.interrupt_callback is not None:
|
||||
self.interrupt_callback()
|
||||
@@ -216,7 +395,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
Returns:
|
||||
bool: True if the environment is ComfyUI, False otherwise.
|
||||
"""
|
||||
return self.env_info.get("app", "") == "comfyui"
|
||||
return self.env_info.get("app", "") == SUPPORTED_APPS.comfyui.value
|
||||
|
||||
def __init_sysvars(self):
|
||||
"""
|
||||
@@ -433,6 +612,61 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
text = text.strip()
|
||||
return text
|
||||
|
||||
def __get_best_parser(self, prompt: str) -> tuple[lark.Lark, str]:
|
||||
"""
|
||||
Checks the prompt and returns the best parser to use based on its content.
|
||||
|
||||
Args:
|
||||
prompt (str): The prompt to check.
|
||||
|
||||
Returns:
|
||||
tuple[lark.Lark, str]: The best parser and its description.
|
||||
"""
|
||||
tests = {
|
||||
"ALLOW_WILDCARDS": re.search(r"(?<!\\)__", prompt) is not None,
|
||||
"ALLOW_CHOICES": re.search(r"(?<!\$\\)\{|\}", prompt) is not None,
|
||||
"ALLOW_COMMVARS": re.search(r"(?<!\\)(?:<ppp:|\$\{)", prompt) is not None,
|
||||
}
|
||||
if tests["ALLOW_WILDCARDS"] and tests["ALLOW_CHOICES"] and tests["ALLOW_COMMVARS"]:
|
||||
return (
|
||||
self.parser_complete_full,
|
||||
"full parser with wildcards, choices, commands and variables",
|
||||
)
|
||||
if tests["ALLOW_WILDCARDS"] and tests["ALLOW_CHOICES"]:
|
||||
return (
|
||||
self.parser_complete_wc_ch,
|
||||
"parser with wildcards and choices",
|
||||
)
|
||||
if tests["ALLOW_WILDCARDS"] and tests["ALLOW_COMMVARS"]:
|
||||
return (
|
||||
self.parser_complete_wc_cv,
|
||||
"parser with wildcards, commands and variables",
|
||||
)
|
||||
if tests["ALLOW_CHOICES"] and tests["ALLOW_COMMVARS"]:
|
||||
return (
|
||||
self.parser_complete_ch_cv,
|
||||
"parser with choices, commands and variables",
|
||||
)
|
||||
if tests["ALLOW_WILDCARDS"]:
|
||||
return (
|
||||
self.parser_complete_wc,
|
||||
"parser with wildcards",
|
||||
)
|
||||
if tests["ALLOW_CHOICES"]:
|
||||
return (
|
||||
self.parser_complete_ch,
|
||||
"parser with choices",
|
||||
)
|
||||
if tests["ALLOW_COMMVARS"]:
|
||||
return (
|
||||
self.parser_complete_cv,
|
||||
"parser with commands and variables",
|
||||
)
|
||||
return (
|
||||
self.parser_full_only_old,
|
||||
"simple parser without new constructs",
|
||||
)
|
||||
|
||||
def __processprompts(self, prompt, negative_prompt):
|
||||
"""
|
||||
Process the prompt and negative prompt.
|
||||
@@ -450,12 +684,26 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
|
||||
# Process prompt
|
||||
p_processor = self.TreeProcessor(self)
|
||||
p_parsed = self.parse_prompt("prompt", prompt, self.parser_complete)
|
||||
(prompt_parser, parser_description) = self.__get_best_parser(prompt)
|
||||
if self.debug_level == DEBUG_LEVEL.full:
|
||||
self.logger.debug(f"Using {parser_description} for prompt")
|
||||
p_parsed = self.parse_prompt(
|
||||
"prompt",
|
||||
prompt,
|
||||
prompt_parser,
|
||||
)
|
||||
prompt = p_processor.start_visit("prompt", p_parsed, False)
|
||||
|
||||
# Process negative prompt
|
||||
n_processor = self.TreeProcessor(self)
|
||||
n_parsed = self.parse_prompt("negative prompt", negative_prompt, self.parser_complete)
|
||||
(n_prompt_parser, n_parser_description) = self.__get_best_parser(negative_prompt)
|
||||
if self.debug_level == DEBUG_LEVEL.full:
|
||||
self.logger.debug(f"Using {n_parser_description} for negative prompt")
|
||||
n_parsed = self.parse_prompt(
|
||||
"negative prompt",
|
||||
negative_prompt,
|
||||
n_prompt_parser,
|
||||
)
|
||||
negative_prompt = n_processor.start_visit("negative prompt", n_parsed, True)
|
||||
|
||||
var_keys = set(self.user_variables.keys()).union(set(self.echoed_variables.keys()))
|
||||
@@ -541,13 +789,13 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
self.logger.info(f"Input seed: {seed}")
|
||||
self.logger.info(self.format_output(f"Input prompt: {prompt}"))
|
||||
self.logger.info(self.format_output(f"Input negative_prompt: {negative_prompt}"))
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
prompt, negative_prompt, all_variables = self.__processprompts(prompt, negative_prompt)
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
if self.debug_level != DEBUG_LEVEL.none:
|
||||
self.logger.info(self.format_output(f"Result prompt: {prompt}"))
|
||||
self.logger.info(self.format_output(f"Result negative_prompt: {negative_prompt}"))
|
||||
self.logger.info(f"Process prompt pair time: {t2 - t1:.3f} seconds")
|
||||
self.logger.info(f"Process prompt pair time: {(t2 - t1) / 1_000_000_000:.3f} seconds")
|
||||
|
||||
# if self.debug_level != DEBUG_LEVEL.none:
|
||||
# self.logger.debug(f"Wildcards memory usage: {self.wildcard_obj.__sizeof__()}")
|
||||
@@ -586,7 +834,8 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
Returns:
|
||||
Tree: The parsed prompt.
|
||||
"""
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
parsed_prompt = None
|
||||
try:
|
||||
if self.debug_level == DEBUG_LEVEL.full:
|
||||
self.logger.debug(self.format_output(f"Parsing {prompt_description}: '{prompt}'"))
|
||||
@@ -602,10 +851,11 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
if raise_parsing_error:
|
||||
raise
|
||||
self.logger.exception(self.format_output(f"Parsing failed on prompt!: {prompt}"))
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
if self.debug_level == DEBUG_LEVEL.full:
|
||||
self.logger.debug("Tree:\n" + textwrap.indent(re.sub(r"\n$", "", parsed_prompt.pretty()), " "))
|
||||
self.logger.debug(f"Parse {prompt_description} time: {t2 - t1:.3f} seconds")
|
||||
self.logger.debug(f"Parse {prompt_description} time: {(t2 - t1) / 1_000_000_000:.3f} seconds")
|
||||
if parsed_prompt:
|
||||
self.logger.debug("Tree:\n" + textwrap.indent(re.sub(r"\n$", "", parsed_prompt.pretty()), " "))
|
||||
return parsed_prompt
|
||||
|
||||
class TreeProcessor(lark.visitors.Interpreter):
|
||||
@@ -658,14 +908,14 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
Returns:
|
||||
str: The processed prompt.
|
||||
"""
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
self.__is_negative = is_negative
|
||||
if self.__ppp.debug_level != DEBUG_LEVEL.none:
|
||||
self.__ppp.logger.info(f"Processing {prompt_description}...")
|
||||
self.visit(parsed_prompt)
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
if self.__ppp.debug_level != DEBUG_LEVEL.none:
|
||||
self.__ppp.logger.info(f"Process {prompt_description} time: {t2 - t1:.3f} seconds")
|
||||
self.__ppp.logger.info(f"Process {prompt_description} time: {(t2 - t1) / 1_000_000_000:.3f} seconds")
|
||||
return self.result
|
||||
|
||||
def __visit(
|
||||
@@ -778,14 +1028,14 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
if name in self.__ppp.user_variables:
|
||||
del self.__ppp.user_variables[name]
|
||||
|
||||
def __debug_end(self, construct: str, start_result: str, duration: float, info=None):
|
||||
def __debug_end(self, construct: str, start_result: str, duration: int, info=None):
|
||||
"""
|
||||
Log the end of a construct processing.
|
||||
|
||||
Args:
|
||||
construct (str): The name of the construct.
|
||||
start_result (str): The initial result.
|
||||
duration (float): The duration of the processing.
|
||||
duration (int): The duration of the processing in ns.
|
||||
info: Additional information to log.
|
||||
"""
|
||||
if self.__ppp.debug_level == DEBUG_LEVEL.full:
|
||||
@@ -794,7 +1044,9 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
if output != "":
|
||||
output = f" >> '{output}'"
|
||||
self.__ppp.logger.debug(
|
||||
self.__ppp.format_output(f"TreeProcessor.{construct} {info}({duration:.3f} seconds){output}")
|
||||
self.__ppp.format_output(
|
||||
f"TreeProcessor.{construct} {info}({duration / 1_000_000_000:.3f} seconds){output}"
|
||||
)
|
||||
)
|
||||
|
||||
def __eval_basiccondition(self, cond_var: str, cond_comp: str, cond_value: str | list[str]) -> bool:
|
||||
@@ -928,7 +1180,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
# if self.__ppp.is_comfy_ui():
|
||||
# self.__ppp.logger.warning("Prompt composition is not supported in ComfyUI.")
|
||||
start_result = self.result
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
self.__visit(tree.children[0])
|
||||
if len(tree.children) > 1:
|
||||
if tree.children[1] is not None:
|
||||
@@ -947,7 +1199,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
self.result += added_result
|
||||
if tree.children[i + 2] is not None:
|
||||
self.result += f":{tree.children[i+2]}"
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end("promptcomp", start_result, t2 - t1)
|
||||
|
||||
def scheduled(self, tree: lark.Tree):
|
||||
@@ -957,7 +1209,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
# if self.__ppp.is_comfy_ui():
|
||||
# self.__ppp.logger.warning("Prompt scheduling is not supported in ComfyUI.")
|
||||
start_result = self.result
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
before = tree.children[0]
|
||||
after = tree.children[-2]
|
||||
pos_str = tree.children[-1]
|
||||
@@ -983,7 +1235,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
else:
|
||||
self.result += f":{pos_str}]"
|
||||
# self.__shell.pop()
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end("scheduled", start_result, t2 - t1, pos_str)
|
||||
|
||||
def alternate(self, tree: lark.Tree):
|
||||
@@ -993,7 +1245,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
# if self.__ppp.is_comfy_ui():
|
||||
# self.__ppp.logger.warning("Prompt alternation is not supported in ComfyUI.")
|
||||
start_result = self.result
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
# self.__shell.append(self.AccumulatedShell("al", len(tree.children)))
|
||||
self.result += "["
|
||||
for i, opt in enumerate(tree.children):
|
||||
@@ -1008,7 +1260,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
if self.__ppp.cup_emptyconstructs and self.result == start_result + "[]":
|
||||
self.result = start_result
|
||||
# self.__shell.pop()
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end("alternate", start_result, t2 - t1)
|
||||
|
||||
def attention(self, tree: lark.Tree):
|
||||
@@ -1016,7 +1268,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
Process a attention change construct in the tree and add it to the accumulated shell.
|
||||
"""
|
||||
start_result = self.result
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
if len(tree.children) == 2:
|
||||
weight_str = tree.children[-1]
|
||||
if weight_str is not None:
|
||||
@@ -1078,7 +1330,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
else:
|
||||
self.result += endtag
|
||||
self.__shell.pop()
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end("attention", start_result, t2 - t1, weight_str)
|
||||
|
||||
def commandstn(self, tree: lark.Tree):
|
||||
@@ -1087,7 +1339,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
"""
|
||||
start_result = self.result
|
||||
info = None
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
if not self.__is_negative:
|
||||
negtagparameters = tree.children[0]
|
||||
if negtagparameters is not None:
|
||||
@@ -1102,7 +1354,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
else:
|
||||
self.warn_or_stop("Ignored negative command in negative prompt")
|
||||
self.__visit(tree.children[1::])
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end("commandstn", start_result, t2 - t1, info)
|
||||
|
||||
def commandstni(self, tree: lark.Tree):
|
||||
@@ -1111,7 +1363,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
"""
|
||||
start_result = self.result
|
||||
info = None
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
if self.__is_negative:
|
||||
negtagparameters = tree.children[0]
|
||||
if negtagparameters is not None:
|
||||
@@ -1124,7 +1376,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
info = f"with {parameters or 'no parameters'}"
|
||||
else:
|
||||
self.warn_or_stop("Ignored negative insertion point command in positive prompt")
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end("commandstni", start_result, t2 - t1, info)
|
||||
|
||||
def __varset(
|
||||
@@ -1137,7 +1389,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
"""
|
||||
Process a generic set command in the tree.
|
||||
"""
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
start_result = self.result
|
||||
if variable.startswith("_"):
|
||||
self.warn_or_stop(f"Invalid variable name '{variable}' detected! System variables cannot be set.")
|
||||
@@ -1186,7 +1438,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
info += "not evaluated yet"
|
||||
else:
|
||||
info += f"'{currentvalue}'"
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end(command, start_result, t2 - t1, info)
|
||||
|
||||
def variableset(self, tree: lark.Tree):
|
||||
@@ -1210,7 +1462,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
"""
|
||||
Process a generic echo command in the tree.
|
||||
"""
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
start_result = self.result
|
||||
if default is not None:
|
||||
default_value = self.__visit(default, True) # for log
|
||||
@@ -1222,7 +1474,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
self.result += v
|
||||
else:
|
||||
self.warn_or_stop(f"Unknown variable {variable}")
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
info = variable
|
||||
if default is not None:
|
||||
info += f" with default '{default_value}'"
|
||||
@@ -1244,7 +1496,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
"""
|
||||
Process an if command in the tree.
|
||||
"""
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
start_result = self.result
|
||||
for i, n in enumerate(tree.children):
|
||||
content = n.children[-1]
|
||||
@@ -1254,12 +1506,12 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
c = self.__get_original_node_content(condition, f"condition {i}")
|
||||
if self.__eval_condition(condition):
|
||||
self.__visit(content)
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end("commandif", start_result, t2 - t1, c)
|
||||
return
|
||||
else: # its an else
|
||||
self.__visit(content)
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end("commandif", start_result, t2 - t1, "else")
|
||||
return
|
||||
|
||||
@@ -1267,13 +1519,13 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
"""
|
||||
Process an extra network construct in the tree.
|
||||
"""
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
start_result = self.result
|
||||
if not self.__ppp.rem_removeextranetworktags:
|
||||
self.result += f"<{tree.children[0]}"
|
||||
self.__visit(tree.children[1])
|
||||
self.result += ">"
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end("extranetworktag", start_result, t2 - t1)
|
||||
|
||||
def __get_choices_internal(
|
||||
@@ -1396,16 +1648,16 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
if prefix != "" and re.match(r"\w", prefix[-1]):
|
||||
prefix += " "
|
||||
for i, c in enumerate(selected_choices):
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
choice_content_obj = c.get("content", c.get("text", None))
|
||||
if isinstance(choice_content_obj, str):
|
||||
choice_content = choice_content_obj
|
||||
else:
|
||||
choice_content = self.__visit(choice_content_obj, False, True)
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
if self.__ppp.debug_level == DEBUG_LEVEL.full:
|
||||
self.__ppp.logger.debug(
|
||||
f"Adding choice {i+1} ({t2-t1:.3f} seconds):\n"
|
||||
f"Adding choice {i+1} ({(t2-t1) / 1_000_000_000:.3f} seconds):\n"
|
||||
+ textwrap.indent(re.sub(r"\n$", "", choice_content), " ")
|
||||
)
|
||||
selected_choices_text.append(choice_content)
|
||||
@@ -1502,7 +1754,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
choice_values = wildcard.choices
|
||||
options = wildcard.options
|
||||
if choice_values is None:
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
choice_values = []
|
||||
n = 0
|
||||
# we check the first choice to see if it is actually options
|
||||
@@ -1599,16 +1851,18 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
f"Error parsing choice '{cv}' in wildcard '{wildcard.key}'! : {e.__class__.__name__}", e
|
||||
)
|
||||
wildcard.choices = choice_values
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
if self.__ppp.debug_level == DEBUG_LEVEL.full:
|
||||
self.__ppp.logger.debug(f"Processed choices for wildcard '{wildcard.key}' ({t2-t1:.3f} seconds)")
|
||||
self.__ppp.logger.debug(
|
||||
f"Processed choices for wildcard '{wildcard.key}' ({(t2-t1) / 1_000_000_000:.3f} seconds)"
|
||||
)
|
||||
return (options, choice_values)
|
||||
|
||||
def wildcard(self, tree: lark.Tree):
|
||||
"""
|
||||
Process a wildcard construct in the tree.
|
||||
"""
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
start_result = self.result
|
||||
applied_options = self.__convert_choices_options(tree.children[0])
|
||||
wildcard_key: str = tree.children[1].value # should be a token
|
||||
@@ -1620,7 +1874,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
if not selected_wildcards:
|
||||
self.detectedWildcards.append(wc)
|
||||
self.result += wc
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end("wildcard", start_result, t2 - t1, wc)
|
||||
return
|
||||
filter_specifier: list[int | str] = None
|
||||
@@ -1667,7 +1921,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
if wildcard is None:
|
||||
self.detectedWildcards.append(wc)
|
||||
self.result += wc
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end("wildcard", start_result, t2 - t1, wc)
|
||||
return
|
||||
(options, choice_values) = self.__check_wildcard_initialization(wildcard)
|
||||
@@ -1688,14 +1942,14 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
elif self.__ppp.wil_ifwildcards != self.__ppp.IFWILDCARDS_CHOICES.remove:
|
||||
self.detectedWildcards.append(wc)
|
||||
self.result += wc
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end("wildcard", start_result, t2 - t1, f"'{wc}'")
|
||||
|
||||
def choices(self, tree: lark.Tree):
|
||||
"""
|
||||
Process a choices construct in the tree.
|
||||
"""
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
start_result = self.result
|
||||
options = self.__convert_choices_options(tree.children[0])
|
||||
choice_values = [self.__convert_choice(c) for c in tree.children[1::]]
|
||||
@@ -1707,19 +1961,19 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
elif self.__ppp.wil_ifwildcards != self.__ppp.IFWILDCARDS_CHOICES.remove:
|
||||
self.detectedWildcards.append(ch)
|
||||
self.result += ch
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end("choices", start_result, t2 - t1, f"'{ch}'")
|
||||
|
||||
def __default__(self, tree):
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
start_result = self.result
|
||||
self.__visit(tree.children)
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end(tree.data.value, start_result, t2 - t1)
|
||||
|
||||
def start(self, tree):
|
||||
self.result = ""
|
||||
t1 = time.time()
|
||||
t1 = time.monotonic_ns()
|
||||
self.__visit(tree.children)
|
||||
# process the found negative tags
|
||||
for negtag in self.__negtags:
|
||||
@@ -1790,5 +2044,5 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
self.add_at["start"].append(content)
|
||||
else:
|
||||
self.__ppp.logger.warning(self.__ppp.format_output(f"Ignoring repeated content: {content}"))
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
self.__debug_end("start", "", t2 - t1)
|
||||
|
||||
+3
-2
@@ -5,6 +5,7 @@ import folder_paths # type: ignore
|
||||
import nodes # type: ignore
|
||||
|
||||
from .ppp import PromptPostProcessor
|
||||
from .ppp_hosts import SUPPORTED_APPS
|
||||
from .ppp_logging import DEBUG_LEVEL, PromptPostProcessorLogFactory
|
||||
from .ppp_wildcards import PPPWildcards
|
||||
|
||||
@@ -20,7 +21,7 @@ class PromptPostProcessorComfyUINode:
|
||||
logger = None
|
||||
|
||||
def __init__(self):
|
||||
lf = PromptPostProcessorLogFactory()
|
||||
lf = PromptPostProcessorLogFactory(SUPPORTED_APPS.comfyui)
|
||||
self.logger = lf.log
|
||||
grammar_filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), "grammar.lark")
|
||||
with open(grammar_filename, "r", encoding="utf-8") as file:
|
||||
@@ -419,7 +420,7 @@ class PromptPostProcessorComfyUINode:
|
||||
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 = {
|
||||
"app": "comfyui",
|
||||
"app": SUPPORTED_APPS.comfyui.value,
|
||||
"models_path": folder_paths.models_dir,
|
||||
"model_filename": modelname or "", # path is relative to checkpoints folder
|
||||
"model_class": modelclass,
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class SUPPORTED_APPS(Enum):
|
||||
comfyui = "comfyui"
|
||||
a1111 = "a1111"
|
||||
forge = "forge"
|
||||
reforge = "reforge"
|
||||
sdnext = "sdnext"
|
||||
|
||||
SUPPORTED_APPS_NAMES = {
|
||||
SUPPORTED_APPS.comfyui: "ComfyUI",
|
||||
SUPPORTED_APPS.sdnext: "SD.Next",
|
||||
SUPPORTED_APPS.forge: "Forge",
|
||||
SUPPORTED_APPS.reforge: "reForge",
|
||||
SUPPORTED_APPS.a1111: "A1111 (or compatible)",
|
||||
}
|
||||
+4
-3
@@ -2,6 +2,7 @@ from enum import Enum
|
||||
import logging
|
||||
import sys
|
||||
import copy
|
||||
from ppp_hosts import SUPPORTED_APPS # pylint: disable=import-error
|
||||
|
||||
|
||||
class DEBUG_LEVEL(Enum):
|
||||
@@ -52,14 +53,14 @@ class PromptPostProcessorLogFactory: # pylint: disable=too-few-public-methods
|
||||
colored_record.levelname = f"{seq}{levelname:8s}{self.COLORS['RESET']}"
|
||||
return super().format(colored_record)
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, app: SUPPORTED_APPS = None): # pylint: disable=unused-argument
|
||||
"""
|
||||
Initializes the PromptPostProcessor class.
|
||||
|
||||
This method sets up the logger for the PromptPostProcessor class and configures its log level and handlers.
|
||||
|
||||
Args:
|
||||
None
|
||||
app (SUPPORTED_APPS): The application for which the logger is being created.
|
||||
|
||||
Returns:
|
||||
None
|
||||
@@ -68,7 +69,7 @@ class PromptPostProcessorLogFactory: # pylint: disable=too-few-public-methods
|
||||
ppplog.propagate = False
|
||||
if not ppplog.handlers:
|
||||
handler = logging.StreamHandler(sys.stdout)
|
||||
handler.setFormatter(self.ColoredFormatter("%(asctime)s %(levelname)s %(message)s")) # Used in A1111 / Forge / reForge / ComfyUI, but not in SD.Next
|
||||
handler.setFormatter(self.ColoredFormatter("%(asctime)s %(levelname)s %(message)s"))
|
||||
ppplog.addHandler(handler)
|
||||
ppplog.setLevel(logging.DEBUG)
|
||||
self.log = PromptPostProcessorLogCustomAdapter(ppplog)
|
||||
|
||||
+3
-3
@@ -93,7 +93,7 @@ class PPPWildcards:
|
||||
self.__wildcards_folders = wildcards_folders or []
|
||||
# if self.__debug_level != DEBUG_LEVEL.none:
|
||||
# self.__logger.info("Refreshing wildcards...")
|
||||
# t1 = time.time()
|
||||
# t1 = time.monotonic_ns()
|
||||
for fullpath in list(self.__wildcard_files.keys()):
|
||||
if fullpath != self.LOCALINPUT_FILENAME:
|
||||
path = os.path.dirname(fullpath)
|
||||
@@ -112,9 +112,9 @@ class PPPWildcards:
|
||||
else:
|
||||
self.wildcards = {}
|
||||
self.__wildcard_files = {}
|
||||
# t2 = time.time()
|
||||
# t2 = time.monotonic_ns()
|
||||
# if self.__debug_level != DEBUG_LEVEL.none:
|
||||
# self.__logger.info(f"Wildcards refresh time: {t2 - t1:.3f} seconds")
|
||||
# self.__logger.info(f"Wildcards refresh time: {(t2 - t1) / 1_000_000_000:.3f} seconds")
|
||||
|
||||
def get_wildcards(self, key: str) -> list[PPPWildcard]:
|
||||
"""
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
[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.11.0"
|
||||
version = "2.12.0"
|
||||
license = { file = "LICENSE.txt" }
|
||||
dependencies = ["lark", "numpy", "pyyaml"]
|
||||
|
||||
|
||||
+40
-37
@@ -15,6 +15,7 @@ from modules.shared import opts # pylint: disable=import-error
|
||||
from modules.paths import models_path # pylint: disable=import-error
|
||||
import gradio as gr # pylint: disable=import-error
|
||||
from ppp import PromptPostProcessor # pylint: disable=import-error
|
||||
from ppp_hosts import SUPPORTED_APPS, SUPPORTED_APPS_NAMES # pylint: disable=import-error
|
||||
from ppp_logging import DEBUG_LEVEL, PromptPostProcessorLogFactory # pylint: disable=import-error
|
||||
from ppp_cache import PPPLRUCache # pylint: disable=import-error
|
||||
from ppp_wildcards import PPPWildcards # pylint: disable=import-error
|
||||
@@ -42,6 +43,7 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
||||
@classmethod
|
||||
def increment_instance_count(cls):
|
||||
cls.instance_count += 1
|
||||
return cls.instance_count
|
||||
|
||||
@classmethod
|
||||
def get_instance_count(cls):
|
||||
@@ -51,27 +53,21 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
||||
"""
|
||||
Initializes the PromptPostProcessor object.
|
||||
|
||||
This method adds callbacks for UI settings and initializes the logger.
|
||||
|
||||
Parameters:
|
||||
None
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
self.increment_instance_count()
|
||||
lf = PromptPostProcessorLogFactory()
|
||||
self.instance_index = self.increment_instance_count()
|
||||
self.name = PromptPostProcessor.NAME
|
||||
self.ppp_logger = lf.log
|
||||
self.ppp_debug_level = DEBUG_LEVEL(getattr(opts, "ppp_gen_debug_level", DEBUG_LEVEL.none.value))
|
||||
self.lru_cache = PPPLRUCache(1000, logger=self.ppp_logger, debug_level=self.ppp_debug_level)
|
||||
grammar_filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../grammar.lark")
|
||||
with open(grammar_filename, "r", encoding="utf-8") as file:
|
||||
self.grammar_content = file.read()
|
||||
self.wildcards_obj = PPPWildcards(lf.log)
|
||||
i = self.get_instance_count()
|
||||
if i == 1: # some UIs create multiple instances
|
||||
self.ppp_logger.info(f"{PromptPostProcessor.NAME} {PromptPostProcessor.VERSION} initialized")
|
||||
self.ppp_logger = None
|
||||
self.ppp_debug_level = DEBUG_LEVEL.none.value
|
||||
self.lru_cache = None
|
||||
self.wildcards_obj = None
|
||||
|
||||
def title(self):
|
||||
"""
|
||||
@@ -164,7 +160,29 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
t1 = time.time()
|
||||
app = (
|
||||
SUPPORTED_APPS.forge
|
||||
if hasattr(p.sd_model, "model_config")
|
||||
else (
|
||||
SUPPORTED_APPS.reforge
|
||||
if hasattr(p.sd_model, "forge_objects")
|
||||
else (
|
||||
SUPPORTED_APPS.sdnext
|
||||
if hasattr(p.sd_model, "is_sdxl") and not hasattr(p.sd_model, "is_ssd")
|
||||
else SUPPORTED_APPS.a1111
|
||||
)
|
||||
)
|
||||
)
|
||||
if self.ppp_logger is None:
|
||||
lf = PromptPostProcessorLogFactory(app)
|
||||
self.ppp_logger = lf.log
|
||||
self.ppp_debug_level = DEBUG_LEVEL(getattr(opts, "ppp_gen_debug_level", DEBUG_LEVEL.none.value))
|
||||
self.lru_cache = PPPLRUCache(1000, logger=self.ppp_logger, debug_level=self.ppp_debug_level)
|
||||
self.wildcards_obj = PPPWildcards(self.ppp_logger)
|
||||
self.ppp_logger.info(
|
||||
f"{PromptPostProcessor.NAME} {PromptPostProcessor.VERSION} initialized, running on {SUPPORTED_APPS_NAMES[app]}"
|
||||
)
|
||||
t1 = time.monotonic_ns()
|
||||
if getattr(opts, "prompt_attention", "") == "Compel parser":
|
||||
self.ppp_logger.warning("Compel parser is not supported!")
|
||||
init_images = getattr(p, "init_images", [None]) or [None]
|
||||
@@ -186,37 +204,22 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
||||
}
|
||||
)
|
||||
|
||||
app_names = {
|
||||
"sdnext": "SD.Next",
|
||||
"forge": "Forge",
|
||||
"reforge": "reForge",
|
||||
"a1111": "A1111 (or compatible)",
|
||||
}
|
||||
app = (
|
||||
"forge"
|
||||
if hasattr(p.sd_model, "model_config")
|
||||
else (
|
||||
"reforge"
|
||||
if hasattr(p.sd_model, "forge_objects")
|
||||
else ("sdnext" if hasattr(p.sd_model, "is_sdxl") and not hasattr(p.sd_model, "is_ssd") else "a1111")
|
||||
)
|
||||
)
|
||||
if self.ppp_debug_level != DEBUG_LEVEL.none:
|
||||
self.ppp_logger.info(f"Post-processing prompts ({'i2i' if is_i2i else 't2i'}) running on {app_names[app]}")
|
||||
self.ppp_logger.info(f"Post-processing prompts ({'i2i' if is_i2i else 't2i'})")
|
||||
models_supported = {x: True for x in PromptPostProcessor.SUPPORTED_MODELS}
|
||||
if app == "sdnext":
|
||||
if app == SUPPORTED_APPS.sdnext:
|
||||
models_supported["ssd"] = False
|
||||
elif app == "forge":
|
||||
elif app == SUPPORTED_APPS.forge:
|
||||
models_supported["ssd"] = False
|
||||
models_supported["auraflow"] = False
|
||||
elif app == "reforge":
|
||||
elif app == SUPPORTED_APPS.reforge:
|
||||
models_supported["flux"] = False
|
||||
models_supported["auraflow"] = False
|
||||
else: # assume A1111 compatible
|
||||
models_supported["flux"] = False
|
||||
models_supported["auraflow"] = False
|
||||
env_info = {
|
||||
"app": app,
|
||||
"app": app.value,
|
||||
"models_path": models_path,
|
||||
"model_filename": getattr(p.sd_model.sd_checkpoint_info, "filename", ""),
|
||||
"model_class": "",
|
||||
@@ -238,7 +241,7 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
||||
"is_wanvideo": False, # WanVideo
|
||||
"is_hidream": False, # HiDream
|
||||
}
|
||||
if app == "sdnext":
|
||||
if app == SUPPORTED_APPS.sdnext:
|
||||
# cannot differentiate SD1 and SD2, we set True to both
|
||||
# LatentDiffusion is for the original backend, StableDiffusionPipeline is for the diffusers backend
|
||||
env_info["model_class"] = p.sd_model.__class__.__name__
|
||||
@@ -250,7 +253,7 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
||||
env_info["is_flux"] = p.sd_model.__class__.__name__ == "FluxPipeline"
|
||||
env_info["is_auraflow"] = p.sd_model.__class__.__name__ == "AuraFlowPipeline"
|
||||
# also supports 'Latent Consistency Model': LatentConsistencyModelPipeline', 'PixArt-Alpha': 'PixArtAlphaPipeline', 'UniDiffuser': 'UniDiffuserPipeline', 'Wuerstchen': 'WuerstchenCombinedPipeline', 'Kandinsky 2.1': 'KandinskyPipeline', 'Kandinsky 2.2': 'KandinskyV22Pipeline', 'Kandinsky 3': 'Kandinsky3Pipeline', 'DeepFloyd IF': 'IFPipeline', 'Custom Diffusers Pipeline': 'DiffusionPipeline', 'InstaFlow': 'StableDiffusionPipeline', 'SegMoE': 'StableDiffusionPipeline', 'Kolors': 'KolorsPipeline', 'AuraFlow': 'AuraFlowPipeline', 'CogView': 'CogView3PlusPipeline'
|
||||
elif app == "forge":
|
||||
elif app == SUPPORTED_APPS.forge:
|
||||
# from repositories\huggingface_guess\huggingface_guess\model_list.py
|
||||
env_info["model_class"] = p.sd_model.model_config.__class__.__name__
|
||||
env_info["is_sd1"] = getattr(p.sd_model, "is_sd1", False)
|
||||
@@ -262,7 +265,7 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
||||
) # p.sd_model.model_config.__class__.__name__ == "SD3" # not actually supported?
|
||||
env_info["is_flux"] = p.sd_model.model_config.__class__.__name__ in ("Flux", "FluxSchnell")
|
||||
env_info["is_auraflow"] = False # p.sd_model.model_config.__class__.__name__ == "AuraFlow" # not supported
|
||||
elif app == "reforge":
|
||||
elif app == SUPPORTED_APPS.reforge:
|
||||
env_info["model_class"] = p.sd_model.__class__.__name__
|
||||
env_info["is_sd1"] = getattr(p.sd_model, "is_sd1", False)
|
||||
env_info["is_sd2"] = getattr(p.sd_model, "is_sd2", False)
|
||||
@@ -451,9 +454,9 @@ class PromptPostProcessorA1111Script(scripts.Script):
|
||||
if p.extra_generation_params.get(k) is None:
|
||||
p.extra_generation_params[k] = v
|
||||
|
||||
t2 = time.time()
|
||||
t2 = time.monotonic_ns()
|
||||
if self.ppp_debug_level != DEBUG_LEVEL.none:
|
||||
self.ppp_logger.info(f"process time: {t2 - t1:.3f} seconds")
|
||||
self.ppp_logger.info(f"process time: {(t2 - t1) / 1_000_000_000:.3f} seconds")
|
||||
|
||||
def ppp_interrupt(self):
|
||||
"""
|
||||
|
||||
@@ -1051,6 +1051,71 @@ class TestPromptPostProcessor(TestPromptPostProcessorBase):
|
||||
ppp=self.comfyuippp,
|
||||
)
|
||||
|
||||
# Performance tests
|
||||
|
||||
def test_parser_performance_simple_simpleparser(
|
||||
self,
|
||||
): # performance test with a large prompt without new constructs
|
||||
large_prompt = ", ".join(
|
||||
["(this:1.2) is a [test] using a [simple|low complexity] prompt with <lora:test:1>"] * 15
|
||||
)
|
||||
self.process(
|
||||
PromptPair(large_prompt, ""),
|
||||
ppp=self.nocupppp,
|
||||
)
|
||||
|
||||
def test_parser_performance_simple_fullparser(
|
||||
self,
|
||||
): # performance test with a large prompt without new constructs but using full parser
|
||||
# we trick it to use the full parser by including some characters
|
||||
large_prompt = "{__${x:}}" + ", ".join(
|
||||
["(this:1.2) is a [test] using a [simple|low complexity] prompt with <lora:test:1>"] * 15
|
||||
)
|
||||
self.process(
|
||||
PromptPair(large_prompt, ""),
|
||||
ppp=self.nocupppp,
|
||||
)
|
||||
|
||||
def test_parser_performance_complex_fullparser(
|
||||
self,
|
||||
): # performance test with a large prompt with new constructs (full parser)
|
||||
large_prompt = ", ".join(["__yaml/wildcard1__, (__yaml/wildcard2__), __yaml/wildcard3__, {one|two|three}"] * 15)
|
||||
self.process(
|
||||
PromptPair(large_prompt, ""),
|
||||
ppp=self.nocupppp,
|
||||
)
|
||||
|
||||
# the following tests are performance tests with only one kind of the old constructs
|
||||
# same number of constructs and approximately the same full length
|
||||
|
||||
def test_parser_performance_simple_attention(self): # performance test with only attention
|
||||
large_prompt = ", ".join(["(one:1.2) two (three) four [five] six"] * 20)
|
||||
self.process(
|
||||
PromptPair(large_prompt, ""),
|
||||
ppp=self.nocupppp,
|
||||
)
|
||||
|
||||
def test_parser_performance_simple_schedules(self): # performance test with only schedules
|
||||
large_prompt = ", ".join(["[one:1:0.5] two [three:0.8] four [five:5:0.2] six"] * 20)
|
||||
self.process(
|
||||
PromptPair(large_prompt, ""),
|
||||
ppp=self.nocupppp,
|
||||
)
|
||||
|
||||
def test_parser_performance_simple_alternation(self): # performance test with only alternation
|
||||
large_prompt = ", ".join(["[one|1] two [three|3] four [five|5] six"] * 20)
|
||||
self.process(
|
||||
PromptPair(large_prompt, ""),
|
||||
ppp=self.nocupppp,
|
||||
)
|
||||
|
||||
def test_parser_performance_simple_extranetwork(self): # performance test with only extra networks
|
||||
large_prompt = ", ".join(["<lora:one:1> two <lora:three:1> four <lora:five:1> six"] * 20)
|
||||
self.process(
|
||||
PromptPair(large_prompt, ""),
|
||||
ppp=self.nocupppp,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user