diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4a9d22c..667ab5d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,12 +17,12 @@ repos: - id: mixed-line-ending - repo: https://github.com/rbubley/mirrors-prettier - rev: v3.3.2 + rev: v3.3.3 hooks: - id: prettier - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.9 + rev: v0.5.6 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/CHANGELOG.md b/CHANGELOG.md index c542be7..2095da5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 2024-08-03 + +- v24.8.0 +- 샘플러 선택칸에 Use same sampler 옵션 추가 +- 컨트롤넷 유니온 모델을 선택할 수 있게 함 + +- webui 1.9.0이상에서 기본 스케줄러가 설정되지 않던 문제 수정 +- issus #656의 문제 해결을 위해 v24.4.0에 적용되었던 프롬프트 표시 기능을 되돌림 +- mediapipe에서 에러가 발생하면 추론이 실패한 것으로 처리하고 조용히 넘어감 + ## 2024-06-16 - v24.6.0 diff --git a/aaaaaa/helper.py b/aaaaaa/helper.py index 27dd6a9..c9c50c9 100644 --- a/aaaaaa/helper.py +++ b/aaaaaa/helper.py @@ -45,7 +45,7 @@ def pause_total_tqdm(): @contextmanager -def preseve_prompts(p: PT): +def preserve_prompts(p: PT): all_pt = copy(p.all_prompts) all_ng = copy(p.all_negative_prompts) try: diff --git a/aaaaaa/ui.py b/aaaaaa/ui.py index a678d82..e4efb54 100644 --- a/aaaaaa/ui.py +++ b/aaaaaa/ui.py @@ -2,6 +2,7 @@ from dataclasses import dataclass from functools import partial +from itertools import chain from types import SimpleNamespace from typing import Any @@ -42,6 +43,9 @@ "depth": ["depth_midas", "depth_hand_refiner"], } +union = list(chain.from_iterable(cn_module_choices.values())) +cn_module_choices["union"] = union + class Widgets(SimpleNamespace): def tolist(self): @@ -82,7 +86,7 @@ def on_widget_change(state: dict, value: Any, *, attr: str): def on_generate_click(state: dict, *values: Any): for attr, value in zip(ALL_ARGS.attrs, values): - state[attr] = value + state[attr] = value # noqa: PERF403 state["is_api"] = () return state @@ -546,11 +550,16 @@ def inpainting(w: Widgets, n: int, is_img2img: bool, webui_info: WebuiInfo): elem_id=eid("ad_use_sampler"), ) + sampler_names = [ + "Use same sampler", + *webui_info.sampler_names, + ] + with gr.Row(): w.ad_sampler = gr.Dropdown( label="ADetailer sampler" + suffix(n), - choices=webui_info.sampler_names, - value=webui_info.sampler_names[0], + choices=sampler_names, + value=sampler_names[1], visible=True, elem_id=eid("ad_sampler"), ) diff --git a/adetailer/__version__.py b/adetailer/__version__.py index a7f5098..45adada 100644 --- a/adetailer/__version__.py +++ b/adetailer/__version__.py @@ -1 +1 @@ -__version__ = "24.6.0" +__version__ = "24.8.0" diff --git a/adetailer/mediapipe.py b/adetailer/mediapipe.py index 25c6900..b05fa00 100644 --- a/adetailer/mediapipe.py +++ b/adetailer/mediapipe.py @@ -21,7 +21,10 @@ def mediapipe_predict( } if model_type in mapping: func = mapping[model_type] - return func(image, confidence) + try: + return func(image, confidence) + except Exception: + return PredictOutput() msg = f"[-] ADetailer: Invalid mediapipe model type: {model_type}, Available: {list(mapping.keys())!r}" raise RuntimeError(msg) diff --git a/controlnet_ext/common.py b/controlnet_ext/common.py index b78dbf3..f485da5 100644 --- a/controlnet_ext/common.py +++ b/controlnet_ext/common.py @@ -8,4 +8,5 @@ "tile": "tile_resample", "depth": "depth_midas", } -cn_model_regex = re.compile("|".join(cn_model_module.keys()), flags=re.I) +_names = [*cn_model_module, "union"] +cn_model_regex = re.compile("|".join(_names), flags=re.IGNORECASE) diff --git a/controlnet_ext/controlnet_ext.py b/controlnet_ext/controlnet_ext.py index 9af1238..bcf7130 100644 --- a/controlnet_ext/controlnet_ext.py +++ b/controlnet_ext/controlnet_ext.py @@ -61,13 +61,13 @@ def update_scripts_args( if (not self.cn_available) or model == "None": return - if module is None or module == "None": + if module == "None": + module = None + if module is None: for m, v in cn_model_module.items(): if m in model: module = v break - else: - module = None cn_units = [ self.external_cn.ControlNetUnit( diff --git a/scripts/!adetailer.py b/scripts/!adetailer.py index d4bbfc6..b655e6e 100644 --- a/scripts/!adetailer.py +++ b/scripts/!adetailer.py @@ -20,7 +20,7 @@ change_torch_load, copy_extra_params, pause_total_tqdm, - preseve_prompts, + preserve_prompts, ) from aaaaaa.p_method import ( get_i, @@ -374,7 +374,10 @@ def get_cfg_scale(self, p, args: ADetailerArgs) -> float: def get_sampler(self, p, args: ADetailerArgs) -> str: if args.ad_use_sampler: + if args.ad_sampler == "Use same sampler": + return p.sampler_name return args.ad_sampler + if hasattr(p, "_ad_orig"): return p._ad_orig.sampler_name return p.sampler_name @@ -382,7 +385,7 @@ def get_sampler(self, p, args: ADetailerArgs) -> str: def get_scheduler(self, p, args: ADetailerArgs) -> dict[str, str]: "webui >= 1.9.0" if not args.ad_use_sampler: - return {} + return {"scheduler": getattr(p, "scheduler", "Automatic")} if args.ad_scheduler == "Use same scheduler": value = getattr(p, "scheduler", "Automatic") @@ -447,8 +450,8 @@ def script_filter(self, p, args: ADetailerArgs): script_runner = copy(p.scripts) script_args = self.script_args_copy(p.script_args) - ad_only_seleted_scripts = opts.data.get("ad_only_seleted_scripts", True) - if not ad_only_seleted_scripts: + ad_only_selected_scripts = opts.data.get("ad_only_selected_scripts", True) + if not ad_only_selected_scripts: return script_runner, script_args ad_script_names_string: str = opts.data.get("ad_script_names", SCRIPT_DEFAULT) @@ -616,23 +619,18 @@ def i2i_prompts_replace( i2i.negative_prompt = negative_prompt @staticmethod - def compare_prompt(p, extra_params: dict[str, Any], processed, n: int = 0): - if not hasattr(p, "_ad_extra_params_result"): - p._ad_extra_params_result = {} - + def compare_prompt(extra_params: dict[str, Any], processed, n: int = 0): pt = "ADetailer prompt" + suffix(n) if pt in extra_params and extra_params[pt] != processed.all_prompts[0]: print( f"[-] ADetailer: applied {ordinal(n + 1)} ad_prompt: {processed.all_prompts[0]!r}" ) - p._ad_extra_params_result[pt] = processed.all_prompts[0] ng = "ADetailer negative prompt" + suffix(n) if ng in extra_params and extra_params[ng] != processed.all_negative_prompts[0]: print( f"[-] ADetailer: applied {ordinal(n + 1)} ad_negative_prompt: {processed.all_negative_prompts[0]!r}" ) - p._ad_extra_params_result[ng] = processed.all_negative_prompts[0] @staticmethod def get_i2i_init_image(p, pp): @@ -784,7 +782,7 @@ def _postprocess_image_inner( finally: p2.close() - self.compare_prompt(p, p.extra_generation_params, processed, n=n) + self.compare_prompt(p.extra_generation_params, processed, n=n) p2 = copy(i2i) p2.init_images = [processed.images[0]] @@ -807,7 +805,7 @@ def postprocess_image(self, p, pp, *args_): if need_call_postprocess(p): dummy = Processed(p, [], p.seed, "") - with preseve_prompts(p): + with preserve_prompts(p): p.scripts.postprocess(copy(p), dummy) is_processed = False @@ -823,17 +821,13 @@ def postprocess_image(self, p, pp, *args_): ) if need_call_process(p): - with preseve_prompts(p): + with preserve_prompts(p): copy_p = copy(p) - if hasattr(p.scripts, "before_process"): - p.scripts.before_process(copy_p) + p.scripts.before_process(copy_p) p.scripts.process(copy_p) self.write_params_txt(params_txt_content) - if hasattr(p, "_ad_extra_params_result"): - p.extra_generation_params.update(p._ad_extra_params_result) - def on_after_component(component, **_kwargs): global txt2img_submit_button, img2img_submit_button @@ -862,7 +856,7 @@ def on_ui_settings(): "ad_extra_models_dir", shared.OptionInfo( default="", - label="Extra paths to scan adetailer models seperated by vertical bars(|)", + label="Extra paths to scan adetailer models separated by vertical bars(|)", component=gr.Textbox, section=section, ) @@ -881,7 +875,7 @@ def on_ui_settings(): ) shared.opts.add_option( - "ad_only_seleted_scripts", + "ad_only_selected_scripts", shared.OptionInfo( True, "Apply only selected scripts to ADetailer", section=section ),