diff --git a/modules/extra_networks.py b/modules/extra_networks.py index 89acf5a4e..3d57d4d7f 100644 --- a/modules/extra_networks.py +++ b/modules/extra_networks.py @@ -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 diff --git a/modules/image/sharpfin.py b/modules/image/sharpfin.py index d8c8ef4e7..dbb1a7ab5 100644 --- a/modules/image/sharpfin.py +++ b/modules/image/sharpfin.py @@ -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: diff --git a/modules/lora/extra_networks_lora.py b/modules/lora/extra_networks_lora.py index e85771e3f..14e99351f 100644 --- a/modules/lora/extra_networks_lora.py +++ b/modules/lora/extra_networks_lora.py @@ -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) diff --git a/modules/lora/lora_load.py b/modules/lora/lora_load.py index 41764b32f..6eb0fd5b1 100644 --- a/modules/lora/lora_load.py +++ b/modules/lora/lora_load.py @@ -62,13 +62,13 @@ def load_safetensors(name, network_on_disk: network.NetworkOnDisk) -> network.Ne 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') + 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}') + 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) @@ -79,7 +79,7 @@ def load_safetensors(name, network_on_disk: network.NetworkOnDisk) -> network.Ne # fallback to standard network loading if l.debug: - log.trace(f'LoRA load: name="{name}" network_on_disk="{network_on_disk.filename}" safetensors') + 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') diff --git a/modules/lora/lora_overrides.py b/modules/lora/lora_overrides.py index d50229b10..cad8b514a 100644 --- a/modules/lora/lora_overrides.py +++ b/modules/lora/lora_overrides.py @@ -3,7 +3,7 @@ from modules import shared from modules.logger import log -debug_log = log.debug if os.environ.get('SD_LORA_DEBUG', None) is not None else lambda *args, **kwargs: None +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 diff --git a/modules/minimax/minimax_video.py b/modules/minimax/minimax_video.py index 5e4592328..85d86fd73 100644 --- a/modules/minimax/minimax_video.py +++ b/modules/minimax/minimax_video.py @@ -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, diff --git a/modules/styles.py b/modules/styles.py index 6fdbb672d..f5136f1a5 100644 --- a/modules/styles.py +++ b/modules/styles.py @@ -243,12 +243,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 +287,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: diff --git a/modules/video_models/video_minimax.py b/modules/video_models/video_minimax.py index 0f69af878..658ac1c75 100644 --- a/modules/video_models/video_minimax.py +++ b/modules/video_models/video_minimax.py @@ -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) diff --git a/scripts/prompt_enhance_ext.py b/scripts/prompt_enhance_ext.py index 1386f38bc..dfb4edba6 100644 --- a/scripts/prompt_enhance_ext.py +++ b/scripts/prompt_enhance_ext.py @@ -279,14 +279,16 @@ class PromptEnhanceScript(scripts_manager.Script): def get_image(self, image): current_image = None try: - if image is not None and isinstance(image, gr.Image): + if (image is not None) and isinstance(image, list) and len(image) > 0: + current_image = image[0] + if (image is not None) and isinstance(image, gr.Image): current_image = image.value - elif image is not None and isinstance(image, Image.Image): # if image is already a PIL image + elif (image is not None) and isinstance(image, Image.Image): # if image is already a PIL image current_image = image - if current_image is not None and (current_image.width <= 64 or current_image.height <= 64): + if (current_image is not None) and (current_image.width <= 64 or current_image.height <= 64): current_image = None # Fallback to Kanvas/Control input if no image from Gradio component (e.g., when Kanvas is active) - if current_image is None and ui_control_helpers.input_source is not None: + if (current_image is None) and (ui_control_helpers.input_source is not None): if isinstance(ui_control_helpers.input_source, list) and len(ui_control_helpers.input_source) > 0: current_image = ui_control_helpers.input_source[0] elif isinstance(ui_control_helpers.input_source, Image.Image): @@ -327,6 +329,8 @@ class PromptEnhanceScript(scripts_manager.Script): prompt = prompt or (self.prompt.value if self.prompt else "") # Check if self.prompt is None if use_vision and is_vision_model(model): # handle vision toggle image = image or self.image + else: + image = None prefix = prefix or '' suffix = suffix or '' min_tokens = min_tokens or self.options.min_tokens @@ -338,7 +342,7 @@ class PromptEnhanceScript(scripts_manager.Script): thinking = thinking or self.options.thinking_mode sample = sample if sample is not None else self.options.do_sample nsfw = nsfw if nsfw is not None else True # Default nsfw to True if not provided - debug_log(f'Prompt enhance: model="{model}" model_class="{self.llm.__class__.__name__ if self.llm is not None else "not loaded"}" nsfw={nsfw} thinking={thinking} prefill="{prefill[:30] if prefill else ""}" use_vision={use_vision} image={image is not None}') + debug_log(f'Prompt enhance: model="{model}" model_class="{self.llm.__class__.__name__ if self.llm is not None else "not loaded"}" nsfw={nsfw} thinking={thinking} prefill="{prefill[:30] if prefill else ""}" vision={use_vision} image={image}') while self.busy: time.sleep(0.1) @@ -395,8 +399,10 @@ class PromptEnhanceScript(scripts_manager.Script): self.busy = True if is_cloud_model(model): - has_prompt = prompt_text is not None and len(prompt_text) > 4 + has_prompt = (prompt_text is not None) and (len(prompt_text) > 4) + has_prefill = (prefill_text is not None) and (len(prefill_text) > 4) system = get_system_prompt(system, self.options, nsfw, has_prompt=has_prompt, is_video=self.parent=='video', is_image=current_image is not None) + debug_log(f'Prompt enhance: prompt="{prompt_text}"') if 'gemini' in model: from modules.caption import gemini kwargs = { @@ -407,7 +413,7 @@ class PromptEnhanceScript(scripts_manager.Script): model_name = model.replace('google/', '') response = gemini.predict(prompt_text, current_image, model_name, system, prefill_text, thinking, kwargs) t1 = time.time() - log.info(f'Prompt enhance: model="{model}" nsfw={nsfw} time={t1-t0:.2f} prefill="{prefill_text[:20] if prefill_text else None}" response={len(response)}') + log.info(f'Prompt enhance: model="{model}" nsfw={nsfw} time={t1-t0:.2f} prompt={has_prompt} prefill={has_prefill} image={current_image} thinking={thinking} response={len(response)}') debug_log(f'Prompt enhance: response="{response}"') self.busy = False return response @@ -419,7 +425,7 @@ class PromptEnhanceScript(scripts_manager.Script): model_name = model.replace('xai/', '') response = grok.predict(prompt_text, current_image, model_name, system, prefill_text, thinking, kwargs) t1 = time.time() - log.info(f'Prompt enhance: model="{model}" nsfw={nsfw} time={t1-t0:.2f} prefill="{prefill_text[:20] if prefill_text else None}" response={len(response)}') + log.info(f'Prompt enhance: model="{model}" nsfw={nsfw} time={t1-t0:.2f} prompt={has_prompt} prefill={has_prefill} image={current_image} thinking={thinking} response={len(response)}') debug_log(f'Prompt enhance: response="{response}"') self.busy = False return response @@ -730,10 +736,11 @@ class PromptEnhanceScript(scripts_manager.Script): jobid = shared.state.begin('LLM') p.extra_generation_params['LLM'] = get_model_repo_from_display(llm_model) p.extra_generation_params['Original'] = p.prompt + image = self_image or p.init_images p.prompt = self.enhance( prompt=p.prompt, seed=p.seed, - image=self_image, + image=image, prefix=prompt_prefix, suffix=prompt_suffix, model=llm_model,