Features: - 8 ComfyUI nodes for TRELLIS2 video-to-3D processing - Onion skinning with configurable frame interval - Multiple rendering modes (PBR, wireframe, cel, normal, depth) - 4 lighting presets (studio, outdoor, dramatic, flat) - Post-processing effects (bloom, DoF, motion blur, outlines) - Progress bars and auto model download - 5 example workflows 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
206 lines
5.9 KiB
Python
206 lines
5.9 KiB
Python
"""Download utilities for TRELLIS2 model with progress tracking."""
|
|
|
|
import logging
|
|
import os
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# TRELLIS2 model configuration
|
|
TRELLIS_HF_REPO = "microsoft/TRELLIS-2-4B"
|
|
TRELLIS_CACHE_DIR = Path.home() / ".cache" / "huggingface" / "hub"
|
|
|
|
# Progress bar fallback for when ComfyUI is not available
|
|
try:
|
|
import comfy.utils
|
|
COMFY_AVAILABLE = True
|
|
except ImportError:
|
|
COMFY_AVAILABLE = False
|
|
|
|
|
|
class ProgressBar:
|
|
"""Fallback progress bar when ComfyUI is not available."""
|
|
|
|
def __init__(self, total: int):
|
|
self.total = total
|
|
self.current = 0
|
|
|
|
def update_absolute(self, current: int, total: Optional[int] = None, desc: str = ""):
|
|
self.current = current
|
|
total = total or self.total
|
|
pct = (current / total * 100) if total > 0 else 0
|
|
logger.info(f"{desc}: {pct:.1f}% ({current}/{total})")
|
|
|
|
def update(self, value: int):
|
|
self.current += value
|
|
pct = (self.current / self.total * 100) if self.total > 0 else 0
|
|
logger.info(f"Progress: {pct:.1f}%")
|
|
|
|
|
|
def get_progress_bar(total: int):
|
|
"""Get a progress bar instance (ComfyUI or fallback)."""
|
|
if COMFY_AVAILABLE:
|
|
return comfy.utils.ProgressBar(total)
|
|
return ProgressBar(total)
|
|
|
|
|
|
def get_trellis_cache_dir() -> Path:
|
|
"""Get the TRELLIS model cache directory."""
|
|
cache_dir = TRELLIS_CACHE_DIR
|
|
cache_dir.mkdir(parents=True, exist_ok=True)
|
|
return cache_dir
|
|
|
|
|
|
def is_trellis_model_downloaded() -> bool:
|
|
"""Check if the TRELLIS model is already downloaded."""
|
|
try:
|
|
from huggingface_hub import snapshot_download, HfFileSystem
|
|
|
|
fs = HfFileSystem()
|
|
# Check if model files exist in cache
|
|
cache_dir = get_trellis_cache_dir()
|
|
|
|
# Look for model files
|
|
model_dir = cache_dir / f"models--{TRELLIS_HF_REPO.replace('/', '--')}"
|
|
if model_dir.exists():
|
|
# Check for key files
|
|
snapshots = model_dir / "snapshots"
|
|
if snapshots.exists():
|
|
# Check any snapshot directory
|
|
for snapshot in snapshots.iterdir():
|
|
if (snapshot / "config.json").exists():
|
|
return True
|
|
return False
|
|
except Exception as e:
|
|
logger.warning(f"Could not check TRELLIS model status: {e}")
|
|
return False
|
|
|
|
|
|
def ensure_trellis_model(pbar: Optional[ProgressBar] = None) -> str:
|
|
"""
|
|
Ensure the TRELLIS model is available, downloading if necessary.
|
|
|
|
Args:
|
|
pbar: Optional progress bar for download progress
|
|
|
|
Returns:
|
|
Path to the TRELLIS model directory
|
|
"""
|
|
try:
|
|
from huggingface_hub import snapshot_download
|
|
except ImportError:
|
|
raise ImportError(
|
|
"huggingface_hub is required for downloading TRELLIS2 model. "
|
|
"Install with: pip install huggingface_hub"
|
|
)
|
|
|
|
if is_trellis_model_downloaded():
|
|
logger.info("TRELLIS2 model found in cache")
|
|
cache_dir = get_trellis_cache_dir()
|
|
model_dir = cache_dir / f"models--{TRELLIS_HF_REPO.replace('/', '--')}"
|
|
# Return the actual model path
|
|
snapshots = model_dir / "snapshots"
|
|
for snapshot in snapshots.iterdir():
|
|
if (snapshot / "config.json").exists():
|
|
return str(snapshot)
|
|
return str(model_dir)
|
|
|
|
logger.info(f"Downloading TRELLIS2 model from {TRELLIS_HF_REPO}...")
|
|
logger.info("This may take a while (~8GB download)")
|
|
|
|
if pbar:
|
|
pbar.update_absolute(0, 100, "Downloading TRELLIS2 model")
|
|
|
|
try:
|
|
model_path = snapshot_download(
|
|
TRELLIS_HF_REPO,
|
|
local_dir_use_symlinks=False,
|
|
)
|
|
|
|
if pbar:
|
|
pbar.update_absolute(100, 100, "TRELLIS2 download complete")
|
|
|
|
logger.info(f"TRELLIS2 model downloaded to {model_path}")
|
|
return model_path
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to download TRELLIS2 model: {e}")
|
|
raise RuntimeError(
|
|
f"Failed to download TRELLIS2 model from {TRELLIS_HF_REPO}. "
|
|
f"Error: {e}\n"
|
|
"Try manually downloading with:\n"
|
|
f" huggingface-cli download {TRELLIS_HF_REPO}"
|
|
)
|
|
|
|
|
|
def check_trellis_dependencies() -> dict:
|
|
"""
|
|
Check if all TRELLIS2 dependencies are available.
|
|
|
|
Returns:
|
|
Dictionary with status of each dependency
|
|
"""
|
|
status = {
|
|
"trellis": False,
|
|
"model_downloaded": False,
|
|
"nvdiffrast": False,
|
|
"cuda": False,
|
|
"rembg": False,
|
|
}
|
|
|
|
# Check TRELLIS package
|
|
try:
|
|
import trellis
|
|
status["trellis"] = True
|
|
except ImportError:
|
|
pass
|
|
|
|
# Check model
|
|
status["model_downloaded"] = is_trellis_model_downloaded()
|
|
|
|
# Check nvdiffrast
|
|
try:
|
|
import nvdiffrast
|
|
status["nvdiffrast"] = True
|
|
except ImportError:
|
|
pass
|
|
|
|
# Check CUDA
|
|
try:
|
|
import torch
|
|
status["cuda"] = torch.cuda.is_available()
|
|
except ImportError:
|
|
pass
|
|
|
|
# Check rembg
|
|
try:
|
|
import rembg
|
|
status["rembg"] = True
|
|
except ImportError:
|
|
pass
|
|
|
|
return status
|
|
|
|
|
|
def print_dependency_status():
|
|
"""Print the status of all dependencies."""
|
|
status = check_trellis_dependencies()
|
|
|
|
print("\nTRELLIS2 Dependency Status:")
|
|
print("-" * 40)
|
|
for name, available in status.items():
|
|
icon = "OK" if available else "MISSING"
|
|
print(f" [{icon}] {name}")
|
|
|
|
if not all(status.values()):
|
|
print("\nTo install missing dependencies:")
|
|
if not status["trellis"]:
|
|
print(" pip install git+https://github.com/microsoft/TRELLIS.git")
|
|
if not status["nvdiffrast"]:
|
|
print(" pip install git+https://github.com/NVlabs/nvdiffrast.git")
|
|
if not status["rembg"]:
|
|
print(" pip install rembg")
|
|
if not status["model_downloaded"]:
|
|
print(f" huggingface-cli download {TRELLIS_HF_REPO}")
|