mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 09:14:35 +02:00
Merge branch 'dev' into feat/filter-sampler-upscaler-choices
This commit is contained in:
@@ -46,6 +46,7 @@ def decode_base64_to_image(encoding, quiet=False):
|
||||
decoded = base64.b64decode(encoding)
|
||||
data = io.BytesIO(decoded)
|
||||
image = Image.open(data)
|
||||
image = image.convert('RGB')
|
||||
return image
|
||||
except Exception as e:
|
||||
log.warning(f'API cannot decode image: {e}')
|
||||
|
||||
@@ -366,11 +366,11 @@ class ReqPromptEnhance(BaseModel):
|
||||
repetition_penalty: Optional[float] = Field(title="Repetition penalty", default=None, description="Penalizes repeated tokens to reduce repetition (1.0=no penalty)")
|
||||
top_k: Optional[int] = Field(title="Top K", default=None, description="Limits token selection to the K most likely candidates")
|
||||
top_p: Optional[float] = Field(title="Top P", default=None, description="Nucleus sampling threshold (0-1)")
|
||||
thinking: bool = Field(title="Thinking", default=False, description="Enable thinking/reasoning mode")
|
||||
keep_thinking: bool = Field(title="Keep thinking", default=False, description="Keep thinking tokens in output")
|
||||
use_vision: bool = Field(title="Use vision", default=True, description="Use vision if model supports it")
|
||||
thinking: Optional[bool] = Field(title="Thinking", default=False, description="Enable thinking/reasoning mode")
|
||||
keep_thinking: Optional[bool] = Field(title="Keep thinking", default=False, description="Keep thinking tokens in output")
|
||||
use_vision: Optional[bool] = Field(title="Use vision", default=True, description="Use vision if model supports it")
|
||||
prefill: Optional[str] = Field(title="Prefill", default=None, description="Text to prefill the model response with")
|
||||
keep_prefill: bool = Field(title="Keep prefill", default=False, description="Keep prefill text in the output")
|
||||
keep_prefill: Optional[bool] = Field(title="Keep prefill", default=False, description="Keep prefill text in the output")
|
||||
custom_args: Optional[str] = Field(title="Custom args", default=None, description="Custom arguments for the model")
|
||||
process_words: Optional[str] = Field(title="Banned words", default=None, description="List of words to process")
|
||||
semantic_threshold: Optional[float] = Field(title="Semantic threshold", default=None, description="Semantic similarity threshold for processed words")
|
||||
|
||||
@@ -226,6 +226,7 @@ class APIProcess:
|
||||
if len(instance) == 0:
|
||||
raise HTTPException(status_code=500, detail="Prompt enhancement script not found")
|
||||
instance = instance[0]
|
||||
decoded = decode_base64_to_image(req.image) if req.image else None
|
||||
prompt = instance.enhance(
|
||||
model=model,
|
||||
prompt=req.prompt,
|
||||
@@ -244,7 +245,7 @@ class APIProcess:
|
||||
use_vision=req.use_vision,
|
||||
prefill=req.prefill or '',
|
||||
keep_prefill=req.keep_prefill,
|
||||
image=decode_base64_to_image(req.image) if req.image else None,
|
||||
image=decoded,
|
||||
seed=seed,
|
||||
nsfw=req.nsfw,
|
||||
custom_args=req.custom_args,
|
||||
|
||||
+20
-18
@@ -7,35 +7,37 @@ request_cost = {
|
||||
"/file": 0,
|
||||
"/internal/progress": 0,
|
||||
"/run/predict": 0,
|
||||
"/sdapi/v1/control": 5,
|
||||
"/sdapi/v1/img2img": 5,
|
||||
"/sdapi/v1/txt2img": 5,
|
||||
"/sdapi/v1/video": 5,
|
||||
"/sdapi/v1/browser/thumb": 0,
|
||||
"/sdapi/v1/network/thumb": 0,
|
||||
"/sdapi/v1/txt2img": 5,
|
||||
"/sdapi/v1/img2img": 5,
|
||||
"/sdapi/v1/control": 5,
|
||||
"/sdapi/v1/video": 5,
|
||||
}
|
||||
log_cost = {
|
||||
"/.well-known/appspecific/com.chrome.devtools.json": -1,
|
||||
"/info": -1,
|
||||
"/file": -1,
|
||||
"/token": -1,
|
||||
"/theme.css": -1,
|
||||
"/sdapi/v1/browser/thumb": -1,
|
||||
"/sdapi/v1/network/thumb": -1,
|
||||
"/run/predict": -1,
|
||||
"/queue/join": -1,
|
||||
"/info": -1,
|
||||
"/icon": -1,
|
||||
"/internal/progress": -1,
|
||||
"/sdapi/v1/version": -1,
|
||||
"/sdapi/v1/log": -1,
|
||||
"/sdapi/v1/torch": -1,
|
||||
"/queue/join": -1,
|
||||
"/run/predict": -1,
|
||||
"/theme.css": -1,
|
||||
"/token": -1,
|
||||
"/sdapi/v1/checkpoint": -1,
|
||||
"/sdapi/v1/gpu-smi": -1,
|
||||
"/sdapi/v1/gpu": -1,
|
||||
"/sdapi/v1/loaded-loras": -1,
|
||||
"/sdapi/v1/log": -1,
|
||||
"/sdapi/v1/memory": -1,
|
||||
"/sdapi/v1/platform": -1,
|
||||
"/sdapi/v1/checkpoint": -1,
|
||||
"/sdapi/v1/loaded-loras": -1,
|
||||
"/sdapi/v1/gpu-smi": -1,
|
||||
"/sdapi/v1/status": 60,
|
||||
"/sdapi/v1/progress": 60,
|
||||
"/sdapi/v1/start": -1,
|
||||
"/sdapi/v1/status": 60,
|
||||
"/sdapi/v1/torch": -1,
|
||||
"/sdapi/v1/version": -1,
|
||||
"/sdapi/v1/browser/thumb": -1,
|
||||
"/sdapi/v1/network/thumb": -1,
|
||||
}
|
||||
log_exclude_suffix = ['.css', '.js', '.ico', '.svg']
|
||||
log_exclude_prefix = ['/assets']
|
||||
|
||||
@@ -271,4 +271,6 @@ def list_extensions():
|
||||
enabled = dirname.lower() not in disabled_extensions
|
||||
extension = Extension(name=dirname, path=path, enabled=enabled, is_builtin=is_builtin)
|
||||
extensions.append(extension)
|
||||
log.debug(f'Extensions: disabled={[e.name for e in extensions if not e.enabled]}')
|
||||
enabled = [e.name for e in extensions if e.enabled]
|
||||
disabled = [e.name for e in extensions if not e.enabled]
|
||||
log.debug(f'Extensions: enabled={enabled} disabled={disabled}')
|
||||
|
||||
@@ -164,6 +164,7 @@ def parse_prompt(prompt: str | None) -> tuple[str, defaultdict[str, list[ExtraNe
|
||||
return ""
|
||||
|
||||
updated_prompt = re.sub(re_extra_net, found, prompt)
|
||||
updated_prompt = updated_prompt.strip(', ')
|
||||
return updated_prompt, res
|
||||
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ def get_cu_seqlens(text_mask, img_len):
|
||||
text_len = text_mask.sum(dim=1)
|
||||
max_len = text_mask.shape[1] + img_len
|
||||
|
||||
cu_seqlens = torch.zeros([2 * batch_size + 1], dtype=torch.int32, device="cuda")
|
||||
cu_seqlens = torch.zeros([2 * batch_size + 1], dtype=torch.int32, device=text_mask.device)
|
||||
|
||||
for i in range(batch_size):
|
||||
s = text_len[i] + img_len
|
||||
|
||||
@@ -208,13 +208,13 @@ def patch_gradio():
|
||||
return {"is_generating": False, "data": [], "error": "empty response"}
|
||||
return response
|
||||
except GeneratorExit as e:
|
||||
log.error(f"Gradio queue: events={len(events)} batch={batch} error: {e}")
|
||||
log.error(f"Gradio queue: events={len(events)} batch={batch} reason=GeneratorExit {e}")
|
||||
return {"is_generating": False, "data": [None, None, None, None, "cancelled", ""], "error": None}
|
||||
except Exception as e:
|
||||
log.error(f"Gradio queue: events={len(events)} batch={batch} error: {e}")
|
||||
log.error(f"Gradio queue: events={len(events)} batch={batch} reason=Exception {e}")
|
||||
raise
|
||||
except BaseException as e:
|
||||
log.error(f"Gradio queue: events={len(events)} batch={batch} error: {e}")
|
||||
log.error(f"Gradio queue: events={len(events)} batch={batch} reason=BaseException {e}")
|
||||
raise
|
||||
|
||||
def wrap_blocks_preprocess_data(self, fn_index: int, inputs: list, state: dict):
|
||||
|
||||
@@ -80,6 +80,7 @@ def image_grid(imgs: list, batch_size=1, rows: int | None = None, cols: int | No
|
||||
for i, img in enumerate(params.imgs):
|
||||
if img is not None:
|
||||
grid.paste(img, box=(i % params.cols * w, i // params.cols * h))
|
||||
grid.is_grid = True # flag image as grid
|
||||
return grid
|
||||
except Exception as e:
|
||||
log.error(f'Grid: images={imgs} {e}')
|
||||
|
||||
+13
-11
@@ -7,6 +7,7 @@ and Triton GPU acceleration when available.
|
||||
Non-CUDA devices fall back to PIL/torch.nn.functional automatically.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import torch
|
||||
from PIL import Image
|
||||
@@ -17,6 +18,7 @@ from modules.image.convert import to_tensor, to_pil
|
||||
_sharpfin_checked = False
|
||||
_sharpfin_ok = False
|
||||
_triton_ok = False
|
||||
debug = log.trace if os.environ.get('SD_PROCESS_DEBUG', None) is not None else lambda *args, **kwargs: None
|
||||
|
||||
|
||||
def check_sharpfin():
|
||||
@@ -104,7 +106,7 @@ def _scale_pil(scale_fn, tensor, out_res, rk, dev, dt, do_linear, src_h, src_w,
|
||||
return scale_fn(tensor, out_res, resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=do_linear, use_sparse=True)
|
||||
except Exception:
|
||||
_triton_ok = False
|
||||
log.info("Sharpfin: Triton sparse disabled, using dense path")
|
||||
log.debug("Sharpfin: Triton sparse disabled, using dense path")
|
||||
return scale_fn(tensor, out_res, resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=do_linear, use_sparse=False)
|
||||
# Mixed axis: split into two single-axis resizes
|
||||
if h > src_h: # H up, W down
|
||||
@@ -115,7 +117,7 @@ def _scale_pil(scale_fn, tensor, out_res, rk, dev, dt, do_linear, src_h, src_w,
|
||||
return scale_fn(intermediate, (h, w), resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=do_linear, use_sparse=True)
|
||||
except Exception:
|
||||
_triton_ok = False
|
||||
log.info("Sharpfin: Triton sparse disabled, using dense path")
|
||||
log.debug("Sharpfin: Triton sparse disabled, using dense path")
|
||||
return scale_fn(intermediate, (h, w), resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=do_linear, use_sparse=False)
|
||||
# H down, W up
|
||||
use_sparse = _want_sparse(dev, rk, True)
|
||||
@@ -125,7 +127,7 @@ def _scale_pil(scale_fn, tensor, out_res, rk, dev, dt, do_linear, src_h, src_w,
|
||||
return scale_fn(intermediate, (h, w), resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=do_linear, use_sparse=False)
|
||||
except Exception:
|
||||
_triton_ok = False
|
||||
log.info("Sharpfin: Triton sparse disabled, using dense path")
|
||||
log.debug("Sharpfin: Triton sparse disabled, using dense path")
|
||||
intermediate = scale_fn(tensor, (h, src_w), resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=do_linear, use_sparse=False)
|
||||
return scale_fn(intermediate, (h, w), resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=do_linear, use_sparse=False)
|
||||
|
||||
@@ -137,24 +139,24 @@ def resize_pil(image: Image.Image, target_size: tuple[int, int], *, kernel=None,
|
||||
is_mask = image.mode == 'L'
|
||||
|
||||
if (image.width == w) and (image.height == h):
|
||||
log.debug(f'Resize image: skip={w}x{h} fn={fn}')
|
||||
# log.debug(f'Resize image: skip={w}x{h} fn={fn}')
|
||||
return image
|
||||
|
||||
from modules import devices
|
||||
dev = device if device is not None else devices.device
|
||||
if not allow_sharpfin(dev):
|
||||
log.debug(f'Resize image: method=PIL source={image.width}x{image.height} target={w}x{h} device={dev} fn={fn}')
|
||||
debug(f'Resize image: method=PIL source={image.width}x{image.height} target={w}x{h} device={dev} fn={fn}')
|
||||
return image.resize((w, h), resample=Image.Resampling.LANCZOS)
|
||||
|
||||
rk = get_kernel(kernel)
|
||||
if rk is None:
|
||||
log.debug(f'Resize image: method=PIL source={image.width}x{image.height} target={w}x{h} kernel=None fn={fn}')
|
||||
debug(f'Resize image: method=PIL source={image.width}x{image.height} target={w}x{h} kernel=None fn={fn}')
|
||||
return image.resize((w, h), resample=Image.Resampling.LANCZOS)
|
||||
|
||||
from modules.sharpfin.functional import scale
|
||||
dt = dtype or torch.float16
|
||||
do_linear = get_linearize(linearize, is_mask=is_mask)
|
||||
log.debug(f'Resize image: method=sharpfin source={image.width}x{image.height} target={w}x{h} kernel={rk} device={dev} linearize={do_linear} fn={fn}')
|
||||
debug(f'Resize image: method=sharpfin source={image.width}x{image.height} target={w}x{h} kernel={rk} device={dev} linearize={do_linear} fn={fn}')
|
||||
tensor = to_tensor(image)
|
||||
if tensor.dim() == 3:
|
||||
tensor = tensor.unsqueeze(0)
|
||||
@@ -182,14 +184,14 @@ def resize_tensor(tensor: torch.Tensor, target_size: tuple[int, int], *, kernel=
|
||||
dev = devices.device
|
||||
if not allow_sharpfin(dev):
|
||||
mode = 'bilinear' if (target_size[0] * target_size[1]) > (tensor.shape[-2] * tensor.shape[-1]) else 'area'
|
||||
log.debug(f'Resize tensor: method=torch mode={mode} shape={tensor.shape} target={target_size} fn={fn}')
|
||||
debug(f'Resize tensor: method=torch mode={mode} shape={tensor.shape} target={target_size} fn={fn}')
|
||||
inp = tensor if tensor.dim() == 4 else tensor.unsqueeze(0)
|
||||
result = torch.nn.functional.interpolate(inp, size=target_size, mode=mode, antialias=mode != 'area')
|
||||
return result.squeeze(0) if tensor.dim() == 3 else result
|
||||
rk = get_kernel(kernel)
|
||||
if rk is None:
|
||||
mode = 'bilinear' if (target_size[0] * target_size[1]) > (tensor.shape[-2] * tensor.shape[-1]) else 'area'
|
||||
log.debug(f'Resize tensor: method=torch mode={mode} shape={tensor.shape} target={target_size} kernel=None fn={fn}')
|
||||
debug(f'Resize tensor: method=torch mode={mode} shape={tensor.shape} target={target_size} kernel=None fn={fn}')
|
||||
inp = tensor if tensor.dim() == 4 else tensor.unsqueeze(0)
|
||||
result = torch.nn.functional.interpolate(inp, size=target_size, mode=mode, antialias=mode != 'area')
|
||||
return result.squeeze(0) if tensor.dim() == 3 else result
|
||||
@@ -206,10 +208,10 @@ def resize_tensor(tensor: torch.Tensor, target_size: tuple[int, int], *, kernel=
|
||||
both_up = (th >= src_h and tw >= src_w)
|
||||
if both_down or both_up:
|
||||
use_sparse = _triton_ok and dev.type == 'cuda' and rk.value == 'magic_kernel_sharp_2021' and both_down
|
||||
log.debug(f'Resize tensor: method=sharpfin shape={tensor.shape} target={target_size} direction={both_up}:{both_down} kernel={rk} sparse={use_sparse} fn={fn}')
|
||||
debug(f'Resize tensor: method=sharpfin shape={tensor.shape} target={target_size} direction={both_up}:{both_down} kernel={rk} sparse={use_sparse} fn={fn}')
|
||||
result = scale(tensor, target_size, resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=linearize, use_sparse=use_sparse)
|
||||
else:
|
||||
log.debug(f'Resize tensor: method=sharpfin shape={tensor.shape} target={target_size} direction={both_up}:{both_down} kernel={rk} sparse=False fn={fn}')
|
||||
debug(f'Resize tensor: method=sharpfin shape={tensor.shape} target={target_size} direction={both_up}:{both_down} kernel={rk} sparse=False fn={fn}')
|
||||
intermediate = scale(tensor, (th, src_w), resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=linearize, use_sparse=False)
|
||||
result = scale(intermediate, (th, tw), resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=linearize, use_sparse=False)
|
||||
if squeezed:
|
||||
|
||||
+29
-21
@@ -182,21 +182,14 @@ def setup_logging(debug=None, trace=None, filename=None):
|
||||
render_options = render_options.update_height(height=render_options.height - self.top - self.bottom)
|
||||
lines = console.render_lines(self.renderable, render_options, style=style, pad=False)
|
||||
_Segment = Segment
|
||||
left = _Segment(" " * self.left, style) if self.left else None
|
||||
right = [_Segment.line()]
|
||||
blank_line: list[Segment] | None = None
|
||||
if self.top:
|
||||
blank_line = [_Segment(f'{" " * width}\\n', style)]
|
||||
yield from blank_line * self.top
|
||||
if left:
|
||||
for line in lines:
|
||||
yield left
|
||||
yield from line
|
||||
yield from right
|
||||
else:
|
||||
for line in lines:
|
||||
yield from line
|
||||
yield from right
|
||||
for line in lines: # self.left is forced to 0 above, so no left-padding segment is ever emitted
|
||||
yield from line
|
||||
yield from right
|
||||
if self.bottom:
|
||||
blank_line = blank_line or [_Segment(f'{" " * width}\\n', style)]
|
||||
yield from blank_line * self.bottom
|
||||
@@ -232,20 +225,26 @@ def setup_logging(debug=None, trace=None, filename=None):
|
||||
log.setLevel(logging.DEBUG) # log to file is always at level debug for facility `sd`
|
||||
log.print = rprint
|
||||
|
||||
# use only the 16 standard ANSI color names (+ dim/bold modifiers) so the theme renders correctly on basic 16-color terminals too
|
||||
theme = Theme({
|
||||
"traceback.border": "black",
|
||||
"inspect.value.border": "black",
|
||||
"traceback.border.syntax_error": "dark_red",
|
||||
"logging.level.info": "blue_violet",
|
||||
"logging.level.debug": "orchid",
|
||||
"logging.level.trace": "dark_blue",
|
||||
"repr.attrib_name": "bright_cyan",
|
||||
"repr.attrib_value": "orchid",
|
||||
"repr.str": "sandy_brown",
|
||||
"repr.number": "bright_green",
|
||||
"repr.bool_true": "bright_green",
|
||||
"traceback.border.syntax_error": "red",
|
||||
|
||||
"logging.level.trace": "dim cyan",
|
||||
"logging.level.debug": "cyan",
|
||||
"logging.level.info": "bright_cyan",
|
||||
"logging.level.warning": "yellow",
|
||||
"logging.level.error": "red",
|
||||
"logging.level.critical": "bold bright_red",
|
||||
|
||||
"repr.attrib_name": "bright_white",
|
||||
"repr.attrib_value": "cyan",
|
||||
"repr.str": "bright_cyan",
|
||||
"repr.none": "yellow",
|
||||
"repr.number": "bright_yellow",
|
||||
"repr.bool_true": "green",
|
||||
"repr.bool_false": "bright_red",
|
||||
"repr.values": "bright_cyan",
|
||||
})
|
||||
|
||||
Padding.__rich_console__ = override_padding
|
||||
@@ -270,7 +269,7 @@ def setup_logging(debug=None, trace=None, filename=None):
|
||||
|
||||
log_filter = LogFilter()
|
||||
# handlers
|
||||
rh = RichHandler(show_time=True, omit_repeated_times=False, show_level=True, show_path=False, markup=False, rich_tracebacks=True, log_time_format='%H:%M:%S-%f', level=level, console=console)
|
||||
rh = RichHandler(show_time=True, omit_repeated_times=False, show_level=True, show_path=False, markup=True, rich_tracebacks=True, log_time_format='%H:%M:%S-%f', level=level, console=console)
|
||||
if trace:
|
||||
rh.formatter = logging.Formatter('[%(module)s][%(pathname)s:%(lineno)d] %(message)s')
|
||||
rh.addFilter(log_filter)
|
||||
@@ -319,3 +318,12 @@ def setup_logging(debug=None, trace=None, filename=None):
|
||||
logging.getLogger("torch").setLevel(logging.DEBUG)
|
||||
else:
|
||||
logging.getLogger("torch").setLevel(logging.WARNING)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup_logging(debug=True, trace=False, filename=None)
|
||||
for l in [logging.TRACE, logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL]:
|
||||
log.log(l, f"Test log level: {logging.getLevelName(l)}")
|
||||
values = [None, True, False, "yes", "no", "sd.next", 1, 0, 1.0, [1,2,3], {"key": "value"}, (1,2), {1,2}, object()]
|
||||
for v in values:
|
||||
log.info(f"Test values: {type(v).__name__}={v}")
|
||||
|
||||
@@ -27,7 +27,7 @@ def get_stepwise(param, step, steps): # from https://github.com/cheald/sd-webui-
|
||||
if m[1][-1] <= 1.0:
|
||||
step = step / (max_steps - step_offset) if max_steps > 0 else 1.0
|
||||
v = np.interp(step, m[1], m[0])
|
||||
debug_log(f"Network load: type=LoRA step={step} steps={max_steps} v={v}")
|
||||
debug_log(f"LoRA: stepwise step={step} steps={max_steps} v={v}")
|
||||
return v
|
||||
else:
|
||||
return m
|
||||
@@ -184,7 +184,7 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork):
|
||||
from modules.lora import lora_sdnq, lora_stack
|
||||
requested = requested + [f'stack={lora_stack.signature()}{lora_sdnq.signature()}'] # settings-only stack or mechanism changes must re-trigger activation
|
||||
if shared.opts.lora_force_reload:
|
||||
debug_log(f'Network check: type=LoRA requested={requested} status="forced"')
|
||||
debug_log(f'LoRA check requested={requested} status="forced"')
|
||||
return True, "forced"
|
||||
sd_model = shared.sd_model.pipe if hasattr(shared.sd_model, 'pipe') else shared.sd_model
|
||||
if sd_model is None:
|
||||
@@ -200,15 +200,15 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork):
|
||||
if len(requested) != len(loaded):
|
||||
sd_model.loaded_loras.clear() # single-entry cache: any activation invalidates state recorded under other filter keys
|
||||
sd_model.loaded_loras[key] = requested
|
||||
debug_log(f'Network check: type=LoRA key="{key}" requested={requested} loaded={loaded} status="num changed"')
|
||||
debug_log(f'LoRA check key="{key}" requested={requested} loaded={loaded} status="num changed"')
|
||||
return True, "num changed"
|
||||
for req, load in zip(requested, loaded, strict=False):
|
||||
if req != load:
|
||||
sd_model.loaded_loras.clear()
|
||||
sd_model.loaded_loras[key] = requested
|
||||
debug_log(f'Network check: type=LoRA key="{key}" requested={requested} loaded={loaded} status="content changed"')
|
||||
debug_log(f'LoRA check key="{key}" requested={requested} loaded={loaded} status="content changed"')
|
||||
return True, "content changed"
|
||||
debug_log(f'Network check: type=LoRA key="{key}" requested={requested} loaded={loaded} status="same"')
|
||||
debug_log(f'LoRA check key="{key}" requested={requested} loaded={loaded} status="same"')
|
||||
return False, "none"
|
||||
|
||||
def activate(self, p, params_list, step=0, include=None, exclude=None): # pylint: disable=arguments-differ
|
||||
@@ -236,7 +236,7 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork):
|
||||
if debug:
|
||||
import sys
|
||||
fn = f'{sys._getframe(2).f_code.co_name}:{sys._getframe(1).f_code.co_name}' # pylint: disable=protected-access
|
||||
debug_log(f'Network load: type=LoRA include={include} exclude={exclude} method={load_method} reason="{load_reason}" requested={requested} fn={fn}')
|
||||
debug_log(f'LoRA load: include={include} exclude={exclude} method={load_method} reason="{load_reason}" requested={requested} fn={fn}')
|
||||
|
||||
if load_method == 'diffusers':
|
||||
has_changed, reason = self.changed(requested)
|
||||
@@ -267,7 +267,7 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork):
|
||||
log.info(f'Network unload: type=LoRA networks={[n.name for n in l.previously_loaded_networks]} mode={networks.effective_mode()}')
|
||||
networks.network_deactivate(include, exclude)
|
||||
networks.network_activate(include, exclude)
|
||||
debug_log(f'Network change: type=LoRA previous={[n.name for n in l.previously_loaded_networks]} current={[n.name for n in l.loaded_networks]}')
|
||||
debug_log(f'LoRA change: previous={[n.name for n in l.previously_loaded_networks]} current={[n.name for n in l.loaded_networks]}')
|
||||
if len(include) == 0:
|
||||
l.previously_loaded_networks = l.loaded_networks.copy()
|
||||
shared.state.end(jobid)
|
||||
|
||||
@@ -487,28 +487,35 @@ def assign_network_names_to_compvis_modules(sd_model):
|
||||
sd_model = getattr(shared.sd_model, "pipe", shared.sd_model) # wrapped model compatibility
|
||||
network_layer_mapping = {}
|
||||
if hasattr(sd_model, 'text_encoder') and sd_model.text_encoder is not None:
|
||||
for name, module in sd_model.text_encoder.named_modules():
|
||||
for name, module in sd_model.text_encoder.named_modules() :
|
||||
prefix = "lora_te1_" if hasattr(sd_model, 'text_encoder_2') else "lora_te_"
|
||||
network_name = prefix + name.replace(".", "_")
|
||||
network_layer_mapping[network_name] = module
|
||||
module.network_layer_name = network_name
|
||||
if hasattr(sd_model, 'text_encoder_2'):
|
||||
if hasattr(sd_model, 'text_encoder_2') and sd_model.text_encoder_2 is not None:
|
||||
for name, module in sd_model.text_encoder_2.named_modules():
|
||||
network_name = "lora_te2_" + name.replace(".", "_")
|
||||
network_layer_mapping[network_name] = module
|
||||
module.network_layer_name = network_name
|
||||
if hasattr(sd_model, 'unet'):
|
||||
if hasattr(sd_model, 'unet') and sd_model.unet is not None:
|
||||
for name, module in sd_model.unet.named_modules():
|
||||
network_name = "lora_unet_" + name.replace(".", "_")
|
||||
network_layer_mapping[network_name] = module
|
||||
module.network_layer_name = network_name
|
||||
if hasattr(sd_model, 'transformer'):
|
||||
if hasattr(sd_model, 'transformer') and sd_model.transformer is not None:
|
||||
for name, module in sd_model.transformer.named_modules():
|
||||
network_name = "lora_transformer_" + name.replace(".", "_")
|
||||
network_layer_mapping[network_name] = module
|
||||
if "norm" in network_name and "linear" not in network_name and shared.sd_model_type != "sd3":
|
||||
continue
|
||||
module.network_layer_name = network_name
|
||||
if hasattr(sd_model, 'transformer_ref') and sd_model.transformer_ref is not None:
|
||||
for name, module in sd_model.transformer_ref.named_modules():
|
||||
network_name = "lora_transformer_" + name.replace(".", "_")
|
||||
network_layer_mapping[network_name] = module
|
||||
if "norm" in network_name and "linear" not in network_name and shared.sd_model_type != "sd3":
|
||||
continue
|
||||
module.network_layer_name = network_name
|
||||
if hasattr(sd_model, 'llm_adapter') and sd_model.llm_adapter is not None:
|
||||
for name, module in sd_model.llm_adapter.named_modules():
|
||||
network_name = "lora_llm_adapter_" + name.replace(".", "_")
|
||||
|
||||
@@ -56,12 +56,19 @@ def lora_dump(lora, dct):
|
||||
def load_safetensors(name, network_on_disk: network.NetworkOnDisk) -> network.Network | None:
|
||||
if not shared.sd_loaded:
|
||||
return None
|
||||
|
||||
sd_model = getattr(shared.sd_model, "pipe", shared.sd_model)
|
||||
|
||||
# cached
|
||||
cached = lora_cache.get(name, None)
|
||||
if cached is not None:
|
||||
if l.debug:
|
||||
log.trace(f'LoRA: load name="{name}" fn="{network_on_disk.filename}" cache=True')
|
||||
return cached
|
||||
|
||||
# native dispatch
|
||||
native_module = NATIVE_DISPATCH.get(shared.sd_model_type)
|
||||
if l.debug:
|
||||
log.trace(f'LoRA: load name="{name}" fn="{network_on_disk.filename}" native={native_module}')
|
||||
if native_module is not None:
|
||||
import importlib
|
||||
mod = importlib.import_module(native_module)
|
||||
@@ -69,6 +76,10 @@ def load_safetensors(name, network_on_disk: network.NetworkOnDisk) -> network.Ne
|
||||
if net is not None:
|
||||
lora_cache[name] = net
|
||||
return net
|
||||
|
||||
# fallback to standard network loading
|
||||
if l.debug:
|
||||
log.trace(f'LoRA: load name="{name}" network_on_disk="{network_on_disk.filename}" safetensors')
|
||||
net = network.Network(name, network_on_disk)
|
||||
net.mtime = os.path.getmtime(network_on_disk.filename)
|
||||
state_dict = sd_models.read_state_dict(network_on_disk.filename, what='network')
|
||||
@@ -96,7 +107,7 @@ def load_safetensors(name, network_on_disk: network.NetworkOnDisk) -> network.Ne
|
||||
emb_dict[vec_name] = weight
|
||||
bundle_embeddings[emb_name] = emb_dict
|
||||
continue
|
||||
if parts[0] in ["clip_l","clip_g","t5","unet","transformer"]:
|
||||
if parts[0] in ["clip_l", "clip_g", "t5", "unet", "transformer", "transformer_2"]:
|
||||
network_part = []
|
||||
while parts and parts[-1] in ["alpha","weight","lora_up","lora_down"]:
|
||||
network_part.insert(0,parts[-1])
|
||||
@@ -147,7 +158,7 @@ def load_safetensors(name, network_on_disk: network.NetworkOnDisk) -> network.Ne
|
||||
if len(keys_failed_to_match) > 0:
|
||||
log.warning(f'Network load: type=LoRA name="{name}" type={set(network_types)} unmatched={len(keys_failed_to_match)} matched={len(matched_networks)}')
|
||||
if l.debug:
|
||||
log.debug(f'Network load: type=LoRA name="{name}" unmatched={keys_failed_to_match}')
|
||||
log.trace(f'Network load: type=LoRA name="{name}" unmatched={keys_failed_to_match}')
|
||||
else:
|
||||
log.debug(f'Network load: type=LoRA name="{name}" type={set(network_types)} keys={len(matched_networks)} dtypes={dtypes} fuse={lora_overrides.fuse_native()}:{shared.opts.lora_fuse_diffusers}')
|
||||
if len(matched_networks) == 0:
|
||||
@@ -172,13 +183,13 @@ def maybe_recompile_model(names, te_multipliers):
|
||||
if not recompile_model:
|
||||
skip_lora_load = True
|
||||
if len(l.loaded_networks) > 0 and l.debug:
|
||||
log.debug('Model Compile: Skipping LoRa loading')
|
||||
log.trace('LoRA: recompile required, skip loading')
|
||||
return recompile_model, skip_lora_load
|
||||
else:
|
||||
recompile_model = True
|
||||
shared.compiled_model_state.lora_model = []
|
||||
if l.debug:
|
||||
log.debug(f'Model recompile check: task={sd_models.get_diffusers_task(shared.sd_model)} recompile={recompile_model} load={skip_lora_load}')
|
||||
log.trace(f'LoRA recompile check: task={sd_models.get_diffusers_task(shared.sd_model)} recompile={recompile_model} load={skip_lora_load}')
|
||||
if recompile_model:
|
||||
current_task = sd_models.get_diffusers_task(shared.sd_model)
|
||||
log.debug(f'Compile: task={current_task} force model reload')
|
||||
@@ -285,7 +296,7 @@ def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=Non
|
||||
if network_on_disk is not None:
|
||||
shorthash = getattr(network_on_disk, 'shorthash', '').lower()
|
||||
if l.debug:
|
||||
log.debug(f'Network load: type=LoRA name="{name}" file="{network_on_disk.filename}" hash="{shorthash}" cached={name in lora_cache}')
|
||||
log.trace(f'LoRA: name="{name}" fn="{network_on_disk.filename}" hash="{shorthash}" cached={name in lora_cache}')
|
||||
try:
|
||||
lora_scale = te_multipliers[i] if te_multipliers else shared.opts.extra_networks_default_multiplier
|
||||
lora_module = lora_modules[i] if lora_modules and len(lora_modules) > i else None
|
||||
@@ -330,8 +341,8 @@ def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=Non
|
||||
try:
|
||||
t1 = time.time()
|
||||
if l.debug:
|
||||
log.trace(f'Network load: type=LoRA list={sd_model.get_list_adapters()}')
|
||||
log.trace(f'Network load: type=LoRA active={sd_model.get_active_adapters()}')
|
||||
log.trace(f'LoRA: list={sd_model.get_list_adapters()}')
|
||||
log.trace(f'LoRA: active={sd_model.get_active_adapters()}')
|
||||
sd_model.set_adapters(adapter_names=lora_diffusers.diffuser_loaded, adapter_weights=lora_diffusers.diffuser_scales)
|
||||
sd_model.enable_lora() # set_adapters does not clear the disabled flag left by a prior removal
|
||||
except Exception as e:
|
||||
@@ -359,7 +370,7 @@ def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=Non
|
||||
networks.network_activate()
|
||||
|
||||
if len(l.loaded_networks) > 0 and l.debug:
|
||||
log.debug(f'Network load: type=LoRA loaded={[n.name for n in l.loaded_networks]} cache={list(lora_cache)} fuse={lora_overrides.fuse_native()}:{shared.opts.lora_fuse_diffusers}')
|
||||
log.trace(f'LoRA: loaded={[n.name for n in l.loaded_networks]} cache={list(lora_cache)} fuse={lora_overrides.fuse_native()}:{shared.opts.lora_fuse_diffusers}')
|
||||
|
||||
if recompile_model:
|
||||
log.info("Network load: type=LoRA model recompile required")
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import os
|
||||
from modules import shared
|
||||
from modules.logger import log
|
||||
|
||||
|
||||
debug_log = log.trace if os.environ.get('SD_LORA_DEBUG', None) is not None else lambda *args, **kwargs: None
|
||||
|
||||
|
||||
force_hashes_diffusers = [ # forced always
|
||||
@@ -116,15 +121,22 @@ def disable_fuse():
|
||||
from modules.lora import lora_common as l
|
||||
from modules.lora import lora_stack
|
||||
if lora_stack.select_possible(len(l.loaded_networks)) or lora_stack.select_engaged():
|
||||
debug_log('LoRA: fuse=False reason="active select mode"')
|
||||
return True # select flips per-layer winners against the pristine backup; a dormant select mode leaves fuse alone
|
||||
sd_model = getattr(shared.sd_model, 'pipe', shared.sd_model)
|
||||
if is_quantized(sd_model):
|
||||
debug_log('LoRA: fuse=False reason="model is quantized"')
|
||||
return True
|
||||
if any(is_quantized(getattr(sd_model, name, None)) for name in fuse_components(sd_model)):
|
||||
debug_log('LoRA: fuse=False reason="component is quantized"')
|
||||
return True
|
||||
if hasattr(sd_model, '_lora_partial'):
|
||||
debug_log('LoRA: fuse=False reason="partial lora applied"')
|
||||
return True
|
||||
return shared.sd_model_type in fuse_ignore
|
||||
if shared.sd_model_type in fuse_ignore:
|
||||
debug_log(f'LoRA: fuse=False reason="model type {shared.sd_model_type} in fuse_ignore"')
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def fuse_native():
|
||||
@@ -134,4 +146,7 @@ def fuse_native():
|
||||
the backup, activate and deactivate passes, since backup mode restores from a
|
||||
stored tensor while fuse mode restores by subtracting the delta.
|
||||
"""
|
||||
return shared.opts.lora_fuse_native and not disable_fuse()
|
||||
result = shared.opts.lora_fuse_native and not disable_fuse()
|
||||
force = os.environ.get('SD_LORA_FUSE', None) is not None
|
||||
debug_log(f'LoRA: native fuse={result} force={force}')
|
||||
return (result or force)
|
||||
|
||||
@@ -56,7 +56,7 @@ from modules.logger import log, console
|
||||
applied_layers: list[str] = []
|
||||
refused_writes: int = 0 # deltas the modules would not take on the last activate pass; infotext reports the network as partial
|
||||
native_active: bool = False
|
||||
default_components = ['text_encoder', 'text_encoder_2', 'text_encoder_3', 'text_encoder_4', 'unet', 'transformer', 'transformer_2', 'llm_adapter']
|
||||
default_components = ['text_encoder', 'text_encoder_2', 'text_encoder_3', 'text_encoder_4', 'unet', 'transformer', 'transformer_2', 'transformer_ref', 'llm_adapter']
|
||||
|
||||
|
||||
class ActivationPass:
|
||||
@@ -72,10 +72,10 @@ class ActivationPass:
|
||||
self.sd_model = getattr(shared.sd_model, "pipe", shared.sd_model)
|
||||
self.fuse = fuse
|
||||
self.elimit = None # the error limiter, bound for the duration of the walk
|
||||
self.wanted_names = tuple((x.name, x.te_multiplier, x.unet_multiplier, x.dyn_dim) for x in l.loaded_networks) if len(l.loaded_networks) > 0 else ()
|
||||
self.wanted_names: tuple[tuple[str, float, list, int | None], ...] = tuple((x.name, x.te_multiplier, x.unet_multiplier, x.dyn_dim) for x in l.loaded_networks) if len(l.loaded_networks) > 0 else ()
|
||||
self.stack_sig = lora_stack.signature() + lora_blocks.signature() + lora_sdnq.signature() # tracked beside network_current_names so stack-setting, block-weight and mechanism changes re-apply
|
||||
self.select_active = len(l.loaded_networks) > 0 and lora_stack.active_select(len(l.loaded_networks)) # restore-only walks have nothing to stack; the count warning would fire on every network-free generation
|
||||
self.component_wanted = ()
|
||||
self.component_wanted: tuple[tuple[str, float, list, int | None], ...] = ()
|
||||
self.device = None
|
||||
self.group_offload = shared.opts.diffusers_offload_mode == "group"
|
||||
self.group_stripped = {}
|
||||
|
||||
@@ -24,6 +24,7 @@ def create_ui(prompt, _negative, styles, overrides, script_inputs, mp4_fps, mp4_
|
||||
with gr.Accordion(open=True, label='Parameters', elem_id='minimax_param_accordion') as _param_accordion:
|
||||
with gr.Row():
|
||||
width, height = ui_sections.create_resolution_inputs('minimax', default_width=1024, default_height=576, step=32)
|
||||
btn_detect_image_size = ToolButton(value=ui_symbols.detect, elem_id="minimax_resize_detect_size")
|
||||
with gr.Row():
|
||||
steps = gr.Slider(minimum=2, maximum=100, step=1, label="MiniMax steps", elem_id='minimax_steps', value=30)
|
||||
frames = gr.Slider(label='MiniMax frames', minimum=22, maximum=362, step=17, value=124, elem_id='minimax_frames')
|
||||
@@ -57,19 +58,29 @@ def create_ui(prompt, _negative, styles, overrides, script_inputs, mp4_fps, mp4_
|
||||
model_info = next((m for m in models['MiniMax'] if m.name == model_name), None)
|
||||
if model_info is None or model_info.name is None or model_info.name == '' or model_info.name == 'None':
|
||||
return gr.update(value='none'), gr.update(visible=False), gr.update(visible=False)
|
||||
log.debug(f'Selected: name="{model_info.name}" repo="{model_info.repo}" cls={model_info.repo_cls}')
|
||||
if model_info.workflow == 'fl2va':
|
||||
workflow = 'fl2va' if init_image is not None else 't2va'
|
||||
else:
|
||||
workflow = model_info.workflow
|
||||
log.debug(f'Video: workflow={workflow} name="{model_info.name}" repo="{model_info.repo}" cls={model_info.repo_cls} image={init_image} selected')
|
||||
return gr.update(value=f'Workflow: {workflow}'), gr.update(visible=workflow != 'ref2va'), gr.update(visible=workflow == 'ref2va')
|
||||
|
||||
def on_load(model_name: str):
|
||||
model_info = next((m for m in models['MiniMax'] if m.name == model_name), None)
|
||||
minimax_video.load_model(model_info.name if model_info is not None else None)
|
||||
|
||||
def on_image_size(init_image):
|
||||
if init_image is not None:
|
||||
try:
|
||||
width, height = init_image.size
|
||||
return gr.update(value=width), gr.update(value=height)
|
||||
except Exception:
|
||||
pass
|
||||
return gr.update(), gr.update()
|
||||
|
||||
model.change(fn=on_change, inputs=[model, init_image], outputs=[workflow, input_accordion, reference_accordion], show_progress='hidden')
|
||||
init_image.change(fn=on_change, inputs=[model, init_image], outputs=[workflow, input_accordion, reference_accordion], show_progress='hidden')
|
||||
btn_detect_image_size.click(fn=on_image_size, inputs=[init_image], outputs=[width, height])
|
||||
btn_load.click(fn=on_load, inputs=[model], outputs=[])
|
||||
|
||||
task_id = gr.Textbox(visible=False, value='')
|
||||
|
||||
@@ -49,23 +49,28 @@ def unwrap_file(entry):
|
||||
return entry
|
||||
|
||||
|
||||
def prepare_inputs(workflow: str | None, init_image: Image.Image | None, last_image: Image.Image | None, reference_media: list | None) -> dict:
|
||||
def prepare_inputs(workflow: str | None, init_image: Image.Image | None, last_image: Image.Image | None, reference_media: list | None, width: int | None = None, height: int | None = None) -> dict:
|
||||
"""The task args a workflow conditions on, resolved before the model load so a rejected request costs nothing."""
|
||||
t_inputs = time.time()
|
||||
from modules.image.resize import resize_image
|
||||
from modules.minimax import minimax_references
|
||||
if minimax_references.get_reference_caps(workflow) is not None:
|
||||
entries = [unwrap_file(entry) for entry in (reference_media or [])]
|
||||
references = minimax_references.resolve(workflow, entries, init_image)
|
||||
log.debug(f'Prepare inputs: workflow={workflow} references={len(references)}')
|
||||
log.debug(f'Video inputs: workflow={workflow} references={len(references)}')
|
||||
return {'references': references}
|
||||
task_args = {}
|
||||
if init_image is not None:
|
||||
if width is not None and height is not None:
|
||||
init_image = resize_image(2, init_image, width, height) # crop to aspect ratio
|
||||
task_args['image'] = init_image
|
||||
if last_image is not None:
|
||||
if width is not None and height is not None:
|
||||
last_image = resize_image(2, last_image, width, height) # crop to aspect ratio
|
||||
task_args['last_image'] = last_image
|
||||
if reference_media:
|
||||
log.warning(f'Video: op=reference workflow={workflow} references not supported, ignoring: count={len(reference_media)}')
|
||||
log.debug(f'Prepare inputs: workflow={workflow} first={init_image} last={last_image}')
|
||||
log.debug(f'Video inputs: workflow={workflow} first={init_image} last={last_image}')
|
||||
timer.video.ts('inputs', t_inputs)
|
||||
return task_args
|
||||
|
||||
@@ -111,18 +116,24 @@ def generate(task_id, _ui_state,
|
||||
# resolved off the registry row so a bad reference is rejected before the load, the same as on the api path
|
||||
selected = models_def.find(engine, model)
|
||||
workflow = getattr(selected, 'workflow', None)
|
||||
task_args = prepare_inputs(workflow, init_image, last_image, reference_media)
|
||||
task_args = prepare_inputs(workflow, init_image, last_image, reference_media, width=width, height=height)
|
||||
workflow = load_model(model) # override workflow based on loaded model
|
||||
if not workflow:
|
||||
progress.finish_task(task_id)
|
||||
log.error('Video: model not loaded')
|
||||
return None, 'Model not loaded'
|
||||
init_images = [] # only so they are available for inspection by rest of the processing
|
||||
if init_image is not None:
|
||||
init_images.append(init_image)
|
||||
if last_image is not None:
|
||||
init_images.append(last_image)
|
||||
p = processing.StableDiffusionProcessingVideo(
|
||||
sd_model=shared.sd_model,
|
||||
video_engine=engine,
|
||||
video_model=model,
|
||||
prompt=prompt,
|
||||
styles=styles,
|
||||
init_images=init_images,
|
||||
seed=int(seed) if seed is not None else -1,
|
||||
steps=int(steps),
|
||||
width=width,
|
||||
|
||||
@@ -490,5 +490,5 @@ def load_upscalers(quiet=False):
|
||||
shared.sd_upscalers = upscalers
|
||||
t1 = time.time()
|
||||
if not quiet:
|
||||
log.info(f"Available Upscalers: items={len(shared.sd_upscalers)} downloaded={len([x for x in shared.sd_upscalers if x.data_path is not None and os.path.isfile(x.data_path)])} user={len([x for x in shared.sd_upscalers if x.custom])} time={t1-t0:.2f} types={upscaler_types}")
|
||||
log.info(f"Available Upscalers: items={len(shared.sd_upscalers)} downloaded={len([x for x in shared.sd_upscalers if x.data_path is not None and os.path.isfile(x.data_path)])} user={len([x for x in shared.sd_upscalers if x.custom])} time={t1-t0:.2f}")
|
||||
return [x.name for x in shared.sd_upscalers]
|
||||
|
||||
@@ -59,18 +59,21 @@ def preload_components(pipe, workflow: str | None, load_config: dict | None = No
|
||||
if spec is None or getattr(spec, 'default_creation_method', None) != 'from_pretrained':
|
||||
continue
|
||||
repo = getattr(spec, 'pretrained_model_name_or_path', None)
|
||||
cls = getattr(spec, 'type_hint', None)
|
||||
cls = getattr(spec, 'type_hint', None) or {}
|
||||
if not repo or cls is None:
|
||||
continue
|
||||
origin = getattr(cls, '__module__', '') or ''
|
||||
cls_name = getattr(cls, '__name__', '') or '' # TODO preload: components with remote code resolve to cls none
|
||||
cls_name = getattr(cls, '__name__', '') or ''
|
||||
subfolder = getattr(spec, 'subfolder', None) or name
|
||||
component = None
|
||||
if origin.startswith('diffusers') and ('Transformer' in cls_name or 'UNet' in cls_name):
|
||||
component = generic.load_transformer(repo, cls_name=cls, load_config=load_config, subfolder=subfolder, trust_remote_code=True)
|
||||
elif origin.startswith('transformers') and 'text_encoder' in name:
|
||||
elif origin.startswith('transformers') and ('text_encoder' in name):
|
||||
# shared substitution is on: the map matches class plus a substring of the repo name, so its entries have to run narrow before broad
|
||||
component = generic.load_text_encoder(repo, cls_name=cls, load_config=load_config, subfolder=subfolder)
|
||||
if 'transformer' in name:
|
||||
# fallback for component with remote-code as it does not have resolvable cls
|
||||
component = generic.load_transformer(repo, cls_name=None, load_config=load_config, subfolder=subfolder, trust_remote_code=True)
|
||||
if component is not None:
|
||||
loaded[name] = component
|
||||
return loaded
|
||||
|
||||
+12
-3
@@ -352,11 +352,18 @@ def process_samples(p: StableDiffusionProcessing, samples):
|
||||
method = p.color_correction_method if p.color_correction_method is not None else getattr(shared.opts, 'color_correction_method', 'histogram')
|
||||
image = apply_color_correction(p.color_corrections[i], image, method=method)
|
||||
|
||||
if p.scripts is not None and isinstance(p.scripts, scripts_manager.ScriptRunner):
|
||||
if p.scripts is not None and isinstance(p.scripts, scripts_manager.ScriptRunner) and not getattr(p, 'is_grid', False):
|
||||
pp = scripts_manager.PostprocessImageArgs(image)
|
||||
p.scripts.postprocess_image(p, pp)
|
||||
if pp.image is not None:
|
||||
image = pp.image
|
||||
if isinstance(pp.image, list) and len(pp.image) > 0: # post process image can return original+processed
|
||||
for i, img in enumerate(pp.image):
|
||||
if i+1 < len(pp.image):
|
||||
out_images.append(img)
|
||||
out_infotexts.append(f"Postprocess image {i+1}")
|
||||
image = pp.image[-1]
|
||||
else:
|
||||
image = pp.image
|
||||
|
||||
grading_params = processing_grading.GradingParams(
|
||||
brightness=getattr(p, 'grading_brightness', 0.0),
|
||||
@@ -609,7 +616,9 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
audio=audio,
|
||||
)
|
||||
if p.scripts is not None and isinstance(p.scripts, scripts_manager.ScriptRunner) and not (shared.state.interrupted or shared.state.skipped):
|
||||
p.scripts.postprocess(p, results)
|
||||
_results = p.scripts.postprocess(p, results)
|
||||
if _results is not None:
|
||||
results = _results
|
||||
timer.process.record('post')
|
||||
p.ops = list(set(p.ops))
|
||||
t3 = time.time()
|
||||
|
||||
@@ -444,7 +444,7 @@ def set_pipeline_args(p, model, prompts:list, negative_prompts:list, prompts_2:l
|
||||
# handle missing resolution
|
||||
if args.get('image', None) is not None and ('width' not in args or 'height' not in args):
|
||||
if 'width' in possible and 'height' in possible:
|
||||
vae_scale_factor = sd_vae.get_vae_scale_factor(model)
|
||||
vae_scale_factor = sd_vae.get_vae_scale_factor(model, init_image=True)
|
||||
if isinstance(args['image'], torch.Tensor) or isinstance(args['image'], np.ndarray):
|
||||
if args['image'].shape[-1] == 3: # nhwc
|
||||
args['width'] = args['image'].shape[-2]
|
||||
|
||||
@@ -738,7 +738,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
||||
|
||||
def init(self, all_prompts=None, all_seeds=None, all_subseeds=None):
|
||||
if self.init_images is not None and len(self.init_images) > 0:
|
||||
vae_scale_factor = sd_vae.get_vae_scale_factor()
|
||||
vae_scale_factor = sd_vae.get_vae_scale_factor(init_image=True)
|
||||
if self.width is None or self.width == 0:
|
||||
self.width = int(vae_scale_factor * (self.init_images[0].width * self.scale_by // vae_scale_factor))
|
||||
if self.height is None or self.height == 0:
|
||||
|
||||
@@ -397,7 +397,7 @@ def resize_init_images(p):
|
||||
p.init_images = [p.image]
|
||||
if getattr(p, 'init_images', None) is not None and len(p.init_images) > 0:
|
||||
p.init_images = decode_images(p.init_images)
|
||||
vae_scale_factor = sd_vae.get_vae_scale_factor()
|
||||
vae_scale_factor = sd_vae.get_vae_scale_factor(init_image=True)
|
||||
tgt_width = vae_scale_factor * math.ceil(p.init_images[0].width / vae_scale_factor)
|
||||
tgt_height = vae_scale_factor * math.ceil(p.init_images[0].height / vae_scale_factor)
|
||||
if p.init_images[0].size != (tgt_width, tgt_height):
|
||||
|
||||
@@ -208,11 +208,6 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No
|
||||
args['Sampler shift'] = get_opt('schedulers_shift') if get_opt('schedulers_shift') != shared.opts.data_labels.get('schedulers_shift').default else None
|
||||
args['Sampler dynamic shift'] = get_opt('schedulers_dynamic_shift') if get_opt('schedulers_dynamic_shift') != shared.opts.data_labels.get('schedulers_dynamic_shift').default else None
|
||||
|
||||
# model specific
|
||||
if shared.sd_model_type == 'h1':
|
||||
args['LLM'] = None if shared.opts.model_h1_llama_repo == 'Default' else shared.opts.model_h1_llama_repo
|
||||
|
||||
# args.update(p.extra_generation_params)
|
||||
for k, v in p.extra_generation_params.items():
|
||||
if isinstance(v, (list, tuple)) and (job_size > index) and (len(v) > 1) and (len(v) == job_size): # likely a per-job param
|
||||
args[k] = v[index]
|
||||
|
||||
@@ -743,15 +743,19 @@ class ScriptRunner:
|
||||
|
||||
def postprocess(self, p: StableDiffusionProcessing, processed):
|
||||
s = ScriptSummary('postprocess')
|
||||
_processed = processed
|
||||
for script in self.alwayson_scripts:
|
||||
try:
|
||||
args = resolve_script_args(script, p.script_args, p.per_script_args)
|
||||
if args is not None:
|
||||
script.postprocess(p, processed, *args)
|
||||
result = script.postprocess(p, _processed, *args)
|
||||
if result is not None: # allow postprocessing script to optionally modify results
|
||||
_processed = result
|
||||
except Exception as e:
|
||||
errors.display(e, f'Running script postprocess: {script.filename}')
|
||||
s.record(script.title())
|
||||
s.report()
|
||||
return _processed
|
||||
|
||||
def postprocess_batch(self, p: StableDiffusionProcessing, images, **kwargs):
|
||||
s = ScriptSummary('postprocess-batch')
|
||||
|
||||
@@ -22,7 +22,6 @@ class PromptCache:
|
||||
self.cache.clear()
|
||||
self.id = id(shared.sd_model)
|
||||
log.debug(f'Encode: prompt cache activate id={self.id} depth={len(self.cache)}')
|
||||
prompt = self._hashable(prompt)
|
||||
negative_prompt = self._hashable(negative_prompt)
|
||||
if (isinstance(prompt, list) and len(prompt) == 1 and isinstance(prompt[0], str)):
|
||||
cached = self.cache.get((prompt[0], negative_prompt, cfg_enabled), None)
|
||||
@@ -41,7 +40,6 @@ class PromptCache:
|
||||
if len(self.cache) >= self.max:
|
||||
oldest_key = next(iter(self.cache))
|
||||
del self.cache[oldest_key]
|
||||
prompt = self._hashable(prompt)
|
||||
negative_prompt = self._hashable(negative_prompt)
|
||||
if (isinstance(prompt, list) and len(prompt) == 1 and isinstance(prompt[0], str)):
|
||||
self.cache[(prompt[0], negative_prompt, cfg_enabled)] = encoded
|
||||
|
||||
@@ -1147,6 +1147,17 @@ def get_diffusers_task(pipe: diffusers.DiffusionPipeline) -> DiffusersTaskType:
|
||||
return DiffusersTaskType.TEXT_2_IMAGE
|
||||
|
||||
|
||||
def pipe_serves_task(pipe: diffusers.DiffusionPipeline, task_type: DiffusersTaskType) -> bool:
|
||||
"""True when the pipeline class is registered for the task in the diffusers auto-pipeline tables."""
|
||||
mappings = {
|
||||
DiffusersTaskType.TEXT_2_IMAGE: diffusers.pipelines.auto_pipeline.AUTO_TEXT2IMAGE_PIPELINES_MAPPING,
|
||||
DiffusersTaskType.IMAGE_2_IMAGE: diffusers.pipelines.auto_pipeline.AUTO_IMAGE2IMAGE_PIPELINES_MAPPING,
|
||||
DiffusersTaskType.INPAINTING: diffusers.pipelines.auto_pipeline.AUTO_INPAINT_PIPELINES_MAPPING,
|
||||
}
|
||||
mapping = mappings.get(task_type)
|
||||
return mapping is not None and pipe.__class__ in mapping.values()
|
||||
|
||||
|
||||
def switch_pipe(cls: type[diffusers.DiffusionPipeline] | str, pipeline: diffusers.DiffusionPipeline | None = None, force = False, args: dict | None = None):
|
||||
"""
|
||||
args:
|
||||
@@ -1354,6 +1365,8 @@ def set_diffuser_pipe(pipe, new_pipe_type):
|
||||
return pipe
|
||||
if get_diffusers_task(pipe) == new_pipe_type:
|
||||
return pipe
|
||||
if pipe_serves_task(pipe, new_pipe_type): # a class registered for several tasks classifies as one of them
|
||||
return pipe
|
||||
|
||||
if get_diffusers_task(pipe) == DiffusersTaskType.MODULAR:
|
||||
return pipe
|
||||
|
||||
+10
-13
@@ -206,20 +206,17 @@ def offload_ondemand(sd_model, include=[], exclude=[], reason='', force=False):
|
||||
|
||||
|
||||
def report_group_stats(sd_model, module_names):
|
||||
"""Per-component stats block once per loaded model; balanced mode prints its own from the hook map."""
|
||||
checkpoint_name = sd_model.sd_checkpoint_info.name if getattr(sd_model, "sd_checkpoint_info", None) is not None else sd_model.__class__.__name__
|
||||
if checkpoint_name in s.group_stats_reported: # keyed by checkpoint since a task switch rebuilds the pipe object
|
||||
"""Per-component stats block once per loaded component; balanced mode prints its own from the hook map."""
|
||||
modules = {name: getattr(sd_model, name, None) for name in module_names}
|
||||
modules = {name: module for name, module in modules.items() if isinstance(module, torch.nn.Module)}
|
||||
pending = {name: module for name, module in modules.items() if not getattr(module, 'sdnext_stats_reported', False)} # a task switch reuses the modules, a reload brings new ones
|
||||
if not pending:
|
||||
return
|
||||
s.group_stats_reported.add(checkpoint_name)
|
||||
total = 0.0
|
||||
counted = []
|
||||
for module_name in module_names:
|
||||
module = getattr(sd_model, module_name, None)
|
||||
if isinstance(module, torch.nn.Module):
|
||||
total += get_module_size(module)[0]
|
||||
counted.append(module_name)
|
||||
report_model_stats(module_name, module)
|
||||
log.info(f'Model class={sd_model.__class__.__name__} modules={len(counted)} size={total:.3f}')
|
||||
for module_name, module in pending.items():
|
||||
module.sdnext_stats_reported = True
|
||||
report_model_stats(module_name, module)
|
||||
total = sum(get_module_size(module)[0] for module in modules.values())
|
||||
log.info(f'Model class={sd_model.__class__.__name__} modules={len(modules)} size={total:.3f}')
|
||||
|
||||
|
||||
def apply_group_offload(sd_model):
|
||||
|
||||
@@ -30,5 +30,4 @@ no_split_module_classes = [
|
||||
]
|
||||
|
||||
accelerate_dtype_byte_size = None # monkey-patch accelerate.utils.modeling.dtype_byte_size
|
||||
group_stats_reported = set()
|
||||
move_stream = None
|
||||
|
||||
@@ -174,7 +174,11 @@ def report_model_stats(module_name, module):
|
||||
size, _params = get_module_size(module)
|
||||
quant = getattr(module, "quantization_method", None)
|
||||
params = sum(p.numel() for p in module.parameters(recurse=True))
|
||||
try:
|
||||
dtype = next(module.parameters(), torch.tensor([])).dtype
|
||||
except Exception:
|
||||
dtype = None
|
||||
logical = get_logical_param_count(module)
|
||||
log.debug(f'Module: name={module_name} cls={module.__class__.__name__} size={size:.3f} params={params} logical={logical} quant={quant}')
|
||||
log.debug(f'Module: name={module_name} cls={module.__class__.__name__} size={size:.3f} params={params} logical={logical} quant={quant} dtype={dtype}')
|
||||
except Exception as e:
|
||||
log.error(f'Module stats: name={module_name} {e}')
|
||||
|
||||
+6
-3
@@ -28,7 +28,7 @@ vae_scale_override = {
|
||||
}
|
||||
|
||||
|
||||
def get_vae_scale_factor(model: DiffusionPipeline | None = None):
|
||||
def get_vae_scale_factor(model: DiffusionPipeline | None = None, init_image: bool = False):
|
||||
if not shared.sd_loaded:
|
||||
vae_scale_factor = 8
|
||||
return vae_scale_factor
|
||||
@@ -58,9 +58,12 @@ def get_vae_scale_factor(model: DiffusionPipeline | None = None):
|
||||
patch_size = model.patch_size
|
||||
if isinstance(patch_size, (tuple, list)): # 3d patch sizes are (t, h, w); spatial term is last
|
||||
patch_size = patch_size[-1]
|
||||
multiple = vae_scale_factor * patch_size
|
||||
if init_image and model is not None and hasattr(model, 'init_image_multiple'): # a pipeline that downsamples its source image needs a larger multiple than its output
|
||||
multiple = max(multiple, int(model.init_image_multiple))
|
||||
if debug:
|
||||
log.trace(f'VAE: cls={model.__class__.__name__ if model else "None"} scale={vae_scale_factor} patch={patch_size}')
|
||||
return vae_scale_factor * patch_size
|
||||
log.trace(f'VAE: cls={model.__class__.__name__ if model else "None"} scale={vae_scale_factor} patch={patch_size} multiple={multiple}')
|
||||
return multiple
|
||||
|
||||
|
||||
def load_vae_dict(filename: str):
|
||||
|
||||
+1
-1
@@ -211,7 +211,7 @@ def restart_server(restart=True):
|
||||
demo.server.should_exit = True
|
||||
demo.server.force_exit = True
|
||||
demo.close(verbose=False)
|
||||
demo.server.close()
|
||||
# demo.server.close()
|
||||
demo.fns = []
|
||||
time.sleep(1)
|
||||
sys.tracebacklimit = 100
|
||||
|
||||
@@ -46,13 +46,13 @@ def get_default_modes(cmd_opts, mem_stat):
|
||||
|
||||
if devices.backend == "zluda":
|
||||
default_sdp_options = ['Math']
|
||||
default_cross_attention = ['Dynamic attention']
|
||||
default_cross_attention = 'Dynamic attention'
|
||||
elif devices.backend == "rocm":
|
||||
agent = devices.get_hip_agent()
|
||||
if agent.gfx_version < 0x1100:
|
||||
default_cross_attention = ['Dynamic attention'] # only RDNA2 and older GPUs needs this
|
||||
default_cross_attention = 'Dynamic attention' # only RDNA2 and older GPUs needs this
|
||||
elif devices.backend in {"cpu", "mps"}:
|
||||
default_cross_attention = ['Dynamic attention']
|
||||
default_cross_attention = 'Dynamic attention'
|
||||
|
||||
if devices.get_optimal_device_name() != "cpu":
|
||||
os.environ.setdefault('SDNQ_USE_OPENVINO_MM', '0')
|
||||
|
||||
+10
-6
@@ -200,14 +200,15 @@ def apply_wildcards_to_prompt(prompt, all_wildcards, seed=-1, silent=False, p: S
|
||||
except Exception as e:
|
||||
log.error(f'Wildcards: wildcard="{wildcard}" error={e}')
|
||||
t1 = time.time()
|
||||
prompt, replaced_file, not_found = apply_file_wildcards(prompt, [], [], recursion=0, seed=seed, p=p)
|
||||
prompt, replaced_files, missing_files = apply_file_wildcards(prompt, [], [], recursion=0, seed=seed, p=p)
|
||||
t2 = time.time()
|
||||
if replaced and not silent:
|
||||
log.debug(f'Apply wildcards: {replaced} path="{shared.opts.wildcards_dir}" type=style time={t1-t0:.2f}')
|
||||
if (len(replaced_file) > 0 or len(not_found) > 0) and not silent:
|
||||
log.debug(f'Apply wildcards: found={replaced_file} missing={not_found} path="{shared.opts.wildcards_dir}" type=file seed={seed} time={t2-t2:.2f}')
|
||||
if (len(replaced_files) > 0 or len(missing_files) > 0) and not silent:
|
||||
log.debug(f'Apply wildcards: found={replaced_files} missing={missing_files} path="{shared.opts.wildcards_dir}" type=file seed={seed} time={t2-t1:.2f}')
|
||||
if p is not None:
|
||||
p.extra_generation_params['Wildcards'] = p.extra_generation_params.get('Wildcards', []) + [replaced_file]
|
||||
wildcards = p.extra_generation_params.get('Wildcards', []) + replaced_files
|
||||
p.extra_generation_params['Wildcards'] = ', '.join(wildcards)
|
||||
if old_state is not None:
|
||||
random.setstate(old_state)
|
||||
return prompt
|
||||
@@ -243,12 +244,15 @@ def apply_styles_to_extra(p, style: Style):
|
||||
'size',
|
||||
]
|
||||
reference_style = get_reference_style()
|
||||
extra = infotext.parse(reference_style) if shared.opts.extra_network_reference_values else {}
|
||||
reference = infotext.parse(reference_style) if shared.opts.extra_network_reference_values else {}
|
||||
extra = reference.copy()
|
||||
style_extra = apply_wildcards_to_prompt(style.extra, [style.wildcards], silent=True, p=p)
|
||||
style_extra = ' ' + style_extra.lower()
|
||||
extra.update(infotext.parse(style_extra))
|
||||
extra.pop('Prompt', None)
|
||||
extra.pop('Negative prompt', None)
|
||||
has_prompt = (style.prompt is not None) and len(style.prompt) > 2
|
||||
has_negative = (style.negative_prompt is not None) and len(style.negative_prompt) > 2
|
||||
if debug_enabled:
|
||||
log.trace(f'Apply style extra: {extra}')
|
||||
|
||||
@@ -284,7 +288,7 @@ def apply_styles_to_extra(p, style: Style):
|
||||
if debug_enabled:
|
||||
log.trace(f'Apply style skip: {k}={v}')
|
||||
skipped.append(f'{k}={v}')
|
||||
log.debug(f'Apply style: name="{style.name}" params={params} settings={settings} unknown={skipped} reference={True if reference_style else False}')
|
||||
log.debug(f'Apply style: name="{style.name}" prompt={has_prompt} negative={has_negative} params={params} settings={settings} unknown={skipped} reference={reference}')
|
||||
|
||||
|
||||
class StyleDatabase:
|
||||
|
||||
@@ -504,6 +504,7 @@ def create_settings(cmd_opts):
|
||||
"openvino_cache_path": OptionInfo('cache', "Folder for OpenVINO cache", folder=True),
|
||||
"onnx_cached_models_path": OptionInfo(os.path.join(paths.models_path, 'ONNX', 'cache'), "Folder for ONNX cached models", folder=True),
|
||||
"onnx_temp_dir": OptionInfo(os.path.join(paths.models_path, 'ONNX', 'temp'), "Folder for ONNX conversion", folder=True),
|
||||
"dlss_pkg_path": OptionInfo('', "Folder with DLSS package", gr.Textbox, { "visible": False}),
|
||||
}))
|
||||
|
||||
# --- Image Options ---
|
||||
@@ -610,13 +611,13 @@ def create_settings(cmd_opts):
|
||||
"ui_disabled": OptionInfo([], "Disabled UI tabs", gr.Dropdown, { 'visible': False }),
|
||||
|
||||
"cards_sep_ui": OptionInfo("<h2>Networks panel</h2>", "", gr.HTML),
|
||||
"extra_networks_card_size": OptionInfo(140, "Network card size (px)", gr.Slider, {"minimum": 20, "maximum": 2000, "step": 1}),
|
||||
"extra_networks_card_size": OptionInfo(130, "Network card size (px)", gr.Slider, {"minimum": 20, "maximum": 2000, "step": 1}),
|
||||
"extra_networks_card_cover": OptionInfo("sidebar", "Network panel position", gr.Radio, {"choices": ["cover", "inline", "sidebar"]}),
|
||||
"extra_networks_card_square": OptionInfo(True, "Disable variable aspect ratio"),
|
||||
|
||||
"other_sep_ui": OptionInfo("<h2>Other...</h2>", "", gr.HTML),
|
||||
"ui_locale": OptionInfo("Auto", "UI locale", gr.Dropdown, lambda: {"choices": theme.list_locales()}),
|
||||
"font_size": OptionInfo(14, "Font size", gr.Slider, {"minimum": 8, "maximum": 32, "step": 1}),
|
||||
"font_size": OptionInfo(15, "Font size", gr.Slider, {"minimum": 8, "maximum": 32, "step": 1}),
|
||||
"gpu_monitor": OptionInfo(3000, "GPU monitor interval", gr.Slider, {"minimum": 100, "maximum": 60000, "step": 100}),
|
||||
"aspect_ratios": OptionInfo("1:1, 4:3, 3:2, 16:9, 16:10, 21:9, 2:3, 3:4, 9:16, 10:16, 9:21", "Allowed aspect ratios"),
|
||||
"compact_view": OptionInfo(False, "Compact view"),
|
||||
|
||||
@@ -27,6 +27,8 @@ refresh_time = 0
|
||||
extra_pages = shared.extra_networks
|
||||
debug = log.trace if os.environ.get('SD_EN_DEBUG', None) is not None else lambda *args, **kwargs: None
|
||||
debug('Trace: EN')
|
||||
|
||||
card_empty = '<div class="card"></div>'
|
||||
card_full = '''
|
||||
<div class='card' onclick={card_click} title='{name}' data-page='{page}' data-name='{name}' data-filename='{filename}' data-short='{short}' data-tags='{tags}' data-mtime='{mtime}' data-size='{size}' data-search='{search}' data-version='{version}' style='--data-color: {color}'>
|
||||
<div class='overlay'>
|
||||
|
||||
@@ -111,6 +111,7 @@ class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage):
|
||||
primary = tag.split(',')[0].strip() if len(tag) > 0 else ''
|
||||
else:
|
||||
primary = ''
|
||||
primary = primary.lower()
|
||||
|
||||
if ('nunchaku' in tag) and (devices.backend != 'cuda' and not shared.cmd_opts.experimental):
|
||||
count['hidden'] += 1
|
||||
|
||||
@@ -110,7 +110,10 @@ def create_guidance_inputs(tab):
|
||||
standard_args = args_base + args_legacy
|
||||
|
||||
def update_stored(component, name):
|
||||
if component is None or name is None:
|
||||
return
|
||||
_stored_args[name] = component
|
||||
|
||||
for component in modular_args:
|
||||
label = getattr(component, 'label', None)
|
||||
value = getattr(component, 'value', None)
|
||||
|
||||
@@ -259,7 +259,8 @@ def create_ui(disabled_tabs=None):
|
||||
if item[1].section is not None and item[1].section[0] == section_id
|
||||
] # find all items in this section
|
||||
hidden = (section_id is None) or ('hidden' in section_id.lower()) or ('hidden' in section_text.lower()) or ('legacy' in section_id.lower()) or ('legacy' in section_text.lower())
|
||||
# log.trace(f'Settings: section="{section_id}" title="{section_text}" items={len(items)} hidden={hidden}')
|
||||
# for (key, _item) in items:
|
||||
# log.trace(f'Settings: id={section_id} text={section_text} key={key} hidden={hidden}')
|
||||
if hidden:
|
||||
for (key, _item) in items:
|
||||
hidden_list.append(key)
|
||||
|
||||
@@ -23,13 +23,13 @@ sort = '⇕'
|
||||
detect = '📐'
|
||||
folder = '📂'
|
||||
random = '🎲️'
|
||||
reuse = '♻️'
|
||||
info = 'ℹ' # noqa
|
||||
reset = '🔄'
|
||||
upload = '⬆️'
|
||||
loading = '↺'
|
||||
reuse = '⬅️'
|
||||
search = '🔍'
|
||||
tools = '🛠'
|
||||
preview = '🖼️'
|
||||
image = '🖌️'
|
||||
resize = '⁜'
|
||||
|
||||
+42
-25
@@ -6,6 +6,7 @@ import installer as i
|
||||
version = SimpleNamespace(**{
|
||||
'url': '',
|
||||
'branch': '',
|
||||
'origin': '',
|
||||
'current': '0000-00-00',
|
||||
'chash': '0000000',
|
||||
'latest': '0000-00-00',
|
||||
@@ -14,34 +15,50 @@ version = SimpleNamespace(**{
|
||||
|
||||
|
||||
def get_version():
|
||||
# try:
|
||||
origin = i.git('remote get-url origin')
|
||||
origin = origin.splitlines()[0]
|
||||
version.branch = i.git('rev-parse --abbrev-ref HEAD')
|
||||
version.branch = version.branch.splitlines()[0]
|
||||
version.url = origin.removesuffix('.git') + '/tree/' + version.branch
|
||||
try:
|
||||
origin = i.git('remote get-url origin')
|
||||
origin = origin.splitlines()
|
||||
if len(origin) > 0:
|
||||
version.origin = origin[0]
|
||||
version.url = version.origin.removesuffix('.git') + '/tree/' + version.branch
|
||||
else:
|
||||
version.origin = 'unknown'
|
||||
i.log.warning('Version: origin URL not found')
|
||||
|
||||
ver = i.git('log --pretty=format:"%h %ad" -1 --date=short')
|
||||
ver = ver.splitlines()[0]
|
||||
version.chash, version.current = ver.split(' ')
|
||||
branch = i.git('rev-parse --abbrev-ref HEAD')
|
||||
branch = branch.splitlines()
|
||||
if len(branch) > 0:
|
||||
version.branch = branch[0]
|
||||
else:
|
||||
version.branch = 'unknown'
|
||||
i.log.warning('Version: branch not found')
|
||||
|
||||
i.git('fetch')
|
||||
ver = i.git(f'log origin/{version.branch} --pretty=format:"%h %ad" -1 --date=short')
|
||||
ver = ver.splitlines()[0]
|
||||
version.lhash, version.latest = ver.split(' ')
|
||||
gitlog = i.git('log --pretty=format:"%h %ad" -1 --date=short')
|
||||
gitlog = gitlog.splitlines()
|
||||
if len(gitlog) > 0:
|
||||
version.chash, version.current = gitlog[0].split(' ')
|
||||
|
||||
# except Exception as e:
|
||||
# i.log.error(f'Version check failed: {e}')
|
||||
i.log.info(f'Version: {vars(version)}')
|
||||
latest = '<div style="color: var(--secondary-500)">You\'re up to date!</div>' if version.chash == version.lhash else '<div style="color: var(--secondary-500)">Update available!</div>'
|
||||
html = f'''
|
||||
<div>URL: <a href="{version.url}" target="_blank">{version.url}</a></div>
|
||||
<div>Current branch: <span style="color: var(--highlight-color)">{version.branch}</span></div>
|
||||
<div>Current version: <span style="color: var(--highlight-color)">{version.current}</span> hash <span style="color: var(--highlight-color)">{version.chash}</span></div>
|
||||
<div>Latest version: <span style="color: var(--highlight-color)">{version.latest}</span> hash <span style="color: var(--highlight-color)">{version.lhash}</span></div>
|
||||
{latest}
|
||||
'''
|
||||
return html
|
||||
i.git('fetch')
|
||||
ver = i.git(f'log origin/{version.branch} --pretty=format:"%h %ad" -1 --date=short')
|
||||
ver = ver.splitlines()
|
||||
if len(ver) > 0 and ' ' in ver[0]:
|
||||
version.lhash, version.latest = ver[0].split(' ')
|
||||
|
||||
i.log.info(f'Version: {vars(version)}')
|
||||
latest = '<div style="color: var(--secondary-500)">You\'re up to date!</div>' if version.chash == version.lhash else '<div style="color: var(--secondary-500)">Update available!</div>'
|
||||
html = f'''
|
||||
<div>URL: <a href="{version.url}" target="_blank">{version.url}</a></div>
|
||||
<div>Origin: <span style="color: var(--highlight-color)">{version.origin}</span></div>
|
||||
<div>Current branch: <span style="color: var(--highlight-color)">{version.branch}</span></div>
|
||||
<div>Current version: <span style="color: var(--highlight-color)">{version.current}</span> hash <span style="color: var(--highlight-color)">{version.chash}</span></div>
|
||||
<div>Latest version: <span style="color: var(--highlight-color)">{version.latest}</span> hash <span style="color: var(--highlight-color)">{version.lhash}</span></div>
|
||||
{latest}
|
||||
'''
|
||||
return html
|
||||
except Exception as e:
|
||||
i.log.error(f'Version: {e}')
|
||||
html = f'<div style="color: var(--error-color)">Error while detecting version<br>{str(e)}</div>'
|
||||
return html
|
||||
|
||||
|
||||
def apply_update(update_rebase, update_submodules, update_extensions):
|
||||
|
||||
@@ -723,6 +723,30 @@ try:
|
||||
image_hijack=False,
|
||||
vae_hijack=False,
|
||||
vae_remote=False),
|
||||
Model(name='MiniMax H3 Pruned SDNQ uint8',
|
||||
url='https://huggingface.co/MiniMaxAI/MiniMax-H3',
|
||||
repo='OzzyGT/MiniMax_H3_sdnq_8bit_pruned',
|
||||
repo_cls='MiniMaxH3ModularPipeline',
|
||||
workflow='fl2va',
|
||||
base=True,
|
||||
te_cls=None,
|
||||
dit_cls=None,
|
||||
te_hijack=False,
|
||||
image_hijack=False,
|
||||
vae_hijack=False,
|
||||
vae_remote=False),
|
||||
Model(name='MiniMax H3 Pruned SDNQ uint8 Ref2VA',
|
||||
url='https://huggingface.co/MiniMaxAI/MiniMax-H3',
|
||||
repo='OzzyGT/MiniMax_H3_sdnq_8bit_pruned',
|
||||
repo_cls='MiniMaxH3ModularPipeline',
|
||||
workflow='ref2va',
|
||||
base=True,
|
||||
te_cls=None,
|
||||
dit_cls=None,
|
||||
te_hijack=False,
|
||||
image_hijack=False,
|
||||
vae_hijack=False,
|
||||
vae_remote=False),
|
||||
Model(name='MiniMax H3',
|
||||
url='https://huggingface.co/MiniMaxAI/MiniMax-H3',
|
||||
repo='MiniMaxAI/MiniMax-H3',
|
||||
@@ -747,6 +771,18 @@ try:
|
||||
image_hijack=False,
|
||||
vae_hijack=False,
|
||||
vae_remote=False),
|
||||
Model(name='MiniMax H3 VDN',
|
||||
url='https://huggingface.co/OpenVDN/vdn-minimax-h3',
|
||||
repo='OpenVDN/vdn-minimax-h3',
|
||||
repo_cls='MiniMaxH3ModularPipeline',
|
||||
workflow='fl2va',
|
||||
base=True,
|
||||
te_cls=None,
|
||||
dit_cls=None,
|
||||
te_hijack=False,
|
||||
image_hijack=False,
|
||||
vae_hijack=False,
|
||||
vae_remote=False),
|
||||
],
|
||||
'Google Veo': [
|
||||
Model(name='Google Veo 3.1 T2V',
|
||||
|
||||
@@ -25,7 +25,7 @@ def apply_overrides(p, pipe, still: bool = False, audio: bool = True):
|
||||
while frames > max_frames:
|
||||
frames -= pipe.vae_frames_per_chunk
|
||||
if frames != getattr(p, 'frames', None):
|
||||
log.debug(f'Pipeline: cls={pipe.__class__.__name__} frames={getattr(p, "frames", None)} aligned={frames}')
|
||||
log.debug(f'Pipeline: cls={pipe.__class__.__name__} frames requested={getattr(p, "frames", None)} aligned={frames}')
|
||||
p.frames = frames
|
||||
p.task_args['num_frames'] = frames
|
||||
p.steps = max(2, p.steps)
|
||||
|
||||
Reference in New Issue
Block a user