"""Local app trees: Models / Wildcards / CustomWorkflows / Output.""" from __future__ import annotations import hashlib from pathlib import Path SKIP_NAMES = {".gitkeep", "README.md", "README.txt", ".gitignore"} WEIGHT_SUFFIXES = {".safetensors", ".ckpt", ".pt", ".pth", ".bin", ".gguf", ".sft", ".onnx"} META_SUFFIXES = {".json", ".civitai.json", ".swarm.json", ".preview.png", ".png", ".webp", ".jpg"} def is_skipped(path: Path) -> bool: name = path.name if name in SKIP_NAMES or name.startswith("."): return True return False def has_payload(root: Path) -> bool: if not root.is_dir(): return False for path in root.rglob("*"): if path.is_file() and not is_skipped(path): return True return False def folder_bytes(root: Path) -> int: if not root.is_dir(): return 0 total = 0 for path in root.rglob("*"): if path.is_file() and not is_skipped(path): total += path.stat().st_size return total def iter_payload_files(root: Path) -> list[Path]: if not root.is_dir(): return [] found = [] for path in sorted(root.rglob("*")): if path.is_file() and not is_skipped(path): found.append(path) return found def is_weight(path: Path) -> bool: return path.suffix.lower() in WEIGHT_SUFFIXES def sha256_file(path: Path, chunk: int = 1024 * 1024) -> str: digest = hashlib.sha256() with path.open("rb") as fh: while True: block = fh.read(chunk) if not block: break digest.update(block) return digest.hexdigest() def sidecar_stem(name: str) -> str: lower = name.lower() for suffix in ( ".civitai.json", ".swarm.json", ".preview.png", ".preview.webp", ".preview.jpg", ".json", ".png", ".webp", ".jpg", ): if lower.endswith(suffix): return name[: -len(suffix)] return Path(name).stem def model_push_set(root: Path) -> list[Path]: """Weights plus same-stem sidecars. Sidecar without weights is skipped.""" files = iter_payload_files(root) weights = [p for p in files if is_weight(p)] wanted: set[Path] = set(weights) stems = {p.stem for p in weights} for path in files: if is_weight(path): continue if sidecar_stem(path.name) in stems: wanted.add(path) return sorted(wanted)