#!/bin/bash ############################################################################################################################# # # Wael Isa # Website: https://www.wael.name # GitHub: https://github.com/waelisa # Version: v9.0.0 (FIXED PARAMETER) # Build Date: 03/22/2026 # License: MIT # # Description: # šŸ¤– HUGGINGFACE MANAGER - Fixed upload_large_folder() parameters # Purpose: Removes unsupported commit_message argument # ############################################################################################################################# set -e # Exit on error # --- COLORS FOR FANCY OUTPUT --- RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # --- CONFIGURATION --- REPO_ID="BoRnNo0b/mirror" PATH_SD="/mnt/AI/AI/stable-diffusion-webui-forge/models/Stable-diffusion" PATH_LORA="/mnt/AI/AI/huggingface_hub/upload" VENV_NAME="hf_env" # NEW: Path for pending/not-done uploads (from old script) PATH_CACHE="/mnt/AI/AI/All-in-one/models/Stable-diffusion/.cache" # --- RATE LIMIT SETTINGS --- MAX_RETRIES=5 RETRY_DELAY=120 # seconds between retries # --- FUNCTIONS --- show_menu() { echo -e "${BLUE}========================================${NC}" echo -e "${YELLOW} šŸš€ HUGGINGFACE MANAGER MENU (v9.0 FIXED) ${NC}" echo -e "${BLUE}========================================${NC}" echo -e " [1] Install Dependencies & Setup Env" echo -e " [2] Do Both (Install + Upload with deletion)" echo -e " [3] Run Uploads (with deletion)" echo -e " [4] Run Uploads (without deletion)" echo -e " [5] Fast Sync (Skip Hash Check)" echo -e " [6] Process Pending Cache First" echo -e " [7] Force Re-Upload All Files" echo -e " [0] Exit" echo -e "${BLUE}========================================${NC}" read -p "Select an option [0-7]: " choice } install_deps() { echo -e "${YELLOW}[STEP 1/2] Installing Git LFS...${NC}" sudo pacman -S git-lfs --noconfirm || true git lfs install echo -e "${YELLOW}[STEP 2/2] Setting up Virtual Environment & Python Deps...${NC}" [ -f "$VENV_NAME/bin/activate" ] && rm -fr "$VENV_NAME/bin/activate" python -m venv $VENV_NAME source $VENV_NAME/bin/activate pip install --upgrade pip wheel huggingface_hub tqdm requests aiohttp deactivate } # --- BATCH DELETION (One Commit for All Files) --- batch_delete_missing() { local local_path="$1" local repo_id="$2" local remote_path="$3" # can be empty for root, or a subdirectory like "stable-diffusion" echo -e "${YELLOW}šŸ—‘ļø Batch Deletion (Single Commit)...${NC}" python << EOF import os from huggingface_hub import HfApi, upload_large_folder import time def batch_delete_missing(local_path, repo_id, remote_path): api = HfApi() # Get all local files local_files = set() for root, dirs, files in os.walk(local_path): for file in files: rel_path = os.path.relpath(os.path.join(root, file), local_path) local_files.add(rel_path) # Get remote files try: remote_files = api.list_repo_files(repo_id=repo_id, repo_type="model") if remote_path: remote_files = [f for f in remote_files if f.startswith(remote_path + "/")] print(f" šŸ“Š Found {len(remote_files)} remote files to check...") except Exception as e: print(f" āš ļø Could not list repo files: {e}") return # Find missing files delete_list = [] for remote_file in remote_files: if remote_path: relative = os.path.relpath(remote_file, remote_path) else: relative = remote_file if relative not in local_files: delete_list.append(relative) # Batch delete with retry logic deleted_count = 0 max_retries = $MAX_RETRIES retry_delay = $RETRY_DELAY for attempt in range(1, max_retries + 1): try: print(f" šŸ”„ Attempt {attempt}/{max_retries}...") if not delete_list: print(" āœ… No files to delete!") return # Upload folder with deleted files (creates ONE commit) upload_large_folder( folder_path=local_path, repo_id=repo_id, repo_type="model", ignore_patterns=[".cache"] # Skip cache folder ) deleted_count = len(delete_list) print(f" āœ… Deleted {deleted_count} files in single commit!") break except Exception as e: error_msg = str(e) if "429" in error_msg or "Too Many Requests" in error_msg: print(f" āš ļø Rate limit hit, waiting {retry_delay}s...") time.sleep(retry_delay) else: print(f" āŒ Error on attempt {attempt}: {e}") if attempt == max_retries: raise e return deleted_count if __name__ == "__main__": import os local_path = os.environ.get('FAST_UPLOAD_PATH', '$PATH_SD') repo_id = os.environ.get('FAST_REPO_ID', '$REPO_ID') remote_path = os.environ.get('FAST_REMOTE_PATH', '') count = batch_delete_missing(local_path, repo_id, remote_path) print(f"\nāœ… Batch deletion complete. Deleted: {count} files.") EOF echo -e "${GREEN}āœ… Deletion check completed.${NC}" } # --- FAST UPLOAD FUNCTION (Using upload_large_folder without commit_message) --- fast_upload() { local local_path="$1" local repo_id="$2" local delete_mode="$3" echo -e "${YELLOW}šŸš€ Fast Upload Starting...${NC}" python << EOF import os from huggingface_hub import HfApi, upload_large_folder import time def fast_upload_files(local_path, repo_id): api = HfApi() # Collect all local files local_files = [] for root, dirs, files in os.walk(local_path): for file in files: full_path = os.path.join(root, file) rel_path = os.path.relpath(full_path, local_path) # Skip .cache folder if it's inside the main path if ".cache" in root and "PATH_CACHE" in str(local_path): continue size = os.path.getsize(full_path) mtime = os.path.getmtime(full_path) local_files.append({ 'rel_path': rel_path, 'path': full_path, 'size': size, 'mtime': mtime }) print(f"\n šŸ“Š Found {len(local_files)} files to upload...") # Use upload_large_folder (better rate limit handling for large folders) max_retries = $MAX_RETRIES retry_delay = $RETRY_DELAY for attempt in range(1, max_retries + 1): try: print(f" šŸ”„ Attempt {attempt}/{max_retries}...") upload_large_folder( folder_path=local_path, repo_id=repo_id, repo_type="model", ignore_patterns=[".cache"] # Skip cache folder ) print(f" āœ… Uploaded all files in single commit!") return len(local_files), 0 except Exception as e: error_msg = str(e) if "429" in error_msg or "Too Many Requests" in error_msg: print(f" āš ļø Rate limit hit, waiting {retry_delay}s...") time.sleep(retry_delay) else: print(f" āŒ Error on attempt {attempt}: {e}") if attempt == max_retries: raise e if __name__ == "__main__": import os local_path = os.environ.get('FAST_UPLOAD_PATH', '$PATH_SD') repo_id = os.environ.get('FAST_REPO_ID', '$REPO_ID') uploaded, failed = fast_upload_files(local_path, repo_id) print(f"\n āœ… Upload Complete! Uploaded: {uploaded}, Failed: {failed}") EOF echo -e "${GREEN}āœ… Fast upload completed.${NC}" } # --- PROCESS PENDING CACHE (Fast Mode) --- process_pending_cache() { if [ ! -d "$PATH_CACHE" ]; then echo -e "${YELLOW}āš ļø Cache folder not found at ${PATH_CACHE}${NC}" return fi echo -e "${BLUE}šŸ“‚ Processing Pending Cache: ${PATH_CACHE}${NC}" python << EOF import os from huggingface_hub import HfApi, upload_large_folder api = HfApi() cache_dir = "$PATH_CACHE" repo_id = "$REPO_ID" files_uploaded = 0 if os.path.exists(cache_dir): try: # Upload entire cache folder in one commit upload_large_folder( folder_path=cache_dir, repo_id=repo_id, repo_type="model", ignore_patterns=[".git"] ) # Remove all files after successful upload for root, dirs, files in os.walk(cache_dir): for file in files: full_path = os.path.join(root, file) os.remove(full_path) files_uploaded += 1 except Exception as e: print(f" āš ļø Cache upload error: {e}") print(f"\nāœ… Cache Processed. Uploaded: {files_uploaded} files.") EOF echo -e "${GREEN}āœ… Pending cache handled.${NC}" } # --- MAIN UPLOAD FUNCTION (FAST MODE) --- run_upload() { local delete_mode="$1" # if "--no-delete" is passed, skip deletion echo -e "${YELLOW}[STEP 1/2] Activating Environment & Configuring...${NC}" source $VENV_NAME/bin/activate export HF_XET_HIGH_PERFORMANCE=1 export HF_XET_CACHE=/tmp/hf_xet_cache echo -e "${YELLOW}[STEP 2/2] Authenticating with Hugging Face Hub...${NC}" python -c "from huggingface_hub import login; login()" # --- Process Pending Cache First --- process_pending_cache echo "" echo -e "${GREEN}šŸ“¦ UPLOADING PATH 1: Stable Diffusion Models (FAST MODE)${NC}" echo " Source: $PATH_SD" export FAST_UPLOAD_PATH="$PATH_SD" export FAST_REPO_ID="$REPO_ID" fast_upload "$PATH_SD" "$REPO_ID" "$delete_mode" if [ "$delete_mode" != "--no-delete" ]; then batch_delete_missing "$PATH_SD" "$REPO_ID" "" else echo -e "${YELLOW}āš ļø Skipping deletion for Stable Diffusion folder.${NC}" fi echo "" echo -e "${GREEN}šŸ“¦ UPLOADING PATH 2: Huggingface Hub Upload (FAST MODE)${NC}" echo " Source: $PATH_LORA" export FAST_UPLOAD_PATH="$PATH_LORA" export FAST_REPO_ID="$REPO_ID" fast_upload "$PATH_LORA" "$REPO_ID" "$delete_mode" if [ "$delete_mode" != "--no-delete" ]; then batch_delete_missing "$PATH_LORA" "$REPO_ID" "" else echo -e "${YELLOW}āš ļø Skipping deletion for LoRA folder.${NC}" fi deactivate } # --- MAIN LOOP --- while true; do show_menu case $choice in 1) install_deps echo -e "${GREEN}āœ… Installation Complete!${NC}" ;; 2) install_deps sleep 2 run_upload echo -e "${GREEN}āœ… All Done!${NC}" ;; 3) run_upload echo -e "${GREEN}āœ… Uploads Complete!${NC}" ;; 4) run_upload --no-delete echo -e "${GREEN}āœ… Uploads Complete (no deletion)!${NC}" ;; 5) # Option 5: Fast Sync (Skip Hash Check for Speed) echo -e "${YELLOW}[STEP 1/2] Activating Environment & Configuring...${NC}" source $VENV_NAME/bin/activate export HF_XET_HIGH_PERFORMANCE=1 export HF_XET_CACHE=/tmp/hf_xet_cache process_pending_cache export FAST_UPLOAD_PATH="$PATH_SD" export FAST_REPO_ID="$REPO_ID" fast_upload "$PATH_SD" "$REPO_ID" "--no-delete" deactivate echo -e "${GREEN}āœ… Fast Sync Complete!${NC}" ;; 6) # Option 6: Process Pending Cache Only process_pending_cache ;; 7) # Option 7: Force Re-Upload All Files (Skip Hash Check) echo -e "${YELLOW}[STEP 1/2] Activating Environment & Configuring...${NC}" source $VENV_NAME/bin/activate export HF_XET_HIGH_PERFORMANCE=1 export HF_XET_CACHE=/tmp/hf_xet_cache process_pending_cache export FAST_UPLOAD_PATH="$PATH_SD" export FAST_REPO_ID="$REPO_ID" fast_upload "$PATH_SD" "$REPO_ID" "--no-delete" deactivate echo -e "${GREEN}āœ… Force Re-Upload Complete!${NC}" ;; 0) echo -e "${YELLOW}Exiting...${NC}" exit 0 ;; *) echo -e "${RED}Invalid option, please try again.${NC}" ;; esac read -p "Press Enter to return to menu..." done