Expose latent upscale sampler controls
This commit is contained in:
@@ -1162,13 +1162,14 @@ What this really means:
|
|||||||
- the node renders the beat once
|
- the node renders the beat once
|
||||||
- the sampled latent is upscaled in latent space to the target size
|
- the sampled latent is upscaled in latent space to the target size
|
||||||
- the conditioning is rebuilt at that target size
|
- the conditioning is rebuilt at that target size
|
||||||
- the node then runs a hard-coded 2-step refinement pass over the upscaled latent
|
- the node then runs a short refinement pass over the upscaled latent with the sampler, scheduler, step count, denoise, and megapixel target you picked on the latent-upscale params node
|
||||||
|
|
||||||
Good starting point:
|
Good starting point:
|
||||||
|
|
||||||
- use the `model` mode when you want the strongest latent detail recovery
|
- use the `model` mode when you want the strongest latent detail recovery
|
||||||
- use the interpolation mode when you want a cheaper resize-only path
|
- use the interpolation mode when you want a cheaper resize-only path
|
||||||
- keep the refinement denoise low to medium
|
- start with `euler_ancestral`, `simple`, `2` steps, and `0.2` denoise
|
||||||
|
- leave width and height at `0` unless you want an exact override; otherwise `megapixels` drives the target size
|
||||||
|
|
||||||
The important part is that this stage is still a latent pass, not a pixel-space resize:
|
The important part is that this stage is still a latent pass, not a pixel-space resize:
|
||||||
|
|
||||||
|
|||||||
@@ -47,9 +47,9 @@
|
|||||||
- Per-shot directives now support `continuity:`, `ref_mode:`, `ref_noise_aug:`, `anchor_add:`, `soundscape:`, and `music:` in addition to the existing timing and wardrobe directives.
|
- Per-shot directives now support `continuity:`, `ref_mode:`, `ref_noise_aug:`, `anchor_add:`, `soundscape:`, and `music:` in addition to the existing timing and wardrobe directives.
|
||||||
|
|
||||||
- `Dumas H3 Latent Upscale Params`
|
- `Dumas H3 Latent Upscale Params`
|
||||||
- Inputs: `mode`, `model_name`, `method`, `width`, `height`, `device`, `precision`, `refine_denoise`
|
- Inputs: `mode`, `model_name`, `method`, `width`, `height`, `device`, `precision`, `sampler_name`, `scheduler`, `steps`, `denoise`, `megapixels`
|
||||||
- Output: `latent_upscale_param`
|
- Output: `latent_upscale_param`
|
||||||
- Bundles the optional latent-space upscaler settings used by `Dumas H3 Long Videos` before decode, so the main node can rebuild conditioning at the target size and run a short refinement pass.
|
- Bundles the optional latent-space upscaler settings used by `Dumas H3 Long Videos` before decode, so the main node can rebuild conditioning at the target size and run a short refinement pass with your chosen sampler, scheduler, step count, and denoise.
|
||||||
|
|
||||||
- `Dumas H3 Beat Prompt`
|
- `Dumas H3 Beat Prompt`
|
||||||
- Inputs: authored through the custom front-end beat editor
|
- Inputs: authored through the custom front-end beat editor
|
||||||
|
|||||||
+58
-13
@@ -4,6 +4,7 @@ import math
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
import comfy.samplers
|
||||||
import folder_paths
|
import folder_paths
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
@@ -33,6 +34,8 @@ LATENTS_STD = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
_LATENT_UPSCALE_FOLDER = "latent_upscale_models"
|
_LATENT_UPSCALE_FOLDER = "latent_upscale_models"
|
||||||
|
MP_UNIT = 1024 * 1024
|
||||||
|
RES_MULTIPLE = 32
|
||||||
|
|
||||||
|
|
||||||
def _models_dir():
|
def _models_dir():
|
||||||
@@ -347,10 +350,29 @@ def _compute_upscale_target(width, height, h_in, w_in):
|
|||||||
return h_out, w_out, eff
|
return h_out, w_out, eff
|
||||||
|
|
||||||
|
|
||||||
|
def _scale_to_megapixels(w, h, mp, multiple=RES_MULTIPLE):
|
||||||
|
if not mp or mp <= 0 or w <= 0 or h <= 0:
|
||||||
|
return int(h), int(w)
|
||||||
|
multiple = max(1, int(multiple))
|
||||||
|
scale = math.sqrt((float(mp) * MP_UNIT) / float(w * h))
|
||||||
|
nw = max(multiple, int(round(w * scale / multiple)) * multiple)
|
||||||
|
nh = max(multiple, int(round(h * scale / multiple)) * multiple)
|
||||||
|
return nh, nw
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_target_size(param, h_in, w_in):
|
||||||
|
width = int(param.get("width", 0) or 0)
|
||||||
|
height = int(param.get("height", 0) or 0)
|
||||||
|
megapixels = float(param.get("megapixels", 0.0) or 0.0)
|
||||||
|
if width > 0 and height > 0:
|
||||||
|
return height, width
|
||||||
|
if megapixels > 0:
|
||||||
|
return _scale_to_megapixels(w_in, h_in, megapixels)
|
||||||
|
return int(h_in), int(w_in)
|
||||||
|
|
||||||
|
|
||||||
def upscale_video_model(video, param):
|
def upscale_video_model(video, param):
|
||||||
model_name = param["model_name"]
|
model_name = param["model_name"]
|
||||||
width = int(param["width"])
|
|
||||||
height = int(param["height"])
|
|
||||||
device = param.get("device", "cuda")
|
device = param.get("device", "cuda")
|
||||||
precision = param.get("precision", "fp16")
|
precision = param.get("precision", "fp16")
|
||||||
|
|
||||||
@@ -359,7 +381,8 @@ def upscale_video_model(video, param):
|
|||||||
compute_dtype = {"fp32": torch.float32, "fp16": torch.float16, "bf16": torch.bfloat16}[precision]
|
compute_dtype = {"fp32": torch.float32, "fp16": torch.float16, "bf16": torch.bfloat16}[precision]
|
||||||
|
|
||||||
_, c, t, h_in, w_in = video.shape
|
_, c, t, h_in, w_in = video.shape
|
||||||
h_out, w_out, eff = _compute_upscale_target(width, height, h_in, w_in)
|
h_out, w_out = _resolve_target_size(param, h_in, w_in)
|
||||||
|
eff = (w_out / float(w_in) + h_out / float(h_in)) / 2.0 if w_in and h_in else 1.0
|
||||||
|
|
||||||
if eff < 1.0 and (w_out < w_in or h_out < h_in):
|
if eff < 1.0 and (w_out < w_in or h_out < h_in):
|
||||||
raise ValueError("This model only supports upscaling (effective scale >= 1.0).")
|
raise ValueError("This model only supports upscaling (effective scale >= 1.0).")
|
||||||
@@ -386,10 +409,8 @@ def upscale_video_model(video, param):
|
|||||||
|
|
||||||
def upscale_video_interp(video, param):
|
def upscale_video_interp(video, param):
|
||||||
method = str(param.get("method") or "bilinear")
|
method = str(param.get("method") or "bilinear")
|
||||||
width = int(param.get("width", 0) or 0)
|
|
||||||
height = int(param.get("height", 0) or 0)
|
|
||||||
_, c, t, h_in, w_in = video.shape
|
_, c, t, h_in, w_in = video.shape
|
||||||
h_out, w_out, _ = _compute_upscale_target(width, height, h_in, w_in)
|
h_out, w_out = _resolve_target_size(param, h_in, w_in)
|
||||||
if h_out == h_in and w_out == w_in:
|
if h_out == h_in and w_out == w_in:
|
||||||
return video, h_in, w_in
|
return video, h_in, w_in
|
||||||
video_bt = video.permute(0, 2, 1, 3, 4).reshape(-1, c, h_in, w_in)
|
video_bt = video.permute(0, 2, 1, 3, 4).reshape(-1, c, h_in, w_in)
|
||||||
@@ -425,23 +446,42 @@ class H3LatentUpscaleParams:
|
|||||||
"method": (["nearest-exact", "bilinear", "area", "bicubic"], {"default": "bilinear",
|
"method": (["nearest-exact", "bilinear", "area", "bicubic"], {"default": "bilinear",
|
||||||
"tooltip": "Interpolation method used when mode = interp."}),
|
"tooltip": "Interpolation method used when mode = interp."}),
|
||||||
"width": ("INT", {"default": 0, "min": 0, "max": 4096, "step": 32,
|
"width": ("INT", {"default": 0, "min": 0, "max": 4096, "step": 32,
|
||||||
"tooltip": "Target upscaled pixel width for the latent refinement stage. 0 keeps the original width and effectively disables the resize."}),
|
"tooltip": "Explicit target width for the latent refinement stage. Leave at 0 to let megapixels choose the size instead."}),
|
||||||
"height": ("INT", {"default": 0, "min": 0, "max": 4096, "step": 32,
|
"height": ("INT", {"default": 0, "min": 0, "max": 4096, "step": 32,
|
||||||
"tooltip": "Target upscaled pixel height for the latent refinement stage. 0 keeps the original height and effectively disables the resize."}),
|
"tooltip": "Explicit target height for the latent refinement stage. Leave at 0 to let megapixels choose the size instead."}),
|
||||||
"device": (["cuda", "cpu"], {"default": "cuda",
|
"device": (["cuda", "cpu"], {"default": "cuda",
|
||||||
"tooltip": "Device used by the H3 latent upscaler model when mode = model."}),
|
"tooltip": "Device used by the H3 latent upscaler model when mode = model."}),
|
||||||
"precision": (["fp16", "fp32", "bf16"], {"default": "fp16",
|
"precision": (["fp16", "fp32", "bf16"], {"default": "fp16",
|
||||||
"tooltip": "Computation precision used by the H3 latent upscaler model when mode = model."}),
|
"tooltip": "Computation precision used by the H3 latent upscaler model when mode = model."}),
|
||||||
"refine_denoise": ("FLOAT", {"default": 0.25, "min": 0.0, "max": 1.0, "step": 0.01,
|
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, {"default": "euler_ancestral",
|
||||||
"tooltip": "How much the 2-step refinement pass may rewrite the upscaled latent. Lower = safer, higher = freer."}),
|
"tooltip": "Sampler used for the latent refinement pass. Default matches the current H3 preference."}),
|
||||||
|
"scheduler": (comfy.samplers.KSampler.SCHEDULERS, {"default": "simple",
|
||||||
|
"tooltip": "Scheduler used for the latent refinement pass."}),
|
||||||
|
"steps": ("INT", {"default": 2, "min": 1, "max": 50, "step": 1,
|
||||||
|
"tooltip": "Number of refinement steps applied after the latent upscaler stage."}),
|
||||||
|
"denoise": ("FLOAT", {"default": 0.2, "min": 0.0, "max": 1.0, "step": 0.01,
|
||||||
|
"tooltip": "How much the refinement pass may rewrite the upscaled latent. Lower = safer, higher = freer."}),
|
||||||
|
"megapixels": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 4.0, "step": 0.01,
|
||||||
|
"tooltip": "Primary target size for the latent refinement stage. If width and height are both set, they win; otherwise the node scales the current shot to this pixel budget while preserving aspect ratio. 0 keeps the incoming latent size."}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def build(self, mode, model_name, method, width, height, device, precision, refine_denoise):
|
def build(self, mode, model_name, method, width, height, device, precision, sampler_name, scheduler, steps, denoise, megapixels):
|
||||||
width = int(width)
|
width = int(width)
|
||||||
height = int(height)
|
height = int(height)
|
||||||
|
steps = int(steps)
|
||||||
if mode == "off":
|
if mode == "off":
|
||||||
return ({"mode": "off", "width": width, "height": height, "refine_denoise": float(refine_denoise)},)
|
return ({
|
||||||
|
"mode": "off",
|
||||||
|
"width": width,
|
||||||
|
"height": height,
|
||||||
|
"sampler_name": sampler_name,
|
||||||
|
"scheduler": scheduler,
|
||||||
|
"steps": steps,
|
||||||
|
"denoise": float(denoise),
|
||||||
|
"refine_denoise": float(denoise),
|
||||||
|
"megapixels": float(megapixels),
|
||||||
|
},)
|
||||||
if width > 0:
|
if width > 0:
|
||||||
width = int(round(width / 32.0)) * 32
|
width = int(round(width / 32.0)) * 32
|
||||||
if height > 0:
|
if height > 0:
|
||||||
@@ -454,7 +494,12 @@ class H3LatentUpscaleParams:
|
|||||||
"height": height,
|
"height": height,
|
||||||
"device": device,
|
"device": device,
|
||||||
"precision": precision,
|
"precision": precision,
|
||||||
"refine_denoise": float(refine_denoise),
|
"sampler_name": sampler_name,
|
||||||
|
"scheduler": scheduler,
|
||||||
|
"steps": steps,
|
||||||
|
"denoise": float(denoise),
|
||||||
|
"refine_denoise": float(denoise),
|
||||||
|
"megapixels": float(megapixels),
|
||||||
},)
|
},)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+45
-28
@@ -33,9 +33,9 @@ and your VRAM, chains them, and returns the finished video + audio.
|
|||||||
Requirements: H3 is CFG-free (cfg 1) and needs no negative prompt -- the node
|
Requirements: H3 is CFG-free (cfg 1) and needs no negative prompt -- the node
|
||||||
makes an empty one internally. The main pass keeps denoise fixed at 1.0: a
|
makes an empty one internally. The main pass keeps denoise fixed at 1.0: a
|
||||||
partial denoise desyncs the joint audio/video schedule. An optional latent
|
partial denoise desyncs the joint audio/video schedule. An optional latent
|
||||||
upscale stage can rebuild the conditioning at a larger target size, run a short
|
upscale stage can rebuild the conditioning at a target size, run a short
|
||||||
refinement pass, and keep the output video-only before the final pixel-space
|
refinement pass with its own sampler controls, and keep the output video-only
|
||||||
upscale options.
|
before the final pixel-space upscale options.
|
||||||
|
|
||||||
Verified against ComfyUI core (comfy_extras/nodes_minimax_h3.py, model_base.py,
|
Verified against ComfyUI core (comfy_extras/nodes_minimax_h3.py, model_base.py,
|
||||||
ldm/minimax/model.py, text_encoders/minimax.py, sd.py).
|
ldm/minimax/model.py, text_encoders/minimax.py, sd.py).
|
||||||
@@ -4068,11 +4068,22 @@ def _video_only_refined_latent(base_latent, refined_latent):
|
|||||||
refined_parts = refined.unbind()
|
refined_parts = refined.unbind()
|
||||||
if len(base_parts) >= 2 and len(refined_parts) >= 1:
|
if len(base_parts) >= 2 and len(refined_parts) >= 1:
|
||||||
return {"samples": comfy.nested_tensor.NestedTensor((refined_parts[0], base_parts[-1]))}
|
return {"samples": comfy.nested_tensor.NestedTensor((refined_parts[0], base_parts[-1]))}
|
||||||
except Exception:
|
except Exception:
|
||||||
return refined_latent
|
return refined_latent
|
||||||
return refined_latent
|
return refined_latent
|
||||||
|
|
||||||
|
|
||||||
|
def _latent_upscale_target_size(base_w, base_h, param):
|
||||||
|
width = int(param.get("width", 0) or 0)
|
||||||
|
height = int(param.get("height", 0) or 0)
|
||||||
|
if width > 0 and height > 0:
|
||||||
|
return width, height
|
||||||
|
megapixels = float(param.get("megapixels", 0.0) or 0.0)
|
||||||
|
if megapixels > 0:
|
||||||
|
return scale_to_megapixels(base_w, base_h, megapixels)
|
||||||
|
return int(base_w), int(base_h)
|
||||||
|
|
||||||
|
|
||||||
def _nested_tensor_parts(samples):
|
def _nested_tensor_parts(samples):
|
||||||
if samples is None:
|
if samples is None:
|
||||||
return ()
|
return ()
|
||||||
@@ -6107,8 +6118,9 @@ class H3LongVideos:
|
|||||||
"Try 256 on a tight card at 1344x768."}),
|
"Try 256 on a tight card at 1344x768."}),
|
||||||
"latent_upscale_param": ("DUMAS_H3_LATENT_UPSCALE_PARAM", {
|
"latent_upscale_param": ("DUMAS_H3_LATENT_UPSCALE_PARAM", {
|
||||||
"tooltip": "Output of 'Dumas H3 Latent Upscale Params'. When connected, the first-pass "
|
"tooltip": "Output of 'Dumas H3 Latent Upscale Params'. When connected, the first-pass "
|
||||||
"latent is upscaled and run through a hard-coded 2-step refinement pass before "
|
"latent is upscaled and run through a short refinement pass before decode, "
|
||||||
"decode. Leave unconnected to skip latent upscaling entirely."}),
|
"using the sampler, scheduler, steps, denoise, and megapixel target from that node. "
|
||||||
|
"Leave unconnected to skip latent upscaling entirely."}),
|
||||||
"upscale": (["off", "rtx", "model", "lanczos"], {"default": "off",
|
"upscale": (["off", "rtx", "model", "lanczos"], {"default": "off",
|
||||||
"tooltip": "Optional post-pass on the finished frames. 'rtx' = NVIDIA RTX Video Super "
|
"tooltip": "Optional post-pass on the finished frames. 'rtx' = NVIDIA RTX Video Super "
|
||||||
"Resolution (Tensor Cores -- fastest and best for video; needs the "
|
"Resolution (Tensor Cores -- fastest and best for video; needs the "
|
||||||
@@ -6422,11 +6434,11 @@ class H3LongVideos:
|
|||||||
# Conditioning is built, so the text encoder and VAEs are dead weight for the
|
# Conditioning is built, so the text encoder and VAEs are dead weight for the
|
||||||
# whole sampling loop -- evict them and keep only the DiT on the card.
|
# whole sampling loop -- evict them and keep only the DiT on the card.
|
||||||
_evict_all_but(model)
|
_evict_all_but(model)
|
||||||
try:
|
try:
|
||||||
sample_start = time.perf_counter()
|
sample_start = time.perf_counter()
|
||||||
(out,) = nodes.common_ksampler(model, seed, steps, cfg, sn, sch, positive, negative,
|
(out,) = nodes.common_ksampler(model, seed, steps, cfg, sn, sch, positive, negative,
|
||||||
latent, denoise=denoise)
|
latent, denoise=denoise)
|
||||||
timing["sample"] += time.perf_counter() - sample_start
|
timing["sample"] += time.perf_counter() - sample_start
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Mark WHERE this failed. `tiled` only affects the DECODE, so the caller's
|
# Mark WHERE this failed. `tiled` only affects the DECODE, so the caller's
|
||||||
# OOM retry cannot help an OOM raised here -- it just re-runs the whole
|
# OOM retry cannot help an OOM raised here -- it just re-runs the whole
|
||||||
@@ -6440,8 +6452,6 @@ class H3LongVideos:
|
|||||||
if (
|
if (
|
||||||
isinstance(latent_upscale_param, dict)
|
isinstance(latent_upscale_param, dict)
|
||||||
and str(latent_upscale_param.get("mode", "off")) != "off"
|
and str(latent_upscale_param.get("mode", "off")) != "off"
|
||||||
and int(latent_upscale_param.get("width", 0) or 0) > 0
|
|
||||||
and int(latent_upscale_param.get("height", 0) or 0) > 0
|
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
latent_start = time.perf_counter()
|
latent_start = time.perf_counter()
|
||||||
@@ -6463,9 +6473,14 @@ class H3LongVideos:
|
|||||||
ref_noise_aug=ref_noise_aug, audio_vae=audio_vae, silent=silent)
|
ref_noise_aug=ref_noise_aug, audio_vae=audio_vae, silent=silent)
|
||||||
upscale_latent["samples"] = comfy.nested_tensor.NestedTensor(
|
upscale_latent["samples"] = comfy.nested_tensor.NestedTensor(
|
||||||
(upscaled_video, parts[1]))
|
(upscaled_video, parts[1]))
|
||||||
|
refine_steps = int(latent_upscale_param.get("steps", 2) or 2)
|
||||||
|
refine_sampler = latent_upscale_param.get("sampler_name", sn)
|
||||||
|
refine_scheduler = latent_upscale_param.get("scheduler", sch)
|
||||||
|
refine_denoise_value = latent_upscale_param.get("denoise", latent_upscale_param.get("refine_denoise", 0.2))
|
||||||
|
refine_denoise = 0.2 if refine_denoise_value is None else float(refine_denoise_value)
|
||||||
(refined_out,) = nodes.common_ksampler(
|
(refined_out,) = nodes.common_ksampler(
|
||||||
model, seed, 2, cfg, sn, sch, upscale_cond, negative, upscale_latent,
|
model, seed, refine_steps, cfg, refine_sampler, refine_scheduler, upscale_cond, negative, upscale_latent,
|
||||||
denoise=float(latent_upscale_param.get("refine_denoise", 0.25) or 0.25))
|
denoise=refine_denoise)
|
||||||
timing["latent_upscale_sample"] += time.perf_counter() - latent_start
|
timing["latent_upscale_sample"] += time.perf_counter() - latent_start
|
||||||
refined_out = _video_only_refined_latent(out, refined_out)
|
refined_out = _video_only_refined_latent(out, refined_out)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -6591,19 +6606,21 @@ class H3LongVideos:
|
|||||||
model, ms_note = apply_h3_model_sampling(model, shift_video, shift_audio)
|
model, ms_note = apply_h3_model_sampling(model, shift_video, shift_audio)
|
||||||
latent_upscale_note = ""
|
latent_upscale_note = ""
|
||||||
if isinstance(latent_upscale_param, dict) and str(latent_upscale_param.get("mode", "off")) != "off":
|
if isinstance(latent_upscale_param, dict) and str(latent_upscale_param.get("mode", "off")) != "off":
|
||||||
target_w = int(latent_upscale_param.get("width", 0) or 0)
|
target_w, target_h = _latent_upscale_target_size(w, h, latent_upscale_param)
|
||||||
target_h = int(latent_upscale_param.get("height", 0) or 0)
|
mode = str(latent_upscale_param.get("mode", "off"))
|
||||||
if target_w > 0 and target_h > 0:
|
detail = f" via {mode}"
|
||||||
mode = str(latent_upscale_param.get("mode", "off"))
|
if mode == "model":
|
||||||
detail = f" via {mode}"
|
detail += f"/{latent_upscale_param.get('model_name', 'none')}"
|
||||||
if mode == "model":
|
else:
|
||||||
detail += f"/{latent_upscale_param.get('model_name', 'none')}"
|
detail += f"/{latent_upscale_param.get('method', 'bilinear')}"
|
||||||
else:
|
denoise_value = latent_upscale_param.get("denoise", latent_upscale_param.get("refine_denoise", 0.2))
|
||||||
detail += f"/{latent_upscale_param.get('method', 'bilinear')}"
|
denoise = 0.2 if denoise_value is None else float(denoise_value)
|
||||||
latent_upscale_note = (
|
latent_upscale_note = (
|
||||||
f" latent upscale: target {target_w}x{target_h}px{detail}; "
|
f" latent upscale: target {target_w}x{target_h}px{detail}; "
|
||||||
f"2-step refinement denoise {float(latent_upscale_param.get('refine_denoise', 0.25) or 0.25):.2f}"
|
f"{int(latent_upscale_param.get('steps', 2) or 2)}-step refinement "
|
||||||
)
|
f"{latent_upscale_param.get('sampler_name', sn)}/{latent_upscale_param.get('scheduler', sch)} "
|
||||||
|
f"denoise {denoise:.2f}"
|
||||||
|
)
|
||||||
|
|
||||||
paras = split_paragraphs(prompt, "##")
|
paras = split_paragraphs(prompt, "##")
|
||||||
if anchor_override.strip():
|
if anchor_override.strip():
|
||||||
|
|||||||
@@ -306,18 +306,21 @@ class DumasH3LongVideosHelperTests(unittest.TestCase):
|
|||||||
latent_upscale_param={
|
latent_upscale_param={
|
||||||
"mode": "model",
|
"mode": "model",
|
||||||
"model_name": "upscale.safetensors",
|
"model_name": "upscale.safetensors",
|
||||||
"width": 256,
|
|
||||||
"height": 128,
|
|
||||||
"device": "cpu",
|
"device": "cpu",
|
||||||
"precision": "fp16",
|
"precision": "fp16",
|
||||||
"refine_denoise": 0.4,
|
"sampler_name": "euler_ancestral",
|
||||||
|
"scheduler": "simple",
|
||||||
|
"steps": 2,
|
||||||
|
"denoise": 0.4,
|
||||||
|
"megapixels": 1.5,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(len(calls), 2)
|
self.assertEqual(len(calls), 2)
|
||||||
self.assertIsNot(calls[1][0][8], first_out)
|
self.assertIsNot(calls[1][0][8], first_out)
|
||||||
self.assertEqual(calls[1][0][8]["samples"].unbind()[0].name, "upv")
|
self.assertEqual(calls[1][0][8]["samples"].unbind()[0].name, "upv")
|
||||||
self.assertEqual(calls[1][0][4], "res_multistep")
|
self.assertEqual(calls[1][0][2], 2)
|
||||||
|
self.assertEqual(calls[1][0][4], "euler_ancestral")
|
||||||
self.assertEqual(calls[1][0][5], "simple")
|
self.assertEqual(calls[1][0][5], "simple")
|
||||||
self.assertAlmostEqual(calls[1][1]["denoise"], 0.4)
|
self.assertAlmostEqual(calls[1][1]["denoise"], 0.4)
|
||||||
self.assertEqual(result[1], first_out)
|
self.assertEqual(result[1], first_out)
|
||||||
@@ -424,11 +427,13 @@ class DumasH3LongVideosHelperTests(unittest.TestCase):
|
|||||||
latent_upscale_param={
|
latent_upscale_param={
|
||||||
"mode": "model",
|
"mode": "model",
|
||||||
"model_name": "upscale.safetensors",
|
"model_name": "upscale.safetensors",
|
||||||
"width": 256,
|
|
||||||
"height": 128,
|
|
||||||
"device": "cpu",
|
"device": "cpu",
|
||||||
"precision": "fp16",
|
"precision": "fp16",
|
||||||
"refine_denoise": 0.4,
|
"sampler_name": "euler_ancestral",
|
||||||
|
"scheduler": "simple",
|
||||||
|
"steps": 2,
|
||||||
|
"denoise": 0.4,
|
||||||
|
"megapixels": 1.5,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1096,6 +1101,7 @@ class DumasH3LongVideosHelperTests(unittest.TestCase):
|
|||||||
|
|
||||||
def test_latent_upscale_params_node_is_exposed(self):
|
def test_latent_upscale_params_node_is_exposed(self):
|
||||||
latent = importlib.import_module("dumas_h3_latent_upscale")
|
latent = importlib.import_module("dumas_h3_latent_upscale")
|
||||||
|
required = latent.H3LatentUpscaleParams.INPUT_TYPES()["required"]
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
latent.NODE_CLASS_MAPPINGS,
|
latent.NODE_CLASS_MAPPINGS,
|
||||||
@@ -1105,6 +1111,11 @@ class DumasH3LongVideosHelperTests(unittest.TestCase):
|
|||||||
latent.NODE_DISPLAY_NAME_MAPPINGS,
|
latent.NODE_DISPLAY_NAME_MAPPINGS,
|
||||||
{"DumasH3LatentUpscaleParams": "Dumas H3 Latent Upscale Params"},
|
{"DumasH3LatentUpscaleParams": "Dumas H3 Latent Upscale Params"},
|
||||||
)
|
)
|
||||||
|
self.assertEqual(required["sampler_name"][1]["default"], "euler_ancestral")
|
||||||
|
self.assertEqual(required["scheduler"][1]["default"], "simple")
|
||||||
|
self.assertEqual(required["steps"][1]["default"], 2)
|
||||||
|
self.assertEqual(required["denoise"][1]["default"], 0.2)
|
||||||
|
self.assertEqual(required["megapixels"][1]["default"], 1.0)
|
||||||
|
|
||||||
def test_compose_persistent_does_not_expand_ambiguous_plural_to_full_cast(self):
|
def test_compose_persistent_does_not_expand_ambiguous_plural_to_full_cast(self):
|
||||||
active = self.module.parse_wardrobe(
|
active = self.module.parse_wardrobe(
|
||||||
|
|||||||
Reference in New Issue
Block a user