Update custom-hires-fix-mod-for-automatic1111-2.9.4/scripts/custom_hires_fix.py
Browse files
custom-hires-fix-mod-for-automatic1111-2.9.4/scripts/custom_hires_fix.py
CHANGED
|
@@ -17,6 +17,8 @@ from modules import images, devices, prompt_parser, sd_models, extra_networks
|
|
| 17 |
|
| 18 |
from logging_utils import logger
|
| 19 |
|
|
|
|
|
|
|
| 20 |
# Ensure we call the upscaler path when resizing (A1111 compat)
|
| 21 |
# --- Compatibility notes ---
|
| 22 |
# Recommended runtime:
|
|
@@ -1190,7 +1192,9 @@ class CustomHiresFix(scripts.Script):
|
|
| 1190 |
|
| 1191 |
# Try detect ControlNet (best-effort; path may vary across installs)
|
| 1192 |
ext_candidates = [
|
|
|
|
| 1193 |
"extensions.sd-webui-controlnet.scripts.external_code",
|
|
|
|
| 1194 |
]
|
| 1195 |
self._cn_ext = None
|
| 1196 |
for mod in ext_candidates:
|
|
@@ -1715,7 +1719,11 @@ class CustomHiresFix(scripts.Script):
|
|
| 1715 |
# ---- Helpers ----
|
| 1716 |
def _maybe_mp_resize(self, base_w, base_h, target_mp: float):
|
| 1717 |
"""Compute size from megapixels while keeping aspect ratio; quantize to multiple of 8."""
|
| 1718 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1719 |
total_px = max(0.01, target_mp) * 1_000_000.0
|
| 1720 |
w_float = math.sqrt(total_px * aspect)
|
| 1721 |
h_float = w_float / aspect
|
|
@@ -1723,6 +1731,7 @@ class CustomHiresFix(scripts.Script):
|
|
| 1723 |
h = max(8, int(round(h_float / 8) * 8))
|
| 1724 |
return w, h
|
| 1725 |
|
|
|
|
| 1726 |
def _compute_denoise(self, base_key: str) -> float:
|
| 1727 |
"""
|
| 1728 |
Returns clamped denoising strength in [0,1] as (config[base_key] + denoise_offset).
|
|
@@ -1804,9 +1813,10 @@ class CustomHiresFix(scripts.Script):
|
|
| 1804 |
|
| 1805 |
def _cond_key(self, width, height, steps_for_cond, prompt: str, negative: str, clip_skip: int):
|
| 1806 |
h = hashlib.sha256()
|
| 1807 |
-
|
|
|
|
| 1808 |
h.update(b"::")
|
| 1809 |
-
h.update((negative or "").encode("utf-8"))
|
| 1810 |
# NEW: учитываем семейство модели (SDXL/SD3) в ключе кэша
|
| 1811 |
xl_flag = int(bool(self.config.get("sdxl_mode", False)) or self.is_sdxl)
|
| 1812 |
key = f"{self._model_hash_for_cache()}|xl={xl_flag}|{width}x{height}|{steps_for_cond}|cs={clip_skip}|{h.hexdigest()}"
|
|
@@ -2401,7 +2411,13 @@ class CustomHiresFix(scripts.Script):
|
|
| 2401 |
steps = min(steps, sfirst)
|
| 2402 |
# NEW: LRU-кэш шума для первой стадии
|
| 2403 |
try:
|
| 2404 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2405 |
except Exception as e:
|
| 2406 |
logger.warning(e)
|
| 2407 |
key_seed = None
|
|
@@ -2615,7 +2631,12 @@ class CustomHiresFix(scripts.Script):
|
|
| 2615 |
else:
|
| 2616 |
# NEW: если размеры не совпали — попробуем кэш
|
| 2617 |
try:
|
| 2618 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2619 |
except Exception as e:
|
| 2620 |
logger.warning(e)
|
| 2621 |
key_seed = None
|
|
@@ -2639,7 +2660,12 @@ class CustomHiresFix(scripts.Script):
|
|
| 2639 |
else:
|
| 2640 |
# NEW: обычный путь — используем LRU-кэш
|
| 2641 |
try:
|
| 2642 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2643 |
except Exception as e:
|
| 2644 |
logger.warning(e)
|
| 2645 |
key_seed = None
|
|
@@ -2969,19 +2995,24 @@ class CustomHiresFix(scripts.Script):
|
|
| 2969 |
def parse_infotext(infotext, params):
|
| 2970 |
try:
|
| 2971 |
block = params.get("Custom Hires Fix")
|
| 2972 |
-
if block is None:
|
| 2973 |
return
|
| 2974 |
-
|
| 2975 |
-
|
| 2976 |
-
|
|
|
|
| 2977 |
elif isinstance(block, str):
|
| 2978 |
-
|
| 2979 |
-
data = json.loads(block)
|
| 2980 |
-
|
| 2981 |
-
|
| 2982 |
-
|
|
|
|
|
|
|
|
|
|
| 2983 |
else:
|
| 2984 |
-
|
|
|
|
| 2985 |
params["Custom Hires Fix"] = data
|
| 2986 |
scale = data.get("scale", 0)
|
| 2987 |
scale_str = str(scale).lower()
|
|
@@ -3116,4 +3147,4 @@ except NameError:
|
|
| 3116 |
_INFOTEXT_HOOK_REGISTERED = False
|
| 3117 |
if not _INFOTEXT_HOOK_REGISTERED:
|
| 3118 |
script_callbacks.on_infotext_pasted(parse_infotext)
|
| 3119 |
-
_INFOTEXT_HOOK_REGISTERED = True
|
|
|
|
| 17 |
|
| 18 |
from logging_utils import logger
|
| 19 |
|
| 20 |
+
_INFOTEXT_HOOK_REGISTERED = False # Guard for callback registration
|
| 21 |
+
|
| 22 |
# Ensure we call the upscaler path when resizing (A1111 compat)
|
| 23 |
# --- Compatibility notes ---
|
| 24 |
# Recommended runtime:
|
|
|
|
| 1192 |
|
| 1193 |
# Try detect ControlNet (best-effort; path may vary across installs)
|
| 1194 |
ext_candidates = [
|
| 1195 |
+
"extensions.sd_webui_controlnet.scripts.external_code",
|
| 1196 |
"extensions.sd-webui-controlnet.scripts.external_code",
|
| 1197 |
+
"extensions-builtin.sd-webui-controlnet.scripts.external_code",
|
| 1198 |
]
|
| 1199 |
self._cn_ext = None
|
| 1200 |
for mod in ext_candidates:
|
|
|
|
| 1719 |
# ---- Helpers ----
|
| 1720 |
def _maybe_mp_resize(self, base_w, base_h, target_mp: float):
|
| 1721 |
"""Compute size from megapixels while keeping aspect ratio; quantize to multiple of 8."""
|
| 1722 |
+
if base_h <= 0 or base_w <= 0:
|
| 1723 |
+
logger.warning(f"Invalid base dimensions: {base_w}x{base_h}")
|
| 1724 |
+
return 512, 512 # Safe fallback
|
| 1725 |
+
|
| 1726 |
+
aspect = base_w / base_h
|
| 1727 |
total_px = max(0.01, target_mp) * 1_000_000.0
|
| 1728 |
w_float = math.sqrt(total_px * aspect)
|
| 1729 |
h_float = w_float / aspect
|
|
|
|
| 1731 |
h = max(8, int(round(h_float / 8) * 8))
|
| 1732 |
return w, h
|
| 1733 |
|
| 1734 |
+
|
| 1735 |
def _compute_denoise(self, base_key: str) -> float:
|
| 1736 |
"""
|
| 1737 |
Returns clamped denoising strength in [0,1] as (config[base_key] + denoise_offset).
|
|
|
|
| 1813 |
|
| 1814 |
def _cond_key(self, width, height, steps_for_cond, prompt: str, negative: str, clip_skip: int):
|
| 1815 |
h = hashlib.sha256()
|
| 1816 |
+
# Безопасная обработка None
|
| 1817 |
+
h.update((prompt or "").encode("utf-8", errors="replace"))
|
| 1818 |
h.update(b"::")
|
| 1819 |
+
h.update((negative or "").encode("utf-8", errors="replace"))
|
| 1820 |
# NEW: учитываем семейство модели (SDXL/SD3) в ключе кэша
|
| 1821 |
xl_flag = int(bool(self.config.get("sdxl_mode", False)) or self.is_sdxl)
|
| 1822 |
key = f"{self._model_hash_for_cache()}|xl={xl_flag}|{width}x{height}|{steps_for_cond}|cs={clip_skip}|{h.hexdigest()}"
|
|
|
|
| 2411 |
steps = min(steps, sfirst)
|
| 2412 |
# NEW: LRU-кэш шума для первой стадии
|
| 2413 |
try:
|
| 2414 |
+
try:
|
| 2415 |
+
seeds = getattr(self.p, "seeds", None)
|
| 2416 |
+
key_seed = seeds[0] if (seeds and len(seeds) > 0) else getattr(self.p, "seed", None)
|
| 2417 |
+
except (IndexError, TypeError, AttributeError) as e:
|
| 2418 |
+
logger.warning(f"Seed extraction warning: {e}")
|
| 2419 |
+
key_seed = None
|
| 2420 |
+
|
| 2421 |
except Exception as e:
|
| 2422 |
logger.warning(e)
|
| 2423 |
key_seed = None
|
|
|
|
| 2631 |
else:
|
| 2632 |
# NEW: если размеры не совпали — попробуем кэш
|
| 2633 |
try:
|
| 2634 |
+
try:
|
| 2635 |
+
seeds = getattr(self.p, "seeds", None)
|
| 2636 |
+
key_seed = seeds[0] if (seeds and len(seeds) > 0) else getattr(self.p, "seed", None)
|
| 2637 |
+
except (IndexError, TypeError, AttributeError) as e:
|
| 2638 |
+
logger.warning(f"Seed extraction warning: {e}")
|
| 2639 |
+
key_seed = None
|
| 2640 |
except Exception as e:
|
| 2641 |
logger.warning(e)
|
| 2642 |
key_seed = None
|
|
|
|
| 2660 |
else:
|
| 2661 |
# NEW: обычный путь — используем LRU-кэш
|
| 2662 |
try:
|
| 2663 |
+
try:
|
| 2664 |
+
seeds = getattr(self.p, "seeds", None)
|
| 2665 |
+
key_seed = seeds[0] if (seeds and len(seeds) > 0) else getattr(self.p, "seed", None)
|
| 2666 |
+
except (IndexError, TypeError, AttributeError) as e:
|
| 2667 |
+
logger.warning(f"Seed extraction warning: {e}")
|
| 2668 |
+
key_seed = None
|
| 2669 |
except Exception as e:
|
| 2670 |
logger.warning(e)
|
| 2671 |
key_seed = None
|
|
|
|
| 2995 |
def parse_infotext(infotext, params):
|
| 2996 |
try:
|
| 2997 |
block = params.get("Custom Hires Fix")
|
| 2998 |
+
if block is None:
|
| 2999 |
return
|
| 3000 |
+
|
| 3001 |
+
# Парсинг с явной обработкой форматов
|
| 3002 |
+
if isinstance(block, dict):
|
| 3003 |
+
data = block
|
| 3004 |
elif isinstance(block, str):
|
| 3005 |
+
if block.startswith("json64:"):
|
| 3006 |
+
data = json.loads(base64.b64decode(block[7:]).decode("utf-8"))
|
| 3007 |
+
else:
|
| 3008 |
+
try:
|
| 3009 |
+
data = json.loads(block)
|
| 3010 |
+
except json.JSONDecodeError:
|
| 3011 |
+
# Fallback для старых строк с одинарными кавычками
|
| 3012 |
+
data = json.loads(block.translate(QUOTE_SINGLE_TO_DOUBLE))
|
| 3013 |
else:
|
| 3014 |
+
logger.warning(f"Unexpected infotext type: {type(block)}")
|
| 3015 |
+
return
|
| 3016 |
params["Custom Hires Fix"] = data
|
| 3017 |
scale = data.get("scale", 0)
|
| 3018 |
scale_str = str(scale).lower()
|
|
|
|
| 3147 |
_INFOTEXT_HOOK_REGISTERED = False
|
| 3148 |
if not _INFOTEXT_HOOK_REGISTERED:
|
| 3149 |
script_callbacks.on_infotext_pasted(parse_infotext)
|
| 3150 |
+
_INFOTEXT_HOOK_REGISTERED = True
|