diff --git a/README.md b/README.md index 5ded94f98..15e224e8f 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,12 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web - One click install and run script (but you still must install python and git) - Outpainting - Inpainting -- Prompt -- Stable Diffusion upscale +- Prompt Matrix +- Stable Diffusion Upscale - Attention, specify parts of text that the model should pay more attention to - - a man in a ((txuedo)) - will pay more attentinoto tuxedo - - a man in a (txuedo:1.21) - alternative syntax -- Loopback, run img2img procvessing multiple times + - a man in a ((tuxedo)) - will pay more attention to tuxedo + - a man in a (tuxedo:1.21) - alternative syntax +- Loopback, run img2img processing multiple times - X/Y plot, a way to draw a 2 dimensional plot of images with different parameters - Textual Inversion - have as many embeddings as you want and use any names you like for them @@ -35,15 +35,15 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web - 4GB video card support (also reports of 2GB working) - Correct seeds for batches - Prompt length validation - - get length of prompt in tokensas you type - - get a warning after geenration if some text was truncated + - get length of prompt in tokens as you type + - get a warning after generation if some text was truncated - Generation parameters - parameters you used to generate images are saved with that image - in PNG chunks for PNG, in EXIF for JPEG - can drag the image to PNG info tab to restore generation parameters and automatically copy them into UI - can be disabled in settings - Settings page -- Running arbitrary python code from UI (must run with commandline flag to enable) +- Running arbitrary python code from UI (must run with --allow-code to enable) - Mouseover hints for most UI elements - Possible to change defaults/mix/max/step values for UI elements via text config - Random artist button diff --git a/modules/images.py b/modules/images.py index f1aed5d6b..d75632440 100644 --- a/modules/images.py +++ b/modules/images.py @@ -311,7 +311,12 @@ def apply_filename_pattern(x, p, seed, prompt): x = x.replace("[cfg]", str(p.cfg_scale)) x = x.replace("[width]", str(p.width)) x = x.replace("[height]", str(p.height)) - x = x.replace("[styles]", sanitize_filename_part(", ".join([x for x in p.styles if not x == "None"]), replace_spaces=False)) + + #currently disabled if using the save button, will work otherwise + # if enabled it will cause a bug because styles is not included in the save_files data dictionary + if hasattr(p, "styles"): + x = x.replace("[styles]", sanitize_filename_part(", ".join([x for x in p.styles if not x == "None"]), replace_spaces=False)) + x = x.replace("[sampler]", sanitize_filename_part(sd_samplers.samplers[p.sampler_index].name, replace_spaces=False)) x = x.replace("[model_hash]", shared.sd_model.sd_model_hash) diff --git a/modules/ui.py b/modules/ui.py index 57aef6ff1..3b81a4f74 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -33,6 +33,7 @@ import modules.gfpgan_model import modules.codeformer_model import modules.styles import modules.generation_parameters_copypaste +from modules.images import apply_filename_pattern, get_next_sequence_number import modules.textual_inversion.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 @@ -96,14 +97,31 @@ def send_gradio_gallery_to_image(x): def save_files(js_data, images, index): - import csv - - os.makedirs(opts.outdir_save, exist_ok=True) - + import csv filenames = [] + #quick dictionary to class object conversion. Its neccesary due apply_filename_pattern requiring it + class MyObject: + def __init__(self, d=None): + if d is not None: + for key, value in d.items(): + setattr(self, key, value) + data = json.loads(js_data) + + p = MyObject(data) + path = opts.outdir_save + save_to_dirs = opts.save_to_dirs + + if save_to_dirs: + dirname = apply_filename_pattern(opts.directories_filename_pattern or "[prompt_words]", p, p.seed, p.prompt) + path = os.path.join(opts.outdir_save, dirname) + + os.makedirs(path, exist_ok=True) + + if index > -1 and opts.save_selected_only and (index >= data["index_of_first_image"]): # ensures we are looking at a specific non-grid picture, and we have save_selected_only + images = [images[index]] infotexts = [data["infotexts"][index]] else: @@ -115,11 +133,20 @@ def save_files(js_data, images, index): if at_start: writer.writerow(["prompt", "seed", "width", "height", "sampler", "cfgs", "steps", "filename", "negative_prompt"]) - filename_base = str(int(time.time() * 1000)) + file_decoration = opts.samples_filename_pattern or "[seed]-[prompt_spaces]" + if file_decoration != "": + file_decoration = "-" + file_decoration.lower() + file_decoration = apply_filename_pattern(file_decoration, p, p.seed, p.prompt) + truncated = (file_decoration[:240] + '..') if len(file_decoration) > 240 else file_decoration + filename_base = truncated extension = opts.samples_format.lower() + + basecount = get_next_sequence_number(path, "") for i, filedata in enumerate(images): - filename = filename_base + ("" if len(images) == 1 else "-" + str(i + 1)) + f".{extension}" - filepath = os.path.join(opts.outdir_save, filename) + file_number = f"{basecount+i:05}" + filename = file_number + filename_base + f".{extension}" + filepath = os.path.join(path, filename) + if filedata.startswith("data:image/png;base64,"): filedata = filedata[len("data:image/png;base64,"):]