Spaces:
Running
Running
Download scripts/build_cert_format_catalog.py from Couscouskabyle/iscc-app: direct link, hf CLI and curl.
- Browser
- Download file 7.22 kB
-
https://huggingface.co/spaces/Couscouskabyle/iscc-app/resolve/main/scripts/build_cert_format_catalog.py
- Command line
-
hf download hf://spaces/Couscouskabyle/iscc-app/scripts/build_cert_format_catalog.py
-
curl -L -o build_cert_format_catalog.py https://huggingface.co/spaces/Couscouskabyle/iscc-app/resolve/main/scripts/build_cert_format_catalog.py
7.22 kB
| """Build the certificate-format catalog from the parsed PDF artifact.""" | |
| from __future__ import annotations | |
| import argparse | |
| import gzip | |
| import json | |
| import shutil | |
| import sqlite3 | |
| import sys | |
| import tempfile | |
| from datetime import datetime, timezone | |
| from pathlib import Path | |
| from urllib.request import Request, urlopen | |
| ROOT = Path(__file__).resolve().parents[1] | |
| if str(ROOT) not in sys.path: | |
| sys.path.insert(0, str(ROOT)) | |
| from collections import defaultdict | |
| from sinetti_services.cert_format_catalog import ( | |
| FormatDoc, | |
| artifact_sha256, | |
| build_catalog, | |
| choose_bucket, | |
| load_format_docs, | |
| pick_exemplar, | |
| thumb_filename, | |
| type_key, | |
| write_catalog, | |
| ) | |
| from cert_pdf_models import PdfDocumentRef | |
| from cert_pdf_ocr import _render_pdf_pages | |
| from ins import _doc_operator_id | |
| def _utc_now() -> str: | |
| return datetime.now(timezone.utc).isoformat(timespec="seconds") | |
| def _iter_ins_records(value): | |
| if isinstance(value, list): | |
| for item in value: | |
| yield from _iter_ins_records(item) | |
| elif isinstance(value, dict): | |
| if ( | |
| "certificate_id" in value | |
| or "codiceDelCertificato" in value | |
| ): | |
| yield value | |
| else: | |
| for item in value.values(): | |
| yield from _iter_ins_records(item) | |
| def _load_ins_cb_map(path: Path) -> dict[str, str]: | |
| """Map INS operator app ids to the newest-issued non-empty issuing CB. | |
| Equal or missing issue dates keep the first non-empty CB encountered. | |
| """ | |
| if not path.exists(): | |
| return {} | |
| payload = json.loads(path.read_text(encoding="utf-8")) | |
| best: dict[str, tuple[str, str]] = {} | |
| for record in _iter_ins_records(payload): | |
| operator_id = _doc_operator_id(record) | |
| issuing_cb = str( | |
| record.get("issuing_cb") | |
| or record.get("organismoDiCertificazione") | |
| or "" | |
| ).strip() | |
| issued = str(record.get("issued") or "").strip() | |
| previous = best.get(operator_id) | |
| if operator_id and issuing_cb and ( | |
| previous is None or issued > previous[0] | |
| ): | |
| best[operator_id] = (issued, issuing_cb) | |
| return { | |
| operator_id: issuing_cb | |
| for operator_id, (_issued, issuing_cb) in best.items() | |
| } | |
| def _open_artifact(path: Path): | |
| if path.suffix != ".gz": | |
| return sqlite3.connect(path), None | |
| temp_dir = tempfile.TemporaryDirectory(prefix="sinetti_cert_formats_") | |
| sqlite_path = Path(temp_dir.name) / "details.sqlite" | |
| with gzip.open(path, "rb") as source, sqlite_path.open("wb") as target: | |
| shutil.copyfileobj(source, target) | |
| return sqlite3.connect(sqlite_path), temp_dir | |
| def _fetch_pdf_bytes(doc: FormatDoc) -> bytes: | |
| if doc.scheme == "REDcert" or doc.pdf_url.startswith("redcert://"): | |
| try: | |
| from redcert_pdf_store import load_hosted_pdf | |
| hosted = load_hosted_pdf(doc.certificate_id) | |
| if hosted: | |
| return bytes(hosted[0]) | |
| except Exception: | |
| pass | |
| from cert_pdf_parsers.redcert import fetch_redcert_pdf_bytes | |
| return fetch_redcert_pdf_bytes( | |
| PdfDocumentRef( | |
| scheme=doc.scheme, | |
| certificate_id=doc.certificate_id, | |
| pdf_url=doc.pdf_url or f"redcert://{doc.certificate_id}", | |
| ) | |
| ) | |
| if not doc.pdf_url.startswith(("http://", "https://")): | |
| return b"" | |
| request = Request( | |
| doc.pdf_url, | |
| headers={"User-Agent": "Sinetti cert-format catalog builder"}, | |
| ) | |
| with urlopen(request, timeout=30) as response: | |
| return response.read() | |
| def _exemplar_docs_by_type_key(docs: list[FormatDoc]) -> dict[str, FormatDoc]: | |
| grouped: dict[tuple[str, str, str], list[FormatDoc]] = defaultdict(list) | |
| for doc in docs: | |
| bucket_kind, bucket_id = choose_bucket( | |
| doc.scheme, | |
| doc.parse_status, | |
| list(doc.reason_codes), | |
| ins_cb=doc.ins_cb, | |
| ) | |
| grouped[(doc.scheme, bucket_kind, bucket_id)].append(doc) | |
| return { | |
| type_key(scheme, bucket_kind, bucket_id): pick_exemplar(bucket_docs) | |
| for (scheme, bucket_kind, bucket_id), bucket_docs in grouped.items() | |
| } | |
| def _add_thumbnails( | |
| catalog: dict, | |
| docs: list[FormatDoc], | |
| *, | |
| thumbs_dir: Path, | |
| ) -> None: | |
| exemplars = _exemplar_docs_by_type_key(docs) | |
| for entries in catalog["schemes"].values(): | |
| for entry in entries: | |
| try: | |
| doc = exemplars[entry["type_key"]] | |
| pdf_bytes = _fetch_pdf_bytes(doc) | |
| if not pdf_bytes: | |
| continue | |
| rendered, _diagnostics = _render_pdf_pages( | |
| pdf_bytes, | |
| pages=[1], | |
| dpi=110, | |
| ) | |
| if not rendered: | |
| continue | |
| filename = thumb_filename(entry["type_key"]) | |
| thumbs_dir.mkdir(parents=True, exist_ok=True) | |
| rendered[0][1].save(thumbs_dir / filename, "PNG") | |
| entry["thumbnail"] = f"cert_format_thumbs/{filename}" | |
| except Exception: | |
| continue | |
| def main(argv: list[str] | None = None) -> int: | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument( | |
| "--artifact", | |
| default=str(ROOT / "data" / "cert_pdf_details.sqlite.gz"), | |
| ) | |
| parser.add_argument( | |
| "--out", | |
| default=str(ROOT / "data" / "cert_format_catalog.json"), | |
| ) | |
| parser.add_argument( | |
| "--ins-index", | |
| default=str(ROOT / "data" / "ins" / "cert_pdfs.json"), | |
| ) | |
| parser.add_argument("--thumbs-dir", default="") | |
| parser.add_argument("--skip-thumbs", action="store_true") | |
| args = parser.parse_args(argv) | |
| artifact = Path(args.artifact) | |
| out = Path(args.out) | |
| conn, temp_dir = _open_artifact(artifact) | |
| try: | |
| docs = load_format_docs( | |
| conn, | |
| ins_cb_by_cert_id=_load_ins_cb_map(Path(args.ins_index)), | |
| ) | |
| finally: | |
| conn.close() | |
| if temp_dir is not None: | |
| temp_dir.cleanup() | |
| catalog = build_catalog(docs, built_at=_utc_now()) | |
| # Lets the freshness guard (tests/test_cert_format_catalog_fresh.py) prove this catalog | |
| # describes the committed details artifact, not an older parse. | |
| catalog["source_sha256"] = artifact_sha256(artifact) | |
| if not args.skip_thumbs: | |
| thumbs_dir = ( | |
| Path(args.thumbs_dir) | |
| if args.thumbs_dir | |
| else out.parent / "cert_format_thumbs" | |
| ) | |
| _add_thumbnails(catalog, docs, thumbs_dir=thumbs_dir) | |
| write_catalog(out, catalog) | |
| report = { | |
| "status": "ok", | |
| "types": sum(len(entries) for entries in catalog["schemes"].values()), | |
| "docs": len(docs), | |
| "path": str(out), | |
| } | |
| print(json.dumps(report, indent=2, sort_keys=True)) | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |