Files
SnapOtter/packages/ai/python/doc_text.py
T
SnapOtterandGitHub 7d37f6e6f5 fix(pdf): flag scanned PDFs in pdf-to-text and serve text as UTF-8 (#603)
When a PDF has no text layer (scanned or image-only), pdf-to-text now
returns a 422 that points at the OCR tool instead of a silent empty file,
and text downloads carry charset=utf-8 so UTF-8 Arabic renders correctly
when the .txt is viewed inline.

Fixes #589
2026-07-21 16:26:43 +08:00

37 lines
1.3 KiB
Python

"""Extract plain text. Args: {"path": in, "out": out-txt-path}. Prints {"chars": N, "hasText": bool}."""
import json
import sys
def main():
args = json.loads(sys.argv[1]) if len(sys.argv) > 1 else {}
path, out = args.get("path"), args.get("out")
if not path or not out:
print(json.dumps({"error": "missing path/out"}))
sys.exit(1)
try:
import fitz
except ImportError:
print(json.dumps({"error": "PyMuPDF not installed"}))
sys.exit(1)
try:
doc = fitz.open(path)
parts = [page.get_text() for page in doc]
doc.close()
text = "\n".join(parts)
# hasText distinguishes a PDF with a real text layer from a scanned or
# image-only PDF, where every page returns "" and only the join newlines
# remain. len(text) alone can't tell them apart, so the caller uses this
# to offer OCR instead of handing back an empty file (#589).
has_text = any(part.strip() for part in parts)
with open(out, "w", encoding="utf-8") as fh:
fh.write(text)
print(json.dumps({"chars": len(text), "hasText": has_text}))
except Exception as exc: # noqa: BLE001
print(json.dumps({"error": str(exc)}))
sys.exit(1)
if __name__ == "__main__":
main()