Download scripts/build_skill_matrix.py from weideyouni/holoaeon: direct link, hf CLI and curl.
- Browser
- Download file 4.97 kB
-
https://huggingface.co/weideyouni/holoaeon/resolve/main/scripts/build_skill_matrix.py
- Command line
-
hf download hf://weideyouni/holoaeon/scripts/build_skill_matrix.py
-
curl -L -o build_skill_matrix.py https://huggingface.co/weideyouni/holoaeon/resolve/main/scripts/build_skill_matrix.py
4.97 kB
| # -*- coding: utf-8 -*- | |
| r""" | |
| build_skill_matrix.py —— 全量技能索引 + F 盘以往项目基座清单(只读扫描,确定性输出) | |
| ================================================================================ | |
| 用法: | |
| python scripts/build_skill_matrix.py # 默认 5 个技能根 + F:\doubaowork | |
| python scripts/build_skill_matrix.py --roots A B # 指定技能根 | |
| python scripts/build_skill_matrix.py --projects P # 指定以往项目目录 | |
| python scripts/build_skill_matrix.py --json out.json # 额外打印摘要到文件 | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import os | |
| import sys | |
| from typing import Dict, List | |
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| from holoaeon.skill_matrix import DEFAULT_INDEX, default_roots # noqa: E402 | |
| from holoaeon.skill_matrix import index as Ix # noqa: E402 | |
| from holoaeon.skill_matrix.mech import semantic_overlap # noqa: E402 | |
| from holoaeon.skill_matrix.index import MECH_LEXICON # noqa: E402 | |
| ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |
| BASELINE = os.path.join(ROOT, "data", "skill_matrix_baseline.json") | |
| SKIP_PREFIX = (".", "_") | |
| FILE_CAP = 4000 | |
| def dir_stats(path: str) -> Dict[str, object]: | |
| files = py = 0 | |
| skill_md = 0 | |
| for base, dirs, names in os.walk(path): | |
| if files >= FILE_CAP: | |
| break | |
| dirs[:] = [d for d in dirs if not d.startswith(".")] | |
| for n in names: | |
| files += 1 | |
| if n.endswith(".py"): | |
| py += 1 | |
| elif n == "SKILL.md": | |
| skill_md += 1 | |
| return {"files": files, "py_files": py, "skill_md": skill_md, "capped": files >= FILE_CAP} | |
| def mech_guess(name: str) -> str: | |
| best, score = "unmapped", 0.0 | |
| for key, words in MECH_LEXICON.items(): | |
| sc = max((semantic_overlap(name, w) for w in words), default=0.0) | |
| if sc > score: | |
| best, score = key, sc | |
| return best | |
| def scan_projects(root: str) -> List[dict]: | |
| rows: List[dict] = [] | |
| if not os.path.isdir(root): | |
| return rows | |
| for entry in sorted(os.listdir(root)): | |
| p = os.path.join(root, entry) | |
| if entry.startswith(SKIP_PREFIX) or not os.path.exists(p): | |
| continue | |
| is_dir = os.path.isdir(p) | |
| stat = os.stat(p) | |
| if is_dir: | |
| ds = dir_stats(p) | |
| kind = "dir" | |
| py = ds["py_files"] | |
| files = ds["files"] | |
| else: | |
| kind = "zip" if entry.lower().endswith(".zip") else ( | |
| "md" if entry.lower().endswith(".md") else "file") | |
| py, files = 0, 1 | |
| rows.append({"name": entry, "kind": kind, | |
| "bytes": int(stat.st_size) if not is_dir else 0, | |
| "files": files, "py_files": py, | |
| "mechanism": mech_guess(entry), | |
| "tier": "基座候选" if (py >= 10 or files >= 50) else "素材"}) | |
| return rows | |
| def main(argv=None) -> int: | |
| ap = argparse.ArgumentParser(description="构建技能索引与基座清单") | |
| ap.add_argument("--roots", nargs="*", default=None) | |
| ap.add_argument("--projects", default=r"F:\doubaowork") | |
| ap.add_argument("--index", default=DEFAULT_INDEX) | |
| ap.add_argument("--baseline", default=BASELINE) | |
| ap.add_argument("--json", default=None) | |
| a = ap.parse_args(argv) | |
| roots = a.roots or default_roots() | |
| idx = Ix.build(roots) | |
| sha = Ix.save(idx, a.index) | |
| base_rows = scan_projects(a.projects) | |
| base = {"source": os.path.abspath(a.projects), | |
| "count": len(base_rows), "entries": base_rows, | |
| "summary": {"dirs": sum(1 for r in base_rows if r["kind"] == "dir"), | |
| "zips": sum(1 for r in base_rows if r["kind"] == "zip"), | |
| "md": sum(1 for r in base_rows if r["kind"] == "md"), | |
| "baseline_candidates": sum(1 for r in base_rows if r["tier"] == "基座候选"), | |
| "py_total": sum(int(r["py_files"]) for r in base_rows)}} | |
| os.makedirs(os.path.dirname(a.baseline), exist_ok=True) | |
| payload = json.dumps(base, ensure_ascii=False, indent=1, sort_keys=True) | |
| with open(a.baseline, "w", encoding="utf-8", newline="\n") as fh: | |
| fh.write(payload) | |
| summary = {"index": {"path": a.index, "digest": idx["digest"], "count": idx["count"], | |
| "sha16": sha, "roots": len(idx["roots"])}, | |
| "stats": idx["stats"], | |
| "baseline": dict(base["summary"], path=a.baseline, | |
| sha16=__import__("hashlib").sha256(payload.encode("utf-8")).hexdigest()[:16])} | |
| print(json.dumps(summary, ensure_ascii=False, indent=1)) | |
| if a.json: | |
| with open(a.json, "w", encoding="utf-8", newline="\n") as fh: | |
| fh.write(json.dumps(summary, ensure_ascii=False, indent=1)) | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |