Skip to main content

Lexo logo

Lexo

PyPI version Python versions CI License: AGPL-3.0

Lexo stands for Local EXtraction and OCR: a local-first desktop document OCR tool. It turns PDFs and images into clean, editable text, with strong support for Burmese (Myanmar script) using free, high-accuracy Google Docs OCR.

Everything runs on your machine. The only network call is the optional OCR provider, which uses your own Google account, so there is nothing to pay for.

Features

  • PDF operations: extract page ranges, split, crop, rotate, merge, and split two-up spreads into separate pages.
  • Visual crop and split editor in the GUI: drag a crop box on the rendered page to remove headers and page numbers, and split scanned two-up spreads. Works on a PDF or a batch of images.
  • Smart OCR routing: digital PDFs use their embedded text layer (instant and lossless); only scanned pages are OCR'd.
  • OCR via Google Docs OCR: free, high-accuracy (especially for Burmese), run on your own Google account. Providers are pluggable behind a single interface.
  • Burmese-aware text handling: NFC normalization and zero-width-space-safe cleaning.
  • Proofread before you export: the desktop app shows each page beside an editable text pane.
  • Exports: plain text (the default), Markdown (with YAML frontmatter), and JSONL (for NLP and LLM workflows).
  • A desktop GUI and a scriptable CLI, both driving the same engine.

Install

Lexo is a Python package. With uv:

uv tool install lexo            # the `lexo` CLI and `lexo gui`

Without uv, use any standard Python installer:

pipx install lexo
# or
python -m pip install lexo

Everything is included in the one install. There are no separate system dependencies to set up.

Quick start

# Digital PDF: extract the embedded text, instantly (plain text by default)
lexo extract report.pdf -o report.txt

# Scanned PDF or image: OCR it (Burmese by default) with your Google account
lexo login
lexo ocr scan.pdf --lang my -o scan.txt

# PDF operations
lexo pdf extract book.pdf --pages "1-3,7,10-" -o subset.pdf
lexo pdf split book.pdf --every 10
lexo pdf crop book.pdf --top 8 --bottom 8 -o trimmed.pdf

# Launch the desktop app
lexo gui

Run lexo --help (or lexo pdf --help) for the full command list.

Video walkthroughs

Short walkthroughs (~1 min each) covering setup and common Burmese OCR workflows.

OCR processing time depends on your network speed and Google Drive's response time. Lexo retries each page automatically on transient failures. If any pages still fail, a "Retry Failed Pages" button appears so you can re-run just those.

1 - Install with uv and one-time Google Cloud setup

Everything needed before the first OCR run: install Lexo with uv tool install lexo → create a Google Cloud project → enable the Drive API → configure the OAuth consent screen → create and download credentials.json → place it in the config directory → run lexo login to sign in.

https://github.com/user-attachments/assets/92d86684-ebaa-438a-a6dd-880d49943405

2 - Main OCR workflow: scanned Burmese PDF (GUI)

Full GUI walkthrough for a scanned Burmese PDF: open the file → use the visual editor to split two-up spreads and crop headers/margins → run Google Docs OCR → review the per-page text → export to plain text.

https://github.com/user-attachments/assets/b247cdc5-0421-4400-bc6c-f4dc35268268

3 - Legacy Windows font PDF: getting real Burmese text with Google OCR (GUI)

Some Burmese documents were created with old non-Unicode Windows fonts such as Win Innwa or Win Myanmar. These fonts render Burmese glyphs by mapping them onto ASCII codepoints, so the PDF actually stores English characters internally - the font is what makes them look Burmese on screen. When you run text extraction on such a file, you get those raw ASCII characters back, which is technically correct but not useful as Burmese text. This video shows how to recognise this case in the GUI and switch to Google Docs OCR instead, which reads the page visually and returns proper Unicode Burmese.

https://github.com/user-attachments/assets/9cd60cbc-6a2b-4925-b076-89e97346e391

Commands

Command Purpose
lexo extract <pdf> Extract the embedded text layer of a digital PDF
lexo ocr <pdf|image> OCR a scanned document (--lang, --force-ocr)
lexo pdf info|extract|split|crop|rotate|merge|split-spread PDF operations
lexo login / lexo logout Sign in to / out of Google (token stored in the OS keychain)
lexo gui Launch the desktop app
lexo info Show the version and where Lexo stores its data
lexo check-update Check PyPI for a newer release

All output formats are available via --format text|markdown|jsonl.

Google Docs OCR setup (one-time)

OCR uses Google Docs OCR, which is free and runs on your own Google account. You bring your own OAuth client credentials (credentials.json). It is a one-time setup:

  1. Create or pick a Google Cloud project at the Google Cloud Console.
  2. Enable the Google Drive API: APIs & Services -> Library -> search "Google Drive API" -> Enable.
  3. Configure the OAuth consent screen: APIs & Services -> OAuth consent screen -> User type External -> add an app name and your email, then add your own Google account under Test users.
  4. Create the OAuth client: APIs & Services -> Credentials -> Create credentials -> OAuth client ID -> Application type Desktop app -> Create -> Download JSON, and rename the file to credentials.json.
  5. Place credentials.json where Lexo looks for it (first match wins):
    • the path in the LEXO_GOOGLE_CREDENTIALS environment variable, or
    • your Lexo config directory (run lexo info to see it), or
    • the current working directory.
  6. Sign in: run lexo login (or in the GUI, Account -> Sign in with Google). A browser opens; approve access. The token is saved in your OS keychain, and credentials.json is only read during login.

Notes:

  • Lexo requests only the least-privilege drive.file scope, so it can touch only the temporary files it creates while running OCR.
  • While the OAuth app stays in Testing status, Google expires the sign-in roughly every 7 days, so you may need to run lexo login again periodically.
  • Sign out any time with lexo logout (or Account -> Sign out); this removes the stored token.

Burmese notes

  • The OCR language hint defaults to my; override with --lang.
  • Extracted text is normalized to Unicode NFC and zero-width spaces are preserved.
  • A Myanmar Unicode font (Noto Sans Myanmar, SIL Open Font License) is bundled so Burmese renders in the GUI regardless of installed system fonts. The license travels with it as OFL.txt.

Tech stack

Area Tools
Language Python 3.11+
CLI Typer
Desktop GUI PySide6 (Qt)
PDF engine PyMuPDF
Images Pillow
OCR Google Docs OCR via the Google Drive API (google-api-python-client + google-auth)
Credentials keyring (OS keychain)
Settings pydantic-settings (env-var config)
Logging structlog
Paths platformdirs
Build & packaging uv + Hatchling
Quality Ruff, mypy, pytest
CI/CD GitHub Actions, PyPI Trusted Publishing

Development

uv sync
uv run ruff check src tests
uv run mypy src/lexo
uv run pytest

Design notes live in docs/ARCHITECTURE.md.

License

AGPL-3.0, to align with PyMuPDF. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lexo-0.2.1.tar.gz (446.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lexo-0.2.1-py3-none-any.whl (460.8 kB view details)

Uploaded Python 3

File details

Details for the file lexo-0.2.1.tar.gz.

File metadata

  • Download URL: lexo-0.2.1.tar.gz
  • Upload date:
  • Size: 446.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for lexo-0.2.1.tar.gz
Algorithm Hash digest
SHA256 eedea9820ac791f655fdbfc220def68b1034eb89c2dbcfeddf84378fbdd2b839
MD5 a8cc56bdef5b877eac4883b36a7ef0f5
BLAKE2b-256 b7252213d725eb306cbe66200f72bdbdf9740e482ed35644df9e2d3177ba89d1

See more details on using hashes here.

Provenance

The following attestation bundles were made for lexo-0.2.1.tar.gz:

Publisher: release.yml on PhilixTheExplorer/lexo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lexo-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: lexo-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 460.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for lexo-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 03e0e5c4d7d94b83fde2eb25a8a65bb612297d7971567cad327aa12ce56ca51a
MD5 05e7b3136a32c73c9f4eda12024dec9e
BLAKE2b-256 5ecbf0ab7ce4a3ccb342ff8ede241565856eff9a108cf81e4915afb2eaced0dd

See more details on using hashes here.

Provenance

The following attestation bundles were made for lexo-0.2.1-py3-none-any.whl:

Publisher: release.yml on PhilixTheExplorer/lexo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.4.1

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

This release

0.2.1 This release

2 files

0.2.0

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page