Created
May 12, 2025 16:51
-
-
Save kenotron/38be0a9abbdb63a2029f8fbd10538b6e to your computer and use it in GitHub Desktop.
Download IPAdapter for a fun side project of producing profession looking headshot photo of myself using ComfyUI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
This script downloads ComfyUI assets, including the IPAdapter_plus custom node and various models. | |
It assumes you are running on Windows and places the files in a "comfyui" folder | |
within your user's Documents directory. | |
''' | |
import os | |
import subprocess | |
import requests | |
from tqdm import tqdm # For progress bar, ensure it's installed: pip install tqdm | |
# --- Configuration --- | |
USER_DOCUMENTS_DIR = os.path.join(os.path.expanduser("~"), "Documents") | |
COMFYUI_BASE_DIR = os.path.join(USER_DOCUMENTS_DIR, "comfyui") | |
CUSTOM_NODES_DIR = os.path.join(COMFYUI_BASE_DIR, "custom_nodes") | |
MODELS_DIR = os.path.join(COMFYUI_BASE_DIR, "models") | |
CLIP_VISION_DIR = os.path.join(MODELS_DIR, "clip_vision") | |
IPADAPTER_MODELS_DIR = os.path.join(MODELS_DIR, "ipadapter") | |
LORAS_DIR = os.path.join(MODELS_DIR, "loras") | |
IPADAPTER_PLUS_REPO_URL = "https://github.com/cubiq/ComfyUI_IPAdapter_plus.git" | |
# Models to download { "url": "target_filename_or_path_relative_to_model_dir" } | |
# Renaming is handled if a different filename is given after the last '/' | |
MODELS_TO_DOWNLOAD = { | |
CLIP_VISION_DIR: [ | |
{"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/image_encoder/model.safetensors", "name": "CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/sdxl_models/image_encoder/model.safetensors", "name": "CLIP-ViT-bigG-14-laion2B-39B-b160k.safetensors"}, | |
{"url": "https://huggingface.co/Kwai-Kolors/Kolors-IP-Adapter-Plus/resolve/main/image_encoder/pytorch_model.bin", "name": "clip-vit-large-patch14-336.bin"}, | |
], | |
IPADAPTER_MODELS_DIR: [ | |
{"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter_sd15.safetensors", "name": "ip-adapter_sd15.safetensors"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter_sd15_light_v11.bin", "name": "ip-adapter_sd15_light_v11.bin"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter-plus_sd15.safetensors", "name": "ip-adapter-plus_sd15.safetensors"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter-plus-face_sd15.safetensors", "name": "ip-adapter-plus-face_sd15.safetensors"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter-full-face_sd15.safetensors", "name": "ip-adapter-full-face_sd15.safetensors"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter_sd15_vit-G.safetensors", "name": "ip-adapter_sd15_vit-G.safetensors"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/sdxl_models/ip-adapter_sdxl_vit-h.safetensors", "name": "ip-adapter_sdxl_vit-h.safetensors"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/sdxl_models/ip-adapter-plus_sdxl_vit-h.safetensors", "name": "ip-adapter-plus_sdxl_vit-h.safetensors"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/sdxl_models/ip-adapter-plus-face_sdxl_vit-h.safetensors", "name": "ip-adapter-plus-face_sdxl_vit-h.safetensors"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/sdxl_models/ip-adapter_sdxl.safetensors", "name": "ip-adapter_sdxl.safetensors"}, | |
# FaceID models | |
{"url": "https://huggingface.co/h94/IP-Adapter-FaceID/resolve/main/ip-adapter-faceid_sd15.bin", "name": "ip-adapter-faceid_sd15.bin"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter-FaceID/resolve/main/ip-adapter-faceid-plusv2_sd15.bin", "name": "ip-adapter-faceid-plusv2_sd15.bin"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter-FaceID/resolve/main/ip-adapter-faceid-portrait-v11_sd15.bin", "name": "ip-adapter-faceid-portrait-v11_sd15.bin"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter-FaceID/resolve/main/ip-adapter-faceid_sdxl.bin", "name": "ip-adapter-faceid_sdxl.bin"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter-FaceID/resolve/main/ip-adapter-faceid-plusv2_sdxl.bin", "name": "ip-adapter-faceid-plusv2_sdxl.bin"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter-FaceID/resolve/main/ip-adapter-faceid-portrait_sdxl.bin", "name": "ip-adapter-faceid-portrait_sdxl.bin"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter-FaceID/resolve/main/ip-adapter-faceid-portrait_sdxl_unnorm.bin", "name": "ip-adapter-faceid-portrait_sdxl_unnorm.bin"}, | |
# Community models | |
{"url": "https://huggingface.co/ostris/ip-composition-adapter/resolve/main/ip_plus_composition_sd15.safetensors", "name": "ip_plus_composition_sd15.safetensors"}, | |
{"url": "https://huggingface.co/ostris/ip-composition-adapter/resolve/main/ip_plus_composition_sdxl.safetensors", "name": "ip_plus_composition_sdxl.safetensors"}, | |
{"url": "https://huggingface.co/Kwai-Kolors/Kolors-IP-Adapter-Plus/resolve/main/ip_adapter_plus_general.bin?download=true", "name": "Kolors-IP-Adapter-Plus.bin"}, | |
{"url": "https://huggingface.co/Kwai-Kolors/Kolors-IP-Adapter-FaceID-Plus/resolve/main/ipa-faceid-plus.bin?download=true", "name": "Kolors-IP-Adapter-FaceID-Plus.bin"}, | |
], | |
LORAS_DIR: [ | |
{"url": "https://huggingface.co/h94/IP-Adapter-FaceID/resolve/main/ip-adapter-faceid_sd15_lora.safetensors", "name": "ip-adapter-faceid_sd15_lora.safetensors"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter-FaceID/resolve/main/ip-adapter-faceid-plusv2_sd15_lora.safetensors", "name": "ip-adapter-faceid-plusv2_sd15_lora.safetensors"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter-FaceID/resolve/main/ip-adapter-faceid_sdxl_lora.safetensors", "name": "ip-adapter-faceid_sdxl_lora.safetensors"}, | |
{"url": "https://huggingface.co/h94/IP-Adapter-FaceID/resolve/main/ip-adapter-faceid-plusv2_sdxl_lora.safetensors", "name": "ip-adapter-faceid-plusv2_sdxl_lora.safetensors"}, | |
] | |
} | |
# --- Helper Functions --- | |
def create_directory_if_not_exists(directory_path): | |
'''Creates a directory if it doesn't already exist.''' | |
if not os.path.exists(directory_path): | |
os.makedirs(directory_path) | |
print(f"Created directory: {directory_path}") | |
else: | |
print(f"Directory already exists: {directory_path}") | |
def download_file(url, destination_path, file_name): | |
'''Downloads a file from a URL to a destination path with a progress bar.''' | |
full_path = os.path.join(destination_path, file_name) | |
if os.path.exists(full_path): | |
print(f"File already exists: {full_path}") | |
return | |
print(f"Downloading {file_name} from {url}...") | |
try: | |
response = requests.get(url, stream=True) | |
response.raise_for_status() # Raise an exception for bad status codes | |
total_size = int(response.headers.get('content-length', 0)) | |
with open(full_path, 'wb') as f, tqdm( | |
desc=file_name, | |
total=total_size, | |
unit='iB', | |
unit_scale=True, | |
unit_divisor=1024, | |
) as bar: | |
for data in response.iter_content(chunk_size=1024): | |
size = f.write(data) | |
bar.update(size) | |
print(f"Successfully downloaded: {full_path}") | |
except requests.exceptions.RequestException as e: | |
print(f"Error downloading {url}: {e}") | |
except Exception as e: | |
print(f"An unexpected error occurred while downloading {url}: {e}") | |
def clone_repo(repo_url, destination_path): | |
'''Clones a git repository.''' | |
repo_name = repo_url.split('/')[-1].replace('.git', '') | |
target_repo_path = os.path.join(destination_path, repo_name) | |
if os.path.exists(target_repo_path): | |
print(f"Repository {repo_name} already exists in {destination_path}. Skipping clone.") | |
# Optionally, you could add logic here to pull latest changes | |
# subprocess.run(["git", "pull"], cwd=target_repo_path, check=True) | |
return | |
print(f"Cloning {repo_url} into {destination_path}...") | |
try: | |
subprocess.run(["git", "clone", repo_url, target_repo_path], check=True, capture_output=True, text=True) | |
print(f"Successfully cloned {repo_name}.") | |
except subprocess.CalledProcessError as e: | |
print(f"Error cloning repository {repo_url}: {e}") | |
print(f"Stdout: {e.stdout}") | |
print(f"Stderr: {e.stderr}") | |
print("Please ensure git is installed and in your system's PATH.") | |
except FileNotFoundError: | |
print("Error: Git command not found. Please ensure git is installed and in your system's PATH.") | |
except Exception as e: | |
print(f"An unexpected error occurred while cloning {repo_url}: {e}") | |
# --- Main Execution --- | |
def main(): | |
print("Starting ComfyUI IPAdapter Plus setup...") | |
# 1. Create base directories | |
print("\n--- Creating Directories ---") | |
create_directory_if_not_exists(COMFYUI_BASE_DIR) | |
create_directory_if_not_exists(CUSTOM_NODES_DIR) | |
create_directory_if_not_exists(MODELS_DIR) | |
create_directory_if_not_exists(CLIP_VISION_DIR) | |
create_directory_if_not_exists(IPADAPTER_MODELS_DIR) | |
create_directory_if_not_exists(LORAS_DIR) | |
# 2. Clone ComfyUI_IPAdapter_plus repository | |
print("\n--- Cloning Repository ---") | |
clone_repo(IPADAPTER_PLUS_REPO_URL, CUSTOM_NODES_DIR) | |
# 3. Download models | |
print("\n--- Downloading Models ---") | |
for directory, models in MODELS_TO_DOWNLOAD.items(): | |
print(f"\nDownloading models for: {directory}") | |
create_directory_if_not_exists(directory) # Ensure sub-directory exists | |
for model_info in models: | |
download_file(model_info["url"], directory, model_info["name"]) | |
print("\n-----------------------------------------") | |
print("ComfyUI IPAdapter Plus setup script finished.") | |
print(f"All files should be located in: {COMFYUI_BASE_DIR}") | |
print("Please ensure you have ComfyUI installed separately.") | |
print("You may need to install insightface for FaceID models: pip install insightface") | |
print("Refer to the IPAdapter_plus documentation for further setup if needed.") | |
print("-----------------------------------------") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment