support for scripts
This commit is contained in:
parent
345028099d
commit
f40617d6c4
|
@ -7,8 +7,9 @@ import modules.shared as shared
|
||||||
import modules.processing as processing
|
import modules.processing as processing
|
||||||
from modules.ui import plaintext_to_html
|
from modules.ui import plaintext_to_html
|
||||||
import modules.images as images
|
import modules.images as images
|
||||||
|
import modules.scripts
|
||||||
|
|
||||||
def img2img(prompt: str, init_img, init_img_with_mask, steps: int, sampler_index: int, mask_blur: int, inpainting_fill: int, use_GFPGAN: bool, prompt_matrix, mode: int, n_iter: int, batch_size: int, cfg_scale: float, denoising_strength: float, seed: int, height: int, width: int, resize_mode: int, upscaler_name: str, upscale_overlap: int, inpaint_full_res: bool):
|
def img2img(prompt: str, init_img, init_img_with_mask, steps: int, sampler_index: int, mask_blur: int, inpainting_fill: int, use_GFPGAN: bool, mode: int, n_iter: int, batch_size: int, cfg_scale: float, denoising_strength: float, seed: int, height: int, width: int, resize_mode: int, upscaler_name: str, upscale_overlap: int, inpaint_full_res: bool, *args):
|
||||||
is_inpaint = mode == 1
|
is_inpaint = mode == 1
|
||||||
is_loopback = mode == 2
|
is_loopback = mode == 2
|
||||||
is_upscale = mode == 3
|
is_upscale = mode == 3
|
||||||
|
@ -35,7 +36,6 @@ def img2img(prompt: str, init_img, init_img_with_mask, steps: int, sampler_index
|
||||||
cfg_scale=cfg_scale,
|
cfg_scale=cfg_scale,
|
||||||
width=width,
|
width=width,
|
||||||
height=height,
|
height=height,
|
||||||
prompt_matrix=prompt_matrix,
|
|
||||||
use_GFPGAN=use_GFPGAN,
|
use_GFPGAN=use_GFPGAN,
|
||||||
init_images=[image],
|
init_images=[image],
|
||||||
mask=mask,
|
mask=mask,
|
||||||
|
@ -128,6 +128,11 @@ def img2img(prompt: str, init_img, init_img_with_mask, steps: int, sampler_index
|
||||||
processed = Processed(p, [combined_image], initial_seed, initial_info)
|
processed = Processed(p, [combined_image], initial_seed, initial_info)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
processed = process_images(p)
|
|
||||||
|
processed = modules.scripts.run(p, *args)
|
||||||
|
|
||||||
|
if processed is None:
|
||||||
|
processed = process_images(p)
|
||||||
|
|
||||||
|
|
||||||
return processed.images, processed.js(), plaintext_to_html(processed.info)
|
return processed.images, processed.js(), plaintext_to_html(processed.info)
|
||||||
|
|
|
@ -28,11 +28,12 @@ def torch_gc():
|
||||||
|
|
||||||
|
|
||||||
class StableDiffusionProcessing:
|
class StableDiffusionProcessing:
|
||||||
def __init__(self, sd_model=None, outpath_samples=None, outpath_grids=None, prompt="", seed=-1, sampler_index=0, batch_size=1, n_iter=1, steps=50, cfg_scale=7.0, width=512, height=512, prompt_matrix=False, use_GFPGAN=False, do_not_save_samples=False, do_not_save_grid=False, extra_generation_params=None, overlay_images=None, negative_prompt=None):
|
def __init__(self, sd_model=None, outpath_samples=None, outpath_grids=None, prompt="", seed=-1, sampler_index=0, batch_size=1, n_iter=1, steps=50, cfg_scale=7.0, width=512, height=512, use_GFPGAN=False, do_not_save_samples=False, do_not_save_grid=False, extra_generation_params=None, overlay_images=None, negative_prompt=None):
|
||||||
self.sd_model = sd_model
|
self.sd_model = sd_model
|
||||||
self.outpath_samples: str = outpath_samples
|
self.outpath_samples: str = outpath_samples
|
||||||
self.outpath_grids: str = outpath_grids
|
self.outpath_grids: str = outpath_grids
|
||||||
self.prompt: str = prompt
|
self.prompt: str = prompt
|
||||||
|
self.prompt_for_display: str = None
|
||||||
self.negative_prompt: str = (negative_prompt or "")
|
self.negative_prompt: str = (negative_prompt or "")
|
||||||
self.seed: int = seed
|
self.seed: int = seed
|
||||||
self.sampler_index: int = sampler_index
|
self.sampler_index: int = sampler_index
|
||||||
|
@ -42,7 +43,6 @@ class StableDiffusionProcessing:
|
||||||
self.cfg_scale: float = cfg_scale
|
self.cfg_scale: float = cfg_scale
|
||||||
self.width: int = width
|
self.width: int = width
|
||||||
self.height: int = height
|
self.height: int = height
|
||||||
self.prompt_matrix: bool = prompt_matrix
|
|
||||||
self.use_GFPGAN: bool = use_GFPGAN
|
self.use_GFPGAN: bool = use_GFPGAN
|
||||||
self.do_not_save_samples: bool = do_not_save_samples
|
self.do_not_save_samples: bool = do_not_save_samples
|
||||||
self.do_not_save_grid: bool = do_not_save_grid
|
self.do_not_save_grid: bool = do_not_save_grid
|
||||||
|
@ -71,8 +71,8 @@ class Processed:
|
||||||
|
|
||||||
def js(self):
|
def js(self):
|
||||||
obj = {
|
obj = {
|
||||||
"prompt": self.prompt,
|
"prompt": self.prompt if type(self.prompt) != list else self.prompt[0],
|
||||||
"seed": int(self.seed),
|
"seed": int(self.seed if type(self.seed) != list else self.seed[0]),
|
||||||
"width": self.width,
|
"width": self.width,
|
||||||
"height": self.height,
|
"height": self.height,
|
||||||
"sampler": self.sampler,
|
"sampler": self.sampler,
|
||||||
|
@ -105,35 +105,22 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
|
||||||
assert p.prompt is not None
|
assert p.prompt is not None
|
||||||
torch_gc()
|
torch_gc()
|
||||||
|
|
||||||
seed = int(random.randrange(4294967294) if p.seed == -1 else p.seed)
|
seed = int(random.randrange(4294967294)) if p.seed == -1 else p.seed
|
||||||
|
|
||||||
os.makedirs(p.outpath_samples, exist_ok=True)
|
os.makedirs(p.outpath_samples, exist_ok=True)
|
||||||
os.makedirs(p.outpath_grids, exist_ok=True)
|
os.makedirs(p.outpath_grids, exist_ok=True)
|
||||||
|
|
||||||
comments = []
|
comments = []
|
||||||
|
|
||||||
prompt_matrix_parts = []
|
if type(prompt) == list:
|
||||||
if p.prompt_matrix:
|
all_prompts = prompt
|
||||||
all_prompts = []
|
|
||||||
prompt_matrix_parts = prompt.split("|")
|
|
||||||
combination_count = 2 ** (len(prompt_matrix_parts) - 1)
|
|
||||||
for combination_num in range(combination_count):
|
|
||||||
selected_prompts = [text.strip().strip(',') for n, text in enumerate(prompt_matrix_parts[1:]) if combination_num & (1 << n)]
|
|
||||||
|
|
||||||
if opts.prompt_matrix_add_to_start:
|
|
||||||
selected_prompts = selected_prompts + [prompt_matrix_parts[0]]
|
|
||||||
else:
|
|
||||||
selected_prompts = [prompt_matrix_parts[0]] + selected_prompts
|
|
||||||
|
|
||||||
all_prompts.append(", ".join(selected_prompts))
|
|
||||||
|
|
||||||
p.n_iter = math.ceil(len(all_prompts) / p.batch_size)
|
|
||||||
all_seeds = len(all_prompts) * [seed]
|
|
||||||
|
|
||||||
print(f"Prompt matrix will create {len(all_prompts)} images using a total of {p.n_iter} batches.")
|
|
||||||
else:
|
else:
|
||||||
all_prompts = p.batch_size * p.n_iter * [prompt]
|
all_prompts = p.batch_size * p.n_iter * [prompt]
|
||||||
all_seeds = [seed + x for x in range(len(all_prompts))]
|
|
||||||
|
if type(seed) == list:
|
||||||
|
all_seeds = seed
|
||||||
|
else:
|
||||||
|
all_seeds = [int(seed + x) for x in range(len(all_prompts))]
|
||||||
|
|
||||||
def infotext(iteration=0, position_in_batch=0):
|
def infotext(iteration=0, position_in_batch=0):
|
||||||
generation_params = {
|
generation_params = {
|
||||||
|
@ -149,7 +136,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
|
||||||
|
|
||||||
generation_params_text = ", ".join([k if k == v else f'{k}: {v}' for k, v in generation_params.items() if v is not None])
|
generation_params_text = ", ".join([k if k == v else f'{k}: {v}' for k, v in generation_params.items() if v is not None])
|
||||||
|
|
||||||
return f"{prompt}\n{generation_params_text}".strip() + "".join(["\n\n" + x for x in comments])
|
return f"{p.prompt_for_display or prompt}\n{generation_params_text}".strip() + "".join(["\n\n" + x for x in comments])
|
||||||
|
|
||||||
if os.path.exists(cmd_opts.embeddings_dir):
|
if os.path.exists(cmd_opts.embeddings_dir):
|
||||||
model_hijack.load_textual_inversion_embeddings(cmd_opts.embeddings_dir, p.sd_model)
|
model_hijack.load_textual_inversion_embeddings(cmd_opts.embeddings_dir, p.sd_model)
|
||||||
|
@ -218,25 +205,13 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
|
||||||
if not p.do_not_save_grid and not unwanted_grid_because_of_img_count:
|
if not p.do_not_save_grid and not unwanted_grid_because_of_img_count:
|
||||||
return_grid = opts.return_grid
|
return_grid = opts.return_grid
|
||||||
|
|
||||||
if p.prompt_matrix:
|
grid = images.image_grid(output_images, p.batch_size)
|
||||||
grid = images.image_grid(output_images, p.batch_size, rows=1 << ((len(prompt_matrix_parts)-1)//2))
|
|
||||||
|
|
||||||
try:
|
|
||||||
grid = images.draw_prompt_matrix(grid, p.width, p.height, prompt_matrix_parts)
|
|
||||||
except Exception:
|
|
||||||
import traceback
|
|
||||||
print("Error creating prompt_matrix text:", file=sys.stderr)
|
|
||||||
print(traceback.format_exc(), file=sys.stderr)
|
|
||||||
|
|
||||||
return_grid = True
|
|
||||||
else:
|
|
||||||
grid = images.image_grid(output_images, p.batch_size)
|
|
||||||
|
|
||||||
if return_grid:
|
if return_grid:
|
||||||
output_images.insert(0, grid)
|
output_images.insert(0, grid)
|
||||||
|
|
||||||
if opts.grid_save:
|
if opts.grid_save:
|
||||||
images.save_image(grid, p.outpath_grids, "grid", seed, prompt, opts.grid_format, info=infotext(), short_filename=not opts.grid_extended_filename)
|
images.save_image(grid, p.outpath_grids, "grid", seed, all_prompts[0], opts.grid_format, info=infotext(), short_filename=not opts.grid_extended_filename)
|
||||||
|
|
||||||
torch_gc()
|
torch_gc()
|
||||||
return Processed(p, output_images, seed, infotext())
|
return Processed(p, output_images, seed, infotext())
|
||||||
|
|
|
@ -2,19 +2,33 @@ import os
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
import modules.ui as ui
|
||||||
import gradio as gr
|
import gradio as gr
|
||||||
|
|
||||||
|
from modules.processing import StableDiffusionProcessing
|
||||||
|
|
||||||
class Script:
|
class Script:
|
||||||
filename = None
|
filename = None
|
||||||
|
args_from = None
|
||||||
|
args_to = None
|
||||||
|
|
||||||
def title(self):
|
def title(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def ui(self, is_img2img):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def run(self, *args):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def describe(self):
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
scripts = []
|
scripts = []
|
||||||
|
|
||||||
|
|
||||||
def load_scripts(basedir, globs):
|
def load_scripts(basedir):
|
||||||
for filename in os.listdir(basedir):
|
for filename in os.listdir(basedir):
|
||||||
path = os.path.join(basedir, filename)
|
path = os.path.join(basedir, filename)
|
||||||
|
|
||||||
|
@ -27,27 +41,73 @@ def load_scripts(basedir, globs):
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
compiled = compile(text, path, 'exec')
|
compiled = compile(text, path, 'exec')
|
||||||
module = ModuleType(filename)
|
module = ModuleType(filename)
|
||||||
module.__dict__.update(globs)
|
|
||||||
exec(compiled, module.__dict__)
|
exec(compiled, module.__dict__)
|
||||||
|
|
||||||
for key, item in module.__dict__.items():
|
for key, script_class in module.__dict__.items():
|
||||||
if type(item) == type and issubclass(item, Script):
|
if type(script_class) == type and issubclass(script_class, Script):
|
||||||
item.filename = path
|
obj = script_class()
|
||||||
|
obj.filename = path
|
||||||
|
|
||||||
scripts.append(item)
|
scripts.append(obj)
|
||||||
|
|
||||||
|
|
||||||
def wrap_call(func, filename, funcname, *args, default=None, **kwargs):
|
def wrap_call(func, filename, funcname, *args, default=None, **kwargs):
|
||||||
try:
|
try:
|
||||||
res = func()
|
res = func(*args, **kwargs)
|
||||||
return res
|
return res
|
||||||
except Exception:
|
except Exception:
|
||||||
print(f"Error calling: {filename/funcname}", file=sys.stderr)
|
print(f"Error calling: {filename}/{funcname}", file=sys.stderr)
|
||||||
print(traceback.format_exc(), file=sys.stderr)
|
print(traceback.format_exc(), file=sys.stderr)
|
||||||
|
|
||||||
return default
|
return default
|
||||||
|
|
||||||
def setup_ui():
|
|
||||||
titles = [wrap_call(script.title, script.filename, "title") for script in scripts]
|
|
||||||
|
|
||||||
gr.Dropdown(options=[""] + titles, value="", type="index")
|
def setup_ui(is_img2img):
|
||||||
|
titles = [wrap_call(script.title, script.filename, "title") or f"{script.filename} [error]" for script in scripts]
|
||||||
|
|
||||||
|
dropdown = gr.Dropdown(label="Script", choices=["None"] + titles, value="None", type="index")
|
||||||
|
|
||||||
|
inputs = [dropdown]
|
||||||
|
|
||||||
|
for script in scripts:
|
||||||
|
script.args_from = len(inputs)
|
||||||
|
controls = script.ui(is_img2img)
|
||||||
|
|
||||||
|
for control in controls:
|
||||||
|
control.visible = False
|
||||||
|
|
||||||
|
inputs += controls
|
||||||
|
script.args_to = len(inputs)
|
||||||
|
|
||||||
|
def select_script(index):
|
||||||
|
if index > 0:
|
||||||
|
script = scripts[index-1]
|
||||||
|
args_from = script.args_from
|
||||||
|
args_to = script.args_to
|
||||||
|
else:
|
||||||
|
args_from = 0
|
||||||
|
args_to = 0
|
||||||
|
|
||||||
|
return [ui.gr_show(True if i == 0 else args_from <= i < args_to) for i in range(len(inputs))]
|
||||||
|
|
||||||
|
dropdown.change(
|
||||||
|
fn=select_script,
|
||||||
|
inputs=[dropdown],
|
||||||
|
outputs=inputs
|
||||||
|
)
|
||||||
|
|
||||||
|
return inputs
|
||||||
|
|
||||||
|
|
||||||
|
def run(p: StableDiffusionProcessing, *args):
|
||||||
|
script_index = args[0] - 1
|
||||||
|
|
||||||
|
if script_index < 0 or script_index >= len(scripts):
|
||||||
|
return None
|
||||||
|
|
||||||
|
script = scripts[script_index]
|
||||||
|
|
||||||
|
script_args = args[script.args_from:script.args_to]
|
||||||
|
processed = script.run(p, *script_args)
|
||||||
|
|
||||||
|
return processed
|
||||||
|
|
|
@ -9,18 +9,28 @@ from ldm.models.diffusion.plms import PLMSSampler
|
||||||
from modules.shared import opts, cmd_opts, state
|
from modules.shared import opts, cmd_opts, state
|
||||||
import modules.shared as shared
|
import modules.shared as shared
|
||||||
|
|
||||||
SamplerData = namedtuple('SamplerData', ['name', 'constructor'])
|
|
||||||
|
SamplerData = namedtuple('SamplerData', ['name', 'constructor', 'aliases'])
|
||||||
|
|
||||||
|
samplers_k_diffusion = [
|
||||||
|
('Euler a', 'sample_euler_ancestral', ['k_euler_a']),
|
||||||
|
('Euler', 'sample_euler', ['k_euler']),
|
||||||
|
('LMS', 'sample_lms', ['k_lms']),
|
||||||
|
('Heun', 'sample_heun', ['k_heun']),
|
||||||
|
('DPM2', 'sample_dpm_2', ['k_dpm_2']),
|
||||||
|
('DPM2 a', 'sample_dpm_2_ancestral', ['k_dpm_2_a']),
|
||||||
|
]
|
||||||
|
|
||||||
|
samplers_data_k_diffusion = [
|
||||||
|
SamplerData(label, lambda model, funcname=funcname: KDiffusionSampler(funcname, model), aliases)
|
||||||
|
for label, funcname, aliases in samplers_k_diffusion
|
||||||
|
if hasattr(k_diffusion.sampling, funcname)
|
||||||
|
]
|
||||||
|
|
||||||
samplers = [
|
samplers = [
|
||||||
*[SamplerData(x[0], lambda model, funcname=x[1]: KDiffusionSampler(funcname, model)) for x in [
|
*samplers_data_k_diffusion,
|
||||||
('Euler a', 'sample_euler_ancestral'),
|
SamplerData('DDIM', lambda model: VanillaStableDiffusionSampler(DDIMSampler, model), []),
|
||||||
('Euler', 'sample_euler'),
|
SamplerData('PLMS', lambda model: VanillaStableDiffusionSampler(PLMSSampler, model), []),
|
||||||
('LMS', 'sample_lms'),
|
|
||||||
('Heun', 'sample_heun'),
|
|
||||||
('DPM2', 'sample_dpm_2'),
|
|
||||||
('DPM2 a', 'sample_dpm_2_ancestral'),
|
|
||||||
] if hasattr(k_diffusion.sampling, x[1])],
|
|
||||||
SamplerData('DDIM', lambda model: VanillaStableDiffusionSampler(DDIMSample, model)),
|
|
||||||
SamplerData('PLMS', lambda model: VanillaStableDiffusionSampler(PLMSSampler, model)),
|
|
||||||
]
|
]
|
||||||
samplers_for_img2img = [x for x in samplers if x.name != 'PLMS']
|
samplers_for_img2img = [x for x in samplers if x.name != 'PLMS']
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,6 @@ class Options:
|
||||||
"export_for_4chan": OptionInfo(True, "If PNG image is larger than 4MB or any dimension is larger than 4000, downscale and save copy as JPG"),
|
"export_for_4chan": OptionInfo(True, "If PNG image is larger than 4MB or any dimension is larger than 4000, downscale and save copy as JPG"),
|
||||||
"enable_pnginfo": OptionInfo(True, "Save text information about generation parameters as chunks to png files"),
|
"enable_pnginfo": OptionInfo(True, "Save text information about generation parameters as chunks to png files"),
|
||||||
"font": OptionInfo("arial.ttf", "Font for image grids that have text"),
|
"font": OptionInfo("arial.ttf", "Font for image grids that have text"),
|
||||||
"prompt_matrix_add_to_start": OptionInfo(True, "In prompt matrix, add the variable combination of text to the start of the prompt, rather than the end"),
|
|
||||||
"enable_emphasis": OptionInfo(True, "Use (text) to make model pay more attention to text text and [text] to make it pay less attention"),
|
"enable_emphasis": OptionInfo(True, "Use (text) to make model pay more attention to text text and [text] to make it pay less attention"),
|
||||||
"save_txt": OptionInfo(False, "Create a text file next to every image with generation parameters."),
|
"save_txt": OptionInfo(False, "Create a text file next to every image with generation parameters."),
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
|
import modules.scripts
|
||||||
from modules.processing import StableDiffusionProcessing, Processed, StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images
|
from modules.processing import StableDiffusionProcessing, Processed, StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images
|
||||||
from modules.shared import opts, cmd_opts
|
from modules.shared import opts, cmd_opts
|
||||||
import modules.shared as shared
|
import modules.shared as shared
|
||||||
|
@ -6,7 +6,7 @@ import modules.processing as processing
|
||||||
from modules.ui import plaintext_to_html
|
from modules.ui import plaintext_to_html
|
||||||
|
|
||||||
|
|
||||||
def txt2img(prompt: str, negative_prompt: str, steps: int, sampler_index: int, use_GFPGAN: bool, prompt_matrix: bool, n_iter: int, batch_size: int, cfg_scale: float, seed: int, height: int, width: int, code: str):
|
def txt2img(prompt: str, negative_prompt: str, steps: int, sampler_index: int, use_GFPGAN: bool, n_iter: int, batch_size: int, cfg_scale: float, seed: int, height: int, width: int, *args):
|
||||||
p = StableDiffusionProcessingTxt2Img(
|
p = StableDiffusionProcessingTxt2Img(
|
||||||
sd_model=shared.sd_model,
|
sd_model=shared.sd_model,
|
||||||
outpath_samples=opts.outdir_samples or opts.outdir_txt2img_samples,
|
outpath_samples=opts.outdir_samples or opts.outdir_txt2img_samples,
|
||||||
|
@ -21,30 +21,13 @@ def txt2img(prompt: str, negative_prompt: str, steps: int, sampler_index: int, u
|
||||||
cfg_scale=cfg_scale,
|
cfg_scale=cfg_scale,
|
||||||
width=width,
|
width=width,
|
||||||
height=height,
|
height=height,
|
||||||
prompt_matrix=prompt_matrix,
|
|
||||||
use_GFPGAN=use_GFPGAN
|
use_GFPGAN=use_GFPGAN
|
||||||
)
|
)
|
||||||
|
|
||||||
if code != '' and cmd_opts.allow_code:
|
processed = modules.scripts.run(p, *args)
|
||||||
p.do_not_save_grid = True
|
|
||||||
p.do_not_save_samples = True
|
|
||||||
|
|
||||||
display_result_data = [[], -1, ""]
|
if processed is not None:
|
||||||
|
pass
|
||||||
def display(imgs, s=display_result_data[1], i=display_result_data[2]):
|
|
||||||
display_result_data[0] = imgs
|
|
||||||
display_result_data[1] = s
|
|
||||||
display_result_data[2] = i
|
|
||||||
|
|
||||||
from types import ModuleType
|
|
||||||
compiled = compile(code, '', 'exec')
|
|
||||||
module = ModuleType("testmodule")
|
|
||||||
module.__dict__.update(globals())
|
|
||||||
module.p = p
|
|
||||||
module.display = display
|
|
||||||
exec(compiled, module.__dict__)
|
|
||||||
|
|
||||||
processed = Processed(p, *display_result_data)
|
|
||||||
else:
|
else:
|
||||||
processed = process_images(p)
|
processed = process_images(p)
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ from PIL import Image
|
||||||
|
|
||||||
import gradio as gr
|
import gradio as gr
|
||||||
import gradio.utils
|
import gradio.utils
|
||||||
|
import gradio.routes
|
||||||
|
|
||||||
from modules.paths import script_path
|
from modules.paths import script_path
|
||||||
from modules.shared import opts, cmd_opts
|
from modules.shared import opts, cmd_opts
|
||||||
|
@ -19,6 +20,7 @@ import modules.shared as shared
|
||||||
from modules.sd_samplers import samplers, samplers_for_img2img
|
from modules.sd_samplers import samplers, samplers_for_img2img
|
||||||
import modules.gfpgan_model as gfpgan
|
import modules.gfpgan_model as gfpgan
|
||||||
import modules.realesrgan_model as realesrgan
|
import modules.realesrgan_model as realesrgan
|
||||||
|
import modules.scripts
|
||||||
|
|
||||||
# this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the bowser will not show any UI
|
# this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the bowser will not show any UI
|
||||||
mimetypes.init()
|
mimetypes.init()
|
||||||
|
@ -131,7 +133,7 @@ def wrap_gradio_call(func):
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
|
||||||
def create_ui(opts, cmd_opts, txt2img, img2img, run_extras, run_pnginfo):
|
def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||||
|
|
||||||
with gr.Blocks(analytics_enabled=False) as txt2img_interface:
|
with gr.Blocks(analytics_enabled=False) as txt2img_interface:
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
|
@ -145,8 +147,7 @@ def create_ui(opts, cmd_opts, txt2img, img2img, run_extras, run_pnginfo):
|
||||||
sampler_index = gr.Radio(label='Sampling method', elem_id="txt2img_sampling", choices=[x.name for x in samplers], value=samplers[0].name, type="index")
|
sampler_index = gr.Radio(label='Sampling method', elem_id="txt2img_sampling", choices=[x.name for x in samplers], value=samplers[0].name, type="index")
|
||||||
|
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
use_GFPGAN = gr.Checkbox(label='GFPGAN', value=False, visible=gfpgan.have_gfpgan)
|
use_gfpgan = gr.Checkbox(label='GFPGAN', value=False, visible=gfpgan.have_gfpgan)
|
||||||
prompt_matrix = gr.Checkbox(label='Prompt matrix', value=False)
|
|
||||||
|
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
batch_count = gr.Slider(minimum=1, maximum=cmd_opts.max_batch_count, step=1, label='Batch count', value=1)
|
batch_count = gr.Slider(minimum=1, maximum=cmd_opts.max_batch_count, step=1, label='Batch count', value=1)
|
||||||
|
@ -160,7 +161,8 @@ def create_ui(opts, cmd_opts, txt2img, img2img, run_extras, run_pnginfo):
|
||||||
|
|
||||||
seed = gr.Number(label='Seed', value=-1)
|
seed = gr.Number(label='Seed', value=-1)
|
||||||
|
|
||||||
code = gr.Textbox(label="Python script", visible=cmd_opts.allow_code, lines=1)
|
with gr.Group():
|
||||||
|
custom_inputs = modules.scripts.setup_ui(is_img2img=False)
|
||||||
|
|
||||||
with gr.Column(variant='panel'):
|
with gr.Column(variant='panel'):
|
||||||
with gr.Group():
|
with gr.Group():
|
||||||
|
@ -185,16 +187,14 @@ def create_ui(opts, cmd_opts, txt2img, img2img, run_extras, run_pnginfo):
|
||||||
negative_prompt,
|
negative_prompt,
|
||||||
steps,
|
steps,
|
||||||
sampler_index,
|
sampler_index,
|
||||||
use_GFPGAN,
|
use_gfpgan,
|
||||||
prompt_matrix,
|
|
||||||
batch_count,
|
batch_count,
|
||||||
batch_size,
|
batch_size,
|
||||||
cfg_scale,
|
cfg_scale,
|
||||||
seed,
|
seed,
|
||||||
height,
|
height,
|
||||||
width,
|
width,
|
||||||
code
|
] + custom_inputs,
|
||||||
],
|
|
||||||
outputs=[
|
outputs=[
|
||||||
txt2img_gallery,
|
txt2img_gallery,
|
||||||
generation_info,
|
generation_info,
|
||||||
|
@ -244,8 +244,7 @@ def create_ui(opts, cmd_opts, txt2img, img2img, run_extras, run_pnginfo):
|
||||||
inpainting_fill = gr.Radio(label='Msked content', choices=['fill', 'original', 'latent noise', 'latent nothing'], value='fill', type="index", visible=False)
|
inpainting_fill = gr.Radio(label='Msked content', choices=['fill', 'original', 'latent noise', 'latent nothing'], value='fill', type="index", visible=False)
|
||||||
|
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
use_GFPGAN = gr.Checkbox(label='GFPGAN', value=False, visible=gfpgan.have_gfpgan)
|
use_gfpgan = gr.Checkbox(label='GFPGAN', value=False, visible=gfpgan.have_gfpgan)
|
||||||
prompt_matrix = gr.Checkbox(label='Prompt matrix', value=False)
|
|
||||||
inpaint_full_res = gr.Checkbox(label='Inpaint at full resolution', value=True, visible=False)
|
inpaint_full_res = gr.Checkbox(label='Inpaint at full resolution', value=True, visible=False)
|
||||||
|
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
|
@ -266,6 +265,10 @@ def create_ui(opts, cmd_opts, txt2img, img2img, run_extras, run_pnginfo):
|
||||||
|
|
||||||
seed = gr.Number(label='Seed', value=-1)
|
seed = gr.Number(label='Seed', value=-1)
|
||||||
|
|
||||||
|
with gr.Group():
|
||||||
|
custom_inputs = modules.scripts.setup_ui(is_img2img=False)
|
||||||
|
|
||||||
|
|
||||||
with gr.Column(variant='panel'):
|
with gr.Column(variant='panel'):
|
||||||
with gr.Group():
|
with gr.Group():
|
||||||
img2img_gallery = gr.Gallery(label='Output', elem_id='img2img_gallery')
|
img2img_gallery = gr.Gallery(label='Output', elem_id='img2img_gallery')
|
||||||
|
@ -291,11 +294,10 @@ def create_ui(opts, cmd_opts, txt2img, img2img, run_extras, run_pnginfo):
|
||||||
init_img_with_mask: gr_show(is_inpaint),
|
init_img_with_mask: gr_show(is_inpaint),
|
||||||
mask_blur: gr_show(is_inpaint),
|
mask_blur: gr_show(is_inpaint),
|
||||||
inpainting_fill: gr_show(is_inpaint),
|
inpainting_fill: gr_show(is_inpaint),
|
||||||
prompt_matrix: gr_show(is_classic),
|
|
||||||
batch_count: gr_show(not is_upscale),
|
batch_count: gr_show(not is_upscale),
|
||||||
batch_size: gr_show(not is_loopback),
|
batch_size: gr_show(not is_loopback),
|
||||||
sd_upscale_upscaler_name: gr_show(is_upscale),
|
sd_upscale_upscaler_name: gr_show(is_upscale),
|
||||||
sd_upscale_overlap:gr_show(is_upscale),
|
sd_upscale_overlap: gr_show(is_upscale),
|
||||||
inpaint_full_res: gr_show(is_inpaint),
|
inpaint_full_res: gr_show(is_inpaint),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,7 +309,6 @@ def create_ui(opts, cmd_opts, txt2img, img2img, run_extras, run_pnginfo):
|
||||||
init_img_with_mask,
|
init_img_with_mask,
|
||||||
mask_blur,
|
mask_blur,
|
||||||
inpainting_fill,
|
inpainting_fill,
|
||||||
prompt_matrix,
|
|
||||||
batch_count,
|
batch_count,
|
||||||
batch_size,
|
batch_size,
|
||||||
sd_upscale_upscaler_name,
|
sd_upscale_upscaler_name,
|
||||||
|
@ -326,8 +327,7 @@ def create_ui(opts, cmd_opts, txt2img, img2img, run_extras, run_pnginfo):
|
||||||
sampler_index,
|
sampler_index,
|
||||||
mask_blur,
|
mask_blur,
|
||||||
inpainting_fill,
|
inpainting_fill,
|
||||||
use_GFPGAN,
|
use_gfpgan,
|
||||||
prompt_matrix,
|
|
||||||
switch_mode,
|
switch_mode,
|
||||||
batch_count,
|
batch_count,
|
||||||
batch_size,
|
batch_size,
|
||||||
|
@ -340,7 +340,7 @@ def create_ui(opts, cmd_opts, txt2img, img2img, run_extras, run_pnginfo):
|
||||||
sd_upscale_upscaler_name,
|
sd_upscale_upscaler_name,
|
||||||
sd_upscale_overlap,
|
sd_upscale_overlap,
|
||||||
inpaint_full_res,
|
inpaint_full_res,
|
||||||
],
|
] + custom_inputs,
|
||||||
outputs=[
|
outputs=[
|
||||||
img2img_gallery,
|
img2img_gallery,
|
||||||
generation_info,
|
generation_info,
|
||||||
|
@ -384,9 +384,6 @@ def create_ui(opts, cmd_opts, txt2img, img2img, run_extras, run_pnginfo):
|
||||||
outputs=[init_img_with_mask],
|
outputs=[init_img_with_mask],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
with gr.Blocks(analytics_enabled=False) as extras_interface:
|
with gr.Blocks(analytics_enabled=False) as extras_interface:
|
||||||
with gr.Row().style(equal_height=False):
|
with gr.Row().style(equal_height=False):
|
||||||
with gr.Column(variant='panel'):
|
with gr.Column(variant='panel'):
|
||||||
|
@ -420,7 +417,6 @@ def create_ui(opts, cmd_opts, txt2img, img2img, run_extras, run_pnginfo):
|
||||||
|
|
||||||
submit.click(**extras_args)
|
submit.click(**extras_args)
|
||||||
|
|
||||||
|
|
||||||
send_to_extras.click(
|
send_to_extras.click(
|
||||||
fn=lambda x: image_from_url_text(x),
|
fn=lambda x: image_from_url_text(x),
|
||||||
_js="extract_image_from_gallery",
|
_js="extract_image_from_gallery",
|
||||||
|
@ -435,7 +431,6 @@ def create_ui(opts, cmd_opts, txt2img, img2img, run_extras, run_pnginfo):
|
||||||
outputs=[image],
|
outputs=[image],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
pnginfo_interface = gr.Interface(
|
pnginfo_interface = gr.Interface(
|
||||||
wrap_gradio_call(run_pnginfo),
|
wrap_gradio_call(run_pnginfo),
|
||||||
inputs=[
|
inputs=[
|
||||||
|
@ -450,7 +445,6 @@ def create_ui(opts, cmd_opts, txt2img, img2img, run_extras, run_pnginfo):
|
||||||
analytics_enabled=False,
|
analytics_enabled=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def create_setting_component(key):
|
def create_setting_component(key):
|
||||||
def fun():
|
def fun():
|
||||||
return opts.data[key] if key in opts.data else opts.data_labels[key].default
|
return opts.data[key] if key in opts.data else opts.data_labels[key].default
|
||||||
|
@ -520,20 +514,16 @@ def create_ui(opts, cmd_opts, txt2img, img2img, run_extras, run_pnginfo):
|
||||||
return demo
|
return demo
|
||||||
|
|
||||||
|
|
||||||
with open(os.path.join(script_path, "script.js"), "r", encoding="utf8") as file:
|
with open(os.path.join(script_path, "script.js"), "r", encoding="utf8") as jsfile:
|
||||||
javascript = file.read()
|
javascript = jsfile.read()
|
||||||
|
|
||||||
def inject_gradio_html(javascript):
|
|
||||||
import gradio.routes
|
|
||||||
|
|
||||||
def template_response(*args, **kwargs):
|
|
||||||
res = gradio_routes_templates_response(*args, **kwargs)
|
|
||||||
res.body = res.body.replace(b'</head>', f'<script>{javascript}</script></head>'.encode("utf8"))
|
|
||||||
res.init_headers()
|
|
||||||
return res
|
|
||||||
|
|
||||||
gradio_routes_templates_response = gradio.routes.templates.TemplateResponse
|
|
||||||
gradio.routes.templates.TemplateResponse = template_response
|
|
||||||
|
|
||||||
|
|
||||||
inject_gradio_html(javascript)
|
def template_response(*args, **kwargs):
|
||||||
|
res = gradio_routes_templates_response(*args, **kwargs)
|
||||||
|
res.body = res.body.replace(b'</head>', f'<script>{javascript}</script></head>'.encode("utf8"))
|
||||||
|
res.init_headers()
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
gradio_routes_templates_response = gradio.routes.templates.TemplateResponse
|
||||||
|
gradio.routes.templates.TemplateResponse = template_response
|
||||||
|
|
27
script.js
27
script.js
|
@ -4,7 +4,7 @@ titles = {
|
||||||
"GFPGAN": "Restore low quality faces using GFPGAN neural network",
|
"GFPGAN": "Restore low quality faces using GFPGAN neural network",
|
||||||
"Euler a": "Euler Ancestral - very creative, each can get acompletely different pictures depending on step count, setting seps tohigher than 30-40 does not help",
|
"Euler a": "Euler Ancestral - very creative, each can get acompletely different pictures depending on step count, setting seps tohigher than 30-40 does not help",
|
||||||
"DDIM": "Denoising Diffusion Implicit Models - best at inpainting",
|
"DDIM": "Denoising Diffusion Implicit Models - best at inpainting",
|
||||||
"Prompt matrix": "Separate prompts into part using vertical pipe character (|) and the script will create a picture for every combination of them (except for first part, which will be present in all combinations)",
|
|
||||||
"Batch count": "How many batches of images to create",
|
"Batch count": "How many batches of images to create",
|
||||||
"Batch size": "How many image to create in a single batch",
|
"Batch size": "How many image to create in a single batch",
|
||||||
"CFG Scale": "Classifier Free Guidance Scale - how strongly the image should conform to prompt - lower values produce more creative results",
|
"CFG Scale": "Classifier Free Guidance Scale - how strongly the image should conform to prompt - lower values produce more creative results",
|
||||||
|
@ -30,6 +30,16 @@ titles = {
|
||||||
|
|
||||||
"Interrupt": "Stop processing images and return any results accumulated so far.",
|
"Interrupt": "Stop processing images and return any results accumulated so far.",
|
||||||
"Save": "Write image to a directory (default - log/images) and generation parameters into csv file.",
|
"Save": "Write image to a directory (default - log/images) and generation parameters into csv file.",
|
||||||
|
|
||||||
|
"X values": "Separate values for X axis using commas.",
|
||||||
|
"Y values": "Separate values for Y axis using commas.",
|
||||||
|
|
||||||
|
"None": "Do not do anything special",
|
||||||
|
"Prompt matrix": "Separate prompts into parts using vertical pipe character (|) and the script will create a picture for every combination of them (except for the first part, which will be present in all combinations)",
|
||||||
|
"X/Y Plot": "Create a grid where images will have different parameters. Use inputs below to specify which parameterswill be shared by columns and rows",
|
||||||
|
"Custom code": "Run python code. Advanced user only. Must run program with --allow-code for this to work",
|
||||||
|
|
||||||
|
"Prompt S/R": "Separate a list of words with commas, and the first word will be used as a keyword: script will search for this word in the prompt, and replace it with others",
|
||||||
}
|
}
|
||||||
|
|
||||||
function gradioApp(){
|
function gradioApp(){
|
||||||
|
@ -37,12 +47,25 @@ function gradioApp(){
|
||||||
}
|
}
|
||||||
|
|
||||||
function addTitles(root){
|
function addTitles(root){
|
||||||
root.querySelectorAll('span, button').forEach(function(span){
|
root.querySelectorAll('span, button, select').forEach(function(span){
|
||||||
tooltip = titles[span.textContent];
|
tooltip = titles[span.textContent];
|
||||||
|
|
||||||
|
if(!tooltip){
|
||||||
|
tooltip = titles[span.value];
|
||||||
|
}
|
||||||
|
|
||||||
if(tooltip){
|
if(tooltip){
|
||||||
span.title = tooltip;
|
span.title = tooltip;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
root.querySelectorAll('select').forEach(function(select){
|
||||||
|
if (select.onchange != null) return;
|
||||||
|
|
||||||
|
select.onchange = function(){
|
||||||
|
select.title = titles[select.value] || "";
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
|
12
style.css
12
style.css
|
@ -22,22 +22,24 @@ button{
|
||||||
overflow: visible !important;
|
overflow: visible !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset span.text-gray-500, .gr-panel div.flex-col div.justify-between label, label.block span{
|
#x_type, #y_type{
|
||||||
|
max-width: 10em;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset span.text-gray-500, .gr-block.gr-box span.text-gray-500, label.block span{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -0.6em;
|
top: -0.6em;
|
||||||
line-height: 1.2em;
|
line-height: 1.2em;
|
||||||
padding: 0 0.5em;
|
padding: 0 0.5em;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
|
||||||
|
|
||||||
fieldset span.text-gray-500, .gr-panel div.flex-col div.justify-between label, label.block span{
|
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border-top: 1px solid #eee;
|
border-top: 1px solid #eee;
|
||||||
border-left: 1px solid #eee;
|
border-left: 1px solid #eee;
|
||||||
border-right: 1px solid #eee;
|
border-right: 1px solid #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark fieldset span.text-gray-500, .dark .gr-panel div.flex-col div.justify-between label, .dark label.block span{
|
.dark fieldset span.text-gray-500, .dark .gr-block.gr-box span.text-gray-500, .dark label.block span{
|
||||||
background-color: rgb(31, 41, 55);
|
background-color: rgb(31, 41, 55);
|
||||||
border-top: 1px solid rgb(55 65 81);
|
border-top: 1px solid rgb(55 65 81);
|
||||||
border-left: 1px solid rgb(55 65 81);
|
border-left: 1px solid rgb(55 65 81);
|
||||||
|
@ -63,4 +65,4 @@ input[type="range"]{
|
||||||
#txt2img_sampling label{
|
#txt2img_sampling label{
|
||||||
padding-left: 0.6em;
|
padding-left: 0.6em;
|
||||||
padding-right: 0.6em;
|
padding-right: 0.6em;
|
||||||
}
|
}
|
||||||
|
|
26
webui.py
26
webui.py
|
@ -55,23 +55,6 @@ def load_model_from_config(config, ckpt, verbose=False):
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
|
||||||
def draw_xy_grid(xs, ys, x_label, y_label, cell):
|
|
||||||
res = []
|
|
||||||
|
|
||||||
ver_texts = [[images.GridAnnotation(y_label(y))] for y in ys]
|
|
||||||
hor_texts = [[images.GridAnnotation(x_label(x))] for x in xs]
|
|
||||||
|
|
||||||
for y in ys:
|
|
||||||
for x in xs:
|
|
||||||
state.job = f"{x + y * len(xs)} out of {len(xs) * len(ys)}"
|
|
||||||
res.append(cell(x, y))
|
|
||||||
|
|
||||||
grid = images.image_grid(res, rows=len(ys))
|
|
||||||
grid = images.draw_grid_annotations(grid, res[0].width, res[0].height, hor_texts, ver_texts)
|
|
||||||
|
|
||||||
return grid
|
|
||||||
|
|
||||||
|
|
||||||
def run_extras(image, GFPGAN_strength, RealESRGAN_upscaling, RealESRGAN_model_index):
|
def run_extras(image, GFPGAN_strength, RealESRGAN_upscaling, RealESRGAN_model_index):
|
||||||
processing.torch_gc()
|
processing.torch_gc()
|
||||||
|
|
||||||
|
@ -138,7 +121,6 @@ try:
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
sd_config = OmegaConf.load(cmd_opts.config)
|
sd_config = OmegaConf.load(cmd_opts.config)
|
||||||
shared.sd_model = load_model_from_config(sd_config, cmd_opts.ckpt)
|
shared.sd_model = load_model_from_config(sd_config, cmd_opts.ckpt)
|
||||||
shared.sd_model = (shared.sd_model if cmd_opts.no_half else shared.sd_model.half())
|
shared.sd_model = (shared.sd_model if cmd_opts.no_half else shared.sd_model.half())
|
||||||
|
@ -150,18 +132,18 @@ else:
|
||||||
|
|
||||||
modules.sd_hijack.model_hijack.hijack(shared.sd_model)
|
modules.sd_hijack.model_hijack.hijack(shared.sd_model)
|
||||||
|
|
||||||
|
modules.scripts.load_scripts(os.path.join(script_path, "scripts"))
|
||||||
|
|
||||||
|
|
||||||
# make the program just exit at ctrl+c without waiting for anything
|
# make the program just exit at ctrl+c without waiting for anything
|
||||||
def sigint_handler(signal, frame):
|
def sigint_handler(sig, frame):
|
||||||
print('Interrupted')
|
print(f'Interrupted with singal {sig} in {frame}')
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
|
|
||||||
|
|
||||||
signal.signal(signal.SIGINT, sigint_handler)
|
signal.signal(signal.SIGINT, sigint_handler)
|
||||||
|
|
||||||
demo = modules.ui.create_ui(
|
demo = modules.ui.create_ui(
|
||||||
opts=opts,
|
|
||||||
cmd_opts=cmd_opts,
|
|
||||||
txt2img=wrap_gradio_gpu_call(modules.txt2img.txt2img),
|
txt2img=wrap_gradio_gpu_call(modules.txt2img.txt2img),
|
||||||
img2img=wrap_gradio_gpu_call(modules.img2img.img2img),
|
img2img=wrap_gradio_gpu_call(modules.img2img.img2img),
|
||||||
run_extras=wrap_gradio_gpu_call(run_extras),
|
run_extras=wrap_gradio_gpu_call(run_extras),
|
||||||
|
|
Loading…
Reference in New Issue