Add nested-safe H3 latent saver (1.27.0)
The stock SaveLatent calls .contiguous() straight on samples["samples"], which fails on H3 because the latent is a NestedTensor holding the video and audio components. This unbinds them first and writes each as its own tensor, so an H3 latent can be taken out of the graph and decoded or inspected offline. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,12 @@ try:
|
||||
except Exception as _e: # noqa
|
||||
print(f"[BFSNodes] MiniMax-H3 direct decode node not loaded: {_e!r}")
|
||||
MMDD_NODE_CLASS_MAPPINGS, MMDD_NODE_DISPLAY_NAME_MAPPINGS = {}, {}
|
||||
try:
|
||||
from .save_h3_latent import NODE_CLASS_MAPPINGS as SVH3_NODE_CLASS_MAPPINGS
|
||||
from .save_h3_latent import NODE_DISPLAY_NAME_MAPPINGS as SVH3_NODE_DISPLAY_NAME_MAPPINGS
|
||||
except Exception as _e: # noqa
|
||||
print(f"[BFSNodes] Save H3 Latent node not loaded: {_e!r}")
|
||||
SVH3_NODE_CLASS_MAPPINGS, SVH3_NODE_DISPLAY_NAME_MAPPINGS = {}, {}
|
||||
try:
|
||||
from .ltx_identity_multiangle import NODE_CLASS_MAPPINGS as MA_NODE_CLASS_MAPPINGS
|
||||
from .ltx_identity_multiangle import NODE_DISPLAY_NAME_MAPPINGS as MA_NODE_DISPLAY_NAME_MAPPINGS
|
||||
@@ -80,6 +86,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
**MMVAE_NODE_CLASS_MAPPINGS,
|
||||
**SHARP_NODE_CLASS_MAPPINGS,
|
||||
**MMDD_NODE_CLASS_MAPPINGS,
|
||||
**SVH3_NODE_CLASS_MAPPINGS,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
@@ -100,4 +107,5 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
**MMVAE_NODE_DISPLAY_NAME_MAPPINGS,
|
||||
**SHARP_NODE_DISPLAY_NAME_MAPPINGS,
|
||||
**MMDD_NODE_DISPLAY_NAME_MAPPINGS,
|
||||
**SVH3_NODE_DISPLAY_NAME_MAPPINGS,
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "bfsnodes"
|
||||
description = "Custom ComfyUI nodes including LTXV Edit Anything, Head-Swap/Anime2Real Bernini conditioning, the AMV Guide Builder, LTX Identity Transfer (IPT2V reference + source-phase RoPE), and MiniMax-H3 single-frame VAE loaders with tile control."
|
||||
version = "1.26.2"
|
||||
version = "1.27.0"
|
||||
license = {file = "LICENSE"}
|
||||
dependencies = [
|
||||
"torch",
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
"""Salva um latente do MiniMax-H3 em disco.
|
||||
|
||||
O `SaveLatent` nativo quebra com o latente do H3: ele chega como NestedTensor (video + audio)
|
||||
e o node chama `.contiguous()` direto. Aqui os componentes sao desempacotados e salvos
|
||||
separadamente, para o latente poder ser inspecionado ou decodificado fora do grafo.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import folder_paths
|
||||
import torch
|
||||
from safetensors.torch import save_file
|
||||
|
||||
|
||||
class SaveH3Latent:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"samples": ("LATENT",),
|
||||
"filename_prefix": ("STRING", {"default": "h3_latent"}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ()
|
||||
FUNCTION = "save"
|
||||
OUTPUT_NODE = True
|
||||
CATEGORY = "BFS/debug"
|
||||
|
||||
def save(self, samples, filename_prefix):
|
||||
z = samples["samples"]
|
||||
tensores = {}
|
||||
if getattr(z, "is_nested", False):
|
||||
for i, parte in enumerate(z.unbind()):
|
||||
t = parte if parte.dim() == 5 else parte.unsqueeze(0)
|
||||
tensores[f"component_{i}"] = t.contiguous().cpu()
|
||||
else:
|
||||
t = z if z.dim() == 5 else z.unsqueeze(0)
|
||||
tensores["component_0"] = t.contiguous().cpu()
|
||||
|
||||
pasta = folder_paths.get_output_directory()
|
||||
n = 0
|
||||
while os.path.exists(os.path.join(pasta, f"{filename_prefix}_{n:05d}.safetensors")):
|
||||
n += 1
|
||||
caminho = os.path.join(pasta, f"{filename_prefix}_{n:05d}.safetensors")
|
||||
meta = {k: str(tuple(v.shape)) for k, v in tensores.items()}
|
||||
save_file(tensores, caminho, metadata={"format": "pt", **meta})
|
||||
print(f"[BFSNodes] latente salvo em {caminho}")
|
||||
for k, v in tensores.items():
|
||||
print(f"[BFSNodes] {k}: {tuple(v.shape)} {v.dtype}")
|
||||
return {}
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {"SaveH3Latent": SaveH3Latent}
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {"SaveH3Latent": "Save H3 Latent / nested-safe (BFS)"}
|
||||
Reference in New Issue
Block a user