Download tools/server_sync.py from DarthSoluke/EgoNetDatasetResearch: direct link, hf CLI and curl.
- Browser
- Download file 6.5 kB
-
https://huggingface.co/spaces/DarthSoluke/EgoNetDatasetResearch/resolve/main/tools/server_sync.py
- Command line
-
hf download hf://spaces/DarthSoluke/EgoNetDatasetResearch/tools/server_sync.py
-
curl -L -o server_sync.py https://huggingface.co/spaces/DarthSoluke/EgoNetDatasetResearch/resolve/main/tools/server_sync.py
6.5 kB
| #!/usr/bin/env python3 | |
| """在存放数据集的服务器上运行:批量生成样例并同步到 Hugging Face。 | |
| 做法与团队 nine-source Space 一致:图片放进一个独立的 HF Dataset 仓库, | |
| Space 只登记固定版本的 URL,网页不依赖 SSH、本机服务或临时隧道。 | |
| export HF_TOKEN=hf_xxx # 或先 hf auth login | |
| python tools/server_sync.py manifest.jsonl \ | |
| --media-repo DarthSoluke/EgoNetDatasetResearch-media \ | |
| --space DarthSoluke/EgoNetDatasetResearch | |
| manifest.jsonl 每行一个样例,两种写法任选: | |
| 已经渲染好的叠加图 | |
| {"dataset": "hograspnet", "rgb": "/SSD/.../0042.png", "gt": "/SSD/.../0042_overlay.png", | |
| "caption": "受试者 01,侧捏", "source": "官方 MANO"} | |
| 只有原图和网格,由本脚本渲染(网格可以是 MANO,也可以是转换后的 SOMA) | |
| {"dataset": "hograspnet", "rgb": "/SSD/.../0042.png", "mesh": "/SSD/.../0042_soma.npz", | |
| "caption": "受试者 01,侧捏", "source": "官方 MANO → R1 → SOMA"} | |
| mesh.npz 的格式见 render_overlay.py(verts、faces、K,可选 joints) | |
| 可选字段:name(样例名,默认取 rgb 文件名)。 | |
| 参数: | |
| --replace 先清掉这些数据集里以前由本脚本同步的样例,再写入新的 | |
| --local-only 只写到本地目录 --out(默认 ./sync_out),不上传,用于先检查 | |
| """ | |
| import argparse | |
| import json | |
| import os | |
| import re | |
| import shutil | |
| import sys | |
| import tempfile | |
| from pathlib import Path | |
| from PIL import Image | |
| sys.path.insert(0, str(Path(__file__).resolve().parent)) | |
| from render_overlay import overlay # noqa: E402 | |
| ORIGIN = "server_sync" | |
| def to_jpg(img, dst, max_side): | |
| img = img.convert("RGB") | |
| s = max_side / max(img.size) | |
| if s < 1: | |
| img = img.resize((round(img.width * s), round(img.height * s)), Image.LANCZOS) | |
| dst.parent.mkdir(parents=True, exist_ok=True) | |
| img.save(dst, "JPEG", quality=86, optimize=True) | |
| def build(manifest, stage, max_side): | |
| import numpy as np | |
| rows = [json.loads(l) for l in Path(manifest).read_text(encoding="utf-8").splitlines() if l.strip()] | |
| items = {} | |
| for i, r in enumerate(rows, 1): | |
| ds = r["dataset"] | |
| name = re.sub(r"[^\w\-]", "_", r.get("name") or Path(r["rgb"]).stem.removesuffix("_rgb")) | |
| rgb = Image.open(r["rgb"]) | |
| if r.get("gt"): | |
| gt = Image.open(r["gt"]) | |
| elif r.get("mesh"): | |
| m = np.load(r["mesh"]) | |
| K = np.array(r["K"]) if r.get("K") else m["K"] | |
| gt = overlay(rgb, m["verts"], m["faces"], K, joints=m["joints"] if "joints" in m.files else None) | |
| else: | |
| sys.exit(f"第 {i} 行既没有 gt 也没有 mesh") | |
| rel_rgb, rel_gt = f"media/{ds}/{name}_rgb.jpg", f"media/{ds}/{name}_gt.jpg" | |
| to_jpg(rgb, stage / rel_rgb, max_side) | |
| to_jpg(gt, stage / rel_gt, max_side) | |
| size = Image.open(stage / rel_rgb).size | |
| items.setdefault(ds, []).append({"id":name,"rgb":rel_rgb,"gt":rel_gt,"modes":[{"label":r.get("source", ""),"src":rel_gt}], | |
| "width":size[0],"height":size[1],"caption":r.get("caption", ""),"source":r.get("source", ""), | |
| "rgb_label":"原始 RGB","strata":r.get("strata",{}),"source_page":r.get("source_page",""), | |
| "evidence_url":r.get("evidence_url",""),"license":r.get("license",""),"note":"","origin":ORIGIN}) | |
| print(f"[{i}/{len(rows)}] {ds}/{name}") | |
| return items | |
| def merge(prev, items, prefix, replace): | |
| for ds, new in items.items(): | |
| old = prev.get(ds, []) | |
| if replace: | |
| old = [p for p in old if p.get("origin") != ORIGIN] | |
| new_paths = {prefix + n["rgb"] for n in new} | |
| old = [p for p in old if p.get("rgb") not in new_paths] | |
| prev[ds] = [dict(n, rgb=prefix+n["rgb"], gt=prefix+n["gt"], | |
| modes=[{"label":m["label"],"src":prefix+m["src"]} for m in n["modes"]]) for n in new] + old | |
| return prev | |
| def main(): | |
| ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) | |
| ap.add_argument("manifest") | |
| ap.add_argument("--media-repo", default="DarthSoluke/EgoNetDatasetResearch-media") | |
| ap.add_argument("--space", default="DarthSoluke/EgoNetDatasetResearch") | |
| ap.add_argument("--max-side", type=int, default=960) | |
| ap.add_argument("--replace", action="store_true") | |
| ap.add_argument("--local-only", action="store_true") | |
| ap.add_argument("--out", default="sync_out") | |
| a = ap.parse_args() | |
| if a.local_only: | |
| out = Path(a.out) | |
| items = build(a.manifest, out, a.max_side) | |
| pf = out / "data/previews.json" | |
| prev = json.loads(pf.read_text(encoding="utf-8")) if pf.exists() else {} | |
| pf.parent.mkdir(parents=True, exist_ok=True) | |
| pf.write_text(json.dumps(merge(prev, items, "", a.replace), ensure_ascii=False, indent=1) + "\n", encoding="utf-8") | |
| print(f"已写到 {out}/,检查无误后去掉 --local-only 重新运行") | |
| return | |
| from huggingface_hub import HfApi, hf_hub_download | |
| api = HfApi(token=os.environ.get("HF_TOKEN")) | |
| stage = Path(tempfile.mkdtemp(prefix="soma_sync_")) | |
| try: | |
| items = build(a.manifest, stage, a.max_side) | |
| api.create_repo(a.media_repo, repo_type="dataset", exist_ok=True) | |
| info = api.upload_folder(repo_id=a.media_repo, repo_type="dataset", folder_path=str(stage), | |
| commit_message=f"同步 {sum(map(len, items.values()))} 对样例:{', '.join(sorted(items))}") | |
| rev = info.oid | |
| prefix = f"https://huggingface.co/datasets/{a.media_repo}/resolve/{rev}/" | |
| cur = hf_hub_download(a.space, "data/previews.json", repo_type="space", token=api.token) | |
| prev = json.loads(Path(cur).read_text(encoding="utf-8")) | |
| merged = merge(prev, items, prefix, a.replace) | |
| tmp = stage / "previews.json" | |
| tmp.write_text(json.dumps(merged, ensure_ascii=False, indent=1) + "\n", encoding="utf-8") | |
| api.upload_file(path_or_fileobj=str(tmp), path_in_repo="data/previews.json", repo_id=a.space, repo_type="space", | |
| commit_message=f"登记样例(媒体版本 {rev[:8]})") | |
| print(f"完成:媒体仓库版本 {rev},已更新 {a.space} 的 data/previews.json") | |
| finally: | |
| shutil.rmtree(stage, ignore_errors=True) | |
| if __name__ == "__main__": | |
| main() | |