From 1dc915a4a9d913ed52accb0efc3ead5f1a2d8e74 Mon Sep 17 00:00:00 2001
From: yyy <102640628+dt-yy@users.noreply.github.com>
Date: Mon, 2 Sep 2024 20:23:46 +0800
Subject: [PATCH] release: release 0.7.1 version (#526)
* Update README_zh-CN.md (#404) (#409)
correct FAQ url
Co-authored-by: sfk <18810651050@163.com>
* add dockerfile (#189)
Co-authored-by: drunkpig <60862764+drunkpig@users.noreply.github.com>
* Update cla.yml
* Update cla.yml
* feat
: add tablemaster with paddleocr to detect and recognize table (#493)
* Update cla.yml
* Update bug_report.yml
* Update README_zh-CN.md (#404)
correct FAQ url
* Update README_zh-CN.md (#404) (#409) (#410)
correct FAQ url
Co-authored-by: sfk <18810651050@163.com>
* Update FAQ_zh_cn.md
add new issue
* Update FAQ_en_us.md
* Update README_Windows_CUDA_Acceleration_zh_CN.md
* Update README_zh-CN.md
* @Thepathakarpit has signed the CLA in opendatalab/MinerU#418
* Update cla.yml
* feat: add tablemaster_paddle (#463)
* Update README_zh-CN.md (#404) (#409)
correct FAQ url
Co-authored-by: sfk <18810651050@163.com>
* add dockerfile (#189)
Co-authored-by: drunkpig <60862764+drunkpig@users.noreply.github.com>
* Update cla.yml
* Update cla.yml
---------
Co-authored-by: drunkpig <60862764+drunkpig@users.noreply.github.com>
Co-authored-by: sfk <18810651050@163.com>
Co-authored-by: Aoyang Fang <222010547@link.cuhk.edu.cn>
Co-authored-by: Xiaomeng Zhao
* (para_split_v2): index out of range issue of span_text first char (#396)
Co-authored-by: liukaiwen
* @Matthijz98 has signed the CLA in opendatalab/MinerU#467
* Create download_models.py
* Create requirements-docker.txt
* feat: add tablemaster with paddleocr to detect and recognize table
* @strongerfly has signed the CLA in opendatalab/MinerU#487
* feat: add tablemaster with paddleocr to detect and recognize table
* feat: add tablemaster with paddleocr to detect and recognize table
* feat: add tablemaster with paddleocr to detect and recognize table
* feat: add tablemaster with paddleocr to detect and recognize table
---------
Co-authored-by: Xiaomeng Zhao
Co-authored-by: sfk <18810651050@163.com>
Co-authored-by: drunkpig <60862764+drunkpig@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Aoyang Fang <222010547@link.cuhk.edu.cn>
Co-authored-by: liukaiwen
* feat: add tablemaster with paddleocr to detect and recognize table (#508)
* Update cla.yml
* Update bug_report.yml
* Update README_zh-CN.md (#404)
correct FAQ url
* Update README_zh-CN.md (#404) (#409) (#410)
correct FAQ url
Co-authored-by: sfk <18810651050@163.com>
* Update FAQ_zh_cn.md
add new issue
* Update FAQ_en_us.md
* Update README_Windows_CUDA_Acceleration_zh_CN.md
* Update README_zh-CN.md
* @Thepathakarpit has signed the CLA in opendatalab/MinerU#418
* Update cla.yml
* feat: add tablemaster_paddle (#463)
* Update README_zh-CN.md (#404) (#409)
correct FAQ url
Co-authored-by: sfk <18810651050@163.com>
* add dockerfile (#189)
Co-authored-by: drunkpig <60862764+drunkpig@users.noreply.github.com>
* Update cla.yml
* Update cla.yml
---------
Co-authored-by: drunkpig <60862764+drunkpig@users.noreply.github.com>
Co-authored-by: sfk <18810651050@163.com>
Co-authored-by: Aoyang Fang <222010547@link.cuhk.edu.cn>
Co-authored-by: Xiaomeng Zhao
* (para_split_v2): index out of range issue of span_text first char (#396)
Co-authored-by: liukaiwen
* @Matthijz98 has signed the CLA in opendatalab/MinerU#467
* Create download_models.py
* Create requirements-docker.txt
* feat: add tablemaster with paddleocr to detect and recognize table
* @strongerfly has signed the CLA in opendatalab/MinerU#487
* feat: add tablemaster with paddleocr to detect and recognize table
* feat: add tablemaster with paddleocr to detect and recognize table
* feat: add tablemaster with paddleocr to detect and recognize table
* feat: add tablemaster with paddleocr to detect and recognize table
* Update cla.yml
* Delete .github/workflows/gpu-ci.yml
* Update Huggingface and ModelScope links to organization account
* feat: add tablemaster with paddleocr to detect and recognize table
---------
Co-authored-by: Xiaomeng Zhao
Co-authored-by: sfk <18810651050@163.com>
Co-authored-by: drunkpig <60862764+drunkpig@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Aoyang Fang <222010547@link.cuhk.edu.cn>
Co-authored-by: liukaiwen
Co-authored-by: yyy <102640628+dt-yy@users.noreply.github.com>
Co-authored-by: wangbinDL
* feat: add tablemaster with paddleocr to detect and recognize table (#511)
* Update cla.yml
* Update bug_report.yml
* Update README_zh-CN.md (#404)
correct FAQ url
* Update README_zh-CN.md (#404) (#409) (#410)
correct FAQ url
Co-authored-by: sfk <18810651050@163.com>
* Update FAQ_zh_cn.md
add new issue
* Update FAQ_en_us.md
* Update README_Windows_CUDA_Acceleration_zh_CN.md
* Update README_zh-CN.md
* @Thepathakarpit has signed the CLA in opendatalab/MinerU#418
* Update cla.yml
* feat: add tablemaster_paddle (#463)
* Update README_zh-CN.md (#404) (#409)
correct FAQ url
Co-authored-by: sfk <18810651050@163.com>
* add dockerfile (#189)
Co-authored-by: drunkpig <60862764+drunkpig@users.noreply.github.com>
* Update cla.yml
* Update cla.yml
---------
Co-authored-by: drunkpig <60862764+drunkpig@users.noreply.github.com>
Co-authored-by: sfk <18810651050@163.com>
Co-authored-by: Aoyang Fang <222010547@link.cuhk.edu.cn>
Co-authored-by: Xiaomeng Zhao
* (para_split_v2): index out of range issue of span_text first char (#396)
Co-authored-by: liukaiwen
* @Matthijz98 has signed the CLA in opendatalab/MinerU#467
* Create download_models.py
* Create requirements-docker.txt
* feat: add tablemaster with paddleocr to detect and recognize table
* @strongerfly has signed the CLA in opendatalab/MinerU#487
* feat: add tablemaster with paddleocr to detect and recognize table
* feat: add tablemaster with paddleocr to detect and recognize table
* feat: add tablemaster with paddleocr to detect and recognize table
* feat: add tablemaster with paddleocr to detect and recognize table
* Update cla.yml
* Delete .github/workflows/gpu-ci.yml
* Update Huggingface and ModelScope links to organization account
* feat: add tablemaster with paddleocr to detect and recognize table
* feat: add tablemaster with paddleocr to detect and recognize table
* feat: add tablemaster with paddleocr to detect and recognize table
---------
Co-authored-by: Xiaomeng Zhao
Co-authored-by: sfk <18810651050@163.com>
Co-authored-by: drunkpig <60862764+drunkpig@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Aoyang Fang <222010547@link.cuhk.edu.cn>
Co-authored-by: liukaiwen
Co-authored-by: yyy <102640628+dt-yy@users.noreply.github.com>
Co-authored-by: wangbinDL
---------
Co-authored-by: drunkpig <60862764+drunkpig@users.noreply.github.com>
Co-authored-by: sfk <18810651050@163.com>
Co-authored-by: Aoyang Fang <222010547@link.cuhk.edu.cn>
Co-authored-by: Xiaomeng Zhao
Co-authored-by: Kaiwen Liu
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: liukaiwen
Co-authored-by: wangbinDL
---
README.md | 10 +--
README_ja-JP.md | 4 +-
README_zh-CN.md | 12 +---
docs/README_Ubuntu_CUDA_Acceleration_en_US.md | 2 +-
docs/README_Ubuntu_CUDA_Acceleration_zh_CN.md | 2 +-
.../README_Windows_CUDA_Acceleration_en_US.md | 2 +-
.../README_Windows_CUDA_Acceleration_zh_CN.md | 2 +-
docs/how_to_download_models_en.md | 15 ++++
docs/how_to_download_models_zh_cn.md | 15 ++++
magic-pdf.template.json | 1 +
magic_pdf/dict2md/ocr_mkcontent.py | 4 ++
magic_pdf/libs/Constants.py | 28 +++++++-
magic_pdf/libs/version.py | 2 +-
magic_pdf/model/magic_model.py | 3 +
magic_pdf/model/pdf_extract_kit.py | 47 ++++++++----
.../structeqtable/StructTableModel.py | 1 -
magic_pdf/model/ppTableModel.py | 67 ++++++++++++++++++
.../resources/model_config/model_configs.yaml | 4 +-
tests/test_table/assets/table.jpg | Bin 0 -> 59389 bytes
tests/test_table/test_tablemaster.py | 18 +++++
20 files changed, 201 insertions(+), 38 deletions(-)
create mode 100644 magic_pdf/model/ppTableModel.py
create mode 100644 tests/test_table/assets/table.jpg
create mode 100644 tests/test_table/test_tablemaster.py
diff --git a/README.md b/README.md
index a67849f8..bc5172c0 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,7 @@
# Changelog
+- 2024/08/30: Version 0.7.1 released, add paddle tablemaster table recognition option
- 2024/08/09: Version 0.7.0b1 released, simplified installation process, added table recognition functionality
- 2024/08/01: Version 0.6.2b1 released, optimized dependency conflict issues and installation documentation
- 2024/07/05: Initial open-source release
@@ -171,7 +172,7 @@ In non-mainline environments, due to the diversity of hardware and software conf
```bash
conda create -n MinerU python=3.10
conda activate MinerU
-pip install magic-pdf[full]==0.7.0b1 --extra-index-url https://wheels.myhloli.com
+pip install -U magic-pdf[full] --extra-index-url https://wheels.myhloli.com
```
#### 2. Download model weight files
@@ -200,6 +201,7 @@ Find the `magic-pdf.json` file in your user directory and configure the "models-
// other config
"models-dir": "D:/models",
"table-config": {
+ "model": "TableMaster", // Another option of this value is 'struct_eqtable'
"is_table_recog_enable": false, // Table recognition is disabled by default, modify this value to enable it
"max_time": 400
}
@@ -311,13 +313,7 @@ TODO
- Comic books, art books, elementary school textbooks, and exercise books are not well-parsed yet
- Enabling OCR may produce better results in PDFs with a high density of formulas
- If you are processing PDFs with a large number of formulas, it is strongly recommended to enable the OCR function. When using PyMuPDF to extract text, overlapping text lines can occur, leading to inaccurate formula insertion positions.
-- **Table Recognition** is currently in the testing phase; recognition speed is slow, and accuracy needs improvement. Below are some performance test results in an Ubuntu 22.04 LTS + Intel(R) Xeon(R) Platinum 8352V CPU @ 2.10GHz + NVIDIA GeForce RTX 4090 environment for reference.
-| Table Size | Parsing Time |
-|---------------|----------------------------|
-| 6\*5 55kb | 37s |
-| 16\*12 284kb | 3m18s |
-| 44\*7 559kb | 4m12s |
# FAQ
[FAQ in Chinese](docs/FAQ_zh_cn.md)
diff --git a/README_ja-JP.md b/README_ja-JP.md
index f1d65107..1293f6c9 100644
--- a/README_ja-JP.md
+++ b/README_ja-JP.md
@@ -116,13 +116,13 @@ pip install detectron2 --extra-index-url https://wheels.myhloli.com
>CUDA/MPSによる加速については、[CUDAまたはMPSによる加速](#4-CUDAまたはMPSによる加速)を参照してください。
```bash
-pip install magic-pdf[full]==0.6.2b1
+pip install -U magic-pdf[full]
```
> ❗️❗️❗️
> 私たちは0.6.2 ベータ版を事前にリリースし、私たちのログに記載されている多くの問題に対処しました。しかし、このビルドはまだ完全なQAテストを経ておらず、最終的なリリース品質を表していません。問題に遭遇した場合は、問題を通じて速やかに報告するか、0.6.1バージョンに戻ることをお願いします。
> ```bash
-> pip install magic-pdf[full-cpu]==0.6.1
+> pip install -U magic-pdf[full]
> ```
diff --git a/README_zh-CN.md b/README_zh-CN.md
index e064a873..69c28108 100644
--- a/README_zh-CN.md
+++ b/README_zh-CN.md
@@ -33,6 +33,7 @@
# 更新记录
+- 2024/08/30 0.7.1发布,集成了paddle tablemaster表格识别功能
- 2024/08/09 0.7.0b1发布,简化安装步骤提升易用性,加入表格识别功能
- 2024/08/01 0.6.2b1发布,优化了依赖冲突问题和安装文档
- 2024/07/05 首次开源
@@ -179,7 +180,7 @@ https://github.com/user-attachments/assets/4bea02c9-6d54-4cd6-97ed-dff14340982c
```bash
conda create -n MinerU python=3.10
conda activate MinerU
-pip install magic-pdf[full]==0.7.0b1 --extra-index-url https://wheels.myhloli.com -i https://pypi.tuna.tsinghua.edu.cn/simple
+pip install -U magic-pdf[full] --extra-index-url https://wheels.myhloli.com -i https://pypi.tuna.tsinghua.edu.cn/simple
```
#### 2. 下载模型权重文件
@@ -208,6 +209,7 @@ cp magic-pdf.template.json ~/magic-pdf.json
// other config
"models-dir": "D:/models",
"table-config": {
+ "model": "TableMaster", // 使用structEqTable请修改为'struct_eqtable'
"is_table_recog_enable": false, // 表格识别功能默认是关闭的,如果需要修改此处的值
"max_time": 400
}
@@ -321,14 +323,6 @@ TODO
- 漫画书、艺术图册、小学教材、习题尚不能很好解析
- 在一些公式密集的PDF上强制启用OCR效果会更好
- 如果您要处理包含大量公式的pdf,强烈建议开启OCR功能。使用pymuPDF提取文字的时候会出现文本行互相重叠的情况导致公式插入位置不准确。
-- **表格识别**目前处于测试阶段,识别速度较慢,识别准确度有待提升。以下是我们在Ubuntu 22.04 LTS + Intel(R) Xeon(R) Platinum 8352V CPU @ 2.10GHz + NVIDIA GeForce RTX 4090环境下的一些性能测试结果,可供参考。
-
-| 表格大小 | 解析耗时 |
-|---------------|----------------------------|
-| 6\*5 55kb | 37s |
-| 16\*12 284kb | 3m18s |
-| 44\*7 559kb | 4m12s |
-
# FAQ
diff --git a/docs/README_Ubuntu_CUDA_Acceleration_en_US.md b/docs/README_Ubuntu_CUDA_Acceleration_en_US.md
index 7186092c..8244fcc3 100644
--- a/docs/README_Ubuntu_CUDA_Acceleration_en_US.md
+++ b/docs/README_Ubuntu_CUDA_Acceleration_en_US.md
@@ -48,7 +48,7 @@
### 5. Install Applications
```sh
- pip install magic-pdf[full]==0.7.0b1 --extra-index-url https://wheels.myhloli.com
+ pip install -U magic-pdf[full] --extra-index-url https://wheels.myhloli.com
```
❗ After installation, make sure to check the version of `magic-pdf` using the following command:
```sh
diff --git a/docs/README_Ubuntu_CUDA_Acceleration_zh_CN.md b/docs/README_Ubuntu_CUDA_Acceleration_zh_CN.md
index f8946ae2..4d9f6090 100644
--- a/docs/README_Ubuntu_CUDA_Acceleration_zh_CN.md
+++ b/docs/README_Ubuntu_CUDA_Acceleration_zh_CN.md
@@ -43,7 +43,7 @@ conda activate MinerU
```
## 5. 安装应用
```bash
-pip install magic-pdf[full]==0.7.0b1 --extra-index-url https://wheels.myhloli.com -i https://pypi.tuna.tsinghua.edu.cn/simple
+pip install -U magic-pdf[full] --extra-index-url https://wheels.myhloli.com -i https://pypi.tuna.tsinghua.edu.cn/simple
```
> ❗️下载完成后,务必通过以下命令确认magic-pdf的版本是否正确
>
diff --git a/docs/README_Windows_CUDA_Acceleration_en_US.md b/docs/README_Windows_CUDA_Acceleration_en_US.md
index 1e762fb6..9e5fb764 100644
--- a/docs/README_Windows_CUDA_Acceleration_en_US.md
+++ b/docs/README_Windows_CUDA_Acceleration_en_US.md
@@ -19,7 +19,7 @@ Download link: https://repo.anaconda.com/archive/Anaconda3-2024.06-1-Windows-x86
### 4. Install Applications
```
- pip install magic-pdf[full]==0.7.0b1 --extra-index-url https://wheels.myhloli.com
+ pip install -U magic-pdf[full] --extra-index-url https://wheels.myhloli.com
```
>❗️After installation, verify the version of `magic-pdf`:
> ```bash
diff --git a/docs/README_Windows_CUDA_Acceleration_zh_CN.md b/docs/README_Windows_CUDA_Acceleration_zh_CN.md
index fbddc4f0..15ca9d18 100644
--- a/docs/README_Windows_CUDA_Acceleration_zh_CN.md
+++ b/docs/README_Windows_CUDA_Acceleration_zh_CN.md
@@ -20,7 +20,7 @@ conda activate MinerU
```
## 4. 安装应用
```bash
-pip install magic-pdf[full]==0.7.0b1 --extra-index-url https://wheels.myhloli.com -i https://pypi.tuna.tsinghua.edu.cn/simple
+pip install -U magic-pdf[full] --extra-index-url https://wheels.myhloli.com -i https://pypi.tuna.tsinghua.edu.cn/simple
```
> ❗️下载完成后,务必通过以下命令确认magic-pdf的版本是否正确
>
diff --git a/docs/how_to_download_models_en.md b/docs/how_to_download_models_en.md
index aade8eac..14f054a0 100644
--- a/docs/how_to_download_models_en.md
+++ b/docs/how_to_download_models_en.md
@@ -44,6 +44,21 @@ The structure of the model folder is as follows, including configuration files a
│ ├── spiece.model
│ ├── tokenizer.json
│ └── tokenizer_config.json
+│ └─ TableMaster
+│ └─ ch_PP-OCRv3_det_infer
+│ ├── inference.pdiparams
+│ ├── inference.pdiparams.info
+│ └── inference.pdmodel
+│ └─ ch_PP-OCRv3_rec_infer
+│ ├── inference.pdiparams
+│ ├── inference.pdiparams.info
+│ └── inference.pdmodel
+│ └─ table_structure_tablemaster_infer
+│ ├── inference.pdiparams
+│ ├── inference.pdiparams.info
+│ └── inference.pdmodel
+│ ├── ppocr_keys_v1.txt
+│ └── table_master_structure_dict.txt
└── README.md
```
#### 2. Check whether the model file is fully downloaded.
diff --git a/docs/how_to_download_models_zh_cn.md b/docs/how_to_download_models_zh_cn.md
index 96889fbc..cbc0e3f8 100644
--- a/docs/how_to_download_models_zh_cn.md
+++ b/docs/how_to_download_models_zh_cn.md
@@ -74,6 +74,21 @@ print(f"模型文件下载路径为:{model_dir}/models")
│ ├── spiece.model
│ ├── tokenizer.json
│ └── tokenizer_config.json
+│ └─ TableMaster
+│ └─ ch_PP-OCRv3_det_infer
+│ ├── inference.pdiparams
+│ ├── inference.pdiparams.info
+│ └── inference.pdmodel
+│ └─ ch_PP-OCRv3_rec_infer
+│ ├── inference.pdiparams
+│ ├── inference.pdiparams.info
+│ └── inference.pdmodel
+│ └─ table_structure_tablemaster_infer
+│ ├── inference.pdiparams
+│ ├── inference.pdiparams.info
+│ └── inference.pdmodel
+│ ├── ppocr_keys_v1.txt
+│ └── table_master_structure_dict.txt
└── README.md
```
diff --git a/magic-pdf.template.json b/magic-pdf.template.json
index f6adfbfa..1eb61101 100644
--- a/magic-pdf.template.json
+++ b/magic-pdf.template.json
@@ -6,6 +6,7 @@
"models-dir":"/tmp/models",
"device-mode":"cpu",
"table-config": {
+ "model": "TableMaster",
"is_table_recog_enable": false,
"max_time": 400
}
diff --git a/magic_pdf/dict2md/ocr_mkcontent.py b/magic_pdf/dict2md/ocr_mkcontent.py
index 0cc887ce..ec5ded1c 100644
--- a/magic_pdf/dict2md/ocr_mkcontent.py
+++ b/magic_pdf/dict2md/ocr_mkcontent.py
@@ -132,6 +132,8 @@ def ocr_mk_markdown_with_para_core_v2(paras_of_layout, mode, img_buket_path=""):
# if processed by table model
if span.get('latex', ''):
para_text += f"\n\n$\n {span['latex']}\n$\n\n"
+ elif span.get('html', ''):
+ para_text += f"\n\n{span['html']}\n\n"
else:
para_text += f"\n![{table_caption}]({join_path(img_buket_path, span['image_path'])}) \n"
for block in para_block['blocks']: # 3rd.拼table_footnote
@@ -256,6 +258,8 @@ def para_to_standard_format_v2(para_block, img_buket_path, page_idx):
if block['type'] == BlockType.TableBody:
if block["lines"][0]["spans"][0].get('latex', ''):
para_content['table_body'] = f"\n\n$\n {block['lines'][0]['spans'][0]['latex']}\n$\n\n"
+ elif block["lines"][0]["spans"][0].get('html', ''):
+ para_content['table_body'] = f"\n\n{block['lines'][0]['spans'][0]['html']}\n\n"
para_content['img_path'] = join_path(img_buket_path, block["lines"][0]["spans"][0]['image_path'])
if block['type'] == BlockType.TableCaption:
para_content['table_caption'] = merge_para_with_text(block)
diff --git a/magic_pdf/libs/Constants.py b/magic_pdf/libs/Constants.py
index d2ad2090..4e132290 100644
--- a/magic_pdf/libs/Constants.py
+++ b/magic_pdf/libs/Constants.py
@@ -10,5 +10,31 @@
# block中lines是否被删除
LINES_DELETED = "lines_deleted"
+# struct eqtable
+STRUCT_EQTABLE = "struct_eqtable"
+
# table recognition max time default value
-TABLE_MAX_TIME_VALUE = 400
\ No newline at end of file
+TABLE_MAX_TIME_VALUE = 400
+
+# pp_table_result_max_length
+TABLE_MAX_LEN = 480
+
+# pp table structure algorithm
+TABLE_MASTER = "TableMaster"
+
+# table master structure dict
+TABLE_MASTER_DICT = "table_master_structure_dict.txt"
+
+# table master dir
+TABLE_MASTER_DIR = "table_structure_tablemaster_infer/"
+
+# pp detect model dir
+DETECT_MODEL_DIR = "ch_PP-OCRv3_det_infer"
+
+# pp rec model dir
+REC_MODEL_DIR = "ch_PP-OCRv3_rec_infer"
+
+# pp rec char dict path
+REC_CHAR_DICT = "ppocr_keys_v1.txt"
+
+
diff --git a/magic_pdf/libs/version.py b/magic_pdf/libs/version.py
index f1f62cb0..a5f830a2 100644
--- a/magic_pdf/libs/version.py
+++ b/magic_pdf/libs/version.py
@@ -1 +1 @@
-__version__ = "0.7.0b1"
+__version__ = "0.7.1"
diff --git a/magic_pdf/model/magic_model.py b/magic_pdf/model/magic_model.py
index d6164bae..ce070321 100644
--- a/magic_pdf/model/magic_model.py
+++ b/magic_pdf/model/magic_model.py
@@ -562,8 +562,11 @@ def remove_duplicate_spans(spans):
elif category_id == 5:
# 获取table模型结果
latex = layout_det.get("latex", None)
+ html = layout_det.get("html", None)
if latex:
span["latex"] = latex
+ elif html:
+ span["html"] = html
span["type"] = ContentType.Table
elif category_id == 13:
span["content"] = layout_det["latex"]
diff --git a/magic_pdf/model/pdf_extract_kit.py b/magic_pdf/model/pdf_extract_kit.py
index fcf26797..f36d3545 100644
--- a/magic_pdf/model/pdf_extract_kit.py
+++ b/magic_pdf/model/pdf_extract_kit.py
@@ -2,7 +2,7 @@
import os
import time
-from magic_pdf.libs.Constants import TABLE_MAX_TIME_VALUE
+from magic_pdf.libs.Constants import *
os.environ['NO_ALBUMENTATIONS_UPDATE'] = '1' # 禁止albumentations检查更新
try:
@@ -34,10 +34,18 @@
from magic_pdf.model.pek_sub_modules.post_process import get_croped_image, latex_rm_whitespace
from magic_pdf.model.pek_sub_modules.self_modify import ModifiedPaddleOCR
from magic_pdf.model.pek_sub_modules.structeqtable.StructTableModel import StructTableModel
-
-
-def table_model_init(model_path, max_time, _device_='cpu'):
- table_model = StructTableModel(model_path, max_time=max_time, device=_device_)
+from magic_pdf.model.ppTableModel import ppTableModel
+
+
+def table_model_init(table_model_type, model_path, max_time, _device_='cpu'):
+ if table_model_type == STRUCT_EQTABLE:
+ table_model = StructTableModel(model_path, max_time=max_time, device=_device_)
+ else:
+ config = {
+ "model_dir": model_path,
+ "device": _device_
+ }
+ table_model = ppTableModel(config)
return table_model
@@ -104,9 +112,11 @@ def __init__(self, ocr: bool = False, show_log: bool = False, **kwargs):
# 初始化解析配置
self.apply_layout = kwargs.get("apply_layout", self.configs["config"]["layout"])
self.apply_formula = kwargs.get("apply_formula", self.configs["config"]["formula"])
+ # table config
self.table_config = kwargs.get("table_config", self.configs["config"]["table_config"])
self.apply_table = self.table_config.get("is_table_recog_enable", False)
self.table_max_time = self.table_config.get("max_time", TABLE_MAX_TIME_VALUE)
+ self.table_model_type = self.table_config.get("model", TABLE_MASTER)
self.apply_ocr = ocr
logger.info(
"DocAnalysis init, this may take some times. apply_layout: {}, apply_formula: {}, apply_ocr: {}, apply_table: {}".format(
@@ -141,10 +151,11 @@ def __init__(self, ocr: bool = False, show_log: bool = False, **kwargs):
if self.apply_ocr:
self.ocr_model = ModifiedPaddleOCR(show_log=show_log)
- # init structeqtable
+ # init table model
if self.apply_table:
- self.table_model = table_model_init(str(os.path.join(models_dir, self.configs["weights"]["table"])),
- max_time = self.table_max_time, _device_=self.device)
+ table_model_dir = self.configs["weights"][self.table_model_type]
+ self.table_model = table_model_init(self.table_model_type, str(os.path.join(models_dir, table_model_dir)),
+ max_time=self.table_max_time, _device_=self.device)
logger.info('DocAnalysis init done!')
def __call__(self, image):
@@ -278,16 +289,28 @@ def crop_img(input_res, input_pil_img, crop_paste_x=0, crop_paste_y=0):
new_image, _ = crop_img(res, pil_img)
single_table_start_time = time.time()
logger.info("------------------table recognition processing begins-----------------")
+ latex_code = None
+ html_code = None
with torch.no_grad():
- latex_code = self.table_model.image2latex(new_image)[0]
+ if self.table_model_type == STRUCT_EQTABLE:
+ latex_code = self.table_model.image2latex(new_image)[0]
+ else:
+ html_code = self.table_model.img2html(new_image)
run_time = time.time() - single_table_start_time
logger.info(f"------------table recognition processing ends within {run_time}s-----")
if run_time > self.table_max_time:
logger.warning(f"------------table recognition processing exceeds max time {self.table_max_time}s----------")
# 判断是否返回正常
- expected_ending = latex_code.strip().endswith('end{tabular}') or latex_code.strip().endswith('end{table}')
- if latex_code and expected_ending:
- res["latex"] = latex_code
+
+ if latex_code:
+ expected_ending = latex_code.strip().endswith('end{tabular}') or latex_code.strip().endswith(
+ 'end{table}')
+ if expected_ending:
+ res["latex"] = latex_code
+ else:
+ logger.warning(f"------------table recognition processing fails----------")
+ elif html_code:
+ res["html"] = html_code
else:
logger.warning(f"------------table recognition processing fails----------")
table_cost = round(time.time() - table_start, 2)
diff --git a/magic_pdf/model/pek_sub_modules/structeqtable/StructTableModel.py b/magic_pdf/model/pek_sub_modules/structeqtable/StructTableModel.py
index cfd9fa2d..2d1ce584 100644
--- a/magic_pdf/model/pek_sub_modules/structeqtable/StructTableModel.py
+++ b/magic_pdf/model/pek_sub_modules/structeqtable/StructTableModel.py
@@ -12,7 +12,6 @@ def __init__(self, model_path, max_new_tokens=2048, max_time=400, device = 'cpu'
self.model = StructTable(self.model_path, self.max_new_tokens, self.max_time)
def image2latex(self, image) -> str:
- #
table_latex = self.model.forward(image)
return table_latex
diff --git a/magic_pdf/model/ppTableModel.py b/magic_pdf/model/ppTableModel.py
new file mode 100644
index 00000000..310bcc79
--- /dev/null
+++ b/magic_pdf/model/ppTableModel.py
@@ -0,0 +1,67 @@
+from paddleocr.ppstructure.table.predict_table import TableSystem
+from paddleocr.ppstructure.utility import init_args
+from magic_pdf.libs.Constants import *
+import os
+from PIL import Image
+import numpy as np
+
+
+class ppTableModel(object):
+ """
+ This class is responsible for converting image of table into HTML format using a pre-trained model.
+
+ Attributes:
+ - table_sys: An instance of TableSystem initialized with parsed arguments.
+
+ Methods:
+ - __init__(config): Initializes the model with configuration parameters.
+ - img2html(image): Converts a PIL Image or NumPy array to HTML string.
+ - parse_args(**kwargs): Parses configuration arguments.
+ """
+
+ def __init__(self, config):
+ """
+ Parameters:
+ - config (dict): Configuration dictionary containing model_dir and device.
+ """
+ args = self.parse_args(**config)
+ self.table_sys = TableSystem(args)
+
+ def img2html(self, image):
+ """
+ Parameters:
+ - image (PIL.Image or np.ndarray): The image of the table to be converted.
+
+ Return:
+ - HTML (str): A string representing the HTML structure with content of the table.
+ """
+ if isinstance(image, Image.Image):
+ image = np.array(image)
+ pred_res, _ = self.table_sys(image)
+ pred_html = pred_res["html"]
+ res = '' + pred_html.replace("",
+ "") + " | \n"
+ return res
+
+ def parse_args(self, **kwargs):
+ parser = init_args()
+ model_dir = kwargs.get("model_dir")
+ table_model_dir = os.path.join(model_dir, TABLE_MASTER_DIR)
+ table_char_dict_path = os.path.join(model_dir, TABLE_MASTER_DICT)
+ det_model_dir = os.path.join(model_dir, DETECT_MODEL_DIR)
+ rec_model_dir = os.path.join(model_dir, REC_MODEL_DIR)
+ rec_char_dict_path = os.path.join(model_dir, REC_CHAR_DICT)
+ device = kwargs.get("device", "cpu")
+ use_gpu = True if device == "cuda" else False
+ config = {
+ "use_gpu": use_gpu,
+ "table_max_len": kwargs.get("table_max_len", TABLE_MAX_LEN),
+ "table_algorithm": TABLE_MASTER,
+ "table_model_dir": table_model_dir,
+ "table_char_dict_path": table_char_dict_path,
+ "det_model_dir": det_model_dir,
+ "rec_model_dir": rec_model_dir,
+ "rec_char_dict_path": rec_char_dict_path,
+ }
+ parser.set_defaults(**config)
+ return parser.parse_args([])
diff --git a/magic_pdf/resources/model_config/model_configs.yaml b/magic_pdf/resources/model_config/model_configs.yaml
index 1b5c3aae..2438a0bb 100644
--- a/magic_pdf/resources/model_config/model_configs.yaml
+++ b/magic_pdf/resources/model_config/model_configs.yaml
@@ -3,6 +3,7 @@ config:
layout: True
formula: True
table_config:
+ model: TableMaster
is_table_recog_enable: False
max_time: 400
@@ -10,4 +11,5 @@ weights:
layout: Layout/model_final.pth
mfd: MFD/weights.pt
mfr: MFR/UniMERNet
- table: TabRec/StructEqTable
\ No newline at end of file
+ struct_eqtable: TabRec/StructEqTable
+ TableMaster: TabRec/TableMaster
\ No newline at end of file
diff --git a/tests/test_table/assets/table.jpg b/tests/test_table/assets/table.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..95fdf84d92908d4b21f49fb516601334867163b1
GIT binary patch
literal 59389
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