laya-ad / code /scripts /fetch_model_modelscope.py
x6nux's picture
laya-ad v1.1:六精度权重 + 模型卡 + 项目代码快照
71dabc7 verified
Raw History Blame Contribute Delete
3.06 kB
#!/usr/bin/env python3
"""从 ModelScope 镜像下载模型权重(HF 直连被墙时的替代路径)。
ModelScope 的下载地址是单文件 API,不支持 huggingface_hub,所以自己拉清单 + 断点续传。
已完整的文件按大小跳过,中断后重跑即可续传。
"""
from __future__ import annotations
import argparse
import json
import os
import subprocess
import sys
import urllib.parse
import urllib.request
API = "https://modelscope.cn/api/v1/models/{repo}/repo/files?Revision={rev}"
FILE_API = "https://modelscope.cn/api/v1/models/{repo}/repo?Revision={rev}&FilePath={path}"
def list_files(repo: str, rev: str) -> list[dict]:
url = API.format(repo=repo, rev=rev)
with urllib.request.urlopen(url, timeout=60) as r:
data = json.load(r)["Data"]["Files"]
return [f for f in data if f["Type"] == "blob" and f["Size"] > 0]
def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("--repo", default="Cloudflare/clef-flash")
ap.add_argument("--rev", default="master")
ap.add_argument("--out", default="models/clef-flash")
ap.add_argument("--verify", action="store_true", help="只校验完整性,不下载")
args = ap.parse_args()
os.makedirs(args.out, exist_ok=True)
files = list_files(args.repo, args.rev)
total = sum(f["Size"] for f in files)
print(f"[list] {len(files)} 个文件,合计 {total/1024**3:.1f} GB")
if args.verify:
missing = [f["Name"] for f in files
if not (os.path.exists(os.path.join(args.out, f["Name"]))
and os.path.getsize(os.path.join(args.out, f["Name"])) == f["Size"])]
if missing:
print(f"[verify] 未完成,缺 {len(missing)} 个文件:{missing}", file=sys.stderr)
sys.exit(1)
print(f"[verify] 全部完整 {total/1024**3:.1f} GB")
return
done_bytes = 0
for i, f in enumerate(files, 1):
name, size = f["Name"], f["Size"]
dest = os.path.join(args.out, name)
if os.path.exists(dest) and os.path.getsize(dest) == size:
print(f"[skip] {name} 已完整")
done_bytes += size
continue
url = FILE_API.format(repo=args.repo, rev=args.rev,
path=urllib.parse.quote(name, safe=""))
print(f"[get ] ({i}/{len(files)}) {name} {size/1024**3:.2f} GB", flush=True)
# -C - 续传;--retry 应对镜像抖动
rc = subprocess.call([
"curl", "-L", "-C", "-", "--retry", "8", "--retry-delay", "5",
"--connect-timeout", "30", "-sS", "-o", dest, url,
])
got = os.path.getsize(dest) if os.path.exists(dest) else 0
if rc != 0 or got != size:
print(f"[fail] {name}: rc={rc} got={got} want={size}", file=sys.stderr)
sys.exit(1)
done_bytes += size
print(f"[ ok ] {name} ({done_bytes/1024**3:.1f}/{total/1024**3:.1f} GB)", flush=True)
print(f"DONE {args.out} {total/1024**3:.1f} GB")
if __name__ == "__main__":
main()