Spaces:
Sleeping
Sleeping
Download scripts/build_examples.py from malteos/cc-repackage: direct link, hf CLI and curl.
- Browser
- Download file 6.5 kB
-
https://huggingface.co/spaces/malteos/cc-repackage/resolve/main/scripts/build_examples.py
- Command line
-
hf download hf://spaces/malteos/cc-repackage/scripts/build_examples.py
-
curl -L -o build_examples.py https://huggingface.co/spaces/malteos/cc-repackage/resolve/main/scripts/build_examples.py
6.5 kB
| #!/usr/bin/env python | |
| """One-time data-prep: build + host the precomputed Example datasets. | |
| For each example defined in ``src/examples.py`` this: | |
| 1. runs the real index scan (``src.index_query`` in cdn mode) with the example's | |
| SQL filter + record cap, writing a capped ``ranges.csv`` locally; | |
| 2. runs the real ``cdxt repackage`` (same local real-fetch path as | |
| ``scripts/verify_real.sh``) to produce the output WARC(s) locally; | |
| 3. uploads the WARC(s) + ranges.csv to the PUBLIC examples bucket; | |
| 4. prints the confirmed ``n_records`` / ``total_bytes`` / ``scan_files`` / filenames | |
| to paste back into ``EXAMPLES`` in ``src/examples.py``. | |
| Needs ``HF_TOKEN`` (bucket read of the CC index + write to the examples bucket) and a | |
| positive-balance HF account is NOT required (no HF Jobs — everything runs locally). | |
| Usage: | |
| HF_TOKEN=... scripts/build_examples.py [--bucket ns/bucket] [--only key,key] [--keep-private] | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import glob | |
| import io | |
| import os | |
| import re | |
| import subprocess | |
| import sys | |
| from contextlib import redirect_stdout | |
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| from src import config, examples # noqa: E402 | |
| CDXT = ".venv/bin/cdxt" | |
| CDXT_SPEC = ( | |
| "cdx_toolkit[hf] @ git+https://github.com/commoncrawl/cdx_toolkit.git@feat/warc-range-sources" | |
| ) | |
| # Build-time only: cap the parquet files scanned for the broad no-domain examples so the | |
| # build takes minutes, not hours (PDFs / homepages are common enough in any few files). | |
| BUILD_MAX_FILES = {"pdfs": 8, "homepages": 4} | |
| _ESTIMATE_RE = re.compile(r"ESTIMATE\s+n_records=(\d+)\s+total_bytes=(\d+)") | |
| _SCAN_RE = re.compile(r"\[index\]\s+(\d+)\s+parquet file\(s\) to scan") | |
| def _run_index(ex, ranges_csv: str) -> tuple[int, int, int, str]: | |
| """Run the real index scan for one example; return (n_records, total_bytes, scan_files, log).""" | |
| from src import index_query | |
| env = { | |
| "CC_INDEX_MODE": "cdn", | |
| "CC_CRAWLS": ",".join(ex.crawls), | |
| "CC_HOSTNAMES": ",".join(ex.hostnames), | |
| "CC_DOMAINS": ",".join(ex.domains), | |
| "CC_LANGUAGES": ",".join(ex.languages), | |
| "CC_SQL_WHERE": ex.sql_where, | |
| "CC_MAX_RECORDS": str(ex.max_records or 0), | |
| "CC_MAX_FILES": str(BUILD_MAX_FILES.get(ex.key, 0)), | |
| "CC_RANGES_OUT": ranges_csv, | |
| } | |
| old = {k: os.environ.get(k) for k in env} | |
| os.environ.update(env) | |
| buf = io.StringIO() | |
| try: | |
| with redirect_stdout(buf): | |
| rc = index_query.main() | |
| finally: | |
| for k, v in old.items(): | |
| if v is None: | |
| os.environ.pop(k, None) | |
| else: | |
| os.environ[k] = v | |
| log = buf.getvalue() | |
| print(log) | |
| if rc != 0: | |
| raise SystemExit(f"index scan failed for {ex.key} (rc={rc})") | |
| m = _ESTIMATE_RE.search(log) | |
| n_records, total_bytes = (int(m.group(1)), int(m.group(2))) if m else (0, 0) | |
| ms = _SCAN_RE.search(log) | |
| scan_files = int(ms.group(1)) if ms else 0 | |
| return n_records, total_bytes, scan_files, log | |
| def _bootstrap_cdxt() -> None: | |
| if not os.access(CDXT, os.X_OK): | |
| print("== installing cdx_toolkit for the fetch step ==") | |
| subprocess.run( | |
| ["uv", "pip", "install", "--python", ".venv", CDXT_SPEC, "uvloop"], check=True | |
| ) | |
| def _run_fetch(ex, ranges_csv: str, out_dir: str) -> list[str]: | |
| """Run the real cdxt repackage locally; return the produced WARC file paths.""" | |
| _bootstrap_cdxt() | |
| out_prefix = os.path.join(out_dir, ex.name) | |
| cmd = [ | |
| CDXT, "-v", "repackage", | |
| "--target-source", "csv", "--csv-path", ranges_csv, | |
| "--warc-download-prefix", f"hf://buckets/{config.CC_BUCKET}", "--hf-reader", "cdn", | |
| "--prefix", out_prefix, | |
| "--processes", "1", "--parallel_readers", str(config.DEFAULT_PARALLEL_READERS), | |
| "--size", str(config.WARC_TARGET_SIZE), | |
| ] | |
| env = dict(os.environ, CDXT_UVLOOP="1") | |
| subprocess.run(cmd, check=True, env=env) | |
| return sorted(glob.glob(f"{out_prefix}*.warc.gz")) | |
| def _upload(api, bucket: str, ex, warcs: list[str], ranges_csv: str) -> list[str]: | |
| add = [(w, f"{ex.path}/{os.path.basename(w)}") for w in warcs] | |
| add.append((ranges_csv, f"{ex.path}/{config.RANGES_CSV_NAME}")) | |
| api.batch_bucket_files(bucket, add=add, token=os.environ["HF_TOKEN"]) | |
| return [os.path.basename(w) for w in warcs] | |
| def main() -> int: | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--bucket", default=examples.EXAMPLES_BUCKET) | |
| ap.add_argument("--only", default="", help="comma-separated example keys to build") | |
| ap.add_argument("--keep-private", action="store_true", help="do NOT make the bucket public") | |
| ap.add_argument("--out-dir", default="/tmp/cc-examples-build") | |
| args = ap.parse_args() | |
| token = os.environ.get("HF_TOKEN") | |
| if not token: | |
| raise SystemExit("set HF_TOKEN") | |
| from huggingface_hub import HfApi | |
| api = HfApi() | |
| api.create_bucket(args.bucket, private=args.keep_private, exist_ok=True, token=token) | |
| print(f"== examples bucket: {args.bucket} (public={not args.keep_private}) ==") | |
| only = {k for k in args.only.split(",") if k} | |
| todo = [ex for ex in examples.EXAMPLES if not only or ex.key in only] | |
| os.makedirs(args.out_dir, exist_ok=True) | |
| results = {} | |
| for ex in todo: | |
| print(f"\n===== building example: {ex.key} =====") | |
| ranges_csv = os.path.join(args.out_dir, f"{ex.key}-ranges.csv") | |
| ex_out = os.path.join(args.out_dir, ex.key) | |
| os.makedirs(ex_out, exist_ok=True) | |
| n_records, total_bytes, scan_files, _ = _run_index(ex, ranges_csv) | |
| if n_records == 0: | |
| print(f"WARNING: {ex.key} matched 0 records — skipping fetch/upload") | |
| continue | |
| warcs = _run_fetch(ex, ranges_csv, ex_out) | |
| files = _upload(api, args.bucket, ex, warcs, ranges_csv) | |
| results[ex.key] = dict( | |
| n_records=n_records, total_bytes=total_bytes, scan_files=scan_files, files=files | |
| ) | |
| print(f" -> {ex.key}: n_records={n_records} total_bytes={total_bytes} " | |
| f"scan_files={scan_files} files={files}") | |
| print("\n===== paste into src/examples.py (per example) =====") | |
| for key, r in results.items(): | |
| print(f"# {key}: n_records={r['n_records']}, total_bytes={r['total_bytes']}, " | |
| f"scan_files={r['scan_files']}, files={r['files']}") | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |