From c7051cc1dde40f8594f836fd9eec4b3972503a23 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 3 Jun 2023 09:04:58 -0400 Subject: [PATCH] extra error handling during image save --- CHANGELOG.md | 4 +++ TODO.md | 3 +++ extensions-builtin/a1111-sd-webui-lycoris | 2 +- extensions-builtin/sd-webui-agent-scheduler | 2 +- extensions-builtin/sd-webui-controlnet | 2 +- .../stable-diffusion-webui-images-browser | 2 +- installer.py | 2 +- javascript/progressbar.js | 5 ++++ modules/images.py | 26 +++++++++++++++---- modules/lora | 2 +- modules/shared.py | 10 +++---- modules/ui.py | 2 +- modules/ui_extra_networks.py | 2 +- 13 files changed, 46 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1d740e4a..1344f5bb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log for SD.Next +## Update for 06/03/2023 + +- new vae decode method to help with larger batch sizes, thanks @bigdog + ## Update for 06/02/2023 Some quality-of-life improvements while working on larger stuff in the background... diff --git a/TODO.md b/TODO.md index 5b9b5faa6..10ba415fb 100644 --- a/TODO.md +++ b/TODO.md @@ -52,3 +52,6 @@ Tech that can be integrated as part of the core workflow... - - shared.info - hints +- localization +- docker +- port `p.all_hr_prompts` diff --git a/extensions-builtin/a1111-sd-webui-lycoris b/extensions-builtin/a1111-sd-webui-lycoris index c1e676b4d..f90a21234 160000 --- a/extensions-builtin/a1111-sd-webui-lycoris +++ b/extensions-builtin/a1111-sd-webui-lycoris @@ -1 +1 @@ -Subproject commit c1e676b4d75c1ff2bd49f0742036eb8691d10ccd +Subproject commit f90a21234b7a7bfdafd4a2406c80d59571d69021 diff --git a/extensions-builtin/sd-webui-agent-scheduler b/extensions-builtin/sd-webui-agent-scheduler index b4fb2c325..aea5146f1 160000 --- a/extensions-builtin/sd-webui-agent-scheduler +++ b/extensions-builtin/sd-webui-agent-scheduler @@ -1 +1 @@ -Subproject commit b4fb2c325f8b9737bcaaafe5a8d379b97d0c958d +Subproject commit aea5146f1e5fc50401b32e9a0236fd16210b96f3 diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet index 84e92d0d0..7b2bf668e 160000 --- a/extensions-builtin/sd-webui-controlnet +++ b/extensions-builtin/sd-webui-controlnet @@ -1 +1 @@ -Subproject commit 84e92d0d0e0784437dde65b619e400965eab368c +Subproject commit 7b2bf668ee4e0ce63dd67c828ea20c064e719796 diff --git a/extensions-builtin/stable-diffusion-webui-images-browser b/extensions-builtin/stable-diffusion-webui-images-browser index 59547c843..5795886be 160000 --- a/extensions-builtin/stable-diffusion-webui-images-browser +++ b/extensions-builtin/stable-diffusion-webui-images-browser @@ -1 +1 @@ -Subproject commit 59547c8431d9a7b020915d7f42a7c5b488e2313f +Subproject commit 5795886bee895c2e69e5c64e67aa643da423511c diff --git a/installer.py b/installer.py index 4fb8d5413..75ecf2958 100644 --- a/installer.py +++ b/installer.py @@ -264,7 +264,7 @@ def check_torch(): log.info('AMD ROCm toolkit detected') os.environ.setdefault('HSA_OVERRIDE_GFX_VERSION', '10.3.0') os.environ.setdefault('PYTORCH_HIP_ALLOC_CONF', 'garbage_collection_threshold:0.8,max_split_size_mb:512') - torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.0.0 torchvision==0.15.1 --index-url https://download.pytorch.org/whl/rocm5.4.2') + torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.0.1 torchvision==0.15.2 --index-url https://download.pytorch.org/whl/rocm5.4.2') xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none') elif allow_ipex and args.use_ipex and shutil.which('sycl-ls') is not None: log.info('Intel OneAPI Toolkit detected') diff --git a/javascript/progressbar.js b/javascript/progressbar.js index adfb21f24..82ac1276d 100644 --- a/javascript/progressbar.js +++ b/javascript/progressbar.js @@ -45,6 +45,7 @@ function checkPaused(state) { } function setProgress(res) { + console.log(res); elements = ['txt2img_generate', 'img2img_generate', 'extras_generate'] const progress = (res?.progress || 0) const perc = res && (progress > 0) ? `${Math.round(100.0 * progress)}%` : '' @@ -70,6 +71,10 @@ function setProgress(res) { } } +function requestInterrupt() { + setProgress(); +} + function randomId() { return `task(${Math.random().toString(36).slice(2, 7)}${Math.random().toString(36).slice(2, 7)}${Math.random().toString(36).slice(2, 7)})`; } diff --git a/modules/images.py b/modules/images.py index e9656b365..d068842eb 100644 --- a/modules/images.py +++ b/modules/images.py @@ -432,7 +432,14 @@ def atomically_save_image(): image, filename, extension, params, exifinfo_data, txt_fullfn = save_queue.get() fn = filename + extension filename = filename.strip() - image_format = Image.registered_extensions()[extension] + if extension[0] != '.': # add dot if missing + extension = '.' + extension + print('image_format', extension) + try: + image_format = Image.registered_extensions()[extension] + except Exception: + shared.log.warning(f'Unknown image format: {extension}') + image_format = 'JPEG' shared.log.debug(f'Saving image: {image_format} {fn} {image.size}') # actual save if image_format == 'PNG': @@ -452,14 +459,23 @@ def atomically_save_image(): if image.mode == 'I;16': image = image.point(lambda p: p * 0.0038910505836576).convert("RGB") exif_bytes = piexif.dump({ "Exif": { piexif.ExifIFD.UserComment: piexif.helper.UserComment.dump(exifinfo_data or "", encoding="unicode") } }) - image.save(fn, format=image_format, quality=shared.opts.jpeg_quality, lossless=shared.opts.webp_lossless, exif=exif_bytes) + try: + image.save(fn, format=image_format, quality=shared.opts.jpeg_quality, lossless=shared.opts.webp_lossless, exif=exif_bytes) + except Exception as e: + shared.log.warning(f'Image save failed: {fn} {e}') else: # shared.log.warning(f'Unrecognized image format: {extension} attempting save as {image_format}') - image.save(fn, format=image_format, quality=shared.opts.jpeg_quality) + try: + image.save(fn, format=image_format, quality=shared.opts.jpeg_quality) + except Exception as e: + shared.log.warning(f'Image save failed: {fn} {e}') # additional metadata saved in files if shared.opts.save_txt and len(exifinfo_data) > 0: - with open(txt_fullfn, "w", encoding="utf8") as file: - file.write(f"{exifinfo_data}\n") + try: + with open(txt_fullfn, "w", encoding="utf8") as file: + file.write(f"{exifinfo_data}\n") + except Exception as e: + shared.log.warning(f'Image description save failed: {txt_fullfn} {e}') with open(os.path.join(paths.data_path, "params.txt"), "w", encoding="utf8") as file: file.write(exifinfo_data) if shared.opts.save_log_fn != '' and len(exifinfo_data) > 0: diff --git a/modules/lora b/modules/lora index 5931948ad..7c38c33ed 160000 --- a/modules/lora +++ b/modules/lora @@ -1 +1 @@ -Subproject commit 5931948adbf0f76017ecc13e716c68a690097c16 +Subproject commit 7c38c33ed62fa1becab94f967a52aca18ffaccc0 diff --git a/modules/shared.py b/modules/shared.py index 73c29aee0..9a51316bf 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -322,11 +322,11 @@ options_templates.update(options_section(('system-paths', "System Paths"), { options_templates.update(options_section(('saving-images', "Image Options"), { "samples_save": OptionInfo(True, "Always save all generated images"), - "samples_format": OptionInfo('jpg', 'File format for generated images', gr.Dropdown, lambda: {"choices": ["jpg", "png", "webp", "tiff", "jp2", "psd"]}), + "samples_format": OptionInfo('jpg', 'File format for generated images', gr.Dropdown, lambda: {"choices": ["jpg", "png", "webp", "tiff", "jp2"]}), "samples_filename_pattern": OptionInfo("[seed]-[prompt_spaces]", "Images filename pattern", component_args=hide_dirs), "save_images_add_number": OptionInfo(True, "Add number to filename when saving", component_args=hide_dirs), "grid_save": OptionInfo(True, "Always save all generated image grids"), - "grid_format": OptionInfo('jpg', 'File format for grids', gr.Dropdown, lambda: {"choices": ["jpg", "png", "webp", "tiff", "jp2", "psd"]}), + "grid_format": OptionInfo('jpg', 'File format for grids', gr.Dropdown, lambda: {"choices": ["jpg", "png", "webp", "tiff", "jp2"]}), "grid_extended_filename": OptionInfo(True, "Add extended info (seed, prompt) to filename when saving grid"), "grid_only_if_multiple": OptionInfo(True, "Do not save grids consisting of one picture"), "grid_prevent_empty_spots": OptionInfo(True, "Prevent empty spots in grid (when set to autodetect)"), @@ -469,7 +469,7 @@ options_templates.update(options_section(('ui', "User interface"), { "ui_tab_reorder": OptionInfo("From Text, From Image, Process Image", "UI tabs order"), "ui_scripts_reorder": OptionInfo("Enable Dynamic Thresholding, ControlNet", "UI scripts order"), "ui_reorder": OptionInfo(", ".join(ui_reorder_categories), "txt2img/img2img UI item order"), - "ui_extra_networks_tab_reorder": OptionInfo("", "Extra networks tab order"), + "ui_extra_networks_tab_reorder": OptionInfo("Checkpoints, Lora, LyCORIS, Textual Inversion, Hypernetworks", "Extra networks tab order"), })) options_templates.update(options_section(('ui', "Live previews"), { @@ -478,8 +478,8 @@ options_templates.update(options_section(('ui', "Live previews"), { "show_progress_grid": OptionInfo(True, "Show previews of all images generated in a batch as a grid"), "notification_audio_enable": OptionInfo(False, "Play a sound when images are finished generating"), "notification_audio_path": OptionInfo("html/notification.mp3","Path to notification sound", component_args=hide_dirs), - "show_progress_every_n_steps": OptionInfo(1, "Live preview display period", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}).info("in sampling steps - show new live preview image every N sampling steps; -1 = only show after completion of batch"), - "show_progress_type": OptionInfo("TAESD", "Live preview method", gr.Radio, {"choices": ["Full", "Approx NN", "Approx cheap", "TAESD"]}).info("Full = slow but pretty; Approx NN and TAESD = fast but low quality; Approx cheap = super fast but terrible otherwise"), + "show_progress_every_n_steps": OptionInfo(1, "Live preview display period", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}), + "show_progress_type": OptionInfo("TAESD", "Live preview method", gr.Radio, {"choices": ["Full", "Approx NN", "Approx cheap", "TAESD"]}), "live_preview_content": OptionInfo("Combined", "Live preview subject", gr.Radio, {"choices": ["Combined", "Prompt", "Negative prompt"]}), "live_preview_refresh_period": OptionInfo(250, "Progressbar/preview update period, in milliseconds") })) diff --git a/modules/ui.py b/modules/ui.py index b0686d10f..9b40e8a4e 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -241,7 +241,7 @@ def create_toprow(is_img2img): submit = gr.Button('Generate', elem_id=f"{id_part}_generate", variant='primary') with gr.Row(elem_id=f"{id_part}_generate_line2"): interrupt = gr.Button('Stop', elem_id=f"{id_part}_interrupt") - interrupt.click(fn=lambda: modules.shared.state.interrupt(), inputs=[], outputs=[]) + interrupt.click(fn=lambda: modules.shared.state.interrupt(), _js="requestInterrupt", inputs=[], outputs=[]) skip = gr.Button('Skip', elem_id=f"{id_part}_skip") skip.click(fn=lambda: modules.shared.state.skip(), inputs=[], outputs=[]) pause = gr.Button('Pause', elem_id=f"{id_part}_pause") diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 12ca03a52..8ea905f5b 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -153,7 +153,7 @@ class ExtraNetworksPage: """ Find a preview PNG for a given path (without extension) and call link_preview on it. """ - preview_extensions = ["jpg", "png", "webp", "tiff", "jp2", "psd"] + preview_extensions = ["jpg", "png", "webp", "tiff", "jp2"] potential_files = sum([[path + "." + ext, path + ".preview." + ext] for ext in preview_extensions], []) for file in potential_files: if os.path.isfile(file):