Remove Ghost Mask reference mode
This commit is contained in:
@@ -58,7 +58,7 @@ This node uses Ollama Locally : you will need to install it (very lightweight) a
|
|||||||
|
|
||||||
- You can still enter your description manually if you don't want to install it but it works very well!
|
- You can still enter your description manually if you don't want to install it but it works very well!
|
||||||
|
|
||||||
- Both references mode work (fixed), Licon MSR and Ghost Mask.
|
- Reference mode included: Licon MSR.
|
||||||
|
|
||||||
- Use their Lora, that is an important step : https://huggingface.co/LiconStudio/LTX-2.3-Multiple-Subject-Reference/tree/main
|
- Use their Lora, that is an important step : https://huggingface.co/LiconStudio/LTX-2.3-Multiple-Subject-Reference/tree/main
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -2534,24 +2534,28 @@ class TimelineEditor {
|
|||||||
this.deleteBtn = deleteBtn;
|
this.deleteBtn = deleteBtn;
|
||||||
|
|
||||||
// --- Ref Option dropdown (sits to the right of Delete) ---
|
// --- Ref Option dropdown (sits to the right of Delete) ---
|
||||||
const refOptionSelect = document.createElement("select");
|
const refOptionSelect = document.createElement("select");
|
||||||
refOptionSelect.className = "prcs-ref-option-select";
|
refOptionSelect.className = "prcs-ref-option-select";
|
||||||
refOptionSelect.title = "Character reference mode";
|
refOptionSelect.title = "Character reference mode";
|
||||||
const REF_OPTIONS = [
|
const REF_OPTIONS = [
|
||||||
{ value: "Ghost Mask (End)", label: "Ghost Mask mode" },
|
{ value: "Licon MSR (Prefix)", label: "Licon MSR" },
|
||||||
{ value: "Licon MSR (Prefix)", label: "Licon MSR" },
|
{ value: "OFF", label: "OFF" },
|
||||||
{ value: "OFF", label: "OFF" },
|
];
|
||||||
];
|
REF_OPTIONS.forEach(opt => {
|
||||||
REF_OPTIONS.forEach(opt => {
|
const o = document.createElement("option");
|
||||||
const o = document.createElement("option");
|
o.value = opt.value;
|
||||||
o.value = opt.value;
|
o.textContent = opt.label;
|
||||||
o.textContent = opt.label;
|
refOptionSelect.appendChild(o);
|
||||||
refOptionSelect.appendChild(o);
|
});
|
||||||
});
|
const refOptionValues = new Set(REF_OPTIONS.map(opt => opt.value));
|
||||||
refOptionSelect.value = this.timeline.reference_mode || "OFF";
|
const initialRefMode = refOptionValues.has(this.timeline.reference_mode)
|
||||||
refOptionSelect.addEventListener("change", (e) => {
|
? this.timeline.reference_mode
|
||||||
this.timeline.reference_mode = e.target.value;
|
: "OFF";
|
||||||
this.commitChanges();
|
refOptionSelect.value = initialRefMode;
|
||||||
|
this.timeline.reference_mode = initialRefMode;
|
||||||
|
refOptionSelect.addEventListener("change", (e) => {
|
||||||
|
this.timeline.reference_mode = e.target.value;
|
||||||
|
this.commitChanges();
|
||||||
});
|
});
|
||||||
this.refOptionSelect = refOptionSelect;
|
this.refOptionSelect = refOptionSelect;
|
||||||
|
|
||||||
|
|||||||
@@ -1698,7 +1698,6 @@ def _build_reference_mode_outputs(
|
|||||||
clean_latent_frames: int,
|
clean_latent_frames: int,
|
||||||
reference_strength: float,
|
reference_strength: float,
|
||||||
optional_latent,
|
optional_latent,
|
||||||
ref_images,
|
|
||||||
resize_method: str,
|
resize_method: str,
|
||||||
divisible_by: int,
|
divisible_by: int,
|
||||||
prepare_tensor_image,
|
prepare_tensor_image,
|
||||||
@@ -1785,52 +1784,6 @@ def _build_reference_mode_outputs(
|
|||||||
)
|
)
|
||||||
return patched, conditioning, latent, out_guide_data
|
return patched, conditioning, latent, out_guide_data
|
||||||
|
|
||||||
extra_refs = []
|
|
||||||
if reference_mode == "Ghost Mask (End)" and ref_images is not None:
|
|
||||||
try:
|
|
||||||
for bi in range(ref_images.shape[0]):
|
|
||||||
extra_refs.append(ref_images[bi:bi + 1])
|
|
||||||
except Exception as e:
|
|
||||||
log.warning("[LTXDirector] Could not process ref_images input: %s", e)
|
|
||||||
|
|
||||||
ghost_refs = char_images + extra_refs
|
|
||||||
is_ghost = reference_mode == "Ghost Mask (End)" and bool(ghost_refs)
|
|
||||||
n_refs = len(ghost_refs) if is_ghost else 0
|
|
||||||
|
|
||||||
if is_ghost:
|
|
||||||
for i, single_ref in enumerate(ghost_refs):
|
|
||||||
ref_tensor = prepare_tensor_image(single_ref, latent_w, latent_h)
|
|
||||||
guide_data["images"].append(ref_tensor)
|
|
||||||
guide_data["insert_frames"].append((clean_latent_frames + i) * 8)
|
|
||||||
guide_data["strengths"].append(float(reference_strength))
|
|
||||||
guide_data["ghost_pre_extend"] = int(n_refs)
|
|
||||||
|
|
||||||
total_latent_frames = clean_latent_frames + n_refs
|
|
||||||
tail_pixels = n_refs * 8
|
|
||||||
local_part = local_prompts.strip() if local_prompts.strip() else global_prompt
|
|
||||||
clean_lengths = segment_lengths.strip() if segment_lengths.strip() else str(duration_frames)
|
|
||||||
injected_local = f"{local_part} | {global_prompt}"
|
|
||||||
injected_lengths = f"{clean_lengths},{tail_pixels}"
|
|
||||||
dummy_full = {"samples": torch.zeros([1, 128, total_latent_frames, latent_grid_h, latent_grid_w], device=_dev)}
|
|
||||||
patched, conditioning = _encode_relay(
|
|
||||||
model, clip, dummy_full, global_prompt, injected_local, injected_lengths, epsilon,
|
|
||||||
)
|
|
||||||
|
|
||||||
if optional_latent is None:
|
|
||||||
latent = {
|
|
||||||
"samples": torch.zeros([1, 128, clean_latent_frames, latent_grid_h, latent_grid_w], device=_dev),
|
|
||||||
"noise_mask": torch.ones((1, 1, clean_latent_frames, latent_grid_h, latent_grid_w), dtype=torch.float32, device=_dev),
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
latent = optional_latent
|
|
||||||
|
|
||||||
log.info(
|
|
||||||
"[LTXDirector] Ghost Mask: %d references; guide will hide them in a tail past "
|
|
||||||
"frame %d (clean_latent_frames=%d). Enable Clean Latent Slice (length=%d) downstream.",
|
|
||||||
n_refs, clean_latent_frames, clean_latent_frames, clean_latent_frames,
|
|
||||||
)
|
|
||||||
return patched, conditioning, latent, guide_data
|
|
||||||
|
|
||||||
if optional_latent is None:
|
if optional_latent is None:
|
||||||
latent = {"samples": torch.zeros([1, 128, clean_latent_frames, latent_grid_h, latent_grid_w], device=_dev)}
|
latent = {"samples": torch.zeros([1, 128, clean_latent_frames, latent_grid_h, latent_grid_w], device=_dev)}
|
||||||
log.info(
|
log.info(
|
||||||
@@ -2054,13 +2007,9 @@ class LTXDirector(io.ComfyNode):
|
|||||||
"vae", optional=True,
|
"vae", optional=True,
|
||||||
tooltip="Optional. Connect the LTX Autoencoder/VAE here to natively encode the MSR visual reference slideshow into the latent prefix. Required for the 'Licon MSR' ref option.",
|
tooltip="Optional. Connect the LTX Autoencoder/VAE here to natively encode the MSR visual reference slideshow into the latent prefix. Required for the 'Licon MSR' ref option.",
|
||||||
),
|
),
|
||||||
io.Float.Input(
|
io.Float.Input(
|
||||||
"reference_strength", default=1.0, min=0.0, max=5.0, step=0.05, optional=True,
|
"reference_strength", default=1.0, min=0.0, max=5.0, step=0.05, optional=True,
|
||||||
tooltip="Guide strength applied to the character reference images (Ghost Mask / Licon MSR ref options).",
|
tooltip="Guide strength applied to the character reference images when using Licon MSR.",
|
||||||
),
|
|
||||||
io.Image.Input(
|
|
||||||
"ref_images", optional=True,
|
|
||||||
tooltip="Ghost Mask only. Extra reference image(s) (e.g. an object) — a single image or a batch. Appended as their own block of hidden reference frames AFTER the @char references, for any number of characters loaded (0-6). Ignored in MSR / OFF modes.",
|
|
||||||
),
|
),
|
||||||
MSRCharacterSetData.Input(
|
MSRCharacterSetData.Input(
|
||||||
"character_set",
|
"character_set",
|
||||||
@@ -2107,7 +2056,7 @@ class LTXDirector(io.ComfyNode):
|
|||||||
custom_width=768, custom_height=512, resize_method="maintain aspect ratio",
|
custom_width=768, custom_height=512, resize_method="maintain aspect ratio",
|
||||||
divisible_by=32, img_compression=0, audio_vae=None, optional_latent=None,
|
divisible_by=32, img_compression=0, audio_vae=None, optional_latent=None,
|
||||||
use_custom_audio=False, inpaint_audio=True, use_custom_motion=True, override_audio=False,
|
use_custom_audio=False, inpaint_audio=True, use_custom_motion=True, override_audio=False,
|
||||||
vae=None, reference_strength=1.0, ref_images=None, character_set=None, timeline=None,
|
vae=None, reference_strength=1.0, character_set=None, timeline=None,
|
||||||
start=None, end=None, duration=None) -> io.NodeOutput:
|
start=None, end=None, duration=None) -> io.NodeOutput:
|
||||||
input_dir = folder_paths.get_input_directory()
|
input_dir = folder_paths.get_input_directory()
|
||||||
image_cache = {}
|
image_cache = {}
|
||||||
@@ -2182,9 +2131,12 @@ class LTXDirector(io.ComfyNode):
|
|||||||
log.info(f"[LTXDirector] execute RECEIVED global_prompt: {repr(global_prompt)}")
|
log.info(f"[LTXDirector] execute RECEIVED global_prompt: {repr(global_prompt)}")
|
||||||
|
|
||||||
# --- Reference option (set by the toolbar "Ref Option" dropdown, stored in timeline JSON) ---
|
# --- Reference option (set by the toolbar "Ref Option" dropdown, stored in timeline JSON) ---
|
||||||
# One of: "Ghost Mask (End)", "Licon MSR (Prefix)", "OFF".
|
# One of: "Licon MSR (Prefix)", "OFF".
|
||||||
reference_mode = tdata.get("reference_mode", "OFF")
|
reference_mode = tdata.get("reference_mode", "OFF")
|
||||||
|
if reference_mode not in {"Licon MSR (Prefix)", "OFF"}:
|
||||||
|
reference_mode = "OFF"
|
||||||
|
tdata["reference_mode"] = reference_mode
|
||||||
|
|
||||||
characters = _extract_runtime_character_entries(
|
characters = _extract_runtime_character_entries(
|
||||||
tdata=tdata,
|
tdata=tdata,
|
||||||
character_set=character_set,
|
character_set=character_set,
|
||||||
@@ -2195,7 +2147,7 @@ class LTXDirector(io.ComfyNode):
|
|||||||
char_images = [img for slot_images in char_slot_images for img in slot_images]
|
char_images = [img for slot_images in char_slot_images for img in slot_images]
|
||||||
|
|
||||||
# --- @charN substitution ---
|
# --- @charN substitution ---
|
||||||
# Ghost Mask / OFF: swap @char tags for their VLM descriptions in the prompt text.
|
# OFF: swap @char tags for their VLM descriptions in the prompt text.
|
||||||
# Licon MSR: leave the tags raw — there the reference IMAGE drives identity, and the
|
# Licon MSR: leave the tags raw — there the reference IMAGE drives identity, and the
|
||||||
# tags are used only to pick which character slots feed the slideshow.
|
# tags are used only to pick which character slots feed the slideshow.
|
||||||
if reference_mode == "Licon MSR (Prefix)":
|
if reference_mode == "Licon MSR (Prefix)":
|
||||||
@@ -2267,7 +2219,6 @@ class LTXDirector(io.ComfyNode):
|
|||||||
clean_latent_frames=clean_latent_frames,
|
clean_latent_frames=clean_latent_frames,
|
||||||
reference_strength=reference_strength,
|
reference_strength=reference_strength,
|
||||||
optional_latent=optional_latent,
|
optional_latent=optional_latent,
|
||||||
ref_images=ref_images,
|
|
||||||
resize_method=resize_method,
|
resize_method=resize_method,
|
||||||
divisible_by=divisible_by,
|
divisible_by=divisible_by,
|
||||||
prepare_tensor_image=prepare_tensor_image,
|
prepare_tensor_image=prepare_tensor_image,
|
||||||
|
|||||||
@@ -808,15 +808,6 @@ class LTXDirectorGuide:
|
|||||||
if auto_snap_ic_grid and model is not None and ic_lora_name != "None":
|
if auto_snap_ic_grid and model is not None and ic_lora_name != "None":
|
||||||
latent_image, noise_mask = _snap_latent_to_downscale(latent_image, noise_mask, latent_downscale_factor, upscale_method)
|
latent_image, noise_mask = _snap_latent_to_downscale(latent_image, noise_mask, latent_downscale_factor, upscale_method)
|
||||||
|
|
||||||
# Ghost Mask: the Director kept the latent clean (so it stays length-matched with the audio
|
|
||||||
# latent) and asked us to pre-extend it here by one hidden frame per reference. The tail
|
|
||||||
# sits past the clean region; the reference images (in guide_data["images"], anchored at
|
|
||||||
# (clean + i)) are written into it by the loop below, then dropped downstream by Clean
|
|
||||||
# Latent Slice (length = clean_latent_frames).
|
|
||||||
_ghost_pre_extend = int(guide_data.get("ghost_pre_extend", 0)) if guide_data else 0
|
|
||||||
if _ghost_pre_extend > 0:
|
|
||||||
latent_image, noise_mask = _append_latent_frames(latent_image, noise_mask, _ghost_pre_extend, mask_fill=1.0)
|
|
||||||
|
|
||||||
_, _, latent_length, latent_height, latent_width = latent_image.shape
|
_, _, latent_length, latent_height, latent_width = latent_image.shape
|
||||||
initial_latent_length = int(latent_length)
|
initial_latent_length = int(latent_length)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user