File size: 4,531 Bytes
5840d20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"""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

# Di bawah ini, ongkos tetap pemuatan model mendominasi sehingga detik/halaman
# jauh lebih besar dari kenyataan pada dokumen besar. Terukur di mesin ini:
# 1 hal -> 54,0 dtk/hal, 5 hal -> 33,2, 20 hal -> 19,0.
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:
            # Manifest rusak/separuh tertulis (run yang mati di tengah). Dilewati,
            # tapi disebutkan — laporan yang diam-diam kehilangan satu run akan
            # memberi angka detik/halaman yang salah tanpa ada tandanya.
            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", {})
        # backend yang tercatat di output MinerU lebih dipercaya daripada 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()