Skip to content

feat: offline cache probe paired with download helper#12

Merged
wavekat-eason merged 1 commit into
mainfrom
feat/is-cached-probe
May 17, 2026
Merged

feat: offline cache probe paired with download helper#12
wavekat-eason merged 1 commit into
mainfrom
feat/is-cached-probe

Conversation

@wavekat-eason

Copy link
Copy Markdown
Contributor

Summary

Adds an offline, pure-filesystem cache probe so consumers can answer "is this preset already on disk?" without touching the network.

  • download::is_repo_cached(repo_id, files) -> bool — generic, mirrors the existing download_files_with_progress(repo_id, files, dest_dir, on_progress) signature.
  • ModelPreset::is_cached(&self) -> bool — convenience method for the sherpa-onnx backend's preset constants.

Why

hf-hub 0.5 has no HF_HUB_OFFLINE support and no public lookup-only download API. The natural "try to construct the backend and see if it succeeds" probe therefore ends up firing a full HuggingFace metadata + download cycle on every cold-cache call — a UI that uses it as a quick "is the model ready?" check ends up silently downloading ~100 MB in the background and never showing its "Download model" CTA. Consumers that want to stay offline during a UI render need a pure-filesystem alternative.

How

The probe walks the on-disk layout hf-hub writes:

<cache_root>/models--<owner>--<repo>/snapshots/<commit>/<file>

…and returns true when at least one snapshot dir contains every requested file. The cache root is resolved exactly the way hf-hub 0.5's Cache::from_env does: honor HF_HOME (appending hub), otherwise default to \$HOME/.cache/huggingface/hub. USERPROFILE is also accepted as a Windows fallback for HOME.

The implementation is split into:

  • pub fn is_repo_cached — public entry point, looks up cache_root from the environment.
  • fn hf_hub_cache_root — env resolution, factored out for clarity.
  • fn snapshot_satisfies_files(cache_root, repo_id, files) — pure logic, factored out so the unit test can drive it against a temp dir without touching the real cache or polluting process-wide env vars.

ModelPreset::is_cached is a one-liner over is_repo_cached(self.model_id, &self.files()), paralleling the existing download_preset_with_progress wrapper.

Tests

Two new unit tests in download::tests:

  • snapshot_probe_matches_hf_hub_layout — builds the cache layout step by step in a temp dir and asserts (a) false for missing repo / empty snapshot dirs / partial files and (b) true once every requested file is present in at least one snapshot. Also covers a second, half-complete snapshot not invalidating a first complete one.
  • snapshot_probe_flattens_slashes_in_repo_id — guards against a silent regression where a slash-bearing repo id (the common case) wouldn't be flattened to <owner>--<repo> and the probe would always look in a non-existent directory.

Pure-fs, no network, no real models needed — runs under the existing make ci matrix.

Test plan

  • make test (9 passed, 0 failed)
  • make lint (clippy clean)
  • make ci (fmt + clippy + test + doc-test all green)

🤖 Generated with Claude Code

Adds `download::is_repo_cached(repo_id, files)` and the convenience
method `ModelPreset::is_cached()` so consumers can decide between
rendering a "Download" affordance and a "Ready" indicator without
risking a silent download.

The motivating gap: `hf-hub` 0.5 has no `HF_HUB_OFFLINE` support and
no public lookup-only API. A naïve "try to construct the backend
and see if it succeeds" probe ends up downloading on every cold-cache
call. The new probe walks `hf-hub`'s on-disk snapshot layout
(`<cache_root>/models--<owner>--<repo>/snapshots/<commit>/<file>`)
without touching the network, mirroring how `hf-hub` itself resolves
the cache root (`HF_HOME` or `\$HOME/.cache/huggingface/hub`).

Pairs with `download_files_with_progress`: the same `(repo_id,
files)` pair you pass there answers "do I still need to download?"
here. Includes unit tests covering missing repo, partial files,
multiple snapshots, and slash-flattening in repo ids.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@wavekat-eason
wavekat-eason merged commit 722a8b6 into main May 17, 2026
3 checks passed
@wavekat-eason
wavekat-eason deleted the feat/is-cached-probe branch May 17, 2026 05:12
@github-actions github-actions Bot mentioned this pull request May 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant