From 0f7d2e95caa20821c553e9ae5b7c51f78973096b Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sun, 14 Sep 2025 13:03:03 -0400 Subject: [PATCH] fix state interrupted checks Signed-off-by: Vladimir Mandic --- modules/postprocess/yolo.py | 2 + modules/processing.py | 142 ++++++++++++++++---------------- modules/processing_diffusers.py | 5 +- modules/processing_helpers.py | 37 +++++---- modules/shared_state.py | 4 +- 5 files changed, 100 insertions(+), 90 deletions(-) diff --git a/modules/postprocess/yolo.py b/modules/postprocess/yolo.py index 74c67cf78..0cd39e0a6 100644 --- a/modules/postprocess/yolo.py +++ b/modules/postprocess/yolo.py @@ -217,6 +217,8 @@ class YoloRestorer(Detailer): return [merged] def restore(self, np_image, p: processing.StableDiffusionProcessing = None): + if shared.state.interrupted or shared.state.skipped: + return np_image if hasattr(p, 'recursion'): return np_image if not hasattr(p, 'detailer_active'): diff --git a/modules/processing.py b/modules/processing.py index 3dea7829c..31378fa4a 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -282,81 +282,83 @@ def process_samples(p: StableDiffusionProcessing, samples): sample = validate_sample(sample) image = Image.fromarray(sample) - if p.restore_faces: - p.ops.append('restore') - if not p.do_not_save_samples and shared.opts.save_images_before_detailer: + if not shared.state.interrupted and not shared.state.skipped: + + if p.restore_faces: + p.ops.append('restore') + if not p.do_not_save_samples and shared.opts.save_images_before_detailer: + info = create_infotext(p, p.prompts, p.seeds, p.subseeds, index=i) + images.save_image(Image.fromarray(sample), path=p.outpath_samples, basename="", seed=p.seeds[i], prompt=p.prompts[i], extension=shared.opts.samples_format, info=info, p=p, suffix="-before-restore") + sample = face_restoration.restore_faces(sample, p) + if sample is not None: + image = Image.fromarray(sample) + + if p.detailer_enabled: + p.ops.append('detailer') + if not p.do_not_save_samples and shared.opts.save_images_before_detailer: + info = create_infotext(p, p.prompts, p.seeds, p.subseeds, index=i) + images.save_image(Image.fromarray(sample), path=p.outpath_samples, basename="", seed=p.seeds[i], prompt=p.prompts[i], extension=shared.opts.samples_format, info=info, p=p, suffix="-before-detailer") + sample = detailer.detail(sample, p) + if sample is not None: + image = Image.fromarray(sample) + + if p.color_corrections is not None and i < len(p.color_corrections): + p.ops.append('color') + if not p.do_not_save_samples and shared.opts.save_images_before_color_correction: + orig = p.color_corrections + p.color_corrections = None + p.color_corrections = orig + image_without_cc = apply_overlay(image, p.paste_to, i, p.overlay_images) + info = create_infotext(p, p.prompts, p.seeds, p.subseeds, index=i) + images.save_image(image_without_cc, path=p.outpath_samples, basename="", seed=p.seeds[i], prompt=p.prompts[i], extension=shared.opts.samples_format, info=info, p=p, suffix="-before-color-correct") + image = apply_color_correction(p.color_corrections[i], image) + + if p.scripts is not None and isinstance(p.scripts, scripts_manager.ScriptRunner): + pp = scripts_manager.PostprocessImageArgs(image) + p.scripts.postprocess_image(p, pp) + if pp.image is not None: + image = pp.image + + if shared.opts.mask_apply_overlay: + image = apply_overlay(image, p.paste_to, i, p.overlay_images) + + if hasattr(p, 'mask_for_overlay') and p.mask_for_overlay and any([shared.opts.save_mask, shared.opts.save_mask_composite, shared.opts.return_mask, shared.opts.return_mask_composite]): + image_mask = p.mask_for_overlay.convert('RGB') + image1 = image.convert('RGBA').convert('RGBa') + image2 = Image.new('RGBa', image.size) + mask = images.resize_image(3, p.mask_for_overlay, image.width, image.height).convert('L') + image_mask_composite = Image.composite(image1, image2, mask).convert('RGBA') info = create_infotext(p, p.prompts, p.seeds, p.subseeds, index=i) - images.save_image(Image.fromarray(sample), path=p.outpath_samples, basename="", seed=p.seeds[i], prompt=p.prompts[i], extension=shared.opts.samples_format, info=info, p=p, suffix="-before-restore") - sample = face_restoration.restore_faces(sample, p) - if sample is not None: - image = Image.fromarray(sample) - - if p.detailer_enabled: - p.ops.append('detailer') - if not p.do_not_save_samples and shared.opts.save_images_before_detailer: - info = create_infotext(p, p.prompts, p.seeds, p.subseeds, index=i) - images.save_image(Image.fromarray(sample), path=p.outpath_samples, basename="", seed=p.seeds[i], prompt=p.prompts[i], extension=shared.opts.samples_format, info=info, p=p, suffix="-before-detailer") - sample = detailer.detail(sample, p) - if sample is not None: - image = Image.fromarray(sample) - - if p.color_corrections is not None and i < len(p.color_corrections): - p.ops.append('color') - if not p.do_not_save_samples and shared.opts.save_images_before_color_correction: - orig = p.color_corrections - p.color_corrections = None - p.color_corrections = orig - image_without_cc = apply_overlay(image, p.paste_to, i, p.overlay_images) - info = create_infotext(p, p.prompts, p.seeds, p.subseeds, index=i) - images.save_image(image_without_cc, path=p.outpath_samples, basename="", seed=p.seeds[i], prompt=p.prompts[i], extension=shared.opts.samples_format, info=info, p=p, suffix="-before-color-correct") - image = apply_color_correction(p.color_corrections[i], image) - - if p.scripts is not None and isinstance(p.scripts, scripts_manager.ScriptRunner): - pp = scripts_manager.PostprocessImageArgs(image) - p.scripts.postprocess_image(p, pp) - if pp.image is not None: - image = pp.image - - if shared.opts.mask_apply_overlay: - image = apply_overlay(image, p.paste_to, i, p.overlay_images) - - if hasattr(p, 'mask_for_overlay') and p.mask_for_overlay and any([shared.opts.save_mask, shared.opts.save_mask_composite, shared.opts.return_mask, shared.opts.return_mask_composite]): - image_mask = p.mask_for_overlay.convert('RGB') - image1 = image.convert('RGBA').convert('RGBa') - image2 = Image.new('RGBa', image.size) - mask = images.resize_image(3, p.mask_for_overlay, image.width, image.height).convert('L') - image_mask_composite = Image.composite(image1, image2, mask).convert('RGBA') - info = create_infotext(p, p.prompts, p.seeds, p.subseeds, index=i) - if shared.opts.save_mask: - images.save_image(image_mask, p.outpath_samples, "", p.seeds[i], p.prompts[i], shared.opts.samples_format, info=info, p=p, suffix="-mask") - if shared.opts.save_mask_composite: - images.save_image(image_mask_composite, p.outpath_samples, "", p.seeds[i], p.prompts[i], shared.opts.samples_format, info=info, p=p, suffix="-mask-composite") - if shared.opts.return_mask: - out_infotexts.append(info) - out_images.append(image_mask) - if shared.opts.return_mask_composite: - out_infotexts.append(info) - out_images.append(image_mask_composite) - - if shared.opts.include_mask: - info = create_infotext(p, p.prompts, p.seeds, p.subseeds, index=i) - if shared.opts.mask_apply_overlay and p.overlay_images is not None and len(p.overlay_images) > 0: - p.image_mask = create_binary_mask(p.overlay_images[0]) - p.image_mask = ImageOps.invert(p.image_mask) - out_infotexts.append(info) - out_images.append(p.image_mask) - elif getattr(p, 'image_mask', None) is not None and isinstance(p.image_mask, Image.Image): - if getattr(p, 'mask_for_detailer', None) is not None: + if shared.opts.save_mask: + images.save_image(image_mask, p.outpath_samples, "", p.seeds[i], p.prompts[i], shared.opts.samples_format, info=info, p=p, suffix="-mask") + if shared.opts.save_mask_composite: + images.save_image(image_mask_composite, p.outpath_samples, "", p.seeds[i], p.prompts[i], shared.opts.samples_format, info=info, p=p, suffix="-mask-composite") + if shared.opts.return_mask: out_infotexts.append(info) - out_images.append(p.mask_for_detailer) - else: + out_images.append(image_mask) + if shared.opts.return_mask_composite: + out_infotexts.append(info) + out_images.append(image_mask_composite) + + if shared.opts.include_mask: + info = create_infotext(p, p.prompts, p.seeds, p.subseeds, index=i) + if shared.opts.mask_apply_overlay and p.overlay_images is not None and len(p.overlay_images) > 0: + p.image_mask = create_binary_mask(p.overlay_images[0]) + p.image_mask = ImageOps.invert(p.image_mask) out_infotexts.append(info) out_images.append(p.image_mask) + elif getattr(p, 'image_mask', None) is not None and isinstance(p.image_mask, Image.Image): + if getattr(p, 'mask_for_detailer', None) is not None: + out_infotexts.append(info) + out_images.append(p.mask_for_detailer) + else: + out_infotexts.append(info) + out_images.append(p.image_mask) - if p.selected_scale_tab_after == 1: - p.width_after, p.height_after = int(image.width * p.scale_by_after), int(image.height * p.scale_by_after) - if p.resize_mode_after != 0 and p.resize_name_after != 'None': - image = images.resize_image(p.resize_mode_after, image, p.width_after, p.height_after, p.resize_name_after, context=p.resize_context_after) + if p.selected_scale_tab_after == 1: + p.width_after, p.height_after = int(image.width * p.scale_by_after), int(image.height * p.scale_by_after) + if p.resize_mode_after != 0 and p.resize_name_after != 'None': + image = images.resize_image(p.resize_mode_after, image, p.width_after, p.height_after, p.resize_name_after, context=p.resize_context_after) info = create_infotext(p, p.prompts, p.seeds, p.subseeds, index=i) if shared.opts.samples_save and not p.do_not_save_samples and p.outpath_samples is not None: diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index 0cfbbc0ec..8353be172 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -547,8 +547,9 @@ def process_diffusers(p: processing.StableDiffusionProcessing): output = SimpleNamespace(images=images) if (output is None or len(output.images) == 0) and has_images: - shared.log.debug('Processing: using input as base output') - output.images = p.init_images + if output is not None: + shared.log.debug('Processing: using input as base output') + output.images = p.init_images if shared.state.interrupted or shared.state.skipped: shared.sd_model = orig_pipeline diff --git a/modules/processing_helpers.py b/modules/processing_helpers.py index 63b38683b..976ab0c32 100644 --- a/modules/processing_helpers.py +++ b/modules/processing_helpers.py @@ -298,28 +298,33 @@ def resize_init_images(p): def resize_hires(p, latents): # input=latents output=pil if not latent_upscaler else latent - jobid = shared.state.begin('Resize') - if not torch.is_tensor(latents): - shared.log.warning('Hires: input is not tensor') - decoded = processing_vae.vae_decode(latents=latents, model=shared.sd_model, vae_type=p.vae_type, output_type='pil', width=p.width, height=p.height) - shared.state.end(jobid) - return decoded - if (p.hr_upscale_to_x == 0 or p.hr_upscale_to_y == 0) and hasattr(p, 'init_hr'): shared.log.error('Hires: missing upscaling dimensions') - shared.state.end(jobid) - return decoded + return latents + + jobid = shared.state.begin('Resize') if p.hr_upscaler.lower().startswith('latent'): + if isinstance(latents, list): + try: + for i in range(len(latents)): + if not torch.is_tensor(latents[i]): + shared.log.warning(f'Hires: input[{i}]={type(latents[i])} not tensor') + latents[i] = processing_vae.vae_encode(image=latents[i], model=shared.sd_model, vae_type=p.vae_type) + latents = torch.cat(latents, dim=0) + except Exception as e: + shared.log.error(f'Hires: prepare latents: {e}') + resized = latents + elif not torch.is_tensor(latents): + shared.log.warning(f'Hires: input={type(latents)} not tensor') resized = images.resize_image(p.hr_resize_mode, latents, p.hr_upscale_to_x, p.hr_upscale_to_y, upscaler_name=p.hr_upscaler, context=p.hr_resize_context) - shared.state.end(jobid) - return resized + else: + decoded = processing_vae.vae_decode(latents=latents, model=shared.sd_model, vae_type=p.vae_type, output_type='pil', width=p.width, height=p.height) + resized = [] + for image in decoded: + resize = images.resize_image(p.hr_resize_mode, image, p.hr_upscale_to_x, p.hr_upscale_to_y, upscaler_name=p.hr_upscaler, context=p.hr_resize_context) + resized.append(resize) - decoded = processing_vae.vae_decode(latents=latents, model=shared.sd_model, vae_type=p.vae_type, output_type='pil', width=p.width, height=p.height) - resized = [] - for image in decoded: - resize = images.resize_image(p.hr_resize_mode, image, p.hr_upscale_to_x, p.hr_upscale_to_y, upscaler_name=p.hr_upscaler, context=p.hr_resize_context) - resized.append(resize) devices.torch_gc() shared.state.end(jobid) return resized diff --git a/modules/shared_state.py b/modules/shared_state.py index 32df815c2..d79e90b86 100644 --- a/modules/shared_state.py +++ b/modules/shared_state.py @@ -189,13 +189,13 @@ class State: self.preview_job = -1 self.duration = None self.paused = False - self.interrupted = False - self.skipped = False self.results = [] def begin(self, title="", task_id=0, api=None): import modules.devices self.clear() + self.interrupted = False + self.skipped = False self.job_history += 1 self.total_jobs += 1 self.current_image = None