diff --git a/ScheduleFuncs.py b/ScheduleFuncs.py index 2d32392..1501fc6 100644 --- a/ScheduleFuncs.py +++ b/ScheduleFuncs.py @@ -6,7 +6,7 @@ import torch import numpy as np import pandas as pd import re - +import json #functions used by PromptSchedule nodes @@ -71,21 +71,6 @@ def prepare_prompt(prompt_series, max_frames, frame_idx, prompt_weight_1 = 0, pr prompt_parsed = prompt_parsed.replace(matched_string, str(parsed_value)) return prompt_parsed.strip() - -def prepare_batch_prompt(prompt_series, max_frames, frame_idx, prompt_weight_1 = 0, prompt_weight_2 = 0, prompt_weight_3 = 0, - prompt_weight_4 = 0): # calculate expressions from the text input and return a string - max_f = max_frames - 1 - pattern = r'`.*?`' # set so the expression will be read between two backticks (``) - regex = re.compile(pattern) - prompt_parsed = str(prompt_series) - - for match in regex.finditer(prompt_parsed): - matched_string = match.group(0) - parsed_string = matched_string.replace('t', f'{frame_idx}').replace("pw_a", f"prompt_weight_1").replace("pw_b",f"prompt_weight_2").replace("pw_c", f"prompt_weight_3").replace("pw_d", f"prompt_weight_4").replace("max_f", f"{max_f}").replace('`', '') # replace t, max_f and `` respectively - parsed_value = numexpr.evaluate(parsed_string) - prompt_parsed = prompt_parsed.replace(matched_string, str(parsed_value)) - return prompt_parsed.strip() - def interpolate_string(animation_prompts, max_frames, current_frame, pre_text, app_text, prompt_weight_1, prompt_weight_2, prompt_weight_3, prompt_weight_4): # parse the conditioning strength and determine in-betweens. @@ -272,145 +257,6 @@ def PoolAnimConditioning(cur_prompt, nxt_prompt, weight, clip): cond_to, pooled_to = clip.encode_from_tokens(tokens, return_pooled=True) return addWeighted([[cond_to, {"pooled_output": pooled_to}]], [[cond_from, {"pooled_output": pooled_from}]], weight) - -def interpolate_prompt_series(animation_prompts, max_frames, pre_text, app_text, prompt_weight_1 = [], - prompt_weight_2 = [], prompt_weight_3 = [], - prompt_weight_4 = []): # parse the conditioning strength and determine in-betweens. - # Get prompts sorted by keyframe - max_f = max_frames # needed for numexpr even though it doesn't look like it's in use. - parsed_animation_prompts = {} - for key, value in animation_prompts.items(): - if check_is_number(key): # default case 0:(1 + t %5), 30:(5-t%2) - parsed_animation_prompts[key] = value - else: # math on the left hand side case 0:(1 + t %5), maxKeyframes/2:(5-t%2) - parsed_animation_prompts[int(numexpr.evaluate(key))] = value - - sorted_prompts = sorted(parsed_animation_prompts.items(), key=lambda item: int(item[0])) - - # Setup containers for interpolated prompts - cur_prompt_series = pd.Series([np.nan for a in range(max_frames)]) - nxt_prompt_series = pd.Series([np.nan for a in range(max_frames)]) - - # simple array for strength values - weight_series = [np.nan] * max_frames - - # in case there is only one keyed promt, set all prompts to that prompt - if len(sorted_prompts) - 1 == 0: - for i in range(0, len(cur_prompt_series) - 1): - current_prompt = sorted_prompts[0][1] - cur_prompt_series[i] = str(pre_text) + " " + str(current_prompt) + " " + str(app_text) - nxt_prompt_series[i] = str(pre_text) + " " + str(current_prompt) + " " + str(app_text) - - # Initialized outside of loop for nan check - current_key = 0 - next_key = 0 - - # For every keyframe prompt except the last - for i in range(0, len(sorted_prompts) - 1): - # Get current and next keyframe - current_key = int(sorted_prompts[i][0]) - next_key = int(sorted_prompts[i + 1][0]) - - # Ensure there's no weird ordering issues or duplication in the animation prompts - # (unlikely because we sort above, and the json parser will strip dupes) - if current_key >= next_key: - print( - f"WARNING: Sequential prompt keyframes {i}:{current_key} and {i + 1}:{next_key} are not monotonously increasing; skipping interpolation.") - continue - - # Get current and next keyframes' positive and negative prompts (if any) - current_prompt = sorted_prompts[i][1] - next_prompt = sorted_prompts[i + 1][1] - - # Calculate how much to shift the weight from current to next prompt at each frame. - weight_step = 1 / (next_key - current_key) - - for f in range(max(current_key, 0), min(next_key, len(cur_prompt_series))): - next_weight = weight_step * (f - current_key) - current_weight = 1 - next_weight - - # add the appropriate prompts and weights to their respective containers. - # print(weight_series) - # print(weight_series[f]) - cur_prompt_series[f] = '' - nxt_prompt_series[f] = '' - weight_series[f] = 0.0 - - cur_prompt_series[f] += (str(pre_text) + " " + str(current_prompt) + " " + str(app_text)) - nxt_prompt_series[f] += (str(pre_text) + " " + str(next_prompt) + " " + str(app_text)) - - weight_series[f] += current_weight - - current_key = next_key - next_key = max_frames - current_weight = 0.0 - # second loop to catch any nan runoff - for f in range(current_key, next_key): - next_weight = weight_step * (f - current_key) - - # add the appropriate prompts and weights to their respective containers. - cur_prompt_series[f] = '' - nxt_prompt_series[f] = '' - weight_series[f] = current_weight - - cur_prompt_series[f] += (str(pre_text) + " " + str(current_prompt) + " " + str(app_text)) - nxt_prompt_series[f] += (str(pre_text) + " " + str(next_prompt) + " " + str(app_text)) - - if isinstance(prompt_weight_1, int): - prompt_weight_1 = tuple([prompt_weight_1] * max_frames) - - if isinstance(prompt_weight_2, int): - prompt_weight_2 = tuple([prompt_weight_2] * max_frames) - - if isinstance(prompt_weight_3, int): - prompt_weight_3 = tuple([prompt_weight_3] * max_frames) - - if isinstance(prompt_weight_4, int): - prompt_weight_4 = tuple([prompt_weight_4] * max_frames) - - # Evaluate the current and next prompt's expressions - for i in range(len(cur_prompt_series)): - cur_prompt_series[i] = prepare_batch_prompt(cur_prompt_series[i], max_frames, i, prompt_weight_1[i], prompt_weight_2[i], prompt_weight_3[i], prompt_weight_4[i]) - nxt_prompt_series[i] = prepare_batch_prompt(nxt_prompt_series[i], max_frames, i, prompt_weight_1[i], prompt_weight_2[i], prompt_weight_3[i], prompt_weight_4[i]) - - # Show the to/from prompts with evaluated expressions for transparency. - for i in range(len(cur_prompt_series)): - print("\n", "Max Frames: ", max_frames, "\n", "Current Prompt: ", cur_prompt_series[i], "\n", - "Next Prompt: ", nxt_prompt_series[i], "\n", "Strength : ", weight_series[i], "\n") - - # Output methods depending if the prompts are the same or if the current frame is a keyframe. - # if it is an in-between frame and the prompts differ, composable diffusion will be performed. - return (cur_prompt_series, nxt_prompt_series, weight_series) - - -def BatchPoolAnimConditioning(cur_prompt_series, nxt_prompt_series, weight_series, clip): - - pooled_out = [] - cond_out = [] - - for i in range(len(cur_prompt_series)): - tokens = clip.tokenize(str(cur_prompt_series[i])) - cond_to, pooled_to = clip.encode_from_tokens(tokens, return_pooled=True) - - tokens = clip.tokenize(str(nxt_prompt_series[i])) - cond_from, pooled_from = clip.encode_from_tokens(tokens, return_pooled=True) - - interpolated_conditioning = addWeighted([[cond_to, {"pooled_output": pooled_to}]], - [[cond_from, {"pooled_output": pooled_from}]], - weight_series[i]) - - interpolated_cond = interpolated_conditioning[0][0] - interpolated_pooled = interpolated_conditioning[0][1].get("pooled_output", pooled_from) - - pooled_out.append(interpolated_pooled) - cond_out.append(interpolated_cond) - - final_pooled_output = torch.cat(pooled_out, dim=0) - final_conditioning = torch.cat(cond_out, dim=0) - - return [[final_conditioning, {"pooled_output": final_pooled_output}]] - - def SDXLencode(clip, width, height, crop_w, crop_h, target_width, target_height, text_g, text_l): tokens = clip.tokenize(text_g) tokens["l"] = clip.tokenize(text_l)["l"] diff --git a/ScheduledNodes.py b/ScheduledNodes.py index 24fab8d..860f351 100644 --- a/ScheduledNodes.py +++ b/ScheduledNodes.py @@ -6,10 +6,11 @@ import torch import numpy as np import pandas as pd import re +import json -from .ScheduleFuncs import check_is_number, interpolate_prompts, interpolate_prompts_SDXL, PoolAnimConditioning, interpolate_string, interpolate_prompt_series, BatchPoolAnimConditioning - +from .ScheduleFuncs import check_is_number, interpolate_prompts, interpolate_prompts_SDXL, PoolAnimConditioning, interpolate_string +from .BatchFuncs import interpolate_prompt_series, BatchPoolAnimConditioning #Max resolution value for Gligen area calculation. MAX_RESOLUTION=8192