doc-page-extractor 0.2.0__tar.gz → 0.2.2__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.
Files changed (51) hide show
  1. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/PKG-INFO +2 -2
  2. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/__init__.py +1 -1
  3. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/extractor.py +30 -27
  4. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/latex.py +10 -8
  5. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/layout_order.py +12 -10
  6. doc_page_extractor-0.2.2/doc_page_extractor/model.py +114 -0
  7. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/ocr.py +13 -20
  8. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/table.py +14 -24
  9. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/types.py +4 -27
  10. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor.egg-info/PKG-INFO +2 -2
  11. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor.egg-info/SOURCES.txt +1 -1
  12. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor.egg-info/requires.txt +1 -1
  13. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/setup.py +2 -2
  14. doc_page_extractor-0.2.0/doc_page_extractor/models.py +0 -92
  15. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/LICENSE +0 -0
  16. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/README.md +0 -0
  17. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/clipper.py +0 -0
  18. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/downloader.py +0 -0
  19. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/layoutreader.py +0 -0
  20. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/ocr_corrector.py +0 -0
  21. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/onnxocr/__init__.py +0 -0
  22. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/onnxocr/cls_postprocess.py +0 -0
  23. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/onnxocr/db_postprocess.py +0 -0
  24. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/onnxocr/imaug.py +0 -0
  25. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/onnxocr/operators.py +0 -0
  26. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/onnxocr/predict_base.py +0 -0
  27. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/onnxocr/predict_cls.py +0 -0
  28. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/onnxocr/predict_det.py +0 -0
  29. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/onnxocr/predict_rec.py +0 -0
  30. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/onnxocr/predict_system.py +0 -0
  31. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/onnxocr/rec_postprocess.py +0 -0
  32. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/onnxocr/utils.py +0 -0
  33. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/overlap.py +0 -0
  34. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/plot.py +0 -0
  35. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/raw_optimizer.py +0 -0
  36. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/rectangle.py +0 -0
  37. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/rotation.py +0 -0
  38. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/struct_eqtable/__init__.py +0 -0
  39. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/struct_eqtable/internvl/__init__.py +0 -0
  40. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/struct_eqtable/internvl/conversation.py +0 -0
  41. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/struct_eqtable/internvl/internvl.py +0 -0
  42. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/struct_eqtable/internvl/internvl_lmdeploy.py +0 -0
  43. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/struct_eqtable/pix2s/__init__.py +0 -0
  44. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/struct_eqtable/pix2s/pix2s.py +0 -0
  45. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/struct_eqtable/pix2s/pix2s_trt.py +0 -0
  46. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor/utils.py +0 -0
  47. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor.egg-info/dependency_links.txt +0 -0
  48. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/doc_page_extractor.egg-info/top_level.txt +0 -0
  49. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/setup.cfg +0 -0
  50. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/tests/__init__.py +0 -0
  51. {doc_page_extractor-0.2.0 → doc_page_extractor-0.2.2}/tests/test_history_bus.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: doc-page-extractor
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: doc page extractor can identify text and format in images and return structured data.
5
5
  Home-page: https://github.com/Moskize91/doc-page-extractor
6
6
  Author: Tao Zeyu
@@ -16,7 +16,7 @@ Requires-Dist: transformers<=4.47,>=4.42.4
16
16
  Requires-Dist: doclayout_yolo>=0.0.3
17
17
  Requires-Dist: pix2tex<=0.2.0,>=0.1.4
18
18
  Requires-Dist: accelerate<2.0,>=1.6.0
19
- Requires-Dist: huggingface_hub>=0.30.2
19
+ Requires-Dist: huggingface_hub<1.0,>=0.30.2
20
20
  Dynamic: author
21
21
  Dynamic: author-email
22
22
  Dynamic: description
@@ -2,6 +2,7 @@ from .extractor import DocExtractor
2
2
  from .clipper import clip, clip_from_image
3
3
  from .plot import plot
4
4
  from .rectangle import Point, Rectangle
5
+ from .model import Model, HuggingfaceModel
5
6
  from .types import (
6
7
  ExtractedResult,
7
8
  OCRFragment,
@@ -12,5 +13,4 @@ from .types import (
12
13
  PlainLayout,
13
14
  FormulaLayout,
14
15
  TableLayout,
15
- ModelsDownloader
16
16
  )
@@ -1,10 +1,11 @@
1
+ import torch
1
2
 
3
+ from os import PathLike
2
4
  from typing import Literal, Generator
3
5
  from PIL.Image import Image
4
6
  from doclayout_yolo import YOLOv10
5
- from logging import Logger, getLogger
6
7
 
7
- from .models import HuggingfaceModelsDownloader
8
+ from .model import Model, HuggingfaceModel
8
9
  from .ocr import OCR
9
10
  from .ocr_corrector import correct_fragments
10
11
  from .raw_optimizer import RawOptimizer
@@ -16,7 +17,6 @@ from .overlap import merge_fragments_as_line, remove_overlap_layouts
16
17
  from .clipper import clip_from_image
17
18
  from .types import (
18
19
  ExtractedResult,
19
- ModelsDownloader,
20
20
  OCRFragment,
21
21
  Layout,
22
22
  LayoutClass,
@@ -29,32 +29,35 @@ from .types import (
29
29
 
30
30
  class DocExtractor:
31
31
  def __init__(
32
- self,
33
- model_cache_dir: str | None = None,
34
- device: Literal["cpu", "cuda"] = "cpu",
35
- models_downloader: ModelsDownloader | None = None,
36
- logger: Logger | None = None,
37
- ):
38
- self._logger = logger or getLogger(__name__)
39
- self._models_downloader = models_downloader or HuggingfaceModelsDownloader(self._logger, model_cache_dir)
32
+ self,
33
+ model_cache_dir: PathLike | None = None,
34
+ device: Literal["cpu", "cuda"] = "cpu",
35
+ model: Model | None = None,
36
+ ) -> None:
37
+
38
+ if model is None:
39
+ if model_cache_dir is None:
40
+ raise ValueError("You must provide a model_cache_dir or a model instance.")
41
+ model = HuggingfaceModel(model_cache_dir)
42
+
43
+ if device == "cuda" and not torch.cuda.is_available():
44
+ device = "cpu"
45
+ print("CUDA is not available. Using CPU instead.")
40
46
 
41
47
  self._device: Literal["cpu", "cuda"] = device
48
+ self._model: Model = model
42
49
  self._yolo: YOLOv10 | None = None
43
- self._ocr: OCR = OCR(
44
- device=device,
45
- get_model_dir=self._models_downloader.onnx_ocr,
46
- )
47
- self._table: Table = Table(
48
- device=device,
49
- get_model_dir=self._models_downloader.struct_eqtable,
50
- )
51
- self._latex: LaTeX = LaTeX(
52
- get_model_dir=self._models_downloader.latex,
53
- device=device,
54
- )
55
- self._layout_order: LayoutOrder = LayoutOrder(
56
- get_model_dir=self._models_downloader.layoutreader,
57
- )
50
+ self._ocr: OCR = OCR(device, model)
51
+ self._table: Table = Table(device, model)
52
+ self._latex: LaTeX = LaTeX(device, model)
53
+ self._layout_order: LayoutOrder = LayoutOrder(device, model)
54
+
55
+ def prepare_models(self):
56
+ self._model.get_onnx_ocr_path()
57
+ self._model.get_yolo_path()
58
+ self._model.get_layoutreader_path()
59
+ self._model.get_struct_eqtable_path()
60
+ self._model.get_latex_path()
58
61
 
59
62
  def extract(
60
63
  self,
@@ -199,7 +202,7 @@ class DocExtractor:
199
202
 
200
203
  def _get_yolo(self) -> YOLOv10:
201
204
  if self._yolo is None:
202
- model_path = self._models_downloader.yolo()
205
+ model_path = self._model.get_yolo_path()
203
206
  self._yolo = YOLOv10(str(model_path))
204
207
  return self._yolo
205
208
 
@@ -6,12 +6,13 @@ from pix2tex.cli import LatexOCR
6
6
  from PIL.Image import Image
7
7
  from typing import Literal
8
8
  from .utils import expand_image
9
- from .types import GetModelDir
9
+ from .model import Model
10
+
10
11
 
11
12
  class LaTeX:
12
- def __init__(self, device: Literal["cpu", "cuda"],get_model_dir: GetModelDir):
13
- self._model_path: str = get_model_dir()
14
- self._model: LatexOCR | None = None
13
+ def __init__(self, device: Literal["cpu", "cuda"], model: Model) -> None:
14
+ self._model: Model = model
15
+ self._latex_model: LatexOCR | None = None
15
16
  self._device: Literal["cpu", "cuda"] = device
16
17
 
17
18
  def extract(self, image: Image) -> str | None:
@@ -21,11 +22,12 @@ class LaTeX:
21
22
  return model(image)
22
23
 
23
24
  def _get_model(self) -> LatexOCR:
24
- if self._model is None:
25
- self._model = LatexOCR(Munch({
25
+ if self._latex_model is None:
26
+ model_path = self._model.get_latex_path()
27
+ self._latex_model = LatexOCR(Munch({
26
28
  "config": os.path.join("settings", "config.yaml"),
27
- "checkpoint": os.path.join(self._model_path, "checkpoints", "weights.pth"),
29
+ "checkpoint": os.path.join(model_path, "checkpoints", "weights.pth"),
28
30
  "no_cuda": self._device == "cpu",
29
31
  "no_resize": False,
30
32
  }))
31
- return self._model
33
+ return self._latex_model
@@ -1,10 +1,11 @@
1
1
  import torch
2
2
 
3
- from typing import Generator
3
+ from typing import Generator, Literal
4
4
  from dataclasses import dataclass
5
5
  from transformers import LayoutLMv3ForTokenClassification
6
6
 
7
- from .types import Layout, LayoutClass, GetModelDir
7
+ from .types import Layout, LayoutClass
8
+ from .model import Model
8
9
  from .layoutreader import prepare_inputs, boxes2inputs, parse_logits
9
10
 
10
11
 
@@ -17,18 +18,19 @@ class _BBox:
17
18
  value: tuple[float, float, float, float]
18
19
 
19
20
  class LayoutOrder:
20
- def __init__(self, get_model_dir: GetModelDir):
21
- self._model_path: str = get_model_dir()
22
- self._model: LayoutLMv3ForTokenClassification | None = None
23
- self._device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
21
+ def __init__(self, device: Literal["cpu", "cuda"], model: Model):
22
+ self._model: Model = model
23
+ self._order_model: LayoutLMv3ForTokenClassification | None = None
24
+ self._device: Literal["cpu", "cuda"] = device
24
25
 
25
26
  def _get_model(self) -> LayoutLMv3ForTokenClassification:
26
- if self._model is None:
27
- self._model = LayoutLMv3ForTokenClassification.from_pretrained(
28
- pretrained_model_name_or_path=self._model_path,
27
+ if self._order_model is None:
28
+ model_path = self._model.get_layoutreader_path()
29
+ self._order_model = LayoutLMv3ForTokenClassification.from_pretrained(
30
+ pretrained_model_name_or_path=model_path,
29
31
  local_files_only=True,
30
32
  ).to(device=self._device)
31
- return self._model
33
+ return self._order_model
32
34
 
33
35
  def sort(self, layouts: list[Layout], size: tuple[int, int]) -> list[Layout]:
34
36
  width, height = size
@@ -0,0 +1,114 @@
1
+ from os import PathLike
2
+ from typing import runtime_checkable, Protocol
3
+ from pathlib import Path
4
+ from threading import Lock
5
+ from huggingface_hub import hf_hub_download, snapshot_download, try_to_load_from_cache
6
+
7
+
8
+ @runtime_checkable
9
+ class Model(Protocol):
10
+ def get_onnx_ocr_path(self) -> Path:
11
+ pass
12
+
13
+ def get_yolo_path(self) -> Path:
14
+ pass
15
+
16
+ def get_layoutreader_path(self) -> Path:
17
+ pass
18
+
19
+ def get_struct_eqtable_path(self) -> Path:
20
+ pass
21
+
22
+ def get_latex_path(self) -> Path:
23
+ pass
24
+
25
+ class HuggingfaceModel(Model):
26
+ def __init__(self, model_cache_dir: PathLike):
27
+ super().__init__()
28
+ self._lock: Lock = Lock()
29
+ self._model_cache_dir: Path = Path(model_cache_dir)
30
+
31
+ def get_onnx_ocr_path(self) -> Path:
32
+ return self._get_model_path(
33
+ repo_id="moskize/OnnxOCR",
34
+ filename="README.md",
35
+ repo_type=None,
36
+ is_snapshot=True,
37
+ wanna_dir_path=True,
38
+ )
39
+
40
+ def get_yolo_path(self) -> Path:
41
+ return self._get_model_path(
42
+ repo_id="opendatalab/PDF-Extract-Kit-1.0",
43
+ filename="models/Layout/YOLO/doclayout_yolo_ft.pt",
44
+ repo_type=None,
45
+ is_snapshot=False,
46
+ wanna_dir_path=False,
47
+ )
48
+
49
+ def get_layoutreader_path(self) -> Path:
50
+ return self._get_model_path(
51
+ repo_id="hantian/layoutreader",
52
+ filename="model.safetensors",
53
+ repo_type=None,
54
+ is_snapshot=True,
55
+ wanna_dir_path=True,
56
+ )
57
+
58
+ def get_struct_eqtable_path(self) -> Path:
59
+ return self._get_model_path(
60
+ repo_id="U4R/StructTable-InternVL2-1B",
61
+ filename="model.safetensors",
62
+ repo_type=None,
63
+ is_snapshot=True,
64
+ wanna_dir_path=True,
65
+ )
66
+
67
+ def get_latex_path(self) -> Path:
68
+ return self._get_model_path(
69
+ repo_id="lukbl/LaTeX-OCR",
70
+ filename="checkpoints/weights.pth",
71
+ repo_type="space",
72
+ is_snapshot=True,
73
+ wanna_dir_path=True,
74
+ )
75
+
76
+ def _get_model_path(
77
+ self,
78
+ repo_id: str,
79
+ filename: str,
80
+ repo_type: str | None,
81
+ is_snapshot: bool,
82
+ wanna_dir_path: bool,
83
+ ) -> Path:
84
+
85
+ with self._lock:
86
+ model_path = try_to_load_from_cache(
87
+ repo_id=repo_id,
88
+ filename=filename,
89
+ repo_type=repo_type,
90
+ cache_dir=self._model_cache_dir
91
+ )
92
+ if isinstance(model_path, str):
93
+ model_path = Path(model_path)
94
+ if wanna_dir_path:
95
+ for _ in Path(filename).parts:
96
+ model_path = model_path.parent
97
+
98
+ else:
99
+ if is_snapshot:
100
+ model_path = snapshot_download(
101
+ cache_dir=self._model_cache_dir,
102
+ repo_id=repo_id,
103
+ repo_type=repo_type,
104
+ )
105
+ else:
106
+ model_path = hf_hub_download(
107
+ cache_dir=self._model_cache_dir,
108
+ repo_id=repo_id,
109
+ repo_type=repo_type,
110
+ filename=filename,
111
+ )
112
+ model_path = Path(model_path)
113
+
114
+ return model_path
@@ -5,7 +5,8 @@ import os
5
5
  from typing import Literal, Generator
6
6
  from dataclasses import dataclass
7
7
  from .onnxocr import TextSystem
8
- from .types import GetModelDir, OCRFragment
8
+ from .types import OCRFragment
9
+ from .model import Model
9
10
  from .rectangle import Rectangle
10
11
  from .utils import is_space_text
11
12
 
@@ -46,17 +47,10 @@ class _OONXParams:
46
47
  det_model_dir: str
47
48
  rec_char_dict_path: str
48
49
 
49
-
50
-
51
-
52
50
  class OCR:
53
- def __init__(
54
- self,
55
- device: Literal["cpu", "cuda"],
56
- get_model_dir: GetModelDir,
57
- ):
51
+ def __init__(self, device: Literal["cpu", "cuda"], model: Model):
58
52
  self._device: Literal["cpu", "cuda"] = device
59
- self._get_model_dir: GetModelDir = get_model_dir
53
+ self._model: Model = model
60
54
  self._text_system: TextSystem | None = None
61
55
 
62
56
  def search_fragments(self, image: np.ndarray) -> Generator[OCRFragment, None, None]:
@@ -89,17 +83,9 @@ class OCR:
89
83
  for box, res in zip(dt_boxes, rec_res):
90
84
  yield box.tolist(), res
91
85
 
92
- def make_model_paths(self) -> list[str]:
93
- model_paths = []
94
- model_dir = self._get_model_dir()
95
- for model_path in _MODELS:
96
- file_name = os.path.join(*model_path)
97
- model_paths.append(os.path.join(model_dir, file_name))
98
- return model_paths
99
-
100
86
  def _get_text_system(self) -> TextSystem:
101
87
  if self._text_system is None:
102
- model_paths = self.make_model_paths()
88
+ model_paths = self._make_model_paths()
103
89
  self._text_system = TextSystem(_OONXParams(
104
90
  use_angle_cls=True,
105
91
  use_gpu=(self._device != "cpu"),
@@ -127,9 +113,16 @@ class OCR:
127
113
  det_model_dir=model_paths[2],
128
114
  rec_char_dict_path=model_paths[3],
129
115
  ))
130
-
131
116
  return self._text_system
132
117
 
118
+ def _make_model_paths(self) -> list[str]:
119
+ model_paths: list[str] = []
120
+ model_dir = self._model.get_onnx_ocr_path()
121
+ for model_path in _MODELS:
122
+ file_name = os.path.join(*model_path)
123
+ model_paths.append(str(model_dir / file_name))
124
+ return model_paths
125
+
133
126
  def _preprocess_image(self, image: np.ndarray) -> np.ndarray:
134
127
  image = self._alpha_to_color(image, (255, 255, 255))
135
128
  # image = cv2.bitwise_not(image) # inv
@@ -1,24 +1,20 @@
1
- import os
2
1
  import torch
3
2
 
4
3
  from typing import Literal, Any
5
4
  from PIL.Image import Image
6
- from .types import TableLayoutParsedFormat, GetModelDir
5
+ from .types import TableLayoutParsedFormat
6
+ from .model import Model
7
7
  from .utils import expand_image
8
8
 
9
9
 
10
10
  OutputFormat = Literal["latex", "markdown", "html"]
11
11
 
12
12
  class Table:
13
- def __init__(
14
- self,
15
- device: Literal["cpu", "cuda"],
16
- get_model_dir: GetModelDir,
17
- ):
18
- self._model: Any | None = None
19
- self._model_path: str = get_model_dir()
13
+ def __init__(self, device: Literal["cpu", "cuda"], model: Model) -> None:
14
+ self._model: Model = model
15
+ self._table_model: Any | None = None
20
16
  self._ban: bool = False
21
- if device == "cpu" or not torch.cuda.is_available():
17
+ if device == "cpu":
22
18
  self._ban = True
23
19
 
24
20
  def predict(self, image: Image, format: TableLayoutParsedFormat) -> str | None:
@@ -47,24 +43,18 @@ class Table:
47
43
 
48
44
  return results[0]
49
45
 
50
- def _get_model(self):
51
- if self._model is None:
52
- local_files_only: bool
53
- if os.path.exists(self._model_path):
54
- local_files_only = True
55
- else:
56
- local_files_only = False
57
- os.makedirs(self._model_path)
58
-
46
+ def _get_model(self) -> Any:
47
+ if self._table_model is None:
59
48
  from .struct_eqtable import build_model
60
- model = build_model(
61
- model_ckpt=self._model_path,
49
+ model_path = self._model.get_struct_eqtable_path()
50
+ table_model = build_model(
51
+ model_ckpt=model_path,
62
52
  max_new_tokens=1024,
63
53
  max_time=30,
64
54
  lmdeploy=False,
65
55
  flash_attn=True,
66
56
  batch_size=1,
67
- local_files_only=local_files_only,
57
+ local_files_only=False,
68
58
  )
69
- self._model = model.cuda()
70
- return self._model
59
+ self._table_model = table_model.cuda()
60
+ return self._table_model
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass
2
- from typing import Literal, Callable, Protocol, runtime_checkable, List
2
+ from typing import Literal
3
3
  from enum import auto, Enum
4
4
  from PIL.Image import Image
5
5
  from .rectangle import Rectangle
@@ -32,7 +32,7 @@ class TableLayoutParsedFormat(Enum):
32
32
  @dataclass
33
33
  class BaseLayout:
34
34
  rect: Rectangle
35
- fragments: List[OCRFragment]
35
+ fragments: list[OCRFragment]
36
36
 
37
37
  @dataclass
38
38
  class PlainLayout(BaseLayout):
@@ -63,29 +63,6 @@ Layout = PlainLayout | TableLayout | FormulaLayout
63
63
  @dataclass
64
64
  class ExtractedResult:
65
65
  rotation: float
66
- layouts: List[Layout]
66
+ layouts: list[Layout]
67
67
  extracted_image: Image | None
68
- adjusted_image: Image | None
69
-
70
- GetModelDir = Callable[[], str]
71
-
72
-
73
- @runtime_checkable
74
- class ModelsDownloader(Protocol):
75
-
76
- def onnx_ocr(self) -> str:
77
- pass
78
-
79
- def yolo(self) -> str:
80
- pass
81
-
82
- def layoutreader(self) -> str:
83
- pass
84
-
85
- def struct_eqtable(self) -> str:
86
- pass
87
-
88
- def latex(self) -> str:
89
- pass
90
-
91
-
68
+ adjusted_image: Image | None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: doc-page-extractor
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: doc page extractor can identify text and format in images and return structured data.
5
5
  Home-page: https://github.com/Moskize91/doc-page-extractor
6
6
  Author: Tao Zeyu
@@ -16,7 +16,7 @@ Requires-Dist: transformers<=4.47,>=4.42.4
16
16
  Requires-Dist: doclayout_yolo>=0.0.3
17
17
  Requires-Dist: pix2tex<=0.2.0,>=0.1.4
18
18
  Requires-Dist: accelerate<2.0,>=1.6.0
19
- Requires-Dist: huggingface_hub>=0.30.2
19
+ Requires-Dist: huggingface_hub<1.0,>=0.30.2
20
20
  Dynamic: author
21
21
  Dynamic: author-email
22
22
  Dynamic: description
@@ -8,7 +8,7 @@ doc_page_extractor/extractor.py
8
8
  doc_page_extractor/latex.py
9
9
  doc_page_extractor/layout_order.py
10
10
  doc_page_extractor/layoutreader.py
11
- doc_page_extractor/models.py
11
+ doc_page_extractor/model.py
12
12
  doc_page_extractor/ocr.py
13
13
  doc_page_extractor/ocr_corrector.py
14
14
  doc_page_extractor/overlap.py
@@ -7,4 +7,4 @@ transformers<=4.47,>=4.42.4
7
7
  doclayout_yolo>=0.0.3
8
8
  pix2tex<=0.2.0,>=0.1.4
9
9
  accelerate<2.0,>=1.6.0
10
- huggingface_hub>=0.30.2
10
+ huggingface_hub<1.0,>=0.30.2
@@ -5,7 +5,7 @@ if "doc_page_extractor.struct_eqtable" not in find_packages():
5
5
 
6
6
  setup(
7
7
  name="doc-page-extractor",
8
- version="0.2.0",
8
+ version="0.2.2",
9
9
  author="Tao Zeyu",
10
10
  author_email="i@taozeyu.com",
11
11
  url="https://github.com/Moskize91/doc-page-extractor",
@@ -23,6 +23,6 @@ setup(
23
23
  "doclayout_yolo>=0.0.3",
24
24
  "pix2tex>=0.1.4,<=0.2.0",
25
25
  "accelerate>=1.6.0,<2.0",
26
- "huggingface_hub>=0.30.2",
26
+ "huggingface_hub>=0.30.2,<1.0",
27
27
  ],
28
28
  )
@@ -1,92 +0,0 @@
1
- import os
2
-
3
- from logging import Logger
4
- from huggingface_hub import hf_hub_download, snapshot_download, try_to_load_from_cache
5
- from .types import ModelsDownloader
6
-
7
- class HuggingfaceModelsDownloader(ModelsDownloader):
8
- def __init__(
9
- self,
10
- logger: Logger,
11
- model_dir_path: str | None
12
- ):
13
- self._logger = logger
14
- self._model_dir_path: str | None = model_dir_path
15
-
16
- def onnx_ocr(self) -> str:
17
- repo_path = try_to_load_from_cache(
18
- repo_id="moskize/OnnxOCR",
19
- filename="README.md",
20
- cache_dir=self._model_dir_path
21
- )
22
- if isinstance(repo_path, str):
23
- return os.path.dirname(repo_path)
24
- else:
25
- self._logger.info("Downloading OCR model...")
26
- return snapshot_download(
27
- cache_dir=self._model_dir_path,
28
- repo_id="moskize/OnnxOCR",
29
- )
30
-
31
- def yolo(self) -> str:
32
- yolo_file_path = try_to_load_from_cache(
33
- repo_id="opendatalab/PDF-Extract-Kit-1.0",
34
- filename="models/Layout/YOLO/doclayout_yolo_ft.pt",
35
- cache_dir=self._model_dir_path
36
- )
37
- if isinstance(yolo_file_path, str):
38
- return yolo_file_path
39
- else:
40
- self._logger.info("Downloading YOLO model...")
41
- return hf_hub_download(
42
- cache_dir=self._model_dir_path,
43
- repo_id="opendatalab/PDF-Extract-Kit-1.0",
44
- filename="models/Layout/YOLO/doclayout_yolo_ft.pt",
45
- )
46
-
47
- def layoutreader(self) -> str:
48
- repo_path = try_to_load_from_cache(
49
- repo_id="hantian/layoutreader",
50
- filename="model.safetensors",
51
- cache_dir=self._model_dir_path
52
- )
53
- if isinstance(repo_path, str):
54
- return os.path.dirname(repo_path)
55
- else:
56
- self._logger.info("Downloading LayoutReader model...")
57
- return snapshot_download(
58
- cache_dir=self._model_dir_path,
59
- repo_id="hantian/layoutreader",
60
- )
61
-
62
- def struct_eqtable(self) -> str:
63
- repo_path = try_to_load_from_cache(
64
- repo_id="U4R/StructTable-InternVL2-1B",
65
- filename="model.safetensors",
66
- cache_dir=self._model_dir_path
67
- )
68
- if isinstance(repo_path, str):
69
- return os.path.dirname(repo_path)
70
- else:
71
- self._logger.info("Downloading StructEqTable model...")
72
- return snapshot_download(
73
- cache_dir=self._model_dir_path,
74
- repo_id="U4R/StructTable-InternVL2-1B",
75
- )
76
-
77
- def latex(self):
78
- repo_path = try_to_load_from_cache(
79
- repo_id="lukbl/LaTeX-OCR",
80
- filename="checkpoints/weights.pth",
81
- repo_type="space",
82
- cache_dir=self._model_dir_path
83
- )
84
- if isinstance(repo_path, str):
85
- return os.path.dirname(os.path.dirname(repo_path))
86
- else:
87
- self._logger.info("Downloading LaTeX model...")
88
- return snapshot_download(
89
- cache_dir=self._model_dir_path,
90
- repo_type="space",
91
- repo_id="lukbl/LaTeX-OCR",
92
- )