"""Report OCR recall and snapping quality per page, from the built index. python tools/ocr_report.py """ from __future__ import annotations import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from spareparts import config, index_db # noqa: E402 def main() -> int: conn = index_db.connect(config.DB_PATH) try: rows = conn.execute( """ SELECT p.pdf_page, (SELECT COUNT(DISTINCT part_no) FROM occurrences o WHERE o.pdf_page = p.pdf_page) AS table_parts, (SELECT COUNT(*) FROM labels l WHERE l.pdf_page = p.pdf_page) AS callouts, (SELECT COUNT(DISTINCT l.part_no) FROM labels l JOIN occurrences o2 ON o2.part_no = l.part_no AND o2.pdf_page = l.pdf_page WHERE l.pdf_page = p.pdf_page) AS matched, (SELECT COUNT(*) FROM labels l WHERE l.pdf_page = p.pdf_page AND l.match_kind = 'fuzzy1') AS fuzzy, (SELECT COUNT(*) FROM labels l WHERE l.pdf_page = p.pdf_page AND l.in_page_table = 0) AS off_table FROM pages p ORDER BY p.pdf_page """ ).fetchall() print(f"{'page':>5} {'table':>6} {'found':>6} {'recall':>7} {'callouts':>9}" f" {'fuzzy':>6} {'not-in-table':>13}") total_table = total_found = total_callouts = total_fuzzy = total_off = 0 for r in rows: recall = 100 * r["matched"] / r["table_parts"] if r["table_parts"] else 0 print(f"{r['pdf_page']:>5} {r['table_parts']:>6} {r['matched']:>6}" f" {recall:>6.1f}% {r['callouts']:>9} {r['fuzzy']:>6} {r['off_table']:>13}") total_table += r["table_parts"]; total_found += r["matched"] total_callouts += r["callouts"]; total_fuzzy += r["fuzzy"] total_off += r["off_table"] print(f"{'ALL':>5} {total_table:>6} {total_found:>6}" f" {100 * total_found / total_table:>6.1f}% {total_callouts:>9}" f" {total_fuzzy:>6} {total_off:>13}") print(f"\nDistinct parts with at least one callout: " f"{conn.execute('SELECT COUNT(DISTINCT part_no) FROM labels').fetchone()[0]}" f" of {conn.execute('SELECT COUNT(*) FROM parts').fetchone()[0]}") print("Exact vs fuzzy snaps: " + ", ".join( f"{r[0]}={r[1]}" for r in conn.execute( "SELECT match_kind, COUNT(*) FROM labels GROUP BY match_kind"))) finally: conn.close() return 0 if __name__ == "__main__": sys.exit(main())