MyCustomNodes / hfDonloder.py
saliacoel's picture
Upload hfDonloder.py
91286ad verified
# ComfyUI/custom_nodes/zip_output_to_hf.py
#
# Node: ZipOutputToHuggingFace
#
# - Zips the ComfyUI output folder
# - Uploads the zip to a Hugging Face repo
# - Returns a direct download URL as STRING
import os
import time
import zipfile
import tempfile
import folder_paths # ComfyUI's helper for paths
try:
from huggingface_hub import HfApi
except ImportError:
HfApi = None
class ZipOutputToHuggingFace:
"""
Zip the ComfyUI output folder and upload the archive to Hugging Face.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
# Where to upload; default to your repo
"hf_repo_id": (
"STRING",
{"default": "saliacoel/MyCustomNodes"},
),
},
"optional": {
# Hugging Face token; can be left empty if you use env vars / hf auth login
"hf_token": (
"STRING",
{
"default": "",
"multiline": False,
},
),
# Prefix for the zip filename
"zip_name_prefix": (
"STRING",
{
"default": "comfy_output",
"multiline": False,
},
),
# Subfolder in the repo to put the zip into
"remote_dir": (
"STRING",
{
"default": "exports",
"multiline": False,
},
),
},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("download_url",)
FUNCTION = "zip_and_upload"
CATEGORY = "utils/huggingface"
OUTPUT_NODE = True # can act as a terminal node in your graph
def zip_and_upload(
self,
hf_repo_id: str,
hf_token: str = "",
zip_name_prefix: str = "comfy_output",
remote_dir: str = "exports",
):
# 1. Check huggingface_hub availability
if HfApi is None:
raise RuntimeError(
"huggingface_hub is not installed.\n"
"Install it in your ComfyUI environment, for example:\n"
" pip install huggingface_hub"
)
# 2. Get ComfyUI output directory
output_dir = folder_paths.get_output_directory()
if not os.path.isdir(output_dir):
raise RuntimeError(f"Output directory does not exist: {output_dir}")
# 3. Ensure there is at least one file to zip
has_files = False
for _, _, files in os.walk(output_dir):
if files:
has_files = True
break
if not has_files:
raise RuntimeError(
f"No files found in output directory: {output_dir}"
)
# 4. Create zip in a temp directory (so we don't zip the zip)
timestamp = time.strftime("%Y%m%d-%H%M%S")
safe_prefix = (zip_name_prefix or "").strip() or "comfy_output"
zip_filename = f"{safe_prefix}_{timestamp}.zip"
tmp_dir = tempfile.gettempdir()
zip_path = os.path.join(tmp_dir, zip_filename)
zip_abs = os.path.abspath(zip_path)
# 5. Build the zip archive of everything under output/
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zipf:
for root, _, files in os.walk(output_dir):
for fname in files:
file_path = os.path.join(root, fname)
# Just in case tempdir == output_dir, avoid zipping ourselves
if os.path.abspath(file_path) == zip_abs:
continue
rel_path = os.path.relpath(file_path, output_dir)
zipf.write(file_path, arcname=rel_path)
# 6. Prepare Hugging Face upload
repo_id = (hf_repo_id or "").strip()
if not repo_id:
# Clean up zip if we created it but can't use it
try:
os.remove(zip_path)
except OSError:
pass
raise RuntimeError("hf_repo_id cannot be empty")
remote_dir = (remote_dir or "").strip().strip("/")
if remote_dir:
path_in_repo = f"{remote_dir}/{zip_filename}"
else:
path_in_repo = zip_filename
api = HfApi()
# 7. Upload to Hugging Face
try:
api.upload_file(
path_or_fileobj=zip_path,
path_in_repo=path_in_repo,
repo_id=repo_id,
# token is optional; if empty, hf_hub will use env/CLI token if present
token=hf_token or None,
)
except Exception as e:
# Clean up local zip on failure
try:
os.remove(zip_path)
except OSError:
pass
raise RuntimeError(f"Failed to upload to Hugging Face: {e}")
# 8. Build a direct download URL
# This gives the raw file: https://huggingface.co/{repo_id}/resolve/main/{path_in_repo}
download_url = f"https://huggingface.co/{repo_id}/resolve/main/{path_in_repo}"
# 9. Clean up temp zip (we only keep the file on HF)
try:
os.remove(zip_path)
except OSError:
pass
# Return as a single STRING output
return (download_url,)
# Register node with ComfyUI
NODE_CLASS_MAPPINGS = {
"ZipOutputToHuggingFace": ZipOutputToHuggingFace,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"ZipOutputToHuggingFace": "Zip Output → Hugging Face",
}