extractfold 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- extractfold-0.1.1/.gitignore +218 -0
- extractfold-0.1.1/AGENTS.md +9 -0
- extractfold-0.1.1/CHANGELOG.md +31 -0
- extractfold-0.1.1/CLAUDE.md +23 -0
- extractfold-0.1.1/CODEX.md +12 -0
- extractfold-0.1.1/CONTRIBUTING.md +25 -0
- extractfold-0.1.1/LICENSE +21 -0
- extractfold-0.1.1/PKG-INFO +228 -0
- extractfold-0.1.1/README.md +145 -0
- extractfold-0.1.1/benchmark.py +121 -0
- extractfold-0.1.1/docs/benchmarks.md +37 -0
- extractfold-0.1.1/docs/conventions/golden-rules.md +15 -0
- extractfold-0.1.1/docs/tasks/_TEMPLATE.md +38 -0
- extractfold-0.1.1/docs/tasks/azure_docint.md +38 -0
- extractfold-0.1.1/docs/tasks/benchmark.md +38 -0
- extractfold-0.1.1/docs/tasks/cli.md +40 -0
- extractfold-0.1.1/docs/tasks/docfold_llm.md +38 -0
- extractfold-0.1.1/docs/tasks/docs-packaging-ci.md +42 -0
- extractfold-0.1.1/docs/tasks/evaluation.md +38 -0
- extractfold-0.1.1/docs/tasks/fenic.md +51 -0
- extractfold-0.1.1/docs/tasks/google_docai.md +38 -0
- extractfold-0.1.1/docs/tasks/instructor.md +38 -0
- extractfold-0.1.1/docs/tasks/lift.md +40 -0
- extractfold-0.1.1/docs/tasks/llamaextract.md +38 -0
- extractfold-0.1.1/docs/tasks/llm_structured.md +40 -0
- extractfold-0.1.1/docs/tasks/nuextract.md +38 -0
- extractfold-0.1.1/docs/tasks/provider_router.md +70 -0
- extractfold-0.1.1/docs/tasks/resilient-chunked-extraction.md +61 -0
- extractfold-0.1.1/docs/tasks/text-first-row-extraction.md +222 -0
- extractfold-0.1.1/docs/tasks/textract.md +38 -0
- extractfold-0.1.1/pyproject.toml +128 -0
- extractfold-0.1.1/src/extractfold/__init__.py +40 -0
- extractfold-0.1.1/src/extractfold/chunking.py +187 -0
- extractfold-0.1.1/src/extractfold/cli.py +159 -0
- extractfold-0.1.1/src/extractfold/engines/__init__.py +33 -0
- extractfold-0.1.1/src/extractfold/engines/_common.py +143 -0
- extractfold-0.1.1/src/extractfold/engines/azure_docint_engine.py +135 -0
- extractfold-0.1.1/src/extractfold/engines/base.py +510 -0
- extractfold-0.1.1/src/extractfold/engines/docfold_llm_engine.py +97 -0
- extractfold-0.1.1/src/extractfold/engines/fenic_engine.py +189 -0
- extractfold-0.1.1/src/extractfold/engines/google_docai_engine.py +144 -0
- extractfold-0.1.1/src/extractfold/engines/instructor_engine.py +96 -0
- extractfold-0.1.1/src/extractfold/engines/lift_engine.py +112 -0
- extractfold-0.1.1/src/extractfold/engines/llamaextract_engine.py +95 -0
- extractfold-0.1.1/src/extractfold/engines/llm_structured_engine.py +188 -0
- extractfold-0.1.1/src/extractfold/engines/nuextract_engine.py +115 -0
- extractfold-0.1.1/src/extractfold/engines/provider_router_engine.py +135 -0
- extractfold-0.1.1/src/extractfold/engines/router.py +7 -0
- extractfold-0.1.1/src/extractfold/engines/textract_engine.py +120 -0
- extractfold-0.1.1/src/extractfold/evaluation/__init__.py +26 -0
- extractfold-0.1.1/src/extractfold/evaluation/metrics.py +164 -0
- extractfold-0.1.1/src/extractfold/evaluation/runner.py +144 -0
- extractfold-0.1.1/src/extractfold/parsing.py +101 -0
- extractfold-0.1.1/src/extractfold/py.typed +1 -0
- extractfold-0.1.1/src/extractfold/schema.py +128 -0
- extractfold-0.1.1/src/extractfold/text.py +285 -0
- extractfold-0.1.1/tests/__init__.py +1 -0
- extractfold-0.1.1/tests/engines/__init__.py +1 -0
- extractfold-0.1.1/tests/engines/helpers.py +31 -0
- extractfold-0.1.1/tests/engines/test_azure_docint_engine.py +37 -0
- extractfold-0.1.1/tests/engines/test_base.py +150 -0
- extractfold-0.1.1/tests/engines/test_docfold_llm_engine.py +46 -0
- extractfold-0.1.1/tests/engines/test_engine_roster.py +22 -0
- extractfold-0.1.1/tests/engines/test_fenic_engine.py +82 -0
- extractfold-0.1.1/tests/engines/test_google_docai_engine.py +36 -0
- extractfold-0.1.1/tests/engines/test_instructor_engine.py +41 -0
- extractfold-0.1.1/tests/engines/test_lift_engine.py +45 -0
- extractfold-0.1.1/tests/engines/test_llamaextract_engine.py +28 -0
- extractfold-0.1.1/tests/engines/test_llm_structured_engine.py +67 -0
- extractfold-0.1.1/tests/engines/test_nuextract_engine.py +39 -0
- extractfold-0.1.1/tests/engines/test_provider_router_engine.py +110 -0
- extractfold-0.1.1/tests/engines/test_router.py +188 -0
- extractfold-0.1.1/tests/engines/test_textract_engine.py +48 -0
- extractfold-0.1.1/tests/evaluation/__init__.py +1 -0
- extractfold-0.1.1/tests/evaluation/test_metrics.py +90 -0
- extractfold-0.1.1/tests/evaluation/test_runner.py +29 -0
- extractfold-0.1.1/tests/test_benchmark.py +47 -0
- extractfold-0.1.1/tests/test_cli.py +120 -0
- extractfold-0.1.1/tests/test_imports.py +63 -0
- extractfold-0.1.1/tests/test_packaging.py +35 -0
- extractfold-0.1.1/tests/text/test_chunked_extraction.py +230 -0
- extractfold-0.1.1/tests/text/test_chunking.py +106 -0
- extractfold-0.1.1/tests/text/test_parsing.py +84 -0
- extractfold-0.1.1/tests/text/test_schema_conversion.py +148 -0
- extractfold-0.1.1/tests/text/test_text_helpers.py +216 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
# Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
# poetry.lock
|
|
109
|
+
# poetry.toml
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
114
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
115
|
+
# pdm.lock
|
|
116
|
+
# pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# pixi
|
|
121
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
122
|
+
# pixi.lock
|
|
123
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
124
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
125
|
+
.pixi
|
|
126
|
+
|
|
127
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
128
|
+
__pypackages__/
|
|
129
|
+
|
|
130
|
+
# Celery stuff
|
|
131
|
+
celerybeat-schedule
|
|
132
|
+
celerybeat.pid
|
|
133
|
+
|
|
134
|
+
# Redis
|
|
135
|
+
*.rdb
|
|
136
|
+
*.aof
|
|
137
|
+
*.pid
|
|
138
|
+
|
|
139
|
+
# RabbitMQ
|
|
140
|
+
mnesia/
|
|
141
|
+
rabbitmq/
|
|
142
|
+
rabbitmq-data/
|
|
143
|
+
|
|
144
|
+
# ActiveMQ
|
|
145
|
+
activemq-data/
|
|
146
|
+
|
|
147
|
+
# SageMath parsed files
|
|
148
|
+
*.sage.py
|
|
149
|
+
|
|
150
|
+
# Environments
|
|
151
|
+
.env
|
|
152
|
+
.envrc
|
|
153
|
+
.venv
|
|
154
|
+
env/
|
|
155
|
+
venv/
|
|
156
|
+
ENV/
|
|
157
|
+
env.bak/
|
|
158
|
+
venv.bak/
|
|
159
|
+
|
|
160
|
+
# Spyder project settings
|
|
161
|
+
.spyderproject
|
|
162
|
+
.spyproject
|
|
163
|
+
|
|
164
|
+
# Rope project settings
|
|
165
|
+
.ropeproject
|
|
166
|
+
|
|
167
|
+
# mkdocs documentation
|
|
168
|
+
/site
|
|
169
|
+
|
|
170
|
+
# mypy
|
|
171
|
+
.mypy_cache/
|
|
172
|
+
.dmypy.json
|
|
173
|
+
dmypy.json
|
|
174
|
+
|
|
175
|
+
# Pyre type checker
|
|
176
|
+
.pyre/
|
|
177
|
+
|
|
178
|
+
# pytype static type analyzer
|
|
179
|
+
.pytype/
|
|
180
|
+
|
|
181
|
+
# Cython debug symbols
|
|
182
|
+
cython_debug/
|
|
183
|
+
|
|
184
|
+
# PyCharm
|
|
185
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
186
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
187
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
188
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
189
|
+
# .idea/
|
|
190
|
+
|
|
191
|
+
# Abstra
|
|
192
|
+
# Abstra is an AI-powered process automation framework.
|
|
193
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
194
|
+
# Learn more at https://abstra.io/docs
|
|
195
|
+
.abstra/
|
|
196
|
+
|
|
197
|
+
# Visual Studio Code
|
|
198
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
199
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
200
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
201
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
202
|
+
# .vscode/
|
|
203
|
+
# Temporary file for partial code execution
|
|
204
|
+
tempCodeRunnerFile.py
|
|
205
|
+
|
|
206
|
+
# Ruff stuff:
|
|
207
|
+
.ruff_cache/
|
|
208
|
+
|
|
209
|
+
# PyPI configuration file
|
|
210
|
+
.pypirc
|
|
211
|
+
|
|
212
|
+
# Marimo
|
|
213
|
+
marimo/_static/
|
|
214
|
+
marimo/_lsp/
|
|
215
|
+
__marimo__/
|
|
216
|
+
|
|
217
|
+
# Streamlit
|
|
218
|
+
.streamlit/secrets.toml
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
@/Users/m/.codex/RTK.md
|
|
2
|
+
|
|
3
|
+
# extractfold Agent Notes
|
|
4
|
+
|
|
5
|
+
- Preserve the public API in `src/extractfold/engines/base.py`.
|
|
6
|
+
- Follow the proposal -> failing test -> implementation -> verification loop.
|
|
7
|
+
- Unit tests must not require model weights, network, or cloud credentials.
|
|
8
|
+
- Optional engines must import heavy dependencies lazily inside methods.
|
|
9
|
+
- Base package dependencies must remain empty.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.1] - 2026-08-20
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- Publish releases through a dedicated OIDC PyPI workflow so release tags do
|
|
13
|
+
not depend on the general test workflow.
|
|
14
|
+
|
|
15
|
+
## [0.1.0] - 2026-08-19
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- `fenic` engine adapter for typedef-ai's fenic `semantic.extract`, behind the
|
|
19
|
+
`extractfold[fenic]` extra.
|
|
20
|
+
- Initial extractfold package scaffold with schema-first engine contract.
|
|
21
|
+
- Router, CLI, evaluation runner, benchmark harness, docs, packaging, and CI.
|
|
22
|
+
- Engine adapters for Lift, NuExtract, LLM structured outputs, Instructor,
|
|
23
|
+
LlamaExtract, Azure Document Intelligence, Google Document AI, AWS Textract,
|
|
24
|
+
and docfold plus LLM extraction.
|
|
25
|
+
- Dependency-free `provider_router` engine for injected model gateways over
|
|
26
|
+
prepared text.
|
|
27
|
+
- Opt-in resilient chunk execution for `extract_rows_chunked(..., continue_on_error=True)`.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
- Exclude `.claude` from the sdist; its out-of-tree symlinks broke building a
|
|
31
|
+
wheel from the sdist.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
## Project
|
|
4
|
+
|
|
5
|
+
extractfold turns documents plus JSON Schema into schema-conformant dictionaries.
|
|
6
|
+
It is the structured-extraction sibling of docfold.
|
|
7
|
+
|
|
8
|
+
## Workflow
|
|
9
|
+
|
|
10
|
+
- Use TDD for every feature and engine.
|
|
11
|
+
- Write or update `docs/tasks/<name>.md` from `docs/tasks/_TEMPLATE.md`.
|
|
12
|
+
- Confirm the new test fails for the expected reason before implementing.
|
|
13
|
+
- Keep the public contract in `src/extractfold/engines/base.py` backward compatible.
|
|
14
|
+
- Keep core imports dependency-free.
|
|
15
|
+
- Put heavy SDK/model imports inside methods.
|
|
16
|
+
|
|
17
|
+
## Gates
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
ruff check src/ tests/
|
|
21
|
+
mypy src/
|
|
22
|
+
pytest tests/ -m "not integration"
|
|
23
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Development Setup
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install -e ".[dev]"
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Adding An Engine
|
|
10
|
+
|
|
11
|
+
1. Add `docs/tasks/<engine>.md` from `docs/tasks/_TEMPLATE.md`.
|
|
12
|
+
2. Write stubbed unit tests and a skipped `integration` test.
|
|
13
|
+
3. Confirm the unit test fails before writing adapter code.
|
|
14
|
+
4. Implement the adapter behind `ExtractionEngine`.
|
|
15
|
+
5. Add an optional extra in `pyproject.toml`.
|
|
16
|
+
6. Register the engine in the CLI router and priority order.
|
|
17
|
+
7. Run the quality gates.
|
|
18
|
+
|
|
19
|
+
## Quality Gates
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
ruff check src/ tests/
|
|
23
|
+
mypy src/
|
|
24
|
+
pytest tests/ -m "not integration"
|
|
25
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mike Sadofyev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: extractfold
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Schema-guided structured data extraction from documents.
|
|
5
|
+
Project-URL: Homepage, https://github.com/mihailorama/extractfold
|
|
6
|
+
Project-URL: Documentation, https://github.com/mihailorama/extractfold/tree/main/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/mihailorama/extractfold
|
|
8
|
+
Project-URL: Issues, https://github.com/mihailorama/extractfold/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/mihailorama/extractfold/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: Mihailorama <mihailorama@gmail.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: document-extraction,json-schema,llm,ocr,structured-data
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
+
Classifier: Topic :: Text Processing :: General
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Provides-Extra: all
|
|
26
|
+
Requires-Dist: anthropic>=0.40; extra == 'all'
|
|
27
|
+
Requires-Dist: azure-ai-documentintelligence>=1.0; extra == 'all'
|
|
28
|
+
Requires-Dist: boto3>=1.28; extra == 'all'
|
|
29
|
+
Requires-Dist: docfold>=0.6; extra == 'all'
|
|
30
|
+
Requires-Dist: fenic>=0.13; extra == 'all'
|
|
31
|
+
Requires-Dist: google-cloud-documentai>=3.0; extra == 'all'
|
|
32
|
+
Requires-Dist: google-genai>=1.0; extra == 'all'
|
|
33
|
+
Requires-Dist: instructor>=1.6; extra == 'all'
|
|
34
|
+
Requires-Dist: llama-cloud-services>=0.6; extra == 'all'
|
|
35
|
+
Requires-Dist: openai>=1.50; extra == 'all'
|
|
36
|
+
Requires-Dist: requests>=2.31; extra == 'all'
|
|
37
|
+
Requires-Dist: torch>=2.0; extra == 'all'
|
|
38
|
+
Requires-Dist: transformers>=4.40; extra == 'all'
|
|
39
|
+
Provides-Extra: azure-docint
|
|
40
|
+
Requires-Dist: azure-ai-documentintelligence>=1.0; extra == 'azure-docint'
|
|
41
|
+
Provides-Extra: dev
|
|
42
|
+
Requires-Dist: mypy>=1.8; extra == 'dev'
|
|
43
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
44
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
45
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
46
|
+
Requires-Dist: tomli>=2.0; (python_version < '3.11') and extra == 'dev'
|
|
47
|
+
Provides-Extra: docfold-llm
|
|
48
|
+
Requires-Dist: anthropic>=0.40; extra == 'docfold-llm'
|
|
49
|
+
Requires-Dist: docfold>=0.6; extra == 'docfold-llm'
|
|
50
|
+
Requires-Dist: google-genai>=1.0; extra == 'docfold-llm'
|
|
51
|
+
Requires-Dist: openai>=1.50; extra == 'docfold-llm'
|
|
52
|
+
Provides-Extra: evaluation
|
|
53
|
+
Provides-Extra: fenic
|
|
54
|
+
Requires-Dist: fenic>=0.13; extra == 'fenic'
|
|
55
|
+
Provides-Extra: google-docai
|
|
56
|
+
Requires-Dist: google-cloud-documentai>=3.0; extra == 'google-docai'
|
|
57
|
+
Provides-Extra: instructor
|
|
58
|
+
Requires-Dist: instructor>=1.6; extra == 'instructor'
|
|
59
|
+
Requires-Dist: openai>=1.50; extra == 'instructor'
|
|
60
|
+
Provides-Extra: lift
|
|
61
|
+
Requires-Dist: requests>=2.31; extra == 'lift'
|
|
62
|
+
Provides-Extra: llamaextract
|
|
63
|
+
Requires-Dist: llama-cloud-services>=0.6; extra == 'llamaextract'
|
|
64
|
+
Provides-Extra: llm-structured
|
|
65
|
+
Requires-Dist: anthropic>=0.40; extra == 'llm-structured'
|
|
66
|
+
Requires-Dist: google-genai>=1.0; extra == 'llm-structured'
|
|
67
|
+
Requires-Dist: openai>=1.50; extra == 'llm-structured'
|
|
68
|
+
Provides-Extra: nuextract
|
|
69
|
+
Requires-Dist: torch>=2.0; extra == 'nuextract'
|
|
70
|
+
Requires-Dist: transformers>=4.40; extra == 'nuextract'
|
|
71
|
+
Provides-Extra: nuextract-vllm
|
|
72
|
+
Requires-Dist: vllm>=0.5; extra == 'nuextract-vllm'
|
|
73
|
+
Provides-Extra: provider-router
|
|
74
|
+
Provides-Extra: test
|
|
75
|
+
Requires-Dist: mypy>=1.8; extra == 'test'
|
|
76
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'test'
|
|
77
|
+
Requires-Dist: pytest>=7.0; extra == 'test'
|
|
78
|
+
Requires-Dist: ruff>=0.4; extra == 'test'
|
|
79
|
+
Requires-Dist: tomli>=2.0; (python_version < '3.11') and extra == 'test'
|
|
80
|
+
Provides-Extra: textract
|
|
81
|
+
Requires-Dist: boto3>=1.28; extra == 'textract'
|
|
82
|
+
Description-Content-Type: text/markdown
|
|
83
|
+
|
|
84
|
+
# extractfold
|
|
85
|
+
|
|
86
|
+
`extractfold` is the structured-data sibling of `docfold`.
|
|
87
|
+
|
|
88
|
+
- `docfold`: document -> representation, such as Markdown, HTML, text, or layout.
|
|
89
|
+
- `extractfold`: document + JSON Schema -> schema-conformant Python `dict`.
|
|
90
|
+
|
|
91
|
+
The core package has no required third-party dependencies. Engines that need model
|
|
92
|
+
weights, cloud SDKs, or provider SDKs live behind optional extras and import those
|
|
93
|
+
dependencies lazily.
|
|
94
|
+
|
|
95
|
+
## Install
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install extractfold
|
|
99
|
+
pip install "extractfold[provider_router]"
|
|
100
|
+
pip install "extractfold[llm_structured]"
|
|
101
|
+
pip install "extractfold[all]"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Quick Start
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
import asyncio
|
|
108
|
+
|
|
109
|
+
from extractfold.engines import LLMStructuredEngine
|
|
110
|
+
|
|
111
|
+
schema = {
|
|
112
|
+
"type": "object",
|
|
113
|
+
"required": ["invoice_id", "total"],
|
|
114
|
+
"properties": {
|
|
115
|
+
"invoice_id": {"type": "string"},
|
|
116
|
+
"vendor": {"type": "string"},
|
|
117
|
+
"total": {"type": "number"},
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async def main() -> None:
|
|
122
|
+
result = await LLMStructuredEngine().extract("invoice.pdf", schema)
|
|
123
|
+
print(result.data)
|
|
124
|
+
|
|
125
|
+
asyncio.run(main())
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## CLI
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
extractfold extract invoice.pdf --schema invoice --engine llm_structured
|
|
132
|
+
extractfold extract invoice.pdf --schema schema.json --out result.json
|
|
133
|
+
extractfold compare invoice.pdf --schema schema.json --engines llm_structured,lift
|
|
134
|
+
extractfold list-engines
|
|
135
|
+
extractfold benchmark ./dataset --engines llm_structured,lift --out results.json
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Engine Comparison
|
|
139
|
+
|
|
140
|
+
| Engine | Type | License | Schema | Nested | Confidence | Provenance | Local/Remote | Speed | Cost |
|
|
141
|
+
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
142
|
+
| `lift` | Datalab Lift adapter | SaaS | Native | Yes | Yes | Yes | Remote | Fast | Paid API |
|
|
143
|
+
| `nuextract` | Open model | Model license | Prompt JSON | Yes | No | No | Local | Medium | Hardware |
|
|
144
|
+
| `provider_router` | Injected model gateway | App-defined | Prompt JSON | Yes | No | No | Remote | App-defined | App-defined |
|
|
145
|
+
| `llm_structured` | LLM structured outputs | Provider terms | Tool/JSON mode | Yes | No | No | Remote | Medium | Paid tokens |
|
|
146
|
+
| `instructor` | Pydantic/JSON extraction | MIT library + provider terms | Pydantic/JSON Schema | Yes | No | No | Remote by default | Medium | Paid tokens |
|
|
147
|
+
| `fenic` | typedef-ai fenic `semantic.extract` | Apache-2.0 library + provider terms | Pydantic (converted from JSON Schema) | Yes | No | No | Remote by default | Medium | Paid tokens |
|
|
148
|
+
| `llamaextract` | LlamaCloud Extract | SaaS | Native | Yes | No | No | Remote | Fast | Paid API |
|
|
149
|
+
| `azure_docint` | Azure Document Intelligence | SaaS | Query fields | Limited | Yes | Yes | Remote | Fast | Paid API |
|
|
150
|
+
| `google_docai` | Google Document AI | SaaS | Custom extractor/entities | Yes | Yes | Yes | Remote | Fast | Paid API |
|
|
151
|
+
| `textract` | AWS Textract | SaaS | QUERIES/FORMS | Limited | Yes | Yes | Remote | Fast | Paid API |
|
|
152
|
+
| `docfold_llm` | Composite | Mixed | LLM structured | Yes | Depends on LLM | Depends on LLM | Remote by default | Medium | Parse + token cost |
|
|
153
|
+
|
|
154
|
+
## How To Choose
|
|
155
|
+
|
|
156
|
+
| Need | Use |
|
|
157
|
+
| --- | --- |
|
|
158
|
+
| Existing model gateway, retries, and telemetry | `provider_router` |
|
|
159
|
+
| Best practical default for arbitrary schemas | `llm_structured` |
|
|
160
|
+
| First-party Datalab Lift workflow | `lift` |
|
|
161
|
+
| Local/open-model extraction | `nuextract` |
|
|
162
|
+
| Existing `instructor` stack | `instructor` |
|
|
163
|
+
| Existing fenic dataframe pipelines | `fenic` |
|
|
164
|
+
| Managed extraction SaaS | `llamaextract` |
|
|
165
|
+
| Enterprise cloud OCR/forms/query fields | `azure_docint`, `google_docai`, or `textract` |
|
|
166
|
+
| Clean Markdown/text before extraction | `docfold_llm` |
|
|
167
|
+
|
|
168
|
+
## Engine Examples
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from extractfold.engines import (
|
|
172
|
+
AzureDocIntEngine,
|
|
173
|
+
DocfoldLLMEngine,
|
|
174
|
+
FenicEngine,
|
|
175
|
+
GoogleDocAIEngine,
|
|
176
|
+
InstructorEngine,
|
|
177
|
+
LiftEngine,
|
|
178
|
+
LLMStructuredEngine,
|
|
179
|
+
LlamaExtractEngine,
|
|
180
|
+
NuExtractEngine,
|
|
181
|
+
ProviderRouterEngine,
|
|
182
|
+
TextractEngine,
|
|
183
|
+
)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
async def provider_call(**kwargs):
|
|
188
|
+
# Call an application-owned gateway and return JSON-compatible data.
|
|
189
|
+
return {"invoice_id": "INV-001", "total": 125.5}
|
|
190
|
+
|
|
191
|
+
result = await ProviderRouterEngine(provider_call=provider_call).extract("invoice.txt", "invoice")
|
|
192
|
+
result = await LiftEngine().extract("invoice.pdf", "invoice")
|
|
193
|
+
result = await NuExtractEngine(backend="hf").extract("invoice.txt", "invoice")
|
|
194
|
+
result = await LLMStructuredEngine(provider="anthropic").extract("invoice.pdf", "invoice")
|
|
195
|
+
result = await LLMStructuredEngine(provider="openai").extract("invoice.pdf", "invoice")
|
|
196
|
+
result = await LLMStructuredEngine(provider="gemini").extract("invoice.pdf", "invoice")
|
|
197
|
+
result = await InstructorEngine().extract("invoice.pdf", "invoice")
|
|
198
|
+
result = await FenicEngine().extract("invoice.txt", "invoice")
|
|
199
|
+
result = await LlamaExtractEngine().extract("invoice.pdf", "invoice")
|
|
200
|
+
result = await AzureDocIntEngine().extract("invoice.pdf", "invoice")
|
|
201
|
+
result = await GoogleDocAIEngine().extract("invoice.pdf", "invoice")
|
|
202
|
+
result = await TextractEngine().extract("invoice.pdf", "invoice")
|
|
203
|
+
result = await DocfoldLLMEngine().extract("invoice.pdf", "invoice")
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Evaluation
|
|
207
|
+
|
|
208
|
+
`extractfold.evaluation` scores prediction folders shaped like this:
|
|
209
|
+
|
|
210
|
+
```text
|
|
211
|
+
dataset/
|
|
212
|
+
gold/invoice.json
|
|
213
|
+
predictions/llm_structured/invoice.json
|
|
214
|
+
predictions/lift/invoice.json
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Metrics include field accuracy, schema compliance, precision/recall/F1,
|
|
218
|
+
hallucination rate, type correctness, normalized value matching, and nested array
|
|
219
|
+
alignment.
|
|
220
|
+
|
|
221
|
+
## Development
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
pip install -e ".[dev]"
|
|
225
|
+
ruff check src/ tests/
|
|
226
|
+
mypy src/
|
|
227
|
+
pytest tests/ -m "not integration"
|
|
228
|
+
```
|