| from __future__ import annotations |
|
|
| from collections import UserList |
| from functools import cached_property, partial |
| from typing import Any, Literal, NamedTuple, Union |
|
|
| import pydantic |
| from pydantic import ( |
| BaseModel, |
| Extra, |
| NonNegativeFloat, |
| NonNegativeInt, |
| PositiveInt, |
| confloat, |
| constr, |
| ) |
|
|
|
|
| class Arg(NamedTuple): |
| attr: str |
| name: str |
|
|
|
|
| class ArgsList(UserList): |
| @cached_property |
| def attrs(self) -> tuple[str]: |
| return tuple(attr for attr, _ in self) |
|
|
| @cached_property |
| def names(self) -> tuple[str]: |
| return tuple(name for _, name in self) |
|
|
|
|
| class ADetailerArgs(BaseModel, extra=Extra.forbid): |
| ad_model: str = "None" |
| ad_prompt: str = "" |
| ad_negative_prompt: str = "" |
| ad_confidence: confloat(ge=0.0, le=1.0) = 0.3 |
| ad_mask_min_ratio: confloat(ge=0.0, le=1.0) = 0.0 |
| ad_mask_max_ratio: confloat(ge=0.0, le=1.0) = 1.0 |
| ad_dilate_erode: int = 32 |
| ad_x_offset: int = 0 |
| ad_y_offset: int = 0 |
| ad_mask_merge_invert: Literal["None", "Merge", "Merge and Invert"] = "None" |
| ad_mask_blur: NonNegativeInt = 4 |
| ad_denoising_strength: confloat(ge=0.0, le=1.0) = 0.4 |
| ad_inpaint_only_masked: bool = True |
| ad_inpaint_only_masked_padding: NonNegativeInt = 0 |
| ad_use_inpaint_width_height: bool = False |
| ad_inpaint_width: PositiveInt = 512 |
| ad_inpaint_height: PositiveInt = 512 |
| ad_use_steps: bool = False |
| ad_steps: PositiveInt = 28 |
| ad_use_cfg_scale: bool = False |
| ad_cfg_scale: NonNegativeFloat = 7.0 |
| ad_restore_face: bool = False |
| ad_controlnet_model: constr(regex=r".*(inpaint|tile|scribble|lineart|openpose).*|^None$") = "None" |
| ad_controlnet_weight: confloat(ge=0.0, le=1.0) = 1.0 |
| ad_controlnet_guidance_end: confloat(ge=0.0, le=1.0) = 1.0 |
|
|
| @staticmethod |
| def ppop( |
| p: dict[str, Any], |
| key: str, |
| pops: list[str] | None = None, |
| cond: Any = None, |
| ): |
| if pops is None: |
| pops = [key] |
| value = p[key] |
| cond = (not bool(value)) if cond is None else value == cond |
|
|
| if cond: |
| for k in pops: |
| p.pop(k) |
|
|
| def extra_params(self, suffix: str = ""): |
| if self.ad_model == "None": |
| return {} |
|
|
| p = {name: getattr(self, attr) for attr, name in ALL_ARGS} |
| ppop = partial(self.ppop, p) |
|
|
| ppop("ADetailer prompt") |
| ppop("ADetailer negative prompt") |
| ppop("ADetailer mask min ratio", cond=0.0) |
| ppop("ADetailer mask max ratio", cond=1.0) |
| ppop("ADetailer x offset", cond=0) |
| ppop("ADetailer y offset", cond=0) |
| ppop("ADetailer mask merge/invert", cond="None") |
| ppop("ADetailer inpaint only masked", ["ADetailer inpaint padding"]) |
| ppop( |
| "ADetailer use inpaint width/height", |
| [ |
| "ADetailer use inpaint width/height", |
| "ADetailer inpaint width", |
| "ADetailer inpaint height", |
| ], |
| ) |
| ppop( |
| "ADetailer use separate steps", |
| ["ADetailer use separate steps", "ADetailer steps"], |
| ) |
| ppop( |
| "ADetailer use separate CFG scale", |
| ["ADetailer use separate CFG scale", "ADetailer CFG scale"], |
| ) |
| ppop("ADetailer restore face") |
| ppop( |
| "ADetailer ControlNet model", |
| ["ADetailer ControlNet model", "ADetailer ControlNet weight", "ADetailer ControlNet guidance end"], |
| cond="None", |
| ) |
|
|
| if suffix: |
| p = {k + suffix: v for k, v in p.items()} |
|
|
| return p |
|
|
|
|
| class EnableChecker(BaseModel): |
| a0: Union[bool, dict] |
| a1: Any |
|
|
| def is_enabled(self) -> bool: |
| ad_model = ALL_ARGS[0].attr |
| if isinstance(self.a0, dict): |
| return self.a0.get(ad_model, "None") != "None" |
| if not isinstance(self.a1, dict): |
| return False |
| return self.a0 and self.a1.get(ad_model, "None") != "None" |
|
|
|
|
| _all_args = [ |
| ("ad_enable", "ADetailer enable"), |
| ("ad_model", "ADetailer model"), |
| ("ad_prompt", "ADetailer prompt"), |
| ("ad_negative_prompt", "ADetailer negative prompt"), |
| ("ad_confidence", "ADetailer confidence"), |
| ("ad_mask_min_ratio", "ADetailer mask min ratio"), |
| ("ad_mask_max_ratio", "ADetailer mask max ratio"), |
| ("ad_x_offset", "ADetailer x offset"), |
| ("ad_y_offset", "ADetailer y offset"), |
| ("ad_dilate_erode", "ADetailer dilate/erode"), |
| ("ad_mask_merge_invert", "ADetailer mask merge/invert"), |
| ("ad_mask_blur", "ADetailer mask blur"), |
| ("ad_denoising_strength", "ADetailer denoising strength"), |
| ("ad_inpaint_only_masked", "ADetailer inpaint only masked"), |
| ("ad_inpaint_only_masked_padding", "ADetailer inpaint padding"), |
| ("ad_use_inpaint_width_height", "ADetailer use inpaint width/height"), |
| ("ad_inpaint_width", "ADetailer inpaint width"), |
| ("ad_inpaint_height", "ADetailer inpaint height"), |
| ("ad_use_steps", "ADetailer use separate steps"), |
| ("ad_steps", "ADetailer steps"), |
| ("ad_use_cfg_scale", "ADetailer use separate CFG scale"), |
| ("ad_cfg_scale", "ADetailer CFG scale"), |
| ("ad_restore_face", "ADetailer restore face"), |
| ("ad_controlnet_model", "ADetailer ControlNet model"), |
| ("ad_controlnet_weight", "ADetailer ControlNet weight"), |
| ("ad_controlnet_guidance_end", "ADetailer ControlNet guidance end"), |
| ] |
|
|
| AD_ENABLE = Arg(*_all_args[0]) |
| _args = [Arg(*args) for args in _all_args[1:]] |
| ALL_ARGS = ArgsList(_args) |
|
|
| BBOX_SORTBY = [ |
| "None", |
| "Position (left to right)", |
| "Position (center to edge)", |
| "Area (large to small)", |
| ] |
| MASK_MERGE_INVERT = ["None", "Merge", "Merge and Invert"] |
|
|