From 8cefc18dc501a96fbbcbb4957a51da48aaf15a16 Mon Sep 17 00:00:00 2001 From: Longado Date: Sun, 13 Sep 2026 09:51:30 +0800 Subject: [PATCH 1/2] =?UTF-8?q?test(model-store):=20=E5=A4=8D=E7=8E=B0=20H?= =?UTF-8?q?F=20tree=20API=20=E8=BF=94=E5=9B=9E=E8=A3=B8=20LFS=20oid=20?= =?UTF-8?q?=E6=97=B6=E6=A8=A1=E5=9E=8B=E4=B8=8B=E8=BD=BD=E8=A2=AB=E6=8B=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit huggingface.co 与 hf-mirror.com 的 /api/models/{repo}/tree 接口里 lfs.oid 是不带 sha256: 前缀的 64 位十六进制,现有解析只认前缀形式,导致本地模型 下载直接报 unsupported Hugging Face LFS oid。 --- .../crates/openless-core/src/model_store.rs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/openless-all/app/crates/openless-core/src/model_store.rs b/openless-all/app/crates/openless-core/src/model_store.rs index a87aa0a42..f27790d9c 100644 --- a/openless-all/app/crates/openless-core/src/model_store.rs +++ b/openless-all/app/crates/openless-core/src/model_store.rs @@ -2940,6 +2940,31 @@ mod tests { .is_err()); } + #[test] + fn hf_tree_accepts_bare_lfs_oid_from_live_api() { + // Shape returned by huggingface.co and hf-mirror.com for Qwen/Qwen3-ASR-0.6B + // (2026-09-13): `lfs.oid` is the bare hex digest, without a `sha256:` prefix. + let entries = vec![serde_json::json!({ + "type": "file", + "oid": "3d4b2a1f0e9c8b7a6d5e4f3a2b1c0d9e8f7a6b5c", + "size": 1876091704u64, + "path": "model.safetensors", + "lfs": { + "oid": "79d6cbd4c98c7bbffe9db2edac07f56cd6637d0d5944b27f6c2b8353840323ea", + "size": 1876091704u64, + "pointerSize": 135 + } + })]; + let files = parse_hf_tree_page("Qwen/Qwen3-ASR-0.6B", "qwen3-asr-0.6b", &entries).unwrap(); + assert_eq!(files.len(), 1); + assert_eq!(files[0].path, "model.safetensors"); + assert_eq!(files[0].size_bytes, 1_876_091_704); + assert_eq!( + files[0].sha256.as_deref(), + Some("79d6cbd4c98c7bbffe9db2edac07f56cd6637d0d5944b27f6c2b8353840323ea") + ); + } + #[test] fn hf_link_pagination_accepts_same_origin_and_rejects_redirected_origin() { let current = "https://huggingface.co/api/models/org/model/tree/main?limit=1000"; From 4eebba2cad4f4768ae3bccdcaaf76cb416ee05a8 Mon Sep 17 00:00:00 2001 From: Longado Date: Sun, 13 Sep 2026 09:53:01 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(model-store):=20=E6=8E=A5=E5=8F=97=20HF?= =?UTF-8?q?=20tree=20API=20=E8=BF=94=E5=9B=9E=E7=9A=84=E8=A3=B8=20LFS=20oi?= =?UTF-8?q?d=EF=BC=8C=E4=BF=AE=E5=A4=8D=E6=9C=AC=E5=9C=B0=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E4=B8=8B=E8=BD=BD=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2.0 起 parse_lfs_sha256 只接受 sha256: 前缀,但 huggingface.co 与 hf-mirror.com 的 tree 接口返回的是裸 64 位十六进制,导致下载 Qwen3-ASR 等本地模型时直接报 unsupported Hugging Face LFS oid。改为前缀可选, 仍校验 64 位十六进制。 --- openless-all/app/crates/openless-core/src/model_store.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openless-all/app/crates/openless-core/src/model_store.rs b/openless-all/app/crates/openless-core/src/model_store.rs index f27790d9c..ab61b1818 100644 --- a/openless-all/app/crates/openless-core/src/model_store.rs +++ b/openless-all/app/crates/openless-core/src/model_store.rs @@ -2485,10 +2485,10 @@ fn parse_hf_tree_page_for_entry( Ok(files) } +/// The Hugging Face tree API returns `lfs.oid` as a bare SHA-256 hex digest; +/// the `sha256:`-prefixed form (as in Git LFS pointer files) is accepted too. fn parse_lfs_sha256(oid: &str) -> Result { - let digest = oid - .strip_prefix("sha256:") - .ok_or_else(|| invalid("unsupported Hugging Face LFS oid"))?; + let digest = oid.strip_prefix("sha256:").unwrap_or(oid); if digest.len() != 64 || !digest.bytes().all(|byte| byte.is_ascii_hexdigit()) { return Err(invalid("invalid Hugging Face LFS sha256 oid")); }