deepdoctection 0.44.1__py3-none-any.whl → 0.46__py3-none-any.whl

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.

Potentially problematic release.


This version of deepdoctection might be problematic. Click here for more details.

Files changed (33) hide show
  1. deepdoctection/__init__.py +7 -3
  2. deepdoctection/analyzer/config.py +44 -0
  3. deepdoctection/analyzer/factory.py +264 -7
  4. deepdoctection/configs/profiles.jsonl +2 -1
  5. deepdoctection/dataflow/parallel_map.py +7 -1
  6. deepdoctection/datapoint/box.py +5 -5
  7. deepdoctection/datapoint/image.py +5 -5
  8. deepdoctection/datapoint/view.py +73 -52
  9. deepdoctection/eval/cocometric.py +1 -0
  10. deepdoctection/extern/__init__.py +1 -0
  11. deepdoctection/extern/base.py +8 -1
  12. deepdoctection/extern/d2detect.py +1 -1
  13. deepdoctection/extern/doctrocr.py +18 -2
  14. deepdoctection/extern/fastlang.py +2 -2
  15. deepdoctection/extern/hflayoutlm.py +17 -10
  16. deepdoctection/extern/hflm.py +432 -7
  17. deepdoctection/extern/tessocr.py +17 -1
  18. deepdoctection/pipe/language.py +4 -4
  19. deepdoctection/pipe/lm.py +7 -3
  20. deepdoctection/pipe/order.py +12 -6
  21. deepdoctection/pipe/refine.py +10 -1
  22. deepdoctection/pipe/text.py +6 -0
  23. deepdoctection/pipe/transform.py +3 -0
  24. deepdoctection/utils/file_utils.py +34 -5
  25. deepdoctection/utils/logger.py +38 -1
  26. deepdoctection/utils/settings.py +2 -0
  27. deepdoctection/utils/transform.py +43 -18
  28. deepdoctection/utils/viz.py +24 -15
  29. {deepdoctection-0.44.1.dist-info → deepdoctection-0.46.dist-info}/METADATA +16 -21
  30. {deepdoctection-0.44.1.dist-info → deepdoctection-0.46.dist-info}/RECORD +33 -33
  31. {deepdoctection-0.44.1.dist-info → deepdoctection-0.46.dist-info}/WHEEL +0 -0
  32. {deepdoctection-0.44.1.dist-info → deepdoctection-0.46.dist-info}/licenses/LICENSE +0 -0
  33. {deepdoctection-0.44.1.dist-info → deepdoctection-0.46.dist-info}/top_level.txt +0 -0
@@ -27,7 +27,7 @@ from dataclasses import asdict
27
27
  from itertools import chain, product
28
28
  from typing import DefaultDict, Optional, Sequence, Union
29
29
 
30
- import networkx as nx # type: ignore
30
+ from lazy_imports import try_import
31
31
 
32
32
  from ..datapoint.annotation import ImageAnnotation
33
33
  from ..datapoint.box import merge_boxes
@@ -35,10 +35,15 @@ from ..datapoint.image import Image, MetaAnnotation
35
35
  from ..extern.base import DetectionResult
36
36
  from ..mapper.maputils import MappingContextManager
37
37
  from ..utils.error import ImageError
38
+ from ..utils.file_utils import networkx_available
38
39
  from ..utils.settings import CellType, LayoutType, ObjectTypes, Relationships, TableType, get_type
39
40
  from .base import PipelineComponent
40
41
  from .registry import pipeline_component_registry
41
42
 
43
+ with try_import() as import_guard:
44
+ import networkx as nx # type: ignore
45
+
46
+
42
47
  __all__ = ["TableSegmentationRefinementService", "generate_html_string"]
43
48
 
44
49
 
@@ -441,6 +446,10 @@ class TableSegmentationRefinementService(PipelineComponent):
441
446
  table_names: Sequence of table object types.
442
447
  cell_names: Sequence of cell object types.
443
448
  """
449
+ if not networkx_available():
450
+ raise ModuleNotFoundError(
451
+ "TableSegmentationRefinementService requires networkx. Please install separately."
452
+ )
444
453
  self.table_name = table_names
445
454
  self.cell_names = cell_names
446
455
  super().__init__("table_segment_refine")
@@ -129,6 +129,12 @@ class TextExtractionService(PipelineComponent):
129
129
  width, height = self.predictor.get_width_height(predictor_input) # type: ignore
130
130
 
131
131
  for detect_result in detect_result_list:
132
+ if width is not None and height is not None:
133
+ box = detect_result.box
134
+ if box:
135
+ if box[0] >= width or box[1] >= height or box[2] >= width or box[3] >= height:
136
+ continue
137
+
132
138
  if isinstance(self.predictor, TextRecognizer):
133
139
  detect_ann_id = detect_result.uuid
134
140
  else:
@@ -77,6 +77,9 @@ class SimpleTransformService(PipelineComponent):
77
77
  score=ann.score,
78
78
  class_id=ann.category_id,
79
79
  uuid=ann.annotation_id,
80
+ angle=detection_result.angle,
81
+ image_width=dp.width, # we need the original width, not the transformed width
82
+ image_height=dp.height, # same with height
80
83
  )
81
84
  )
82
85
  output_detect_results = self.transform_predictor.transform_coords(detect_results)
@@ -8,6 +8,7 @@
8
8
  Utilities for maintaining dependencies and dealing with external library packages. Parts of this file is adapted from
9
9
  <https://github.com/huggingface/transformers/blob/master/src/transformers/file_utils.py>
10
10
  """
11
+ import importlib.metadata
11
12
  import importlib.util
12
13
  import multiprocessing as mp
13
14
  import string
@@ -17,7 +18,6 @@ from shutil import which
17
18
  from types import ModuleType
18
19
  from typing import Any, Union, no_type_check
19
20
 
20
- import importlib_metadata
21
21
  import numpy as np
22
22
  from packaging import version
23
23
 
@@ -72,9 +72,9 @@ def get_tf_version() -> str:
72
72
 
73
73
  for pkg in candidates:
74
74
  try:
75
- tf_version = importlib_metadata.version(pkg)
75
+ tf_version = importlib.metadata.version(pkg)
76
76
  break
77
- except importlib_metadata.PackageNotFoundError:
77
+ except importlib.metadata.PackageNotFoundError:
78
78
  pass
79
79
  return tf_version
80
80
 
@@ -175,6 +175,19 @@ def get_pytorch_requirement() -> Requirement:
175
175
  return "torch", pytorch_available(), _PYTORCH_ERR_MSG
176
176
 
177
177
 
178
+ _PYZMQ_AVAILABLE = importlib.util.find_spec("zmq") is not None
179
+
180
+
181
+ def pyzmq_available() -> bool:
182
+ """
183
+ Returns whether pyzmq is installed.
184
+
185
+ Returns:
186
+ bool: True if pyzmq is installed, False otherwise.
187
+ """
188
+ return bool(_PYZMQ_AVAILABLE)
189
+
190
+
178
191
  # lxml
179
192
  _LXML_AVAILABLE = importlib.util.find_spec("lxml") is not None
180
193
  _LXML_ERR_MSG = f"lxml must be installed. {_GENERIC_ERR_MSG}"
@@ -232,7 +245,7 @@ _DISTANCE_ERR_MSG = f"distance must be installed. {_GENERIC_ERR_MSG}"
232
245
 
233
246
  def distance_available() -> bool:
234
247
  """
235
- Returns whether `distance` is available.
248
+ Returns True if `distance` is available.
236
249
 
237
250
  Returns:
238
251
  bool: `True` if `distance` is available, False otherwise.
@@ -250,6 +263,22 @@ def get_distance_requirement() -> Requirement:
250
263
  return "distance", distance_available(), _DISTANCE_ERR_MSG
251
264
 
252
265
 
266
+ # networkx
267
+ _NETWORKX_AVAILABLE = importlib.util.find_spec("networkx") is not None
268
+
269
+
270
+ def networkx_available() -> bool:
271
+ """
272
+ Checks if networkx is installed.
273
+
274
+ Returns:
275
+ bool: True if networkx is installed, False otherwise.
276
+ :return:
277
+ """
278
+ return bool(_NETWORKX_AVAILABLE)
279
+
280
+
281
+ # numpy
253
282
  _NUMPY_V1_ERR_MSG = "numpy v1 must be installed."
254
283
 
255
284
 
@@ -263,7 +292,7 @@ def numpy_v1_available() -> bool:
263
292
  Returns:
264
293
  True if the installed NumPy version is 1, otherwise False
265
294
  """
266
- major_version = np.__version__.split('.', maxsplit=1)[0]
295
+ major_version = np.__version__.split(".", maxsplit=1)[0]
267
296
  print(f"major version: {major_version}")
268
297
  if major_version in (1, "1"):
269
298
  return True
@@ -143,6 +143,43 @@ class FileFormatter(logging.Formatter):
143
143
 
144
144
 
145
145
  _LOG_DIR = None
146
+
147
+
148
+ def _coerce_log_level(val: Any) -> Union[int, str]:
149
+ """Normalize environment log level values.
150
+
151
+ Accepts integer values (e.g., ``20``), numeric strings (``"20"``),
152
+ or names case-insensitively (``"info"``, ``"Warn"``, ...). Returns
153
+ either an integer level number or a valid uppercase level name
154
+ accepted by the :mod:`logging` module.
155
+
156
+ Args:
157
+ val: The raw value from the environment variable ``LOG_LEVEL``.
158
+
159
+ Returns:
160
+ int | str: The corresponding logging level as an int or an
161
+ uppercase string. Defaults to ``"INFO"`` if the input is invalid.
162
+ """
163
+ if isinstance(val, int):
164
+ return val
165
+ if val is None:
166
+ return "INFO"
167
+ s = str(val).strip()
168
+ if s.isdigit():
169
+ return int(s)
170
+ name = s.upper()
171
+ if name == "WARN":
172
+ name = "WARNING"
173
+ if name in logging._nameToLevel: # pylint: disable=W0212
174
+ return name
175
+ lvl = logging.getLevelName(name)
176
+ return lvl if isinstance(lvl, int) else "INFO"
177
+
178
+
179
+ # resolve level from LOG_LEVEL only
180
+ _ENV_LOG_LEVEL = os.environ.get("LOG_LEVEL", "INFO")
181
+ _RESOLVED_LOG_LEVEL = _coerce_log_level(_ENV_LOG_LEVEL)
182
+
146
183
  _CONFIG_DICT: dict[str, Any] = {
147
184
  "version": 1,
148
185
  "disable_existing_loggers": False,
@@ -155,7 +192,7 @@ _CONFIG_DICT: dict[str, Any] = {
155
192
  },
156
193
  "root": {
157
194
  "handlers": ["streamhandler"],
158
- "level": os.environ.get("LOG_LEVEL", "INFO"),
195
+ "level": _RESOLVED_LOG_LEVEL,
159
196
  "propagate": os.environ.get("LOG_PROPAGATE", "False") in ENV_VARS_TRUE,
160
197
  },
161
198
  }
@@ -108,6 +108,7 @@ class DocumentType(ObjectTypes):
108
108
  GOVERNMENT_TENDERS = "government_tenders"
109
109
  MANUALS = "manuals"
110
110
  PATENTS = "patents"
111
+ BANK_STATEMENT = "bank_statement"
111
112
 
112
113
 
113
114
  @object_types_registry.register("LayoutType")
@@ -296,6 +297,7 @@ class Languages(ObjectTypes):
296
297
  BOSNIAN = "bos"
297
298
  NORWEGIAN_NOVOSIBIRSK = "nno"
298
299
  URDU = "urd"
300
+ SWAHILI = "swa"
299
301
  NOT_DEFINED = "nn"
300
302
 
301
303
 
@@ -408,8 +408,35 @@ class RotationTransform(BaseTransform):
408
408
  angle: Angle to rotate the image. Must be one of 90, 180, 270, or 360 degrees.
409
409
  """
410
410
  self.angle = angle
411
- self.image_width: Optional[int] = None
412
- self.image_height: Optional[int] = None
411
+ self.image_width: Optional[Union[int, float]] = None
412
+ self.image_height: Optional[Union[int, float]] = None
413
+
414
+ def set_angle(self, angle: Literal[90, 180, 270, 360]) -> None:
415
+ """
416
+ Set angle
417
+
418
+ Args:
419
+ angle: One of 90, 180, 270, or 360 degrees.
420
+ """
421
+ self.angle = angle
422
+
423
+ def set_image_width(self, image_width: Union[int, float]) -> None:
424
+ """
425
+ Set image width
426
+
427
+ Args:
428
+ image_width: Either a positive integer or 1.
429
+ """
430
+ self.image_width = image_width
431
+
432
+ def set_image_height(self, image_height: Union[int, float]) -> None:
433
+ """
434
+ Set image height
435
+
436
+ Args:
437
+ image_height: Either a positive integer or 1.
438
+ """
439
+ self.image_height = image_height
413
440
 
414
441
  def apply_image(self, img: PixelValues) -> PixelValues:
415
442
  """
@@ -442,17 +469,16 @@ class RotationTransform(BaseTransform):
442
469
  raise ValueError("Initialize image_width and image_height first")
443
470
 
444
471
  if self.angle == 90:
445
- coords[:, [0, 1, 2, 3]] = coords[:, [1, 0, 3, 2]]
472
+ self.image_width = self.image_height
473
+ coords[:, [0, 1, 2, 3]] = coords[:, [1, 2, 3, 0]]
446
474
  coords[:, [1, 3]] = self.image_width - coords[:, [1, 3]]
447
- coords[:, [0, 1, 2, 3]] = coords[:, [0, 3, 2, 1]]
448
475
  elif self.angle == 180:
449
- coords[:, [0, 2]] = self.image_width - coords[:, [0, 2]]
450
- coords[:, [1, 3]] = self.image_height - coords[:, [1, 3]]
451
- coords[:, [0, 1, 2, 3]] = coords[:, [2, 3, 0, 1]]
476
+ coords[:, [0, 2]] = self.image_width - coords[:, [2, 0]]
477
+ coords[:, [1, 3]] = self.image_height - coords[:, [3, 1]]
452
478
  elif self.angle == 270:
453
- coords[:, [0, 1, 2, 3]] = coords[:, [1, 0, 3, 2]]
479
+ self.image_height = self.image_width
480
+ coords[:, [0, 1, 2, 3]] = coords[:, [3, 0, 1, 2]]
454
481
  coords[:, [0, 2]] = self.image_height - coords[:, [0, 2]]
455
- coords[:, [0, 1, 2, 3]] = coords[:, [2, 1, 0, 3]]
456
482
 
457
483
  return coords
458
484
 
@@ -473,17 +499,16 @@ class RotationTransform(BaseTransform):
473
499
  raise ValueError("Initialize image_width and image_height first")
474
500
 
475
501
  if self.angle == 90:
476
- coords[:, [0, 1, 2, 3]] = coords[:, [1, 0, 3, 2]]
477
- coords[:, [0, 2]] = self.image_width - coords[:, [0, 2]]
478
- coords[:, [0, 1, 2, 3]] = coords[:, [2, 1, 0, 3]]
502
+ self.image_height = self.image_width
503
+ coords[:, [0, 1, 2, 3]] = coords[:, [3, 0, 1, 2]]
504
+ coords[:, [0, 2]] = self.image_height - coords[:, [0, 2]]
479
505
  elif self.angle == 180:
480
- coords[:, [0, 2]] = self.image_width - coords[:, [0, 2]]
481
- coords[:, [1, 3]] = self.image_height - coords[:, [1, 3]]
482
- coords[:, [0, 1, 2, 3]] = coords[:, [2, 3, 0, 1]]
506
+ coords[:, [0, 2]] = self.image_width - coords[:, [2, 0]]
507
+ coords[:, [1, 3]] = self.image_height - coords[:, [3, 1]]
483
508
  elif self.angle == 270:
484
- coords[:, [0, 1, 2, 3]] = coords[:, [1, 0, 3, 2]]
485
- coords[:, [1, 3]] = self.image_height - coords[:, [1, 3]]
486
- coords[:, [0, 1, 2, 3]] = coords[:, [0, 3, 2, 1]]
509
+ self.image_width = self.image_height
510
+ coords[:, [0, 1, 2, 3]] = coords[:, [1, 2, 3, 0]]
511
+ coords[:, [1, 3]] = self.image_width - coords[:, [1, 3]]
487
512
  return coords
488
513
 
489
514
  def clone(self) -> RotationTransform:
@@ -20,10 +20,11 @@ Visualisation utils. Copied and pasted from
20
20
  """
21
21
 
22
22
  import base64
23
+ import hashlib
23
24
  import os
24
25
  import sys
25
26
  from io import BytesIO
26
- from typing import Any, Optional, Sequence, no_type_check
27
+ from typing import Any, Optional, Sequence, Tuple, Union, no_type_check
27
28
 
28
29
  import numpy as np
29
30
  import numpy.typing as npt
@@ -177,17 +178,23 @@ _COLORS = (
177
178
  )
178
179
 
179
180
 
180
- def random_color(rgb: bool = True, maximum: int = 255) -> tuple[int, int, int]:
181
+ def random_color(
182
+ rgb: bool = True, maximum: int = 255, deterministic_input_str: Optional[str] = None
183
+ ) -> tuple[int, int, int]:
181
184
  """
182
185
  Args:
183
186
  rgb: Whether to return RGB colors or BGR colors.
184
187
  maximum: Either 255 or 1.
188
+ deterministic_input_str: A string to use for deterministic color generation.
185
189
 
186
190
  Returns:
187
191
  A tuple of three integers representing the color.
188
192
  """
189
-
190
- idx = np.random.randint(0, len(_COLORS))
193
+ if deterministic_input_str:
194
+ hash_digest = hashlib.md5(deterministic_input_str.encode("utf-8")).hexdigest()
195
+ idx = int(hash_digest, 16) % len(_COLORS)
196
+ else:
197
+ idx = np.random.randint(0, len(_COLORS))
191
198
  ret = _COLORS[idx] * maximum
192
199
  if not rgb:
193
200
  ret = ret[::-1]
@@ -197,7 +204,7 @@ def random_color(rgb: bool = True, maximum: int = 255) -> tuple[int, int, int]:
197
204
  def draw_boxes(
198
205
  np_image: PixelValues,
199
206
  boxes: npt.NDArray[float32],
200
- category_names_list: Optional[list[Optional[str]]] = None,
207
+ category_names_list: Optional[list[Tuple[Union[str, None], Union[str, None]]]] = None,
201
208
  color: Optional[BGR] = None,
202
209
  font_scale: float = 1.0,
203
210
  rectangle_thickness: int = 4,
@@ -210,7 +217,8 @@ def draw_boxes(
210
217
  Args:
211
218
  np_image: Image as `np.ndarray`.
212
219
  boxes: A numpy array of shape Nx4 where each row is `[x1, y1, x2, y2]`.
213
- category_names_list: List of N category names.
220
+ category_names_list: List of N tuples. The first element is the category name, whereas the second element is
221
+ the value, that is going to be displayed in the text box..
214
222
  color: A 3-tuple BGR color (in range `[0, 255]`).
215
223
  font_scale: Font scale of text box.
216
224
  rectangle_thickness: Thickness of bounding box.
@@ -230,13 +238,14 @@ def draw_boxes(
230
238
  category_to_color = {}
231
239
  if box_color_by_category and category_names_list is not None:
232
240
  category_names = set(category_names_list)
233
- category_to_color = {category: random_color() for category in category_names}
234
-
241
+ category_to_color = {
242
+ category[1]: random_color(deterministic_input_str=category[1]) for category in category_names
243
+ }
235
244
  boxes = np.array(boxes, dtype="int32")
236
245
  if category_names_list is not None:
237
246
  assert len(category_names_list) == len(boxes), f"{len(category_names_list)} != {len(boxes)}"
238
247
  else:
239
- category_names_list = [None] * len(boxes)
248
+ category_names_list = [(None, None)] * len(boxes)
240
249
  areas = (boxes[:, 2] - boxes[:, 0] + 1) * (boxes[:, 3] - boxes[:, 1] + 1)
241
250
  sorted_inds = np.argsort(-areas) # draw large ones first
242
251
  assert areas.min() > 0, areas.min()
@@ -255,12 +264,12 @@ def draw_boxes(
255
264
  np_image = cv2.cvtColor(np_image, cv2.COLOR_GRAY2BGR).astype(np.uint8)
256
265
  for i in sorted_inds:
257
266
  box = boxes[i, :]
258
- choose_color = category_to_color.get(category_names_list[i]) if category_to_color is not None else color
267
+ choose_color = category_to_color.get(category_names_list[i][1]) if category_to_color is not None else color
259
268
  if choose_color is None:
260
269
  choose_color = random_color()
261
- if category_names_list[i] is not None:
270
+ if category_names_list[i][0] is not None:
262
271
  np_image = viz_handler.draw_text(
263
- np_image, (box[0], box[1]), category_names_list[i], color=choose_color, font_scale=font_scale
272
+ np_image, (box[0], box[1]), category_names_list[i][0], color=choose_color, font_scale=font_scale
264
273
  )
265
274
  np_image = viz_handler.draw_rectangle(
266
275
  np_image, (box[0], box[1], box[2], box[3]), choose_color, rectangle_thickness
@@ -423,7 +432,7 @@ class VizPackageHandler:
423
432
 
424
433
  @staticmethod
425
434
  def _cv2_read_image(path: PathLikeOrStr) -> PixelValues:
426
- return cv2.imread(os.fspath(path), cv2.IMREAD_COLOR).astype(np.uint8)
435
+ return cv2.imread(os.fspath(path), cv2.IMREAD_COLOR).astype(np.uint8) # type: ignore
427
436
 
428
437
  @staticmethod
429
438
  def _pillow_read_image(path: PathLikeOrStr) -> PixelValues:
@@ -517,7 +526,7 @@ class VizPackageHandler:
517
526
  @staticmethod
518
527
  def _cv2_convert_b64_to_np(image: B64Str) -> PixelValues:
519
528
  np_array = np.fromstring(base64.b64decode(image), np.uint8) # type: ignore
520
- np_array = cv2.imdecode(np_array, cv2.IMREAD_COLOR).astype(np.float32)
529
+ np_array = cv2.imdecode(np_array, cv2.IMREAD_COLOR).astype(np.float32) # type: ignore
521
530
  return np_array.astype(uint8)
522
531
 
523
532
  @staticmethod
@@ -543,7 +552,7 @@ class VizPackageHandler:
543
552
  def _cv2_convert_bytes_to_np(image_bytes: bytes) -> PixelValues:
544
553
  np_array = np.frombuffer(image_bytes, np.uint8)
545
554
  np_image = cv2.imdecode(np_array, cv2.IMREAD_COLOR)
546
- return np_image
555
+ return np_image # type: ignore
547
556
 
548
557
  @staticmethod
549
558
  def _pillow_convert_bytes_to_np(image_bytes: bytes) -> PixelValues:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepdoctection
3
- Version: 0.44.1
3
+ Version: 0.46
4
4
  Summary: Repository for Document AI
5
5
  Home-page: https://github.com/deepdoctection/deepdoctection
6
6
  Author: Dr. Janis Meyer
@@ -19,18 +19,15 @@ Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
20
  Requires-Dist: catalogue==2.0.10
21
21
  Requires-Dist: huggingface_hub>=0.26.0
22
- Requires-Dist: importlib-metadata>=5.0.0
23
22
  Requires-Dist: jsonlines==3.1.0
24
23
  Requires-Dist: lazy-imports==0.3.1
25
24
  Requires-Dist: mock==4.0.3
26
- Requires-Dist: networkx>=2.7.1
27
- Requires-Dist: numpy<2.0,>=1.21
25
+ Requires-Dist: numpy>2.0
28
26
  Requires-Dist: packaging>=20.0
29
27
  Requires-Dist: Pillow>=10.0.0
30
28
  Requires-Dist: pypdf>=6.0.0
31
29
  Requires-Dist: pypdfium2>=4.30.0
32
30
  Requires-Dist: pyyaml>=6.0.1
33
- Requires-Dist: pyzmq>=16
34
31
  Requires-Dist: scipy>=1.13.1
35
32
  Requires-Dist: termcolor>=1.1
36
33
  Requires-Dist: tabulate>=0.7.7
@@ -38,18 +35,15 @@ Requires-Dist: tqdm>=4.64.0
38
35
  Provides-Extra: tf
39
36
  Requires-Dist: catalogue==2.0.10; extra == "tf"
40
37
  Requires-Dist: huggingface_hub>=0.26.0; extra == "tf"
41
- Requires-Dist: importlib-metadata>=5.0.0; extra == "tf"
42
38
  Requires-Dist: jsonlines==3.1.0; extra == "tf"
43
39
  Requires-Dist: lazy-imports==0.3.1; extra == "tf"
44
40
  Requires-Dist: mock==4.0.3; extra == "tf"
45
- Requires-Dist: networkx>=2.7.1; extra == "tf"
46
- Requires-Dist: numpy<2.0,>=1.21; extra == "tf"
41
+ Requires-Dist: numpy>2.0; extra == "tf"
47
42
  Requires-Dist: packaging>=20.0; extra == "tf"
48
43
  Requires-Dist: Pillow>=10.0.0; extra == "tf"
49
44
  Requires-Dist: pypdf>=6.0.0; extra == "tf"
50
45
  Requires-Dist: pypdfium2>=4.30.0; extra == "tf"
51
46
  Requires-Dist: pyyaml>=6.0.1; extra == "tf"
52
- Requires-Dist: pyzmq>=16; extra == "tf"
53
47
  Requires-Dist: scipy>=1.13.1; extra == "tf"
54
48
  Requires-Dist: termcolor>=1.1; extra == "tf"
55
49
  Requires-Dist: tabulate>=0.7.7; extra == "tf"
@@ -58,30 +52,28 @@ Requires-Dist: tensorpack==0.11; extra == "tf"
58
52
  Requires-Dist: protobuf==3.20.1; extra == "tf"
59
53
  Requires-Dist: tensorflow-addons>=0.17.1; extra == "tf"
60
54
  Requires-Dist: tf2onnx>=1.9.2; extra == "tf"
61
- Requires-Dist: python-doctr==0.9.0; extra == "tf"
55
+ Requires-Dist: python-doctr==0.10.0; extra == "tf"
62
56
  Requires-Dist: pycocotools>=2.0.2; extra == "tf"
63
57
  Requires-Dist: boto3==1.34.102; extra == "tf"
64
58
  Requires-Dist: pdfplumber>=0.11.0; extra == "tf"
65
- Requires-Dist: fasttext-wheel; extra == "tf"
59
+ Requires-Dist: pyzmq>=16; extra == "tf"
66
60
  Requires-Dist: jdeskew>=0.2.2; extra == "tf"
67
61
  Requires-Dist: apted==1.0.3; extra == "tf"
68
62
  Requires-Dist: distance==0.1.3; extra == "tf"
69
63
  Requires-Dist: lxml>=4.9.1; extra == "tf"
64
+ Requires-Dist: networkx>=2.7.1; extra == "tf"
70
65
  Provides-Extra: pt
71
66
  Requires-Dist: catalogue==2.0.10; extra == "pt"
72
67
  Requires-Dist: huggingface_hub>=0.26.0; extra == "pt"
73
- Requires-Dist: importlib-metadata>=5.0.0; extra == "pt"
74
68
  Requires-Dist: jsonlines==3.1.0; extra == "pt"
75
69
  Requires-Dist: lazy-imports==0.3.1; extra == "pt"
76
70
  Requires-Dist: mock==4.0.3; extra == "pt"
77
- Requires-Dist: networkx>=2.7.1; extra == "pt"
78
- Requires-Dist: numpy<2.0,>=1.21; extra == "pt"
71
+ Requires-Dist: numpy>2.0; extra == "pt"
79
72
  Requires-Dist: packaging>=20.0; extra == "pt"
80
73
  Requires-Dist: Pillow>=10.0.0; extra == "pt"
81
74
  Requires-Dist: pypdf>=6.0.0; extra == "pt"
82
75
  Requires-Dist: pypdfium2>=4.30.0; extra == "pt"
83
76
  Requires-Dist: pyyaml>=6.0.1; extra == "pt"
84
- Requires-Dist: pyzmq>=16; extra == "pt"
85
77
  Requires-Dist: scipy>=1.13.1; extra == "pt"
86
78
  Requires-Dist: termcolor>=1.1; extra == "pt"
87
79
  Requires-Dist: tabulate>=0.7.7; extra == "pt"
@@ -89,15 +81,16 @@ Requires-Dist: tqdm>=4.64.0; extra == "pt"
89
81
  Requires-Dist: timm>=0.9.16; extra == "pt"
90
82
  Requires-Dist: transformers>=4.48.0; extra == "pt"
91
83
  Requires-Dist: accelerate>=0.29.1; extra == "pt"
92
- Requires-Dist: python-doctr==0.9.0; extra == "pt"
84
+ Requires-Dist: python-doctr==0.10.0; extra == "pt"
93
85
  Requires-Dist: pycocotools>=2.0.2; extra == "pt"
94
86
  Requires-Dist: boto3==1.34.102; extra == "pt"
95
87
  Requires-Dist: pdfplumber>=0.11.0; extra == "pt"
96
- Requires-Dist: fasttext-wheel; extra == "pt"
88
+ Requires-Dist: pyzmq>=16; extra == "pt"
97
89
  Requires-Dist: jdeskew>=0.2.2; extra == "pt"
98
90
  Requires-Dist: apted==1.0.3; extra == "pt"
99
91
  Requires-Dist: distance==0.1.3; extra == "pt"
100
92
  Requires-Dist: lxml>=4.9.1; extra == "pt"
93
+ Requires-Dist: networkx>=2.7.1; extra == "pt"
101
94
  Provides-Extra: docs
102
95
  Requires-Dist: tensorpack==0.11; extra == "docs"
103
96
  Requires-Dist: boto3==1.34.102; extra == "docs"
@@ -183,7 +176,8 @@ It also provides a framework for training, evaluating and inferencing Document A
183
176
  [**LiLT**](https://github.com/jpWang/LiLT) and selected
184
177
  [**Bert**](https://huggingface.co/docs/transformers/model_doc/xlm-roberta)-style including features like sliding windows.
185
178
  - Text mining for native PDFs with [**pdfplumber**](https://github.com/jsvine/pdfplumber),
186
- - Language detection with [**fastText**](https://github.com/facebookresearch/fastText),
179
+ - Language detection with `papluca/xlm-roberta-base-language-detection`. [**fastText**](https://github.com/facebookresearch/fastText) is still available but
180
+ but will be removed in a future version.
187
181
  - Deskewing and rotating images with [**jdeskew**](https://github.com/phamquiluan/jdeskew).
188
182
  - Fine-tuning and evaluation tools.
189
183
  - Lot's of [tutorials](https://github.com/deepdoctection/notebooks)
@@ -294,7 +288,7 @@ alt="text" width="40%">
294
288
 
295
289
  - Linux or macOS. Windows is not supported but there is a [Dockerfile](./docker/pytorch-cpu-jupyter/Dockerfile) available.
296
290
  - Python >= 3.9
297
- - 2.2 \<= PyTorch **or** 2.11 \<= Tensorflow < 2.16. (For lower Tensorflow versions the code will only run on a GPU).
291
+ - 2.6 \<= PyTorch **or** 2.11 \<= Tensorflow < 2.16. (For lower Tensorflow versions the code will only run on a GPU).
298
292
  Tensorflow support will be stopped from Python 3.11 onwards.
299
293
  - To fine-tune models, a GPU is recommended.
300
294
 
@@ -321,7 +315,7 @@ For a simple setup which is enough to parse documents with the default setting,
321
315
 
322
316
  ```
323
317
  pip install transformers
324
- pip install python-doctr==0.9.0
318
+ pip install python-doctr==0.10.0 # If you use Python 3.10 or higher you can use the latest version.
325
319
  pip install deepdoctection
326
320
  ```
327
321
 
@@ -329,8 +323,9 @@ pip install deepdoctection
329
323
 
330
324
  ```
331
325
  pip install tensorpack
332
- pip install python-doctr==0.9.0
333
326
  pip install deepdoctection
327
+ pip install "numpy>=1.21,<2.0" --upgrade --force-reinstall # because TF 2.11 does not support numpy 2.0
328
+ pip install "python-doctr==0.9.0"
334
329
  ```
335
330
 
336
331
  Both setups are sufficient to run the [**introduction notebook**](https://github.com/deepdoctection/notebooks/blob/main/Get_Started.ipynb).