From c09c7e0f0a44041adfd9bd028dd12a35d9cef6f0 Mon Sep 17 00:00:00 2001 From: MarcusNyne <69087098+MarcusNyne@users.noreply.github.com> Date: Mon, 16 Sep 2024 18:31:06 -0400 Subject: [PATCH 1/6] Save additional images - Added global setting "Save incremental step images" - When this setting is set, and there are multiple models, images between inpainting applications will be saved. This excludes "solo" generations - Added a model-level setting "Solo generation". When checked, this model will not be added to the final image. Instead, a new "solo" image will be generated from the original image with only this model applied. --- aaaaaa/ui.py | 2 ++ adetailer/args.py | 2 ++ scripts/!adetailer.py | 76 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 73 insertions(+), 7 deletions(-) diff --git a/aaaaaa/ui.py b/aaaaaa/ui.py index 4b9b484e..b38115d9 100644 --- a/aaaaaa/ui.py +++ b/aaaaaa/ui.py @@ -710,3 +710,5 @@ def controlnet(w: Widgets, n: int, is_img2img: bool): interactive=controlnet_exists, elem_id=eid("ad_controlnet_guidance_end"), ) + + w.ad_solo_generation = gr.Checkbox(label="Solo generation" + suffix(n), value=False, elem_id=eid("ad_solo_generation")) \ No newline at end of file diff --git a/adetailer/args.py b/adetailer/args.py index 4efcdd7f..3cd18831 100644 --- a/adetailer/args.py +++ b/adetailer/args.py @@ -95,6 +95,7 @@ class ADetailerArgs(BaseModel, extra=Extra.forbid): ad_controlnet_weight: confloat(ge=0.0, le=1.0) = 1.0 ad_controlnet_guidance_start: confloat(ge=0.0, le=1.0) = 0.0 ad_controlnet_guidance_end: confloat(ge=0.0, le=1.0) = 1.0 + ad_solo_generation = False is_api: bool = True @validator("is_api", pre=True) @@ -252,6 +253,7 @@ def need_skip(self) -> bool: ("ad_controlnet_weight", "ADetailer ControlNet weight"), ("ad_controlnet_guidance_start", "ADetailer ControlNet guidance start"), ("ad_controlnet_guidance_end", "ADetailer ControlNet guidance end"), + ("ad_solo_generation", "ADetailer solo generation"), ] _args = [Arg(*args) for args in _all_args] diff --git a/scripts/!adetailer.py b/scripts/!adetailer.py index 52baf157..6a49e359 100644 --- a/scripts/!adetailer.py +++ b/scripts/!adetailer.py @@ -48,6 +48,7 @@ ADetailerArgs, InpaintBBoxMatchMode, SkipImg2ImgOrig, + _all_args, ) from adetailer.common import PredictOutput, ensure_pil_image, safe_mkdir from adetailer.mask import ( @@ -563,7 +564,7 @@ def save_image(self, p, image, *, condition: str, suffix: str) -> None: save_prompt = p.prompt seed, _ = self.get_seed(p) - if opts.data.get(condition, False): + if condition is True or opts.data.get(condition, False): ad_save_images_dir: str = opts.data.get("ad_save_images_dir", "") if not ad_save_images_dir.strip(): @@ -901,17 +902,56 @@ def postprocess_image(self, p, pp: PPImage, *args_): with preserve_prompts(p): p.scripts.postprocess(copy(p), dummy) + last_index = 0 + for n, args in enumerate(arg_list): + if args.need_skip() and args.ad_solo_generation is False: + last_index = n + + save_incrementals = [] + save_solos = [] + is_processed = False with CNHijackRestore(), pause_total_tqdm(), cn_allow_script_control(): for n, args in enumerate(arg_list): - if args.need_skip(): + if args.need_skip() or args.ad_solo_generation: continue is_processed |= self._postprocess_image_inner(p, pp, args, n=n) - if is_processed and not is_skip_img2img(p): - self.save_image( - p, init_image, condition="ad_save_images_before", suffix="-ad-before" - ) + if n < last_index: + save_incrementals.append((n,copy(pp.image))) + + for n, args in enumerate(arg_list): + if args.need_skip() or args.ad_solo_generation is False: + continue + pp_solo = copy(pp) + pp_solo.image = init_image + if self._postprocess_image_inner(p, pp_solo, args, n=n): + save_solos.append((n, pp_solo.image, args)) + + if is_processed: + if not is_skip_img2img(p): + self.save_image( + p, init_image, condition="ad_save_images_before", suffix="-ad-before" + ) + + for save in save_incrementals: + self.save_image( + p, + save[1], + condition="ad_save_step_images", + suffix=f"-ad-step-{save[0]+1}", + ) + + all_extra_params = p.extra_generation_params + for save in save_solos: + p.extra_generation_params = self.fix_extra_generation_params(all_extra_params, save[2]) + self.save_image( + p, + save[1], + condition=True, + suffix=f"-ad-solo-{save[0]+1}", + ) + p.extra_generation_params = all_extra_params if need_call_process(p): with preserve_prompts(p): @@ -921,7 +961,24 @@ def postprocess_image(self, p, pp: PPImage, *args_): self.write_params_txt(params_txt_content) - + def fix_extra_generation_params(self, params:dict, args:ADetailerArgs): + ad_params = {} + for params_k in list(params.keys()): + found = False + for i, (k,v) in enumerate (_all_args): + if v in params_k: + found = True + break + if not found: + ad_params[params_k] = params[params_k] + + for i, (k,v) in enumerate (_all_args): + if hasattr(args,k): + args_v = getattr(args,k) + if args_v is not None and args_v != '': + ad_params[v] = args_v + return ad_params + def on_after_component(component, **_kwargs): global txt2img_submit_button, img2img_submit_button if getattr(component, "elem_id", None) == "txt2img_generate": @@ -977,6 +1034,11 @@ def on_ui_settings(): shared.OptionInfo(False, "Save images before ADetailer", section=section), ) + shared.opts.add_option( + "ad_save_step_images", + shared.OptionInfo(False, "Save incremental step images", section=section), + ) + shared.opts.add_option( "ad_only_selected_scripts", shared.OptionInfo( From d5cea64ebae13234755b3e2b0b5cba557c2afde8 Mon Sep 17 00:00:00 2001 From: MarcusNyne <69087098+MarcusNyne@users.noreply.github.com> Date: Mon, 16 Sep 2024 23:30:09 -0400 Subject: [PATCH 2/6] Location of solo generation checkbox --- aaaaaa/ui.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aaaaaa/ui.py b/aaaaaa/ui.py index b38115d9..6763caae 100644 --- a/aaaaaa/ui.py +++ b/aaaaaa/ui.py @@ -711,4 +711,5 @@ def controlnet(w: Widgets, n: int, is_img2img: bool): elem_id=eid("ad_controlnet_guidance_end"), ) - w.ad_solo_generation = gr.Checkbox(label="Solo generation" + suffix(n), value=False, elem_id=eid("ad_solo_generation")) \ No newline at end of file + with gr.Column(variant="compact"): + w.ad_solo_generation = gr.Checkbox(label="Solo generation" + suffix(n), value=False, elem_id=eid("ad_solo_generation")) From 9be63719898e326ec172e9311aaeafdd52d0c2d1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 04:22:33 +0000 Subject: [PATCH 3/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- aaaaaa/ui.py | 6 +++++- scripts/!adetailer.py | 26 ++++++++++++++++---------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/aaaaaa/ui.py b/aaaaaa/ui.py index 6763caae..044baf12 100644 --- a/aaaaaa/ui.py +++ b/aaaaaa/ui.py @@ -712,4 +712,8 @@ def controlnet(w: Widgets, n: int, is_img2img: bool): ) with gr.Column(variant="compact"): - w.ad_solo_generation = gr.Checkbox(label="Solo generation" + suffix(n), value=False, elem_id=eid("ad_solo_generation")) + w.ad_solo_generation = gr.Checkbox( + label="Solo generation" + suffix(n), + value=False, + elem_id=eid("ad_solo_generation"), + ) diff --git a/scripts/!adetailer.py b/scripts/!adetailer.py index 6a49e359..714fdfb2 100644 --- a/scripts/!adetailer.py +++ b/scripts/!adetailer.py @@ -918,7 +918,7 @@ def postprocess_image(self, p, pp: PPImage, *args_): is_processed |= self._postprocess_image_inner(p, pp, args, n=n) if n < last_index: - save_incrementals.append((n,copy(pp.image))) + save_incrementals.append((n, copy(pp.image))) for n, args in enumerate(arg_list): if args.need_skip() or args.ad_solo_generation is False: @@ -931,7 +931,10 @@ def postprocess_image(self, p, pp: PPImage, *args_): if is_processed: if not is_skip_img2img(p): self.save_image( - p, init_image, condition="ad_save_images_before", suffix="-ad-before" + p, + init_image, + condition="ad_save_images_before", + suffix="-ad-before", ) for save in save_incrementals: @@ -944,7 +947,9 @@ def postprocess_image(self, p, pp: PPImage, *args_): all_extra_params = p.extra_generation_params for save in save_solos: - p.extra_generation_params = self.fix_extra_generation_params(all_extra_params, save[2]) + p.extra_generation_params = self.fix_extra_generation_params( + all_extra_params, save[2] + ) self.save_image( p, save[1], @@ -961,24 +966,25 @@ def postprocess_image(self, p, pp: PPImage, *args_): self.write_params_txt(params_txt_content) - def fix_extra_generation_params(self, params:dict, args:ADetailerArgs): + def fix_extra_generation_params(self, params: dict, args: ADetailerArgs): ad_params = {} for params_k in list(params.keys()): found = False - for i, (k,v) in enumerate (_all_args): + for i, (k, v) in enumerate(_all_args): if v in params_k: found = True break if not found: ad_params[params_k] = params[params_k] - for i, (k,v) in enumerate (_all_args): - if hasattr(args,k): - args_v = getattr(args,k) - if args_v is not None and args_v != '': + for i, (k, v) in enumerate(_all_args): + if hasattr(args, k): + args_v = getattr(args, k) + if args_v is not None and args_v != "": ad_params[v] = args_v return ad_params - + + def on_after_component(component, **_kwargs): global txt2img_submit_button, img2img_submit_button if getattr(component, "elem_id", None) == "txt2img_generate": From f8195da1271543aeb388dc6c877e9d97cc36b54b Mon Sep 17 00:00:00 2001 From: MarcusNyne <69087098+MarcusNyne@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:36:17 -0400 Subject: [PATCH 4/6] ruff fixes --- scripts/!adetailer.py | 60 +++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/scripts/!adetailer.py b/scripts/!adetailer.py index 6a49e359..914c7dd5 100644 --- a/scripts/!adetailer.py +++ b/scripts/!adetailer.py @@ -886,6 +886,22 @@ def _postprocess_image_inner( return False + def _postprocess_fork(self, init_image, p, pp:PPImage, args, n): + processed = False + save_incremental = None + save_solo = None + if not args.need_skip(): + if not args.ad_solo_generation: + processed = self._postprocess_image_inner(p, pp, args, n=n[0]) + if n[0] < n[1]: + save_incremental = (n[0],copy(pp.image)) + elif not args.need_skip() and args.ad_solo_generation: + pp_solo = copy(pp) + pp_solo.image = init_image + if self._postprocess_image_inner(p, pp_solo, args, n=n[0]): + save_solo = (n[0], pp_solo.image, args) + return (processed, save_incremental, save_solo) + @rich_traceback def postprocess_image(self, p, pp: PPImage, *args_): if getattr(p, "_ad_disabled", False) or not self.is_ad_enabled(*args_): @@ -902,10 +918,7 @@ def postprocess_image(self, p, pp: PPImage, *args_): with preserve_prompts(p): p.scripts.postprocess(copy(p), dummy) - last_index = 0 - for n, args in enumerate(arg_list): - if args.need_skip() and args.ad_solo_generation is False: - last_index = n + last_index = self._find_last_index(arg_list) save_incrementals = [] save_solos = [] @@ -913,20 +926,10 @@ def postprocess_image(self, p, pp: PPImage, *args_): is_processed = False with CNHijackRestore(), pause_total_tqdm(), cn_allow_script_control(): for n, args in enumerate(arg_list): - if args.need_skip() or args.ad_solo_generation: - continue - is_processed |= self._postprocess_image_inner(p, pp, args, n=n) - - if n < last_index: - save_incrementals.append((n,copy(pp.image))) - - for n, args in enumerate(arg_list): - if args.need_skip() or args.ad_solo_generation is False: - continue - pp_solo = copy(pp) - pp_solo.image = init_image - if self._postprocess_image_inner(p, pp_solo, args, n=n): - save_solos.append((n, pp_solo.image, args)) + fork_result = self._postprocess_fork(init_image, p, pp, args, (n,last_index)) + is_processed |= fork_result[0] + save_incrementals.append(fork_result[1]) + save_solos.append(fork_result[2]) if is_processed: if not is_skip_img2img(p): @@ -934,7 +937,7 @@ def postprocess_image(self, p, pp: PPImage, *args_): p, init_image, condition="ad_save_images_before", suffix="-ad-before" ) - for save in save_incrementals: + for save in filter(None, save_incrementals): self.save_image( p, save[1], @@ -943,8 +946,8 @@ def postprocess_image(self, p, pp: PPImage, *args_): ) all_extra_params = p.extra_generation_params - for save in save_solos: - p.extra_generation_params = self.fix_extra_generation_params(all_extra_params, save[2]) + for save in filter(None, save_solos): + p.extra_generation_params = self._fix_extra_generation_params(all_extra_params, save[2]) self.save_image( p, save[1], @@ -961,24 +964,31 @@ def postprocess_image(self, p, pp: PPImage, *args_): self.write_params_txt(params_txt_content) - def fix_extra_generation_params(self, params:dict, args:ADetailerArgs): + def _find_last_index(self, arg_list): + last_index = 0 + for n, args in enumerate(arg_list): + if args.need_skip() and args.ad_solo_generation is False: + last_index = n + return last_index + + def _fix_extra_generation_params(self, params:dict, args:ADetailerArgs): ad_params = {} for params_k in list(params.keys()): found = False - for i, (k,v) in enumerate (_all_args): + for _, (_,v) in enumerate (_all_args): if v in params_k: found = True break if not found: ad_params[params_k] = params[params_k] - for i, (k,v) in enumerate (_all_args): + for _, (k,v) in enumerate (_all_args): if hasattr(args,k): args_v = getattr(args,k) if args_v is not None and args_v != '': ad_params[v] = args_v return ad_params - + def on_after_component(component, **_kwargs): global txt2img_submit_button, img2img_submit_button if getattr(component, "elem_id", None) == "txt2img_generate": From 1504422c794649351344aaf0812103caeac859f8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 20:40:47 +0000 Subject: [PATCH 5/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- scripts/!adetailer.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/scripts/!adetailer.py b/scripts/!adetailer.py index ccc80136..26334c52 100644 --- a/scripts/!adetailer.py +++ b/scripts/!adetailer.py @@ -886,7 +886,7 @@ def _postprocess_image_inner( return False - def _postprocess_fork(self, init_image, p, pp:PPImage, args, n): + def _postprocess_fork(self, init_image, p, pp: PPImage, args, n): processed = False save_incremental = None save_solo = None @@ -894,7 +894,7 @@ def _postprocess_fork(self, init_image, p, pp:PPImage, args, n): if not args.ad_solo_generation: processed = self._postprocess_image_inner(p, pp, args, n=n[0]) if n[0] < n[1]: - save_incremental = (n[0],copy(pp.image)) + save_incremental = (n[0], copy(pp.image)) elif not args.need_skip() and args.ad_solo_generation: pp_solo = copy(pp) pp_solo.image = init_image @@ -926,7 +926,9 @@ def postprocess_image(self, p, pp: PPImage, *args_): is_processed = False with CNHijackRestore(), pause_total_tqdm(), cn_allow_script_control(): for n, args in enumerate(arg_list): - fork_result = self._postprocess_fork(init_image, p, pp, args, (n,last_index)) + fork_result = self._postprocess_fork( + init_image, p, pp, args, (n, last_index) + ) is_processed |= fork_result[0] save_incrementals.append(fork_result[1]) save_solos.append(fork_result[2]) @@ -950,7 +952,9 @@ def postprocess_image(self, p, pp: PPImage, *args_): all_extra_params = p.extra_generation_params for save in filter(None, save_solos): - p.extra_generation_params = self._fix_extra_generation_params(all_extra_params, save[2]) + p.extra_generation_params = self._fix_extra_generation_params( + all_extra_params, save[2] + ) self.save_image( p, save[1], @@ -974,24 +978,25 @@ def _find_last_index(self, arg_list): last_index = n return last_index - def _fix_extra_generation_params(self, params:dict, args:ADetailerArgs): + def _fix_extra_generation_params(self, params: dict, args: ADetailerArgs): ad_params = {} for params_k in list(params.keys()): found = False - for _, (_,v) in enumerate (_all_args): + for _, (_, v) in enumerate(_all_args): if v in params_k: found = True break if not found: ad_params[params_k] = params[params_k] - for _, (k,v) in enumerate (_all_args): - if hasattr(args,k): - args_v = getattr(args,k) - if args_v is not None and args_v != '': + for _, (k, v) in enumerate(_all_args): + if hasattr(args, k): + args_v = getattr(args, k) + if args_v is not None and args_v != "": ad_params[v] = args_v return ad_params + def on_after_component(component, **_kwargs): global txt2img_submit_button, img2img_submit_button if getattr(component, "elem_id", None) == "txt2img_generate": From ef54f01a82987b932e24442dc842678c8e99281a Mon Sep 17 00:00:00 2001 From: MarcusNyne <69087098+MarcusNyne@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:55:24 -0400 Subject: [PATCH 6/6] skip bug in _find_last_index() --- scripts/!adetailer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/!adetailer.py b/scripts/!adetailer.py index ccc80136..fc16c8f6 100644 --- a/scripts/!adetailer.py +++ b/scripts/!adetailer.py @@ -970,7 +970,7 @@ def postprocess_image(self, p, pp: PPImage, *args_): def _find_last_index(self, arg_list): last_index = 0 for n, args in enumerate(arg_list): - if args.need_skip() and args.ad_solo_generation is False: + if not args.need_skip() and args.ad_solo_generation is False: last_index = n return last_index