from collections import namedtuple from copy import copy from itertools import permutations import random from PIL import Image import numpy as np import modules.scripts as scripts import gradio as gr from modules import images from modules.processing import process_images, Processed from modules.shared import opts, cmd_opts, state import modules.shared as shared import modules.sd_samplers import modules.sd_models import re def apply_field(field): def fun(p, x, xs): setattr(p, field, x) return fun def apply_prompt(p, x, xs): p.prompt = p.prompt.replace(xs[0], x) p.negative_prompt = p.negative_prompt.replace(xs[0], x) def apply_order(p, x, xs): token_order = [] # Initally grab the tokens from the prompt, so they can be replaced in order of earliest seen for token in x: token_order.append((p.prompt.find(token), token)) token_order.sort(key=lambda t: t[0]) prompt_parts = [] # Split the prompt up, taking out the tokens for _, token in token_order: n = p.prompt.find(token) prompt_parts.append(p.prompt[0:n]) p.prompt = p.prompt[n + len(token):] # Rebuild the prompt with the tokens in the order we want prompt_tmp = "" for idx, part in enumerate(prompt_parts): prompt_tmp += part prompt_tmp += x[idx] p.prompt = prompt_tmp + p.prompt samplers_dict = {} for i, sampler in enumerate(modules.sd_samplers.samplers): samplers_dict[sampler.name.lower()] = i for alias in sampler.aliases: samplers_dict[alias.lower()] = i def apply_sampler(p, x, xs): sampler_index = samplers_dict.get(x.lower(), None) if sampler_index is None: raise RuntimeError(f"Unknown sampler: {x}") p.sampler_index = sampler_index def apply_checkpoint(p, x, xs): info = modules.sd_models.get_closet_checkpoint_match(x) assert info is not None, f'Checkpoint for {x} not found' modules.sd_models.reload_model_weights(shared.sd_model, info) def format_value_add_label(p, opt, x): if type(x) == float: x = round(x, 8) return f"{opt.label}: {x}" def format_value(p, opt, x): if type(x) == float: x = round(x, 8) return x def format_value_join_list(p, opt, x): return ", ".join(x) def do_nothing(p, x, xs): pass def format_nothing(p, opt, x): return "" def str_permutations(x): """dummy function for specifying it in AxisOption's type when you want to get a list of permutations""" return x AxisOption = namedtuple("AxisOption", ["label", "type", "apply", "format_value"]) AxisOptionImg2Img = namedtuple("AxisOptionImg2Img", ["label", "type", "apply", "format_value"]) axis_options = [ AxisOption("Nothing", str, do_nothing, format_nothing), AxisOption("Seed", int, apply_field("seed"), format_value_add_label), AxisOption("Var. seed", int, apply_field("subseed"), format_value_add_label), AxisOption("Var. strength", float, apply_field("subseed_strength"), format_value_add_label), AxisOption("Steps", int, apply_field("steps"), format_value_add_label), AxisOption("CFG Scale", float, apply_field("cfg_scale"), format_value_add_label), AxisOption("Prompt S/R", str, apply_prompt, format_value), AxisOption("Prompt order", str_permutations, apply_order, format_value_join_list), AxisOption("Sampler", str, apply_sampler, format_value), AxisOption("Checkpoint name", str, apply_checkpoint, format_value), AxisOption("Sigma Churn", float, apply_field("s_churn"), format_value_add_label), AxisOption("Sigma min", float, apply_field("s_tmin"), format_value_add_label), AxisOption("Sigma max", float, apply_field("s_tmax"), format_value_add_label), AxisOption("Sigma noise", float, apply_field("s_noise"), format_value_add_label), AxisOption("Eta", float, apply_field("eta"), format_value_add_label), AxisOptionImg2Img("Denoising", float, apply_field("denoising_strength"), format_value_add_label), # as it is now all AxisOptionImg2Img items must go after AxisOption ones ] def draw_xy_grid(p, xs, ys, x_labels, y_labels, cell, draw_legend): res = [] ver_texts = [[images.GridAnnotation(y)] for y in y_labels] hor_texts = [[images.GridAnnotation(x)] for x in x_labels] first_pocessed = None state.job_count = len(xs) * len(ys) * p.n_iter for iy, y in enumerate(ys): for ix, x in enumerate(xs): state.job = f"{ix + iy * len(xs) + 1} out of {len(xs) * len(ys)}" processed = cell(x, y) if first_pocessed is None: first_pocessed = processed try: res.append(processed.images[0]) except: res.append(Image.new(res[0].mode, res[0].size)) grid = images.image_grid(res, rows=len(ys)) if draw_legend: grid = images.draw_grid_annotations(grid, res[0].width, res[0].height, hor_texts, ver_texts) first_pocessed.images = [grid] return first_pocessed re_range = re.compile(r"\s*([+-]?\s*\d+)\s*-\s*([+-]?\s*\d+)(?:\s*\(([+-]\d+)\s*\))?\s*") re_range_float = re.compile(r"\s*([+-]?\s*\d+(?:.\d*)?)\s*-\s*([+-]?\s*\d+(?:.\d*)?)(?:\s*\(([+-]\d+(?:.\d*)?)\s*\))?\s*") re_range_count = re.compile(r"\s*([+-]?\s*\d+)\s*-\s*([+-]?\s*\d+)(?:\s*\[(\d+)\s*\])?\s*") re_range_count_float = re.compile(r"\s*([+-]?\s*\d+(?:.\d*)?)\s*-\s*([+-]?\s*\d+(?:.\d*)?)(?:\s*\[(\d+(?:.\d*)?)\s*\])?\s*") re_non_escaped_comma = re.compile(r"(?