Skip to content

OCR fallback via kind='ocr_text' artifact (concrete path for #13 OCR item) #18

Description

@deOliveira-R

Refines the OCR line-item in the v2 umbrella (#13) with a concrete path now that the artifact infrastructure (commit e2b7342) is in place.

The gap

Scanned PDFs have no extractable text. PyMuPDF returns empty pages → zero chunks → invisible to both keyword and chunk-level semantic search. Only the item-level SPECTER2 embedding (title + abstract) surfaces them at all, and that relies on Crossref/GROBID having given us an abstract — which usually fails for scans.

Plan

  1. New CLI: `grimoire artifacts build --kind ocr_text [--since YYYY-MM-DD] [-j N]`.
  2. Walks items where:
    • `primary` artifact exists, and
    • `extract.pdf.has_extractable_text()` returns False (body is empty/degenerate), and
    • no `ocr_text` artifact yet.
  3. Each worker thread:
    • Pulls the primary CAS blob.
    • Runs ocrmypdf or pure Tesseract over it — the plan chose `ocrmypdf` (plan §4 tech-stack row).
    • Stores the plain-text result as the `ocr_text` artifact (source: `tesseract-` or `ocrmypdf-`).
  4. Extend `index.py` so when chunking a PDF item:
    • Prefer `ocr_text` artifact over raw PyMuPDF extraction when the latter is empty.
    • Reuse the existing chunker; no schema change (page numbers become approximate/synthetic for scans).
  5. Bonus: add a soft `metadata_confidence` reduction when the source is OCR so the dedup tier-4 is more cautious.

Acceptance

  • `grimoire artifacts build --kind ocr_text` walks scanned PDFs, writes `ocr_text` artifacts.
  • Indexer consumes OCR text when PyMuPDF gives nothing; scanned papers become searchable.
  • Throughput is bounded: 30 s – 2 min per page as the plan warns; `-j N` parallelism respected.
  • Non-scanned PDFs are untouched.
  • Test with a synthetic image-only PDF (built via pymupdf with `insert_image` + a pre-rendered PNG of text) + a stubbed OCR callable; assert end-to-end behavior.

Notes

  • The `ocrmypdf` dependency is heavy (pulls in Tesseract, poppler). Keep it in an optional extra (`[ocr]`) so it's not mandatory for users who don't need it.
  • Processing cost is bounded per-scan and embarrassingly parallel — user has explicitly said processing isn't a concern.
  • This closes the "invariant 7 (paper + DOI ⇒ venue)" soft-failure path for a lot of items where OCR could have provided a first-page abstract for Crossref backfill — worth measuring on the real library once landed.

Once this ships, update the corresponding checkbox in #13.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions