sofhiaazzhr's picture
[NOTICKET] feat(knowledge-parsing): document parsing half of the knowledge pipeline
5840d20
Raw
History Blame
3.04 kB
"""Catatan satu kali jalan — bahan mentah untuk angka justifikasi biaya.
Yang WAJIB tercatat dan gampang terlupa: backend yang benar-benar dipakai dan
versi MinerU. Tanpa keduanya, angka CPU hari ini tidak sah dibandingkan dengan
angka GPU bulan depan — padahal perbandingan itulah inti argumennya.
Backend dibaca dari `_middle.json` keluaran MinerU (`_backend`), bukan dari
config, supaya yang tercatat adalah kenyataan, bukan niat.
"""
from __future__ import annotations
import json
import platform
from dataclasses import asdict, dataclass, field
from datetime import datetime
from pathlib import Path
from typing import Any
@dataclass
class CatatanDokumen:
doc_id: str
source: str
status: str # "ok" | "gagal"
pages: int = 0
detik_parse: float = 0.0
detik_normalisasi: float = 0.0
dari_cache: bool = False
jumlah_chunk: int = 0
backend_tercatat: str | None = None
pemeriksaan: dict[str, Any] = field(default_factory=dict)
galat: str | None = None
@property
def detik_per_halaman(self) -> float | None:
return self.detik_parse / self.pages if self.pages else None
@dataclass
class Manifest:
run_id: str
dimulai: str
config: dict[str, Any]
mineru_version: str | None = None
mesin: dict[str, str] = field(default_factory=dict)
dokumen: list[CatatanDokumen] = field(default_factory=list)
@classmethod
def baru(cls, config: dict[str, Any]) -> Manifest:
return cls(
run_id=datetime.now().strftime("%Y%m%d-%H%M%S"),
dimulai=datetime.now().isoformat(timespec="seconds"),
config=config,
mesin={
"os": platform.platform(),
"python": platform.python_version(),
"prosesor": platform.processor() or "?",
},
)
def ringkasan(self) -> dict[str, Any]:
ok = [d for d in self.dokumen if d.status == "ok"]
halaman = sum(d.pages for d in ok)
# Hanya run NYATA yang dihitung untuk kecepatan — hasil dari cache
# akan membuat angkanya terlihat jauh lebih cepat dari kenyataan.
nyata = [d for d in ok if not d.dari_cache]
detik = sum(d.detik_parse for d in nyata)
halaman_nyata = sum(d.pages for d in nyata)
return {
"dokumen_ok": len(ok),
"dokumen_gagal": len(self.dokumen) - len(ok),
"total_halaman": halaman,
"halaman_terukur": halaman_nyata,
"detik_parse_terukur": round(detik, 1),
"detik_per_halaman": round(detik / halaman_nyata, 2) if halaman_nyata else None,
"total_peringatan": sum(
d.pemeriksaan.get("jumlah_peringatan", 0) for d in self.dokumen
),
}
def simpan(self, path: Path) -> None:
isi = asdict(self)
isi["ringkasan"] = self.ringkasan()
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(isi, indent=2, ensure_ascii=False), encoding="utf-8")