Files
2025-05-07 13:23:16 -04:00

160 lines
5.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
import torch
from PIL import Image
from torchvision import transforms
class TagKeywordBlocker:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image": ("IMAGE",),
"tags": ("STRING", {"multiline": True, "default": "Plug a image tagger like WD14 into this box"}),
"keywords": ("STRING", {"multiline": True, "default": "List the tags you want to filter for and block in this text box, ie nude, penis, naked, ect. you can use and or logic like the following example. "boobs/boob+nipple/nipples" / is the or option and + is the and option. using the and function will only trigger if both words are found IE: nipple+boob, will only tirgger if both are found"})
}
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "filter_image"
CATEGORY = "Keyword Image Blocker"
def __init__(self):
base = os.path.dirname(__file__)
self.warning_path = os.path.join(base, "assets", "warning.png")
self.to_tensor = transforms.ToTensor()
def _to_hwc(self, t: torch.Tensor) -> torch.Tensor:
"""Convert any [1,C,H,W], [C,H,W] or [1,H,W,C], [H,W,C] → [H,W,3]"""
print(f"[DEBUG _to_hwc] before: dim={t.dim()}, shape={tuple(t.shape)}")
# drop batch dim
if t.dim() == 4 and t.shape[0] == 1:
t = t.squeeze(0)
print(f"[DEBUG _to_hwc] dropped batch → shape={tuple(t.shape)}")
# now t.dim()==3
if t.dim() != 3:
raise RuntimeError(f"[DEBUG _to_hwc] Unexpected tensor dim: {t.shape}")
# channels-first [C,H,W]?
if t.shape[0] == 3:
t = t.permute(1, 2, 0) # → [H,W,C]
print(f"[DEBUG _to_hwc] permuted CHW→HWC → shape={tuple(t.shape)}")
# or maybe it's already [H,W,C]?
elif t.shape[-1] == 3:
print(f"[DEBUG _to_hwc] already HWC → shape={tuple(t.shape)}")
else:
raise RuntimeError(f"[DEBUG _to_hwc] No channel dim found in: {t.shape}")
return t
def filter_image(self, image, tags, keywords):
# break inputs into list
frames = image if isinstance(image, (list, tuple)) else [image]
# log incoming frames
print(f"[DEBUG filter_image] got {len(frames)} frame(s)")
for i, frm in enumerate(frames):
if isinstance(frm, torch.Tensor):
print(f" Frame {i}: Tensor dim={frm.dim()}, shape={tuple(frm.shape)}, "
f"dtype={frm.dtype}, device={frm.device}")
else:
print(f" Frame {i}: {type(frm)} size={frm.size if hasattr(frm, 'size') else 'N/A'}")
# keyword check
raw = str(tags).lower()
kws = [k.strip().lower() for k in keywords.split(",") if k.strip()]
hit = False
for keyword in kws:
groups = keyword.split("+")
all_groups_met = True
for group in groups:
alternatives = group.split("/")
found_in_group = False
for alt in alternatives:
if alt in raw:
found_in_group = True
break
if not found_in_group:
all_groups_met = False
break
if all_groups_met:
hit = True
break
print(f"[DEBUG filter_image] tags='{raw}', keywords={kws}, hit={hit}")
# pick largest tensor frame to size warning
best, area = None, -1
for frm in frames:
if not isinstance(frm, torch.Tensor):
continue
t = frm
# detect H×W
if t.dim() == 4 and t.shape[-1] == 3:
H, W = t.shape[1], t.shape[2]
elif t.dim() == 4 and t.shape[1] == 3:
H, W = t.shape[2], t.shape[3]
elif t.dim() == 3 and t.shape[0] == 3:
H, W = t.shape[1], t.shape[2]
elif t.dim() == 3 and t.shape[-1] == 3:
H, W = t.shape[0], t.shape[1]
else:
continue
a = H * W
if a > area:
best, area = frm, a
# if no tensor frames, bail out and just pass originals in HWC
if best is None or not hit:
out = []
for frm in frames:
if isinstance(frm, torch.Tensor):
out.append(self._to_hwc(frm))
else:
# fallback: convert PIL→tensor HWC
t = self.to_tensor(frm).permute(1, 2, 0)
out.append(t)
print("[DEBUG filter_image] no hit or no tensors → passing through HWC tensors")
return (out,)
# on hit: size warning to best frame
# extract H,W from best
t0 = best
if t0.dim() == 4 and t0.shape[-1] == 3:
H, W = t0.shape[1], t0.shape[2]
elif t0.dim() == 4 and t0.shape[1] == 3:
H, W = t0.shape[2], t0.shape[3]
elif t0.dim() == 3 and t0.shape[0] == 3:
H, W = t0.shape[1], t0.shape[2]
else:
H, W = t0.shape[0], t0.shape[1]
# load & resize warning
pil_warn = Image.open(self.warning_path).convert("RGB")
pil_warn = pil_warn.resize((W, H), resample=Image.LANCZOS)
# to tensor CHW→HWC
warn_t = self.to_tensor(pil_warn).permute(1, 2, 0)
warn_t = warn_t.to(best.device).to(best.dtype)
print(f"[DEBUG filter_image] hit → warning tensor shape={tuple(warn_t.shape)}")
# return single-element list
return ([warn_t],)
NODE_CLASS_MAPPINGS = {
"TagKeywordBlocker": TagKeywordBlocker
}
NODE_DISPLAY_NAME_MAPPINGS = {
"TagKeywordBlocker": "Keyword Image Blocker"
}