Skip to main content

RenZi 认字

Local OCR extraction + LLM text correction. PaddleOCR recognizes text in images, a local Ollama model corrects OCR mistakes, and an optional Flask web UI ties it together. Everything runs offline — no cloud APIs.

What It Does

RenZi takes images containing Chinese/English text and produces clean electronic text:

  1. OCR — PaddleOCR (PP-OCRv5) extracts text plus per-region bounding boxes and confidence scores.
  2. Visualization — renders an annotated image (green boxes) and a reconstructed text bitmap that preserves the original layout on a white canvas.
  3. Correction — sends the raw OCR text to a local Ollama model (gemma3:1b by default) that fixes typos and misrecognized characters while keeping the original language and line structure.

Supported formats: .png, .jpg, .jpeg, .bmp, .tiff, .tif, .webp.

What it does not do: streaming OCR, mobile capture, cloud OCR, translation between languages.

Features

  • Single image or whole-directory batch OCR
  • PaddleOCR 3.6 + PP-OCRv5 server detection/recognition models
  • Optional annotated image and reconstructed text bitmap PNGs
  • Local Ollama LLM correction (offline, no API keys)
  • Flask web UI with drag-and-drop upload and side-by-side raw/corrected text
  • Unified Python API with ToolResult dataclass
  • OpenAI function-calling tools schema for agent integration
  • CLI with unified flags (-V -v -q --json -o)

Requirements

  • Python >= 3.9
  • PaddleOCR 3.6.0 + PaddlePaddle 3.0.0 (see install notes below)
  • Ollama running locally with a model pulled (e.g. ollama pull gemma3:1b)
  • A CJK TrueType font for bitmap rendering (auto-detected on Windows/macOS/Linux)

PaddlePaddle version pin

The known-good combination is PaddlePaddle 3.0.0 + PaddleOCR 3.6.0. Newer PaddlePaddle (3.1+) breaks old model loading via the PIR executor. Install from the Baidu mirror:

pip install paddlepaddle==3.0.0 -i https://mirror.baidu.com/pypi/simple

Installation

pip install -e .

For development dependencies:

pip install -e ".[dev]"

Ollama setup (for correction)

ollama pull gemma3:1b

Quick Start

Recognize one image and print text:

renzi photo.jpg

Batch a directory and write .txt transcripts:

renzi images/ -l ch -o transcripts/

Full pipeline with annotated image + text bitmap + corrected text file:

renzi scan.png --pipeline --bbox annotated.png --bitmap bitmap.png -o fixed.txt

Correct OCR text piped on stdin:

echo "我在吉林省、长春市" | renzi --correct -

Launch the web UI:

python -m renzi.web
# open http://127.0.0.1:8765

CLI Usage

renzi [-V] [-v] [-q] [--json] [-l LANG] [--confidence N] [-o PATH]
     [--bbox PATH] [--bitmap PATH] [--ollama-base URL] [--ollama-model NAME]
     [--timeout S] [--correct] [--pipeline] [PATH]
Flag Meaning
-V, --version Print version and exit
-v, --verbose Show per-item confidence and geometry
-q, --quiet Suppress non-essential output
--json Output results as JSON
-l, --lang OCR language hint (default ch)
--confidence Minimum OCR confidence (default 0.5)
-o, --output Output file (single) or directory (batch)
--bbox Write annotated image PNG to this path
--bitmap Write reconstructed text bitmap PNG to this path
--ollama-base Ollama API base URL
--ollama-model Ollama model name
--timeout LLM request timeout in seconds
--correct Correct text from stdin instead of running OCR
--pipeline Run OCR + render + LLM correction

Python API

from renzi import extract, extract_dir, correct, pipeline, ToolResult

# Single image
result = extract(image_path="photo.jpg", lang="ch")
print(result.success)        # True
print(result.data["text"])   # raw OCR text
for it in result.data["items"]:
    print(it["text"], it["confidence"], it["bbox"])

# Directory batch with text files
result = extract_dir(directory="images/", output="transcripts/")
for filename, info in result.data.items():
    print(filename, info["text"][:50])

# Correct raw OCR text
result = correct(text="我在吉林省、长春市")
print(result.data["text"])      # corrected
print(result.data["used_llm"])  # True/False

# Full pipeline with visualizations
result = pipeline(
    image_path="scan.png",
    bbox_image="annotated.png",
    bitmap_image="bitmap.png",
    output="fixed.txt",
)

Agent Integration

from renzi.tools import TOOLS, dispatch

# Register TOOLS in your OpenAI function-calling client, then:
result = dispatch("renzi_pipeline", {
    "image_path": "scan.png",
    "bbox_image": "annotated.png",
    "bitmap_image": "bitmap.png",
})

Web UI

from renzi.web import run
run(port=8765)

Drag-and-drop upload, three-up image comparison (original / annotated / text bitmap), and side-by-side raw vs corrected text with one-click copy and re-correct.

Model Cache

PaddleOCR downloads models on first run from ModelScope into ~/.paddlex/official_models/. To bundle models offline, place them in a directory and point PADDLEX_HOME (or RENZI_MODEL_DIR) at it:

export RENZI_MODEL_DIR=/path/to/official_models
renzi photo.jpg

Development

pip install -e ".[dev]"
ruff format . && ruff check . && pytest

License

GPL-3.0

Metadata

Release files for renzi 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for renzi 0.1.0
File Size Uploaded Provenance
renzi-0.1.0.tar.gz 24.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for renzi 0.1.0
File Interpreter ABI Platform
renzi-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 48.2 kB

Release files / renzi-0.1.0.tar.gz

Download URL renzi-0.1.0.tar.gz
Size 24.9 kB
Tags Source
SHA-256 checksum
How to use checksums
a8f80262926efe77c0032ed4948dc7b38cebddc7a8e8f3827e6c9326067437b5
BLAKE2b-256 checksum
How to use checksums
14a6c435d38cc7c548cb04f75e09bb9ba91097991f350a4d48c9621c809705cd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.12

Release files / renzi-0.1.0-py3-none-any.whl

Download URL renzi-0.1.0-py3-none-any.whl
Size 23.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
eaa54a68f5277107580178158faad147fd67b1dcdd9aee6a37a311d304deb15f
BLAKE2b-256 checksum
How to use checksums
8873c87f0feddb59caf144e5793f94cb72a18944aaa7305218ded0af61f466d9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.12

Security for renzi 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

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