| """Upload a trained Objectverse Diary LoRA adapter folder to Hugging Face Hub.""" |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import json |
| from pathlib import Path |
| from typing import Any |
|
|
|
|
| REQUIRED_ADAPTER_FILES = ("adapter_config.json",) |
| ADAPTER_WEIGHT_FILES = ("adapter_model.safetensors", "adapter_model.bin") |
|
|
|
|
| def validate_adapter_dir(adapter_dir: Path) -> dict[str, object]: |
| if not adapter_dir.exists() or not adapter_dir.is_dir(): |
| raise FileNotFoundError(f"Adapter directory does not exist: {adapter_dir}") |
|
|
| missing = [name for name in REQUIRED_ADAPTER_FILES if not (adapter_dir / name).exists()] |
| has_weights = any((adapter_dir / name).exists() for name in ADAPTER_WEIGHT_FILES) |
| if not has_weights: |
| missing.append("adapter_model.safetensors or adapter_model.bin") |
| if missing: |
| raise ValueError(f"Adapter directory is missing required files: {', '.join(missing)}") |
|
|
| files = sorted(path.name for path in adapter_dir.iterdir() if path.is_file()) |
| return { |
| "adapter_dir": str(adapter_dir), |
| "files": files, |
| "file_count": len(files), |
| } |
|
|
|
|
| def upload_adapter( |
| *, |
| adapter_dir: Path, |
| repo_id: str, |
| private: bool, |
| commit_message: str, |
| dry_run: bool, |
| ) -> dict[str, object]: |
| summary = validate_adapter_dir(adapter_dir) |
| summary.update( |
| { |
| "repo_id": repo_id, |
| "private": private, |
| "commit_message": commit_message, |
| "dry_run": dry_run, |
| } |
| ) |
| if dry_run: |
| summary["uploaded"] = False |
| return summary |
|
|
| from huggingface_hub import HfApi |
|
|
| api = HfApi() |
| api.create_repo(repo_id=repo_id, repo_type="model", private=private, exist_ok=True) |
| api.upload_folder( |
| folder_path=str(adapter_dir), |
| repo_id=repo_id, |
| repo_type="model", |
| commit_message=commit_message, |
| ) |
| summary["uploaded"] = True |
| summary["url"] = f"https://huggingface.co/{repo_id}" |
| return summary |
|
|
|
|
| def _print_json(payload: dict[str, Any]) -> None: |
| print(json.dumps(payload, indent=2, sort_keys=True), flush=True) |
|
|
|
|
| def _parse_args() -> argparse.Namespace: |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument("--adapter-dir", type=Path, required=True) |
| parser.add_argument("--repo-id", required=True) |
| parser.add_argument("--private", action="store_true") |
| parser.add_argument( |
| "--commit-message", |
| default="Upload Objectverse Diary LoRA adapter", |
| ) |
| parser.add_argument("--dry-run", action="store_true") |
| return parser.parse_args() |
|
|
|
|
| def main() -> None: |
| args = _parse_args() |
| _print_json( |
| upload_adapter( |
| adapter_dir=args.adapter_dir, |
| repo_id=args.repo_id, |
| private=args.private, |
| commit_message=args.commit_message, |
| dry_run=args.dry_run, |
| ) |
| ) |
|
|
|
|
| if __name__ == "__main__": |
| try: |
| main() |
| except Exception as exc: |
| raise SystemExit(str(exc)) from exc |
|
|