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.0.tar.gz (445.1 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.0-py3-none-any.whl (459.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: lexo-0.2.0.tar.gz
  • Upload date:
  • Size: 445.1 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.0.tar.gz
Algorithm Hash digest
SHA256 10f7d9da1abd5b8aafc4915eced883b2ec390d5477663daeb44c6e87b5f2683c
MD5 7085d221730662eefcf2b1e9c979c048
BLAKE2b-256 16e7678941ecefdea623e3551ac462f06f2d9a8887c6e8a6ff522111a8d38179

See more details on using hashes here.

Provenance

The following attestation bundles were made for lexo-0.2.0.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.0-py3-none-any.whl.

File metadata

  • Download URL: lexo-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 459.4 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d2b564d9b9cc2bbf7127c7d207975916d926e082dc4c6947d1c509ae37af0e58
MD5 ba6d2e7114de14d3ff8d103afaae4839
BLAKE2b-256 43f881b9753b8d7b16021c068cb2aa7fc3c7fdf99296115c0db97df2d91f50f3

See more details on using hashes here.

Provenance

The following attestation bundles were made for lexo-0.2.0-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

0.2.1

2 files

This release

0.2.0 This release

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