sceptre

mcp
Guvenlik Denetimi
Basarisiz
Health Uyari
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 8 GitHub stars
Code Basarisiz
  • rm -rf — Recursive force deletion command in .github/workflows/benchmarks.yaml
Permissions Gecti
  • Permissions — No dangerous permissions requested

Bu listing icin henuz AI raporu yok.

SUMMARY

EasyOCR's accuracy, Rust's speed and footprint — CRAFT + gen2 CRNN OCR over ONNX, as a library, CLI, and MCP server.

README.md

Xberg

sceptre

EasyOCR's accuracy in a single Rust binary — CRAFT text detection and gen2 CRNN recognition over ONNX, with no Python
runtime.

What and Why?

EasyOCR is accurate, but it is a PyTorch stack: a Python interpreter, a multi-gigabyte runtime, and a heavy process to
keep warm. sceptre is a from-scratch Rust reimplementation of the same pipeline — CRAFT text detection then gen2
CRNN
recognition with CTC decoding, over ONNX — that keeps the accuracy and drops all of that.

It agrees with EasyOCR's output across the scripts it supports, runs several
times faster on a fraction of the memory — even a cold one-shot run beats EasyOCR warm (measured
figures
) — and ships as one self-contained executable. Models download once, cache locally, and run
offline thereafter. Use it as a Rust library, a CLI, or an MCP server.

Every model call goes through one backend seam, so the deployment target is a build-time choice rather than a rewrite:
ONNX Runtime for native speed, pure-Rust ONNX for WASM and Android, and candle for GPU devices or a build that links
no ONNX Runtime at all.

Features

Feature Description
Parity accuracy Validated against real EasyOCR output across the gen2 scripts — English, Latin, Simplified Chinese, Japanese, Korean, Cyrillic, Telugu, Kannada — on text (word/char-F1) and boxes (IoU), held to a per-image floor rather than character-for-character equality
Several times faster Higher throughput than EasyOCR warm on the same corpus; even a cold, one-shot CLI run beats EasyOCR's already-loaded reader (measured figures)
A fraction of the memory Peak RSS several times lower than the Python + torch process, measured like-for-like as whole-process peaks
One binary, no Python A single self-contained executable. Models download once, cache locally, and run offline thereafter — nothing to pip install, no interpreter to ship
Three surfaces The same engine as a Rust library, a CLI (sceptre), and an MCP server for agents
Three backends, one seam ONNX Runtime (ort) for native speed, pure-Rust ONNX (tract) for WASM / Android, and candle for a GPU or a build with no ONNX Runtime at all
Pure-Rust image decoding PNG, JPEG, BMP, GIF, TIFF, WebP, and NetPBM

⭐ Star this repo to show your support — it helps others discover sceptre.

Quick Start

Install

cargo install sceptre-cli

That default build is self-contained: it links a prebuilt ONNX Runtime fetched at build time (ort-bundled) and enables
model download (download), so the binary needs no ORT_DYLIB_PATH and no separately installed libonnxruntime.

The models — CRAFT plus the gen2 recognizers — are fetched from Hugging Face on first use, cached under the standard HF
cache, and sha256-verified as they download. Every run after that reads the cached models with no network.

Targets with no prebuilt ONNX Runtime. ort publishes prebuilts for a fixed target list.
x86_64-apple-darwin (Intel macOS), every *-unknown-linux-musl (Alpine),
armv7-unknown-linux-gnueabihf, riscv64gc-*, *-unknown-freebsd, i686-*, s390x, and
powerpc64le have none, so the default install fails at build time with ort-sys's own
no prebuilt binaries available for target .... Two remedies:

cargo install sceptre-cli --features ort-dynamic                          # bring your own libonnxruntime
cargo install sceptre-cli --no-default-features --features tract,download  # pure Rust, then --backend tract

--features ort-dynamic is additive, but it still wins over the bundled default: load-dynamic
implies ort-sys/disable-linking, which the ort-sys build script checks before its download
branch. So switching ONNX Runtime provisioning never needs --no-default-features — only the
pure-Rust path does, because it has to drop ort from the graph entirely.

CLI

One image or many in a single warm process:

sceptre run receipt.png --lang english --format json
sceptre run page1.png page2.png page3.png            # batch: models load once
sceptre run sign.jpg --lang english --lang korean    # multi-language
sceptre run page.png --lang english --timings        # per-stage load/detect/recognize breakdown
sceptre run huge-scan.png --canvas-size 1600         # trade some accuracy for lower peak memory

Decodes PNG, JPEG, BMP, GIF, TIFF, WebP, and NetPBM (all pure-Rust; HEIF/AVIF/JPEG-2000
are out of scope — see adrs/0022).

Library

use sceptre::{Reader, ReadOptions};

let reader = Reader::builder().build()?;
for line in reader.readtext("receipt.png".as_ref(), &ReadOptions::default())?.lines {
    println!("{} ({:.2})", line.text, line.confidence);
}
# Ok::<(), sceptre::OcrError>(())

The library ships default = [], so enable a backend and model download:
sceptre = { version = "0.5", features = ["ort-bundled", "download"] } (see Feature flags).

WASM and mobile hosts can avoid filesystem and network assumptions by calling model_descriptors,
fetching the selected artifacts, constructing a VerifiedModelProvider, and passing it to
Reader::builder().model_provider(...).build_warmed().

Android and iOS hosts that package ONNX assets as real files may instead set both
model.detector_path and model.recognizer_path; the default provider then bypasses Hugging Face.

MCP server

Expose a readtext tool to an agent. The mcp subcommand is behind the mcp cargo feature, which is off by default:

cargo install sceptre-cli --features mcp
sceptre mcp --lang english

Benchmarks

Measured against upstream EasyOCR over a mixed corpus — documents, tables, rotated scans, scene
text and receipts, across the English, Latin, Chinese-simplified, Japanese and Korean recognizer
groups — on CPU. Both engines are measured identically: each a fresh subprocess per language
group under /usr/bin/time, at its native multi-threaded default, loading its model/reader once and
processing every image — so peak RSS is a like-for-like whole-process figure (EasyOCR's legitimately
includes the torch runtime). Numbers vary with hardware and load; the ratios are the point.

The table below is generated from benchmarks/published/latest.json
by task python:publish; CI fails if the two drift apart. Do not edit it by hand.

Engine Throughput (img/s) Peak RSS Mean CER Mean token-F1
EasyOCR (warm/batch) 0.47 20.2 GB 0.554 0.348
sceptre (warm/batch) 1.07 (~2.3×) 6.5 GB (~3× lower) 0.570 0.361
sceptre (cold CLI run) 1.12 (~2.4×) 6.5 GB 0.570 0.361

Measured with sceptre 0.4.0 (ort/cpu, ONNX Runtime 1.28.0) against EasyOCR 1.7.2 (torch 2.13.0) on
Darwin/arm64, over 40 of 43 corpus entries. Regenerate with task python:benchmark then task python:publish.

The accuracy columns are the parity check — sceptre and EasyOCR land on the same reading of the
corpus; the win is speed and memory. Even a cold, one-shot CLI run, which pays model load on every
invocation, still beats EasyOCR's already-warm reader.

Runtime scope. Every figure above — speed, memory, and the parity claim — was produced on the
ort backend running the CPU execution provider, which is what model.accelerator defaults to.
The same ONNX graph produces different numeric output on a different provider, so an accelerated run
is a different measurement, not a faster one. Select one with --accelerator or
model.accelerator; which values a backend accepts differs, because ort reaches hardware through
ONNX Runtime execution providers while candle addresses devices directly:

Backend Accelerators Cargo feature
ort coreml, directml, cuda ort-coreml, ort-directml, ort-cuda
tract — (CPU only)
candle metal, cuda candle-metal, candle-cuda

For ort the linked ONNX Runtime build must also carry the provider. An explicitly requested
accelerator that cannot be used is a hard error, not a silent fall back to CPU — only auto is
allowed to settle for whatever it finds. The parity figures above cover only the ort backend's CPU
execution provider, validated against the golden fixtures under
crates/sceptre/tests/data/golden/: every accelerator is
unvalidated in CI, which has no GPU runner, so none of the numbers above should be assumed to
transfer. candle is a compatibility and deployment option, not a fast one — on a GPU it is still
several times slower than ort on the CPU (see ADR 0031).
Re-run the parity harness on your own target before relying on them.

cargo bench covers the internal hot paths; the head-to-head harness (task python:benchmark)
re-measures and writes the gitignored benchmark-results/comparison.{json,md}. Use
--group labeled --limit 3 --repeats 1 for a fast inner-loop run, --baseline <prior.json> to see
per-image deltas, and --assert for the regression gate (see
ADR 0021). task python:publish then distils that
report into the committed artifact and regenerates the table above; task python:publish:check is
the drift gate CI runs (see ADR 0030).
Parity fixtures live under
crates/sceptre/tests/data/golden/.

How it works

Three stages behind one Reader, mirroring EasyOCR's latest pipeline:

  1. Detect — CRAFT produces region/link heat-maps; thresholding, connected components, and
    min-area boxes become text lines (horizontal and rotated).
  2. Recognize — each line is cropped, normalized, and run through a gen2 CRNN; CTC greedy decoding
    turns the logits into text and a confidence.
  3. Inference — every model call goes through one backend seam: ort (native ONNX Runtime),
    tract (pure Rust), or candle (hand-written networks over the same ONNX weights, able to run
    on Metal or CUDA). config, types, and geometry stay backend-agnostic.

Design decisions live as MADR records under adrs/; conventions live in .ai-rulez/.

Scope

Targets EasyOCR's current models — the CRAFT detector and all eight gen2 (*_g2) recognizers
(English, Latin, Simplified Chinese, Japanese, Korean, Cyrillic, Telugu, Kannada).
Legacy gen1 models, DBNet, and beam-search decoding are out of scope
(see adrs/0002 and
adrs/0026). ONNX artifacts are first-party exports,
built from EasyOCR's weights and hosted on the sceptre-ocr
Hugging Face org (Apache-2.0; see adrs/0025).

Feature flags

Feature Enables Library CLI
ort Native ONNX Runtime backend (desktop / server), provisioning-agnostic
ort-bundled ort with a prebuilt runtime fetched at build time (zero-config) default
ort-dynamic ort loading libonnxruntime at runtime via ORT_DYLIB_PATH (no build-time download)
tract Pure-Rust ONNX backend (WASM / Android), selected at runtime with --backend tract
download Runtime model download + cache from Hugging Face default
mcp MCP (rmcp) server surface
ort-coreml / ort-directml / ort-cuda Compile in the matching ONNX Runtime execution provider for model.accelerator
candle Native-tensor backend needing no ONNX Runtime, selected at runtime with --backend candle (see ADR 0031)
candle-metal / candle-cuda Compile in the matching GPU device for model.accelerator on the candle backend
bench Exposes the crate's internal hot paths through a bench seam for criterion benchmarking (see ADR 0015)

The library ships default = []. The CLI ships default = ["ort-bundled", "download"], so
cargo install sceptre-cli produces a self-contained binary; --features ort-dynamic overrides the
provisioning strategy without --no-default-features (see Install).

Configuration (OcrConfig) is backend-agnostic. The CLI builds it from OcrConfig::default() plus
flags — there is no config-file loader and no SCEPTRE_* environment variable. The CLI does read one
env var, EASYOCR_LOG (sets --log-level), a name kept from the project's EasyOCR lineage.
cache_dir, registry_owner, detector_path, and recognizer_path are library-only fields with no
CLI flag.

Development

task setup    # fetch deps, install git hooks
task check    # cargo fmt + clippy -D warnings + test + poly lint
task bench    # criterion microbenchmarks (--features bench)

Coding conventions are generated from .ai-rulez/ into CLAUDE.md / AGENTS.md — edit the source,
then run ai-rulez generate.

Documentation

Full guides, the configuration reference, backend and accelerator selection, and the benchmark
methodology live at docs.sceptre.xberg.io. The Rust API
reference is on docs.rs.

Part of Xberg.io

  • Xberg — the open-source content-intelligence engine: text, tables, and metadata from 101 formats (115 file extensions), with OCR, transcription, and code intelligence. MIT.
  • Xberg Pro — a complete self-hosted content-intelligence backend in a single container. Commercial.
  • Xberg Enterprise — the distributed, governed content-intelligence platform, scaled on Kubernetes with team governance and support. Commercial.
  • crawlberg — web crawling and scraping with HTML→Markdown and headless-Chrome fallback.
  • html-to-markdown — fast, lossless HTML→Markdown engine.
  • liter-llm — universal LLM API client with native bindings for 14 languages and 165 providers.
  • tree-sitter-language-pack — tree-sitter grammars and code-intelligence primitives.
  • alef — the polyglot binding generator that produces every per-language binding across the 5 polyglot repos.

Contributing

Contributions welcome! See CONTRIBUTING.md for setup instructions and guidelines.

License

MIT License. Model weights are distributed under their own licenses — the gen2 EasyOCR
models and the first-party sceptre-ocr ONNX exports derived
from them are Apache-2.0.

Yorumlar (0)

Sonuc bulunamadi