estravon-backend-benchmarks
Prerequisite: you need estravon-backend installed and reachable with the
engines you want to compare configured – MinerU installed locally
(pip install "estravon-backend[mineru]"), and/or MISTRAL_API_KEY /
DATALAB_API_KEY / REPLICATE_API_TOKEN set as environment variables in
the shell/process that calls compare() – e.g. export MISTRAL_API_KEY=...
before running your script, or os.environ["MISTRAL_API_KEY"] = ... before
calling compare(). This package orchestrates estravon-backend; it never
extracts anything on its own, and it never reads or passes engine credentials
itself – see “A note on API keys” below for exactly how they reach the
engine. See estravon-backend’s docs/API.md for the engine-decision table
and how to get each engine’s key.
Picking up the .env file from estravon-backend’s own setup:
estravon-backend’s README has you create a .env file (e.g.
MISTRAL_API_KEY=your_key_here) in that repo’s root, and estravon loads
it automatically – but only from its own process’s current working
directory at startup. This package spawns estravon as a subprocess from
wherever your notebook’s kernel happens to be running, which usually isn’t
that directory – so the reliable way to make the same key visible here is
to load that .env explicitly, once, before calling compare():
from pathlib import Path
from dotenv import load_dotenv
load_dotenv(Path("~/path/to/estravon-backend/.env").expanduser())
python-dotenv ships as a dependency of estravon-backend itself, so if
you’ve already installed that (this package’s own prerequisite, above),
it’s already available – no separate install. .expanduser() resolves ~
portably on Linux/macOS/Windows; for a literal $HOME-style variable
instead, use os.path.expandvars(...). Once loaded, the variables are in
your notebook process’s own environment, and LocalEngineProcess (Mode A)
inherits them when it spawns estravon – it doesn’t matter what that
subprocess’s own working directory ends up being.
Install
!pip install estravon-backend-benchmarks
Also installable via git, e.g. for the latest unreleased commit on main, or for contributing (editing a notebook under nbs/):
pip install git+https://github.com/tiberavonltd/estravon-backend-benchmarks.git
To contribute, clone and install in dev mode instead:
git clone https://github.com/tiberavonltd/estravon-backend-benchmarks.git
cd estravon-backend-benchmarks
pip install -e ".[dev]"
nbdev-install-hooks # keeps notebook diffs clean on commit
See CONTRIBUTING.md for the edit-notebook -> nbdev-export -> nbdev-test loop
(nbdev 3.x only ships hyphenated console scripts – nbdev_install_hooks with an
underscore will not be found).
Quickstart
compare() has two modes (see estravon-backend’s docs/API.md section
“Engine selection” for why there’s no single-URL multi-engine mode – engine
choice is fixed per running instance, on purpose):
- Mode A (below, the common case): pass
engines=[...]and this package spawns one pinnedestravon --backend <engine> --port <N>subprocess per engine for you – nothing to configure beyond havingestravon-backendinstalled with the relevant keys/local models available. - Mode B: pass
engine_urls={"mistral": "http://host:port", ...}instead, if you already have separately-running single-engine instances.
A note on API keys – two different things share the name “api_key”:
- Engine credentials (
MISTRAL_API_KEY,DATALAB_API_KEY,REPLICATE_API_TOKEN) are read byestravon-backenditself from the environment – this package never touches them. In Mode A,LocalEngineProcessspawnsestravon --backend <engine> ...as a plain subprocess that inherits your calling process’s environment, so setting them before you callcompare()is enough; there’s no parameter for them here because there doesn’t need to be one. compare()’s ownapi_key=parameter is a different thing entirely: it’s only used in Mode B, forwarded as theX-API-Keyheader to authenticate to a hostedestravon-backendinstance (the same header the hosted service’s own billing/auth uses) – it has nothing to do with which engine that instance runs. In Mode A it’s hardcoded toNone: locally spawned instances have no such auth layer.
The cell below is marked non-executing in this rendered copy of the notebook
(no backend/engines are available in the environment that builds these
docs) – otherwise it’s exactly what you’d run locally, unmodified: it uses
get_artusi() (a real, public-domain 1891 cookbook PDF, downloaded and
cached on first call – see estravon_bench.io) instead of a placeholder
path, so there’s nothing to swap in before trying it.
from estravon_bench.compare import compare
from estravon_bench.io import get_artusi
result = compare(
pdf_path=str(get_artusi()), # public-domain 1891 cookbook -- downloaded/cached on first call
page_range="1-4",
engines=["mineru", "mistral"], # whichever engines you have configured
mode="balanced",
)
print(result.to_markdown_table())
This prints a side-by-side table:
| engine | time (s) | cost (usd) | local | pages | status |
|---|---|---|---|---|---|
| mineru | 34.10 | free (local) | yes | 4 | ok |
| mistral | 2.30 | $0.0080 | no | 4 | ok |
Then look at each engine’s actual output:
for r in result:
print(f"--- {r.engine} ---")
print(r.markdown[:500] if r.ok else f"ERROR: {r.error}")
print(result.diff("mineru", "mistral")) # optional -- line diff for eyeballing
⚠️ The two-step fetch is handled for you – Client.fetch_markdown()
already does the md_url → actual text round trip described in
estravon-backend’s docs/API.md. If you’re extending client.py
yourself, that’s the detail to know about; compare()’s own callers never
see a bare URL.
Honest-cost labelling: local=True engines (MinerU today) show
cost_usd=0.0 and the table renders “free (local)” – that means zero
dollars, not zero effort or best value. A free engine that’s ten times
slower is not automatically the right choice.
Scope: this is an evaluation aid for comparing engines on your own PDFs apples-to-apples – not a production layer, and not a leaderboard. It compares your PDF on your configured engines; it makes no claim about which engine is best in general.
Images
Engines that extract images (Datalab and Mistral, real-verified; any future engine automatically once it returns image_urls) have them fetched for you – result.images is a {filename: bytes} dict per engine, populated by compare() the same way result.markdown is. to_markdown_table()’s images column shows the count per engine at a glance.
No automated image comparison here – engines encode/crop/caption images differently even for “the same” figure, so this package limits itself to presence/count and letting you look:
from IPython.display import Image
row = result.get("mistral")
for filename, data in row.images.items():
print(filename, f"{len(data)} bytes")
display(Image(data=data))
Combining results from separate compare() calls
Running one engine at a time (different session, different machine, resource constraints) instead of passing engines=[...] all at once? Merge the results back into one ComparisonResultList afterwards – + and .merge() both return a new list without touching the originals; .extend() mutates the first list in place if you’d rather accumulate into one object as you go:
from estravon_bench.compare import compare
from estravon_bench.io import get_artusi
from estravon_bench.report import ComparisonResultList
pdf = str(get_artusi())
mineru_result = compare(pdf, "1-4", engines=["mineru"])
mistral_result = compare(pdf, "1-4", engines=["mistral"])
combined = mineru_result + mistral_result # new list, both inputs untouched
# equivalent, and reads better for more than two lists:
combined = ComparisonResultList.merge(mineru_result, mistral_result)
mineru_result.extend(mistral_result) # or: mutate mineru_result in place instead
print(combined.to_markdown_table())
Saving and loading a comparison run
ComparisonResultList.save(dir_path) writes the whole list to disk as plain files – manifest.json plus one subdirectory per engine holding result.md and an images/ folder – not a database or a binary format, so any file browser, git diff, or image viewer can inspect a saved run directly. ComparisonResultList.load(dir_path) reads it back into real ComparisonResult objects, markdown/images/metadata all restored exactly:
from estravon_bench.report import ComparisonResultList
result.save("runs/mineru_vs_mistral")
# ...later, or in a different session:
reloaded = ComparisonResultList.load("runs/mineru_vs_mistral")
print(reloaded.to_markdown_table())
Worked examples
Real, live-run engine comparisons – actual findings, not illustrative examples – live in a separate notebook: 06_worked_examples.ipynb.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file estravon_backend_benchmarks-0.2.2.tar.gz.
File metadata
- Download URL: estravon_backend_benchmarks-0.2.2.tar.gz
- Upload date:
- Size: 22.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8413b3510043c095a22c7995ac5eaac868d63961a558976818b267a359e00617
|
|
| MD5 |
d2e9c72309f7fca9d479a4e50b1c0bec
|
|
| BLAKE2b-256 |
67938e78a885fa802b4da9fbf99e71bcb0a9425468d201f8dac3b8266336c7d4
|
Provenance
The following attestation bundles were made for estravon_backend_benchmarks-0.2.2.tar.gz:
Publisher:
publish.yml on tiberavonltd/estravon-backend-benchmarks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
estravon_backend_benchmarks-0.2.2.tar.gz -
Subject digest:
8413b3510043c095a22c7995ac5eaac868d63961a558976818b267a359e00617 - Sigstore transparency entry: 2361785732
- Sigstore integration time:
-
Permalink:
tiberavonltd/estravon-backend-benchmarks@137ea295864b0205db88ad1a3778b201bafc4f1f -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/tiberavonltd
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@137ea295864b0205db88ad1a3778b201bafc4f1f -
Trigger Event:
push
-
Statement type:
File details
Details for the file estravon_backend_benchmarks-0.2.2-py3-none-any.whl.
File metadata
- Download URL: estravon_backend_benchmarks-0.2.2-py3-none-any.whl
- Upload date:
- Size: 25.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2e866c7c4290b8bbf4e43935139885d86ec32cb264ae4916141e5a036193a9b7
|
|
| MD5 |
bf104e4aaad9655161336f4cae35fdee
|
|
| BLAKE2b-256 |
e2529d7060b9e02ccb14791a937291afb91e227e8939bb8ab92f2c074f69ee2b
|
Provenance
The following attestation bundles were made for estravon_backend_benchmarks-0.2.2-py3-none-any.whl:
Publisher:
publish.yml on tiberavonltd/estravon-backend-benchmarks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
estravon_backend_benchmarks-0.2.2-py3-none-any.whl -
Subject digest:
2e866c7c4290b8bbf4e43935139885d86ec32cb264ae4916141e5a036193a9b7 - Sigstore transparency entry: 2361785734
- Sigstore integration time:
-
Permalink:
tiberavonltd/estravon-backend-benchmarks@137ea295864b0205db88ad1a3778b201bafc4f1f -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/tiberavonltd
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@137ea295864b0205db88ad1a3778b201bafc4f1f -
Trigger Event:
push
-
Statement type: