Skip to content

Commit 7658082

Browse files
authored
Merge pull request #31 from opendatalab/0.1.16
0.1.16
2 parents 2d15b5c + ca3e8b3 commit 7658082

File tree

12 files changed

+585
-10
lines changed

12 files changed

+585
-10
lines changed
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3+
4+
name: Python package
5+
6+
on:
7+
push:
8+
tags:
9+
- '*released'
10+
workflow_dispatch:
11+
12+
13+
jobs:
14+
15+
update-version:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout repository
19+
uses: actions/checkout@v4
20+
with:
21+
ref: master
22+
fetch-depth: 0
23+
24+
- name: Set up Python
25+
uses: actions/setup-python@v5
26+
with:
27+
python-version: "3.10"
28+
29+
- name: Update version.py
30+
run: |
31+
python update_version.py
32+
33+
- name: Verify version.py
34+
run: |
35+
ls -l mineru_vl_utils/version.py
36+
cat mineru_vl_utils/version.py
37+
38+
- name: Commit changes
39+
run: |
40+
git config --local user.email "${{ github.actor }}@users.noreply.github.com"
41+
git config --local user.name "${{ github.actor }}"
42+
git add mineru_vl_utils/version.py
43+
if git diff-index --quiet HEAD; then
44+
echo "No changes to commit"
45+
else
46+
git commit -m "Update version.py with new version"
47+
fi
48+
id: commit_changes
49+
50+
- name: Push changes
51+
if: steps.commit_changes.outcome == 'success'
52+
env:
53+
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
54+
run: |
55+
git push origin HEAD:master
56+
57+
check-install:
58+
needs: [ update-version ]
59+
runs-on: ubuntu-latest
60+
strategy:
61+
fail-fast: false
62+
matrix:
63+
python-version: ["3.10", "3.11", "3.12", "3.13"]
64+
65+
steps:
66+
- name: Checkout code
67+
uses: actions/checkout@v4
68+
with:
69+
ref: master
70+
fetch-depth: 0
71+
72+
- name: Verify version.py
73+
run: |
74+
ls -l mineru_vl_utils/version.py
75+
cat mineru_vl_utils/version.py
76+
77+
- name: Set up Python ${{ matrix.python-version }}
78+
uses: actions/setup-python@v5
79+
with:
80+
python-version: ${{ matrix.python-version }}
81+
82+
- name: Install mineru_vl_utils
83+
run: |
84+
python -m pip install --upgrade pip
85+
pip install -e .
86+
87+
build:
88+
needs: [ check-install ]
89+
runs-on: ubuntu-latest
90+
strategy:
91+
fail-fast: false
92+
matrix:
93+
python-version: [ "3.10"]
94+
95+
steps:
96+
97+
- name: Checkout code
98+
uses: actions/checkout@v4
99+
with:
100+
ref: master
101+
fetch-depth: 0
102+
103+
- name: Install wheel
104+
run: |
105+
python -m pip install wheel
106+
pip install build
107+
108+
- name: Build wheel
109+
run: |
110+
python -m build --wheel
111+
112+
- name: Upload artifact
113+
uses: actions/upload-artifact@v4
114+
with:
115+
name: wheel-file
116+
path: dist/*.whl
117+
retention-days: 30
118+
119+
release:
120+
needs: [ build ]
121+
runs-on: ubuntu-latest
122+
steps:
123+
- name: Checkout code
124+
uses: actions/checkout@v4
125+
126+
- name: Download artifact
127+
uses: actions/download-artifact@v4
128+
with:
129+
name: wheel-file
130+
path: dist
131+
132+
- name: Create and Upload Release
133+
id: create_release
134+
uses: softprops/action-gh-release@4634c16e79c963813287e889244c50009e7f0981
135+
with:
136+
files: './dist/*.whl'
137+
env:
138+
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
139+
140+
- name: Publish distribution to PyPI
141+
run: |
142+
pip install -U twine id keyring packaging readme-renderer requests requests-toolbelt rfc3986 rich urllib3
143+
twine check dist/*
144+
twine upload dist/* -u __token__ -p ${{ secrets.PYPI_TOKEN }}

README.md

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ and handling responses from the MinerU Vision-Language Model.
77

88
## About Backends
99

10-
We provides 4 different backends(deployment modes):
10+
We provides 6 different backends(deployment modes):
1111

1212
1. **http-client**: A HTTP client for interacting with the OpenAI-compatible model server.
1313
2. **transformers**: A backend for using HuggingFace Transformers models. (slow but simple to install)
1414
3. **mlx-engine**: A backend for using Apple Silicon devices with macOS.
15-
4. **vllm-engine**: A backend for using the VLLM synchronous batching engine.
16-
5. **vllm-async-engine**: A backend for using the VLLM asynchronous engine. (requires async programming)
15+
4. **lmdeploy-engine**: A backend for using the LmDeploy engine.
16+
5. **vllm-engine**: A backend for using the VLLM synchronous batching engine.
17+
6. **vllm-async-engine**: A backend for using the VLLM asynchronous engine. (requires async programming)
1718

1819
## About Output Format
1920

@@ -67,6 +68,12 @@ For `mlx-engine` backend, install the package with the `mlx` extra:
6768
pip install -U "mineru-vl-utils[mlx]"
6869
```
6970

71+
For `lmdeploy-engine` backend, install the package with the `lmdeploy` extra:
72+
73+
```bash
74+
pip install -U "mineru-vl-utils[lmdeploy]"
75+
```
76+
7077
> [!NOTE]
7178
> For using the `http-client` backend, you still need to have another
7279
> `vllm`(or other LLM deployment tool) environment to serve the model as a http server.
@@ -176,6 +183,54 @@ extracted_blocks = client.two_step_extract(image)
176183
print(extracted_blocks)
177184
```
178185

186+
### `lmdeploy-engine` Example
187+
188+
For default inference engine(`turbomind` by now).
189+
190+
```python
191+
from lmdeploy.serve.vl_async_engine import VLAsyncEngine
192+
from mineru_vl_utils import MinerUClient
193+
from PIL import Image
194+
195+
if __name__ == "__main__":
196+
lmdeploy_engine = VLAsyncEngine("opendatalab/MinerU2.5-2509-1.2B")
197+
198+
client = MinerUClient(
199+
backend="lmdeploy-engine",
200+
lmdeploy_engine=lmdeploy_engine,
201+
)
202+
203+
image = Image.open("/path/to/the/test/image.png")
204+
extracted_blocks = client.two_step_extract(image)
205+
print(extracted_blocks)
206+
```
207+
208+
For pytorch inference engine and `ascend` accelerator.
209+
210+
```python
211+
from lmdeploy import PytorchEngineConfig
212+
from lmdeploy.serve.vl_async_engine import VLAsyncEngine
213+
from mineru_vl_utils import MinerUClient
214+
from PIL import Image
215+
216+
if __name__ == "__main__":
217+
lmdeploy_engine = VLAsyncEngine(
218+
"opendatalab/MinerU2.5-2509-1.2B",
219+
backend="pytorch",
220+
backend_config=PytorchEngineConfig(
221+
device_type="ascend",
222+
),
223+
)
224+
225+
client = MinerUClient(
226+
backend="lmdeploy-engine",
227+
lmdeploy_engine=lmdeploy_engine,
228+
)
229+
230+
image = Image.open("/path/to/the/test/image.png")
231+
extracted_blocks = client.two_step_extract(image)
232+
print(extracted_blocks)
233+
```
179234

180235
### `vllm-engine` Example
181236

mineru_vl_utils/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import importlib
22
from typing import TYPE_CHECKING
33

4-
__version__ = "0.1.15"
5-
__version_info__ = (0, 1, 15)
4+
from mineru_vl_utils.version import __version__
5+
66

77
__lazy_attrs__ = {
88
"MinerUClient": (".mineru_client", "MinerUClient"),
@@ -31,5 +31,4 @@ def __getattr__(name: str):
3131
"MinerUSamplingParams",
3232
"MinerULogitsProcessor",
3333
"__version__",
34-
"__version_info__",
3534
]

mineru_vl_utils/mineru_client.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,14 +263,22 @@ async def aio_post_process(
263263
class MinerUClient:
264264
def __init__(
265265
self,
266-
backend: Literal["http-client", "transformers", "mlx-engine", "vllm-engine", "vllm-async-engine"],
266+
backend: Literal[
267+
"http-client",
268+
"transformers",
269+
"mlx-engine",
270+
"lmdeploy-engine",
271+
"vllm-engine",
272+
"vllm-async-engine",
273+
],
267274
model_name: str | None = None,
268275
server_url: str | None = None,
269276
server_headers: dict[str, str] | None = None,
270277
model=None, # transformers model
271278
processor=None, # transformers processor
272279
vllm_llm=None, # vllm.LLM model
273280
vllm_async_llm=None, # vllm.v1.engine.async_llm.AsyncLLM instance
281+
lmdeploy_engine=None, # lmdeploy.serve.vl_async_engine.VLAsyncEngine instance
274282
model_path: str | None = None,
275283
prompts: dict[str, str] = DEFAULT_PROMPTS,
276284
system_prompt: str = DEFAULT_SYSTEM_PROMPT,
@@ -328,6 +336,20 @@ def __init__(
328336
raise ImportError("Please install mlx-vlm to use the mlx-engine backend.")
329337
model, processor = mlx_load(model_path)
330338

339+
elif backend == "lmdeploy-engine":
340+
if lmdeploy_engine is None:
341+
if not model_path:
342+
raise ValueError("model_path must be provided when lmdeploy_engine is None.")
343+
344+
try:
345+
from lmdeploy.serve.vl_async_engine import VLAsyncEngine
346+
except ImportError:
347+
raise ImportError("Please install lmdeploy to use the lmdeploy-engine backend.")
348+
349+
lmdeploy_engine = VLAsyncEngine(
350+
model_path,
351+
)
352+
331353
elif backend == "vllm-engine":
332354
if vllm_llm is None:
333355
if not model_path:
@@ -360,6 +382,7 @@ def __init__(
360382
server_headers=server_headers,
361383
model=model,
362384
processor=processor,
385+
lmdeploy_engine=lmdeploy_engine,
363386
vllm_llm=vllm_llm,
364387
vllm_async_llm=vllm_async_llm,
365388
system_prompt=system_prompt,
@@ -393,7 +416,7 @@ def __init__(
393416
self.use_tqdm = use_tqdm
394417
self.debug = debug
395418

396-
if backend in ("http-client", "vllm-async-engine"):
419+
if backend in ("http-client", "vllm-async-engine", "lmdeploy-engine"):
397420
self.batching_mode = "concurrent"
398421
else: # backend in ("transformers", "vllm-engine")
399422
self.batching_mode = "stepping"

mineru_vl_utils/post_process/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from .equation_unbalanced_braces import try_fix_unbalanced_braces
12
from ..structs import ContentBlock
23
from .equation_block import do_handle_equation_block
34
from .equation_double_subscript import try_fix_equation_double_subscript
@@ -23,6 +24,7 @@ def _process_equation(content: str, debug: bool) -> str:
2324
content = try_fix_equation_eqqcolon(content, debug=debug)
2425
content = try_fix_equation_big(content, debug=debug)
2526
content = try_fix_equation_leq(content, debug=debug)
27+
content = try_fix_unbalanced_braces(content, debug=debug)
2628
return content
2729

2830

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Copyright (c) Opendatalab. All rights reserved.
2+
def try_fix_unbalanced_braces(latex_formula: str, debug: bool = False):
3+
"""
4+
检测LaTeX公式中的花括号是否闭合,并删除无法配对的花括号
5+
6+
Args:
7+
latex_formula (str): 输入的LaTeX公式
8+
9+
Returns:
10+
str: 删除无法配对的花括号后的LaTeX公式
11+
"""
12+
stack = [] # 存储左括号的索引
13+
unmatched = set() # 存储不匹配括号的索引
14+
i = 0
15+
16+
while i < len(latex_formula):
17+
# 检查是否是转义的花括号
18+
if latex_formula[i] in ['{', '}']:
19+
# 计算前面连续的反斜杠数量
20+
backslash_count = 0
21+
j = i - 1
22+
while j >= 0 and latex_formula[j] == '\\':
23+
backslash_count += 1
24+
j -= 1
25+
26+
# 如果前面有奇数个反斜杠,则该花括号是转义的,不参与匹配
27+
if backslash_count % 2 == 1:
28+
i += 1
29+
continue
30+
31+
# 否则,该花括号参与匹配
32+
if latex_formula[i] == '{':
33+
stack.append(i)
34+
else: # latex_formula[i] == '}'
35+
if stack: # 有对应的左括号
36+
stack.pop()
37+
else: # 没有对应的左括号
38+
unmatched.add(i)
39+
40+
i += 1
41+
42+
# 所有未匹配的左括号
43+
unmatched.update(stack)
44+
45+
# 构建新字符串,删除不匹配的括号
46+
return ''.join(char for i, char in enumerate(latex_formula) if i not in unmatched)

mineru_vl_utils/version.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__version__ = "0.1.15"

0 commit comments

Comments
 (0)