diff --git a/BENCHMARKS.md b/BENCHMARKS.md index dfa46d8..93ade5f 100644 --- a/BENCHMARKS.md +++ b/BENCHMARKS.md @@ -20,23 +20,44 @@ Ground truth: `convert_main_content` field (html2text with bodywidth=0, ignore_l ### Notes -- **pg/s**: pages/second on a single A100 80GB GPU. -- **Pulpie models** use a naive sequential inference loop (no batching). Throughput can be improved with batched inference. +- **pg/s** (this table): pages/second during the full WebMainBench quality run on a + single A100 80GB, with Pulpie using a naive sequential loop (no batching). The + batched throughput numbers in the section below are the ones to use for + speed/cost — batching roughly 6x's Pulpie Small on A100 (4.0 → 25.7). +- **Dripper** ([MinerU-HTML v1.1](https://huggingface.co/opendatalab/MinerU-HTML-v1.1-hunyuan0.5B-compact)) uses vLLM with guided regex decoding for batched inference. - **Dripper** ([MinerU-HTML v1.1](https://huggingface.co/opendatalab/MinerU-HTML-v1.1-hunyuan0.5B-compact)) uses vLLM with guided regex decoding for batched inference. - **Empty**: pages where the method produced no output (context overflow for Dripper, no blocks detected for Pulpie). - **magic-html**: [opendatalab/magic-html](https://github.com/opendatalab/magic-html) rule-based extractor. - **Trafilatura**: [trafilatura](https://github.com/adbar/trafilatura) with `include_tables=True`. - **Raw html2text**: full HTML passed directly through html2text (no extraction). +### Throughput (500 real Common Crawl pages) + +L4 throughput: + +| Method | Pages/sec (L4) | Pages/sec (A100, batched) | +|--------|----------------|---------------------------| +| Pulpie Small | **13.7** | 25.7 | +| Pulpie Base | 3.9 | 7.7 | +| Pulpie Large | 1.3 | 3.5 | +| Dripper | 0.68 | 3.6 | + +Pulpie Small runs **20x faster than Dripper on L4** and **7.1x faster on A100**. + ### Cost comparison (1B pages, projected) -| Setup | pg/s | GPU-hours | Cost (RunPod) | -|-------|------|-----------|---------------| -| Pulpie Small on L4 | 15.1 | 18,400 | $6,500 | -| Pulpie Small on A100 | 4.0 (unbatched) | 69,400 | $9,700 | -| Dripper on A100 (vLLM) | 3.5 | 79,400 | $77,000 | +L4 at $0.39/hr, using the throughputs above: + +| Setup | Pages/sec | GPU-hours / 1B | Cost / 1B pages | +|-------|-----------|----------------|-----------------| +| Pulpie Small on L4 | 13.7 | 20,300 | **~$7,900** | +| Pulpie Base on L4 | 3.9 | 71,200 | ~$28,000 | +| Pulpie Large on L4 | 1.3 | 214,000 | ~$83,000 | +| Dripper on L4 | 0.68 | 408,000 | ~$159,000 | + +Pulpie Small matches Dripper quality (0.862 vs 0.864) at **~20x lower cost** on an L4. -Pulpie Small matches Dripper quality (0.862 vs 0.864) at ~12x lower cost. +Full analysis: [Pulpie: Pareto-Optimal Models for Cleaning the Web](https://usefeyn.com/blog/pulpie-pareto-optimal-models-for-cleaning-the-web/). ### Hardware diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 6c68b9e..67d9d80 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,157 @@ -

- - - pulpie - -

+
-Fast content extraction from HTML using encoder models. 16x faster than autoregressive approaches at the same quality. + + + pulpie + -## Install +[![PyPI version](https://img.shields.io/pypi/v/pulpie.svg)](https://pypi.org/project/pulpie/) +[![Python versions](https://img.shields.io/pypi/pyversions/pulpie.svg)](https://pypi.org/project/pulpie/) +[![License](https://img.shields.io/github/license/chonkie-inc/pulpie.svg)](https://github.com/chonkie-inc/pulpie/blob/main/LICENSE) +[![Downloads](https://static.pepy.tech/badge/pulpie)](https://pepy.tech/project/pulpie) +[![Blog](https://img.shields.io/badge/blog-read%20the%20writeup-E34C26.svg)](https://usefeyn.com/blog/pulpie-pareto-optimal-models-for-cleaning-the-web/) +[![GitHub stars](https://img.shields.io/github/stars/chonkie-inc/pulpie.svg)](https://github.com/chonkie-inc/pulpie/stargazers) + +_Pareto-optimal models for cleaning the web — extract main content from HTML at one twentieth the cost._ + +[Install](#installation) • +[Usage](#usage) • +[Models](#models) • +[How it works](#how-it-works) • +[Benchmarks](#benchmarks) • +[Blog](https://usefeyn.com/blog/pulpie-pareto-optimal-models-for-cleaning-the-web/) + +
+ +Pulpie extracts the main content from raw HTML — stripping navigation, ads, sidebars, and footers — using small encoder models that label every block in a single forward pass. It approaches state-of-the-art extraction quality while running up to **20x faster** and **20x cheaper** than autoregressive extractors. + +**⚡ Fast** — an encoder labels every block in one forward pass (13.7 pages/sec on an L4)
+**🎯 Accurate** — matches SOTA quality: 0.862–0.873 ROUGE-5 F1 on WebMainBench
+**🪶 Small** — the recommended model is 210M params, fits on any GPU
+**💸 Cheap** — clean 1 billion pages for ~$7,900 vs ~$159,000 for the leading decoder
+**📦 Simple** — `pip install pulpie`, then `Extractor().extract(html)`
+**🔌 Batched** — overlapped CPU+GPU pipeline scales across multiple GPUs
+ +## Installation ```bash pip install pulpie ``` -For markdown output: +For Markdown output, install the `markdown` extra: + +```bash +pip install "pulpie[markdown]" +``` + +Or with [uv](https://docs.astral.sh/uv/): + ```bash -pip install pulpie[markdown] +uv pip install "pulpie[markdown]" ``` ## Usage +### Basic + ```python from pulpie import Extractor -extractor = Extractor() # downloads pulpie-orange-small (210M) on first use - +extractor = Extractor() # defaults to pulpie-orange-small (210M) result = extractor.extract(html) -print(result.markdown) # clean markdown -print(result.html) # clean HTML -print(result.n_main) # number of content blocks -print(result.n_other) # number of boilerplate blocks -``` -## Models +print(result.markdown) # clean Markdown +print(result.html) # clean HTML +print(result.n_main, result.n_other) # blocks kept vs dropped +``` -| Model | Size | ROUGE-5 | Speed (L4) | -|-------|------|---------|------------| -| `orange-small` | 210M | 0.864 | 15 pps | -| `orange-base` | 610M | 0.849 | ~6 pps | -| `orange-large` | 2.1B | 0.862 | ~2 pps | +The model downloads from Hugging Face on first use. -`orange-small` is the default and recommended model — it matches the 2.1B teacher at 1/10th the size. +### Choosing a model ```python -# Use a specific model -extractor = Extractor(model="orange-large") +extractor = Extractor(model="orange-large") # "orange-small" (default), "orange-base", "orange-large" +extractor = Extractor(model="path/to/model") # or a custom checkpoint +extractor = Extractor(device="cpu") # force CPU +``` + +### Batch processing -# Use a custom model path -extractor = Extractor(model="path/to/your/model") +For bulk extraction, `Pipeline` overlaps CPU preprocessing with GPU inference and self-balances across one or more GPUs: -# Force CPU -extractor = Extractor(device="cpu") +```python +from pulpie import Pipeline, PageInput + +pipeline = Pipeline(model="orange-small") +results = pipeline.extract_batch( + [PageInput(html=h, page_id=i) for i, h in enumerate(pages)] +) ``` +## Models + +All three models are built on [EuroBERT](https://arxiv.org/abs/2503.05500), share a tokenizer, and use the same `<|sep|>` block-marker architecture. Large is the teacher; Base and Small are distilled from it. + +| Model | Hugging Face | Params | ROUGE-5 F1 | Notes | +|-------|--------------|--------|------------|-------| +| **Orange Small** | [`chonkie-ai/pulpie-orange-small`](https://huggingface.co/chonkie-ai/pulpie-orange-small) | 210M | 0.862 | **Recommended** — best size-to-quality ratio | +| Orange Base | [`chonkie-ai/pulpie-orange-base`](https://huggingface.co/chonkie-ai/pulpie-orange-base) | 610M | 0.863 | Distilled from Large | +| Orange Large | [`chonkie-ai/pulpie-orange-large`](https://huggingface.co/chonkie-ai/pulpie-orange-large) | 2.1B | 0.873 | Teacher (highest quality) | + +`orange-small` is the default. Despite being a third the size of Dripper (the leading extractor), it matches its quality (0.862 vs 0.864) while running 20x faster. + ## How it works -Pulpie classifies each HTML block as "main content" or "boilerplate" using a bidirectional encoder. The pipeline: +Pulpie keeps the "read the page" approach of model-based extractors but moves the bottleneck from memory bandwidth to compute by using an encoder instead of a decoder. The pipeline runs in four stages: + +1. **Simplify** — remove scripts, styles, and formatting noise; tag each content block with a unique ID. +2. **Chunk** — split, tokenize, and pack blocks into chunks of up to 8,192 tokens (≈80% of pages fit in one chunk). +3. **Classify** — a single encoder forward pass labels every block as content or boilerplate. +4. **Reconstruct** — return the kept blocks as HTML, or convert them to Markdown. + +A decoder emits labels one token at a time, re-reading the full model from GPU memory each step. An encoder runs one dense forward pass over the whole input — so the gap widens on bandwidth-limited GPUs (7x faster than Dripper on A100, 20x on L4). -1. **Simplify** — Strip scripts, styles, normalize HTML (via MinerU-HTML) -2. **Chunk** — Pack blocks into sequences separated by `<|sep|>` tokens -3. **Classify** — Single encoder forward pass classifies all blocks simultaneously -4. **Reconstruct** — Extract content blocks, convert to markdown +## Benchmarks -## Performance +Quality on the English subset of [WebMainBench](https://github.com/opendatalab/WebMainBench) (6,647 pages), ROUGE-5 F1: -On 500 real Common Crawl pages (NVIDIA L4 GPU): +| Method | Params | ROUGE-5 F1 | Empty pages | +|--------|--------|------------|-------------| +| **Pulpie Orange Large** | 2.1B | **0.873** | 21 | +| Dripper | 0.6B | 0.864 | 135 | +| **Pulpie Orange Base** | 610M | 0.863 | 36 | +| **Pulpie Orange Small** | 210M | 0.862 | 45 | +| magic-html | — | 0.700 | 384 | +| Trafilatura | — | 0.619 | 16 | -- **15.1 pages/sec** (single GPU, 210M model) -- **$6,500** to clean 1 billion pages -- **16.4x faster** than Dripper (autoregressive) on the same hardware -- **433 MB** VRAM — fits on any GPU +Speed and cost (Pulpie Orange Small vs Dripper, 1 billion pages): + +| | Pulpie Orange Small | Dripper | +|--|--------------------|---------| +| Throughput (L4) | **13.7 pages/sec** | 0.68 pages/sec | +| Cost / 1B pages (L4) | **~$7,900** | ~$159,000 | + +Pulpie Orange Small matches Dripper's quality at **20x the throughput** and **20x lower cost** on an L4. See [BENCHMARKS.md](BENCHMARKS.md) for the full comparison, per-difficulty breakdown, and reproduction command. + +## Acknowledgements + +Pulpie builds directly on the work of the MinerU-HTML and Dripper team (Ma et al., 2025). Their `simplify_html` preprocessing, block-level annotation scheme, and the WebMainBench benchmark are foundational to this work. We also use their Dripper 0.6B model to cross-validate our training labels. We're grateful they released their tools and data. + +## Citation + +If you use Pulpie in your research, please cite: + +```bibtex +@note{pulpie2026, + title = {Pulpie: Pareto-Optimal Models for Cleaning the Web}, + author = {Minhas, Bhavnick and Nigam, Shreyash and Feyn Research}, + year = {2026}, + venue = {Feyn Field Notes} +} +``` -## License +--- -Apache 2.0 +
+Built by Chonkie, the open-source work behind Feyn. +