| """Rangkum semua run jadi angka siap pakai untuk justifikasi resource. |
| |
| py -m src.knowledge_parsing.report |
| py -m src.knowledge_parsing.report --scale 6800 |
| |
| `--scale` mengekstrapolasi ke jumlah halaman tertentu (mis. skala BUMA |
| ±6.700-6.800 halaman) memakai detik/halaman yang TERUKUR — dokumen yang |
| diambil dari cache tidak ikut dihitung, karena akan membuat angkanya |
| terlihat jauh lebih cepat dari kenyataan. |
| """ |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import json |
| from pathlib import Path |
|
|
| from .config import PipelineConfig |
|
|
| |
| |
| |
| MIN_HALAMAN_SAHIH = 20 |
|
|
|
|
| def _jam(detik: float) -> str: |
| if detik < 90: |
| return f"{detik:.0f} dtk" |
| if detik < 5400: |
| return f"{detik/60:.1f} mnt" |
| return f"{detik/3600:.1f} jam" |
|
|
|
|
| def kumpulkan(runs_dir: Path) -> list[dict]: |
| hasil = [] |
| for m in sorted(runs_dir.glob("*/manifest.json")): |
| try: |
| hasil.append(json.loads(m.read_text(encoding="utf-8"))) |
| except (OSError, json.JSONDecodeError) as e: |
| |
| |
| |
| print(f" ! lewati manifest tidak terbaca: {m} ({type(e).__name__})") |
| return hasil |
|
|
|
|
| def cetak(runs: list[dict], scale: int | None) -> None: |
| if not runs: |
| print("Belum ada run. Jalankan: py -m src.knowledge_parsing.run --input dokumen/") |
| return |
|
|
| print(f"{'run':<17} {'backend':<9} {'ver':<8} {'dok':>4} {'hal':>5} " |
| f"{'dtk/hal':>8} {'peringatan':>11}") |
| print("-" * 68) |
|
|
| for r in runs: |
| s = r.get("ringkasan", {}) |
| cfg = r.get("config", {}) |
| |
| tercatat = {d.get("backend_tercatat") for d in r.get("dokumen", [])} - {None} |
| backend = "/".join(sorted(tercatat)) if tercatat else cfg.get("backend", "?") |
| dph = s.get("detik_per_halaman") |
| print(f"{r.get('run_id',''):<17} {backend:<9} " |
| f"{str(r.get('mineru_version') or '?')[:7]:<8} " |
| f"{s.get('dokumen_ok',0):>4} {s.get('total_halaman',0):>5} " |
| f"{(f'{dph:.2f}' if dph else '-'):>8} {s.get('total_peringatan',0):>11}") |
|
|
| terukur = [r for r in runs if (r.get("ringkasan") or {}).get("detik_per_halaman")] |
| if not terukur: |
| print("\n(belum ada run yang benar-benar diparse — semua dari cache)") |
| return |
|
|
| print("\n--- ekstrapolasi ---") |
| target = scale or 6800 |
| meragukan = False |
| for r in terukur: |
| s = r["ringkasan"] |
| dph = s["detik_per_halaman"] |
| hal = s.get("halaman_terukur", 0) |
| cfg = r.get("config", {}) |
| tanda = "" |
| if hal < MIN_HALAMAN_SAHIH: |
| tanda = f" ⚠ hanya {hal} hal." |
| meragukan = True |
| print(f" {cfg.get('backend','?'):<9} {dph:>6.2f} dtk/hal → " |
| f"{target} halaman = {_jam(dph * target)}{tanda}") |
|
|
| if meragukan: |
| print( |
| f"\n ⚠ Run dengan < {MIN_HALAMAN_SAHIH} halaman TIDAK layak diekstrapolasi.\n" |
| " Pemuatan model adalah ongkos tetap, jadi dokumen kecil terlihat jauh\n" |
| " lebih lambat per halaman. Terukur sebelumnya di mesin ini:\n" |
| " 1 hal -> 54,0 dtk/hal | 5 hal -> 33,2 | 20 hal -> 19,0\n" |
| " Pakai dokumen >= 20 halaman sebelum angkanya dibawa ke luar." |
| ) |
|
|
| if len(terukur) >= 2: |
| cepat = min(terukur, key=lambda r: r["ringkasan"]["detik_per_halaman"]) |
| lambat = max(terukur, key=lambda r: r["ringkasan"]["detik_per_halaman"]) |
| a = lambat["ringkasan"]["detik_per_halaman"] |
| b = cepat["ringkasan"]["detik_per_halaman"] |
| if b: |
| print(f"\n selisih tercepat vs terlambat: {a/b:.1f}×") |
|
|
|
|
| def main() -> None: |
| p = argparse.ArgumentParser(description="Ringkasan angka dari semua run") |
| p.add_argument("--runs-dir", type=Path, default=None) |
| p.add_argument("--scale", type=int, default=None, |
| help="ekstrapolasi ke berapa halaman (mis. 6800)") |
| a = p.parse_args() |
| cfg = PipelineConfig() |
| cetak(kumpulkan(a.runs_dir or cfg.runs_dir), a.scale) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|