|
| 1 | +from huggingface_hub import ( |
| 2 | + hf_hub_download, |
| 3 | + model_info, |
| 4 | + ModelInfo, |
| 5 | + HfApi, |
| 6 | +) |
| 7 | +from huggingface_hub.errors import RepositoryNotFoundError |
| 8 | +from getpass import getpass |
| 9 | +import os |
| 10 | +import warnings |
| 11 | +import traceback |
| 12 | + |
| 13 | +with warnings.catch_warnings(): |
| 14 | + warnings.simplefilter("ignore") |
| 15 | + |
| 16 | + |
| 17 | +def get_latest_commit_tag(repo_id, repo_type="model"): |
| 18 | + """ |
| 19 | + Get the tag associated with the latest commit in a HF repo. |
| 20 | + Returns the tag name or None if no tag is associated. |
| 21 | + """ |
| 22 | + api = HfApi() |
| 23 | + |
| 24 | + # Get list of commits |
| 25 | + commits = api.list_repo_commits(repo_id=repo_id, repo_type=repo_type) |
| 26 | + |
| 27 | + if not commits: |
| 28 | + return None |
| 29 | + |
| 30 | + latest_commit = commits[0] # Most recent commit is first |
| 31 | + |
| 32 | + # Get all tags in the repository |
| 33 | + tags = api.list_repo_refs(repo_id=repo_id, repo_type=repo_type).tags |
| 34 | + |
| 35 | + # Find tag that points to the latest commit |
| 36 | + for tag in tags: |
| 37 | + if tag.target_commit == latest_commit.commit_id: |
| 38 | + return tag.ref.replace("refs/tags/", "") |
| 39 | + |
| 40 | + return None |
| 41 | + |
| 42 | + |
| 43 | +def download_huggingface_dataset( |
| 44 | + repo: str, |
| 45 | + repo_filename: str, |
| 46 | + version: str = None, |
| 47 | + local_dir: str | None = None, |
| 48 | +): |
| 49 | + """ |
| 50 | + Download a dataset from the Hugging Face Hub. |
| 51 | +
|
| 52 | + Args: |
| 53 | + repo (str): The Hugging Face repo name, in format "{org}/{repo}". |
| 54 | + repo_filename (str): The filename of the dataset. |
| 55 | + version (str, optional): The version of the dataset. Defaults to None. |
| 56 | + local_dir (str, optional): The local directory to save the dataset to. Defaults to None. |
| 57 | + """ |
| 58 | + # Attempt connection to Hugging Face model_info endpoint |
| 59 | + # (https://huggingface.co/docs/huggingface_hub/v0.26.5/en/package_reference/hf_api#huggingface_hub.HfApi.model_info) |
| 60 | + # Attempt to fetch model info to determine if repo is private |
| 61 | + # A RepositoryNotFoundError & 401 likely means the repo is private, |
| 62 | + # but this error will also surface for public repos with malformed URL, etc. |
| 63 | + try: |
| 64 | + fetched_model_info: ModelInfo = model_info(repo) |
| 65 | + is_repo_private: bool = fetched_model_info.private |
| 66 | + except RepositoryNotFoundError as e: |
| 67 | + # If this error type arises, it's likely the repo is private; see docs above |
| 68 | + is_repo_private = True |
| 69 | + pass |
| 70 | + except Exception as e: |
| 71 | + # Otherwise, there probably is just a download error |
| 72 | + raise Exception( |
| 73 | + f"Unable to download dataset {repo_filename} from Hugging Face. This may be because the repo " |
| 74 | + + f"is private, the URL is malformed, or the dataset does not exist. The full error is {traceback.format_exc()}" |
| 75 | + ) |
| 76 | + |
| 77 | + authentication_token: str = None |
| 78 | + if is_repo_private: |
| 79 | + authentication_token: str = get_or_prompt_hf_token() |
| 80 | + |
| 81 | + return hf_hub_download( |
| 82 | + repo_id=repo, |
| 83 | + repo_type="model", |
| 84 | + filename=repo_filename, |
| 85 | + revision=version, |
| 86 | + token=authentication_token, |
| 87 | + local_dir=local_dir, |
| 88 | + ) |
| 89 | + |
| 90 | + |
| 91 | +def get_or_prompt_hf_token() -> str: |
| 92 | + """ |
| 93 | + Either get the Hugging Face token from the environment, |
| 94 | + or prompt the user for it and store it in the environment. |
| 95 | +
|
| 96 | + Returns: |
| 97 | + str: The Hugging Face token. |
| 98 | + """ |
| 99 | + |
| 100 | + token = os.environ.get("HUGGING_FACE_TOKEN") |
| 101 | + if token is None: |
| 102 | + token = getpass( |
| 103 | + "Enter your Hugging Face token (or set HUGGING_FACE_TOKEN environment variable): " |
| 104 | + ) |
| 105 | + # Optionally store in env for subsequent calls in same session |
| 106 | + os.environ["HUGGING_FACE_TOKEN"] = token |
| 107 | + |
| 108 | + return token |
0 commit comments