""" Generate CLIP image embeddings for a folder of reference images. These embeddings are then used to train a STANNO as a style autoencoder, which can be loaded into the ComfyUI STANNODreamCond or STANNODynamicLoRA nodes for conditioning/weight-patch injection. Usage: python scripts/generate_clip_embeddings.py \ --dir my_style_images/ \ --out style_embeddings.npy \ [--model ViT-L-14] [--pretrained openai] Requirements: pip install open-clip-torch Pillow Outputs: A .npy file of shape (N, 768) — one 768-dim CLIP embedding per image. Compatible with SD 1.5 CLIP-L text encoder embedding space. """ from __future__ import annotations import argparse import sys from pathlib import Path import numpy as np def parse_args() -> argparse.Namespace: p = argparse.ArgumentParser(description="Generate CLIP embeddings for a folder of images") p.add_argument("--dir", required=True, help="Folder of input images (png, jpg, webp)") p.add_argument("--out", required=True, help="Output .npy path") p.add_argument("--model", default="ViT-L-14", help="OpenCLIP model name") p.add_argument("--pretrained", default="openai", help="OpenCLIP pretrained weights") p.add_argument("--batch", type=int, default=16, help="Batch size for encoding") p.add_argument("--device", default="cuda", help="Device: cuda or cpu") return p.parse_args() def main() -> None: args = parse_args() try: import torch import open_clip from PIL import Image except ImportError as e: print(f"Missing dependency: {e}") print("Install with: pip install open-clip-torch Pillow") sys.exit(1) image_paths = sorted( p for ext in ("*.png", "*.jpg", "*.jpeg", "*.webp") for p in Path(args.dir).glob(ext) ) if not image_paths: print(f"No images found in {args.dir}") sys.exit(1) print(f"Found {len(image_paths)} images in {args.dir}") model, _, preprocess = open_clip.create_model_and_transforms( args.model, pretrained=args.pretrained ) model.eval().to(args.device) all_embeddings: list[np.ndarray] = [] for i in range(0, len(image_paths), args.batch): batch_paths = image_paths[i : i + args.batch] imgs = torch.stack( [preprocess(Image.open(str(p)).convert("RGB")) for p in batch_paths] ).to(args.device) with torch.no_grad(): feats = model.encode_image(imgs) all_embeddings.append(feats.cpu().numpy()) print(f" Encoded {min(i + args.batch, len(image_paths))}/{len(image_paths)}") embeddings = np.concatenate(all_embeddings, axis=0).astype(np.float32) out_path = Path(args.out) out_path.parent.mkdir(parents=True, exist_ok=True) np.save(str(out_path), embeddings) print(f"\nSaved {embeddings.shape} embeddings → {out_path}") print(f"Use this file with train_stanno_on_embeddings.py or STANNOTrainImages (ComfyUI).") if __name__ == "__main__": main()