Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ permissions:
contents: read

jobs:
native-wheels:
uses: ./.github/workflows/native-wheels.yml

rust:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
with:
workspaces: rust
- run: cargo fmt --manifest-path rust/Cargo.toml --all --check
- run: cargo clippy --manifest-path rust/Cargo.toml --all-targets --locked -- -D warnings
- run: cargo test --manifest-path rust/Cargo.toml --locked

lint-and-test:
runs-on: ubuntu-latest
timeout-minutes: 20
Expand All @@ -25,6 +42,11 @@ jobs:
enable-cache: true
python-version: ${{ matrix.python-version }}

- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: rust

# Lint and validate runner-free pass/skip behavior before installing heavy deps.
- name: Sync dependencies (dev only)
run: uv sync --locked --extra dev
Expand All @@ -49,7 +71,10 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- uses: dtolnay/rust-toolchain@stable
- run: uv build
- name: Build wheel from the source distribution
run: uv build dist/*.tar.gz --wheel --out-dir dist/from-sdist
- name: Smoke-test the wheel in a clean environment
run: |
uv venv /tmp/smoke
Expand Down
52 changes: 52 additions & 0 deletions .github/workflows/native-wheels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Native wheels

on:
workflow_call:

permissions:
contents: read

jobs:
wheels:
name: Wheel (${{ matrix.platform }})
strategy:
fail-fast: false
matrix:
include:
- platform: linux-x86_64
os: ubuntu-22.04
- platform: linux-aarch64
os: ubuntu-24.04-arm
- platform: macos-arm64
os: macos-14
- platform: macos-x86_64
os: macos-15-intel
- platform: windows-x86_64
os: windows-2022
runs-on: ${{ matrix.os }}
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
with:
python-version: "3.12"
- name: Build release wheel
uses: PyO3/maturin-action@v1
with:
maturin-version: "1.14.1"
command: build
args: --release --locked --out dist
manylinux: auto
- name: Install and exercise the wheel
shell: bash
run: |
uv venv smoke
uv pip install --python smoke dist/*.whl pytest
uv run --no-project --python smoke python -c 'from extract_bench.evaluation.metrics.field_grounding.core import BBox, compute_standard_iou_metrics; assert compute_standard_iou_metrics([BBox(1, (0.0, 0.0, 1.0, 1.0))], [BBox(1, (0.0, 0.0, 1.0, 1.0))]).iou == 1.0'
uv run --no-project --python smoke pytest tests/extract_bench/evaluation/metrics/field_grounding/test_native_geometry.py -q
uv run --no-project --python smoke extract-bench version
uv run --no-project --python smoke extract-bench pipelines > /dev/null
- uses: actions/upload-artifact@v4
with:
name: native-wheel-${{ matrix.platform }}
path: dist/*.whl
19 changes: 14 additions & 5 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Publish to PyPI

# Publishes when a version tag (v0.3.0, v1.0.0, ...) is pushed. The tag must
# match `__version__` in src/extract_bench/__init__.py.
# match the workspace package version in rust/Cargo.toml.
#
# Uses PyPI trusted publishing (OIDC): no API token is stored in GitHub.
# One-time setup on pypi.org: project "llama-extract-bench" -> Publishing -> add a
Expand All @@ -13,27 +13,31 @@ on:
tags: ["v*"]

jobs:
native-wheels:
uses: ./.github/workflows/native-wheels.yml

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- name: Check tag matches package version
run: |
pkg_version=$(uv run --no-project python -c "import re,pathlib; print(re.search(r'__version__ = \"([^\"]+)\"', pathlib.Path('src/extract_bench/__init__.py').read_text()).group(1))")
pkg_version=$(uv run --no-project python -c 'import pathlib,tomllib; print(tomllib.loads(pathlib.Path("rust/Cargo.toml").read_text())["workspace"]["package"]["version"])')
tag_version="${GITHUB_REF_NAME#v}"
if [ "$pkg_version" != "$tag_version" ]; then
echo "Tag $GITHUB_REF_NAME does not match __version__ $pkg_version" >&2
echo "Tag $GITHUB_REF_NAME does not match package version $pkg_version" >&2
exit 1
fi
- run: uv build
- uses: dtolnay/rust-toolchain@stable
- run: uv build --sdist
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/

publish:
needs: build
needs: [build, native-wheels]
runs-on: ubuntu-latest
environment: pypi
permissions:
Expand All @@ -44,6 +48,11 @@ jobs:
with:
name: dist
path: dist/
- uses: actions/download-artifact@v4
with:
pattern: native-wheel-*
path: dist/
merge-multiple: true
- uses: pypa/gh-action-pypi-publish@release/v1
- name: Create GitHub release
uses: softprops/action-gh-release@v2
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ uv run extract-bench run llamaextract_agentic
uv run extract-bench serve llamaextract_agentic
```

Source installs require Rust 1.83 or newer and a C linker. Published wheels
include the native geometry extension. Numerical coverage runs in Rust;
Python retains text comparison, scoring decisions, and metric metadata.
The release version lives in `rust/Cargo.toml`; `extract_bench.__version__`
reads the installed package metadata.


> [!WARNING]
> A full run is **370 documents / 4,869 pages** against a metered API, and costs roughly
> **$10 to $1,677** depending on which system you evaluate. Start with `--test`, which runs
Expand Down
41 changes: 19 additions & 22 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -117,28 +117,25 @@ Changelog = "https://github.com/run-llama/ExtractBench/blob/main/CHANGELOG.md"
extract-bench = "extract_bench.cli:main"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.version]
path = "src/extract_bench/__init__.py"

[tool.hatch.build.targets.wheel]
# ``packages`` already carries analysis/static into the wheel; a force-include
# for the same directory makes hatchling add every asset twice and abort.
packages = ["src/extract_bench"]

[tool.hatch.build.targets.sdist]
only-include = [
"src/extract_bench",
"tests",
"README.md",
"LICENSE",
"CHANGELOG.md",
]
exclude = [
"**/__pycache__",
"**/.gitkeep",
requires = ["maturin==1.14.1"]
build-backend = "maturin"

[tool.maturin]
manifest-path = "rust/bindings/python/Cargo.toml"
python-source = "src"
module-name = "extract_bench._native"
features = ["pyo3/extension-module"]
profile = "release"
include = [{ path = "tests/**/*", format = "sdist" }]

[tool.uv]
cache-keys = [
{ file = "pyproject.toml" },
{ file = "src/**/*.py" },
{ file = "src/**/*.pyi" },
{ file = "rust/**/*.toml" },
{ file = "rust/Cargo.lock" },
{ file = "rust/**/*.rs" },
]

[tool.ruff]
Expand Down
137 changes: 137 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[workspace]
members = ["crates/geometry", "bindings/python"]
resolver = "2"

[workspace.package]
version = "1.0.0"
edition = "2021"
rust-version = "1.83"
license = "Apache-2.0"

[workspace.dependencies]
extract-bench-geometry = { path = "crates/geometry" }
pyo3 = "0.29"
17 changes: 17 additions & 0 deletions rust/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
The geometry crate contains binding-free rectangle coverage calculations.
The PyO3 crate only marshals coordinate batches and releases the GIL while the
core runs. Python retains coordinate boundary ordering, page/group scopes,
text comparison, match selection, thresholds, and metric metadata.

Build the optimized mixed Python/Rust package with `uv sync --extra dev` or
`uv build`. Source builds require Rust and a C linker. Run `cargo test
--manifest-path rust/Cargo.toml --locked`, `cargo clippy --manifest-path
rust/Cargo.toml --all-targets --locked -- -D warnings`, and `cargo fmt
--manifest-path rust/Cargo.toml --all --check`. Python tests compare the native
kernel with the frozen Python geometry implementation, including nonfinite
coordinates, degenerate boxes, and candidate thresholds.

The union algorithm intentionally retains the grid traversal and floating
point accumulation order of the Python scorer. An algorithmic replacement
requires separate parity and performance evidence. Native batches use owned
coordinate arrays; they contain no Python objects or document text.
Loading
Loading