deepdoctection 0.31__py3-none-any.whl → 0.33__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 (131) hide show
  1. deepdoctection/__init__.py +16 -29
  2. deepdoctection/analyzer/dd.py +70 -59
  3. deepdoctection/configs/conf_dd_one.yaml +34 -31
  4. deepdoctection/dataflow/common.py +9 -5
  5. deepdoctection/dataflow/custom.py +5 -5
  6. deepdoctection/dataflow/custom_serialize.py +75 -18
  7. deepdoctection/dataflow/parallel_map.py +3 -3
  8. deepdoctection/dataflow/serialize.py +4 -4
  9. deepdoctection/dataflow/stats.py +3 -3
  10. deepdoctection/datapoint/annotation.py +41 -56
  11. deepdoctection/datapoint/box.py +9 -8
  12. deepdoctection/datapoint/convert.py +6 -6
  13. deepdoctection/datapoint/image.py +56 -44
  14. deepdoctection/datapoint/view.py +245 -150
  15. deepdoctection/datasets/__init__.py +1 -4
  16. deepdoctection/datasets/adapter.py +35 -26
  17. deepdoctection/datasets/base.py +14 -12
  18. deepdoctection/datasets/dataflow_builder.py +3 -3
  19. deepdoctection/datasets/info.py +24 -26
  20. deepdoctection/datasets/instances/doclaynet.py +51 -51
  21. deepdoctection/datasets/instances/fintabnet.py +46 -46
  22. deepdoctection/datasets/instances/funsd.py +25 -24
  23. deepdoctection/datasets/instances/iiitar13k.py +13 -10
  24. deepdoctection/datasets/instances/layouttest.py +4 -3
  25. deepdoctection/datasets/instances/publaynet.py +5 -5
  26. deepdoctection/datasets/instances/pubtables1m.py +24 -21
  27. deepdoctection/datasets/instances/pubtabnet.py +32 -30
  28. deepdoctection/datasets/instances/rvlcdip.py +30 -30
  29. deepdoctection/datasets/instances/xfund.py +26 -26
  30. deepdoctection/datasets/save.py +6 -6
  31. deepdoctection/eval/__init__.py +1 -4
  32. deepdoctection/eval/accmetric.py +32 -33
  33. deepdoctection/eval/base.py +8 -9
  34. deepdoctection/eval/cocometric.py +15 -13
  35. deepdoctection/eval/eval.py +41 -37
  36. deepdoctection/eval/tedsmetric.py +30 -23
  37. deepdoctection/eval/tp_eval_callback.py +16 -19
  38. deepdoctection/extern/__init__.py +2 -7
  39. deepdoctection/extern/base.py +339 -134
  40. deepdoctection/extern/d2detect.py +85 -113
  41. deepdoctection/extern/deskew.py +14 -11
  42. deepdoctection/extern/doctrocr.py +141 -130
  43. deepdoctection/extern/fastlang.py +27 -18
  44. deepdoctection/extern/hfdetr.py +71 -62
  45. deepdoctection/extern/hflayoutlm.py +504 -211
  46. deepdoctection/extern/hflm.py +230 -0
  47. deepdoctection/extern/model.py +488 -302
  48. deepdoctection/extern/pdftext.py +23 -19
  49. deepdoctection/extern/pt/__init__.py +1 -3
  50. deepdoctection/extern/pt/nms.py +6 -2
  51. deepdoctection/extern/pt/ptutils.py +29 -19
  52. deepdoctection/extern/tessocr.py +39 -38
  53. deepdoctection/extern/texocr.py +18 -18
  54. deepdoctection/extern/tp/tfutils.py +57 -9
  55. deepdoctection/extern/tp/tpcompat.py +21 -14
  56. deepdoctection/extern/tp/tpfrcnn/__init__.py +20 -0
  57. deepdoctection/extern/tp/tpfrcnn/common.py +7 -3
  58. deepdoctection/extern/tp/tpfrcnn/config/__init__.py +20 -0
  59. deepdoctection/extern/tp/tpfrcnn/config/config.py +13 -10
  60. deepdoctection/extern/tp/tpfrcnn/modeling/__init__.py +20 -0
  61. deepdoctection/extern/tp/tpfrcnn/modeling/backbone.py +18 -8
  62. deepdoctection/extern/tp/tpfrcnn/modeling/generalized_rcnn.py +12 -6
  63. deepdoctection/extern/tp/tpfrcnn/modeling/model_box.py +14 -9
  64. deepdoctection/extern/tp/tpfrcnn/modeling/model_cascade.py +8 -5
  65. deepdoctection/extern/tp/tpfrcnn/modeling/model_fpn.py +22 -17
  66. deepdoctection/extern/tp/tpfrcnn/modeling/model_frcnn.py +21 -14
  67. deepdoctection/extern/tp/tpfrcnn/modeling/model_mrcnn.py +19 -11
  68. deepdoctection/extern/tp/tpfrcnn/modeling/model_rpn.py +15 -10
  69. deepdoctection/extern/tp/tpfrcnn/predict.py +9 -4
  70. deepdoctection/extern/tp/tpfrcnn/preproc.py +12 -8
  71. deepdoctection/extern/tp/tpfrcnn/utils/__init__.py +20 -0
  72. deepdoctection/extern/tp/tpfrcnn/utils/box_ops.py +10 -2
  73. deepdoctection/extern/tpdetect.py +45 -53
  74. deepdoctection/mapper/__init__.py +3 -8
  75. deepdoctection/mapper/cats.py +27 -29
  76. deepdoctection/mapper/cocostruct.py +10 -10
  77. deepdoctection/mapper/d2struct.py +27 -26
  78. deepdoctection/mapper/hfstruct.py +13 -8
  79. deepdoctection/mapper/laylmstruct.py +178 -37
  80. deepdoctection/mapper/maputils.py +12 -11
  81. deepdoctection/mapper/match.py +2 -2
  82. deepdoctection/mapper/misc.py +11 -9
  83. deepdoctection/mapper/pascalstruct.py +4 -4
  84. deepdoctection/mapper/prodigystruct.py +5 -5
  85. deepdoctection/mapper/pubstruct.py +84 -92
  86. deepdoctection/mapper/tpstruct.py +5 -5
  87. deepdoctection/mapper/xfundstruct.py +33 -33
  88. deepdoctection/pipe/__init__.py +1 -1
  89. deepdoctection/pipe/anngen.py +12 -14
  90. deepdoctection/pipe/base.py +52 -106
  91. deepdoctection/pipe/common.py +72 -59
  92. deepdoctection/pipe/concurrency.py +16 -11
  93. deepdoctection/pipe/doctectionpipe.py +24 -21
  94. deepdoctection/pipe/language.py +20 -25
  95. deepdoctection/pipe/layout.py +20 -16
  96. deepdoctection/pipe/lm.py +75 -105
  97. deepdoctection/pipe/order.py +194 -89
  98. deepdoctection/pipe/refine.py +111 -124
  99. deepdoctection/pipe/segment.py +156 -161
  100. deepdoctection/pipe/{cell.py → sub_layout.py} +50 -40
  101. deepdoctection/pipe/text.py +37 -36
  102. deepdoctection/pipe/transform.py +19 -16
  103. deepdoctection/train/__init__.py +6 -12
  104. deepdoctection/train/d2_frcnn_train.py +48 -41
  105. deepdoctection/train/hf_detr_train.py +41 -30
  106. deepdoctection/train/hf_layoutlm_train.py +153 -135
  107. deepdoctection/train/tp_frcnn_train.py +32 -31
  108. deepdoctection/utils/concurrency.py +1 -1
  109. deepdoctection/utils/context.py +13 -6
  110. deepdoctection/utils/develop.py +4 -4
  111. deepdoctection/utils/env_info.py +87 -125
  112. deepdoctection/utils/file_utils.py +6 -11
  113. deepdoctection/utils/fs.py +22 -18
  114. deepdoctection/utils/identifier.py +2 -2
  115. deepdoctection/utils/logger.py +16 -15
  116. deepdoctection/utils/metacfg.py +7 -7
  117. deepdoctection/utils/mocks.py +93 -0
  118. deepdoctection/utils/pdf_utils.py +11 -11
  119. deepdoctection/utils/settings.py +185 -181
  120. deepdoctection/utils/tqdm.py +1 -1
  121. deepdoctection/utils/transform.py +14 -9
  122. deepdoctection/utils/types.py +104 -0
  123. deepdoctection/utils/utils.py +7 -7
  124. deepdoctection/utils/viz.py +74 -72
  125. {deepdoctection-0.31.dist-info → deepdoctection-0.33.dist-info}/METADATA +30 -21
  126. deepdoctection-0.33.dist-info/RECORD +146 -0
  127. {deepdoctection-0.31.dist-info → deepdoctection-0.33.dist-info}/WHEEL +1 -1
  128. deepdoctection/utils/detection_types.py +0 -68
  129. deepdoctection-0.31.dist-info/RECORD +0 -144
  130. {deepdoctection-0.31.dist-info → deepdoctection-0.33.dist-info}/LICENSE +0 -0
  131. {deepdoctection-0.31.dist-info → deepdoctection-0.33.dist-info}/top_level.txt +0 -0
@@ -25,7 +25,6 @@ from itertools import chain
25
25
  from typing import Mapping, Optional
26
26
 
27
27
  from ..datapoint import BoundingBox, CategoryAnnotation, ContainerAnnotation, Image, ImageAnnotation
28
- from ..utils.detection_types import JsonDict
29
28
  from ..utils.fs import load_image_from_file
30
29
  from ..utils.settings import (
31
30
  BioTag,
@@ -37,17 +36,18 @@ from ..utils.settings import (
37
36
  get_type,
38
37
  token_class_tag_to_token_class_with_tag,
39
38
  )
39
+ from ..utils.types import FunsdDict
40
40
  from .maputils import MappingContextManager, curry, maybe_get_fake_score
41
41
 
42
42
 
43
43
  @curry
44
44
  def xfund_to_image(
45
- dp: JsonDict,
45
+ dp: FunsdDict,
46
46
  load_image: bool,
47
47
  fake_score: bool,
48
- categories_dict_name_as_key: Mapping[str, str],
48
+ categories_dict_name_as_key: Mapping[ObjectTypes, int],
49
49
  token_class_names_mapping: Mapping[str, str],
50
- ner_token_to_id_mapping: Mapping[ObjectTypes, Mapping[ObjectTypes, Mapping[ObjectTypes, str]]],
50
+ ner_token_to_id_mapping: Mapping[ObjectTypes, Mapping[ObjectTypes, Mapping[ObjectTypes, int]]],
51
51
  ) -> Optional[Image]:
52
52
  """
53
53
  Map a datapoint of annotation structure as given as from xfund or funsd dataset in to an Image structure
@@ -75,9 +75,9 @@ def xfund_to_image(
75
75
 
76
76
  _, file_name = os.path.split(full_path)
77
77
  external_id = dp.get("uid")
78
- tag_to_id_mapping = ner_token_to_id_mapping[LayoutType.word][WordType.tag]
79
- token_class_to_id_mapping = ner_token_to_id_mapping[LayoutType.word][WordType.token_class]
80
- token_tag_to_id_mapping = ner_token_to_id_mapping[LayoutType.word][WordType.token_tag]
78
+ tag_to_id_mapping = ner_token_to_id_mapping[LayoutType.WORD][WordType.TAG]
79
+ token_class_to_id_mapping = ner_token_to_id_mapping[LayoutType.WORD][WordType.TOKEN_CLASS]
80
+ token_tag_to_id_mapping = ner_token_to_id_mapping[LayoutType.WORD][WordType.TOKEN_TAG]
81
81
 
82
82
  with MappingContextManager(file_name) as mapping_context:
83
83
  image = Image(file_name=file_name, location=full_path, external_id=external_id)
@@ -101,16 +101,16 @@ def xfund_to_image(
101
101
  bbox = BoundingBox(absolute_coords=True, ulx=box[0], uly=box[1], lrx=box[2], lry=box[3])
102
102
  score = maybe_get_fake_score(fake_score)
103
103
  entity_ann = ImageAnnotation(
104
- category_name=LayoutType.text,
104
+ category_name=LayoutType.TEXT,
105
105
  bounding_box=bbox,
106
- category_id=categories_dict_name_as_key[LayoutType.text],
106
+ category_id=categories_dict_name_as_key[LayoutType.TEXT],
107
107
  score=score,
108
108
  )
109
109
  category_name = token_class_names_mapping[entity["label"]]
110
110
  sub_cat_semantic = CategoryAnnotation(
111
111
  category_name=category_name, category_id=token_class_to_id_mapping[get_type(category_name)]
112
112
  )
113
- entity_ann.dump_sub_category(WordType.token_class, sub_cat_semantic)
113
+ entity_ann.dump_sub_category(WordType.TOKEN_CLASS, sub_cat_semantic)
114
114
  image.dump(entity_ann)
115
115
 
116
116
  words = entity.get("words")
@@ -122,61 +122,61 @@ def xfund_to_image(
122
122
  score = maybe_get_fake_score(fake_score)
123
123
 
124
124
  ann = ImageAnnotation(
125
- category_name=LayoutType.word,
125
+ category_name=LayoutType.WORD,
126
126
  bounding_box=bbox,
127
- category_id=categories_dict_name_as_key[LayoutType.word],
127
+ category_id=categories_dict_name_as_key[LayoutType.WORD],
128
128
  score=score,
129
129
  )
130
130
  image.dump(ann)
131
- entity_ann.dump_relationship(Relationships.child, ann.annotation_id)
131
+ entity_ann.dump_relationship(Relationships.CHILD, ann.annotation_id)
132
132
  sub_cat_semantic = CategoryAnnotation(
133
133
  category_name=category_name, category_id=token_class_to_id_mapping[get_type(category_name)]
134
134
  )
135
- ann.dump_sub_category(WordType.token_class, sub_cat_semantic)
136
- sub_cat_chars = ContainerAnnotation(category_name=WordType.characters, value=word["text"])
137
- ann.dump_sub_category(WordType.characters, sub_cat_chars)
138
- if sub_cat_semantic.category_name == TokenClasses.other:
135
+ ann.dump_sub_category(WordType.TOKEN_CLASS, sub_cat_semantic)
136
+ sub_cat_chars = ContainerAnnotation(category_name=WordType.CHARACTERS, value=word["text"])
137
+ ann.dump_sub_category(WordType.CHARACTERS, sub_cat_chars)
138
+ if sub_cat_semantic.category_name == TokenClasses.OTHER:
139
139
  sub_cat_tag = CategoryAnnotation(
140
- category_name=BioTag.outside, category_id=tag_to_id_mapping[BioTag.outside]
140
+ category_name=BioTag.OUTSIDE, category_id=tag_to_id_mapping[BioTag.OUTSIDE]
141
141
  )
142
- ann.dump_sub_category(WordType.tag, sub_cat_tag)
142
+ ann.dump_sub_category(WordType.TAG, sub_cat_tag)
143
143
  # populating ner token to be used for training and evaluation
144
144
  sub_cat_ner_tok = CategoryAnnotation(
145
- category_name=BioTag.outside, category_id=token_tag_to_id_mapping[BioTag.outside]
145
+ category_name=BioTag.OUTSIDE, category_id=token_tag_to_id_mapping[BioTag.OUTSIDE]
146
146
  )
147
- ann.dump_sub_category(WordType.token_tag, sub_cat_ner_tok)
147
+ ann.dump_sub_category(WordType.TOKEN_TAG, sub_cat_ner_tok)
148
148
  elif not idx:
149
149
  sub_cat_tag = CategoryAnnotation(
150
- category_name=BioTag.begin, category_id=tag_to_id_mapping[BioTag.begin]
150
+ category_name=BioTag.BEGIN, category_id=tag_to_id_mapping[BioTag.BEGIN]
151
151
  )
152
- ann.dump_sub_category(WordType.tag, sub_cat_tag)
152
+ ann.dump_sub_category(WordType.TAG, sub_cat_tag)
153
153
  sub_cat_ner_tok = CategoryAnnotation(
154
154
  category_name=token_class_tag_to_token_class_with_tag(
155
- get_type(sub_cat_semantic.category_name), BioTag.begin
155
+ get_type(sub_cat_semantic.category_name), BioTag.BEGIN
156
156
  ),
157
157
  category_id=token_tag_to_id_mapping[
158
158
  token_class_tag_to_token_class_with_tag(
159
- get_type(sub_cat_semantic.category_name), BioTag.begin
159
+ get_type(sub_cat_semantic.category_name), BioTag.BEGIN
160
160
  )
161
161
  ],
162
162
  )
163
- ann.dump_sub_category(WordType.token_tag, sub_cat_ner_tok)
163
+ ann.dump_sub_category(WordType.TOKEN_TAG, sub_cat_ner_tok)
164
164
  else:
165
165
  sub_cat_tag = CategoryAnnotation(
166
- category_name=BioTag.inside, category_id=tag_to_id_mapping[BioTag.inside]
166
+ category_name=BioTag.INSIDE, category_id=tag_to_id_mapping[BioTag.INSIDE]
167
167
  )
168
- ann.dump_sub_category(WordType.tag, sub_cat_tag)
168
+ ann.dump_sub_category(WordType.TAG, sub_cat_tag)
169
169
  sub_cat_ner_tok = CategoryAnnotation(
170
170
  category_name=token_class_tag_to_token_class_with_tag(
171
- get_type(sub_cat_semantic.category_name), BioTag.inside
171
+ get_type(sub_cat_semantic.category_name), BioTag.INSIDE
172
172
  ),
173
173
  category_id=token_tag_to_id_mapping[
174
174
  token_class_tag_to_token_class_with_tag(
175
- get_type(sub_cat_semantic.category_name), BioTag.inside
175
+ get_type(sub_cat_semantic.category_name), BioTag.INSIDE
176
176
  )
177
177
  ],
178
178
  )
179
- ann.dump_sub_category(WordType.token_tag, sub_cat_ner_tok)
179
+ ann.dump_sub_category(WordType.TOKEN_TAG, sub_cat_ner_tok)
180
180
 
181
181
  entity_id_to_ann_id[entity["id"]].append(ann.annotation_id)
182
182
  ann_id_to_entity_id[ann.annotation_id] = entity["id"]
@@ -184,7 +184,7 @@ def xfund_to_image(
184
184
  entity_id_to_entity_link_id[entity["id"]].extend(entity["linking"])
185
185
 
186
186
  # now populating semantic links
187
- word_anns = image.get_annotation(category_names=LayoutType.word)
187
+ word_anns = image.get_annotation(category_names=LayoutType.WORD)
188
188
  for word in word_anns:
189
189
  entity_id = ann_id_to_entity_id[word.annotation_id]
190
190
  all_linked_entities = list(chain(*entity_id_to_entity_link_id[entity_id]))
@@ -193,7 +193,7 @@ def xfund_to_image(
193
193
  ann_ids.extend(entity_id_to_ann_id[linked_entity])
194
194
  for ann_id in ann_ids:
195
195
  if ann_id != word.annotation_id:
196
- word.dump_relationship(Relationships.semantic_entity_link, ann_id)
196
+ word.dump_relationship(Relationships.SEMANTIC_ENTITY_LINK, ann_id)
197
197
 
198
198
  if mapping_context.context_error:
199
199
  return None
@@ -22,7 +22,6 @@ Contains pipeline components that can be plugged into each other and predictors
22
22
 
23
23
  from .anngen import *
24
24
  from .base import *
25
- from .cell import *
26
25
  from .common import *
27
26
  from .concurrency import *
28
27
  from .doctectionpipe import *
@@ -33,5 +32,6 @@ from .order import *
33
32
  from .refine import *
34
33
  from .registry import *
35
34
  from .segment import *
35
+ from .sub_layout import *
36
36
  from .text import *
37
37
  from .transform import *
@@ -19,11 +19,11 @@
19
19
  Module for datapoint populating helpers
20
20
  """
21
21
  from dataclasses import asdict
22
- from typing import Dict, List, Mapping, Optional, Union
22
+ from typing import Mapping, Optional, Union
23
23
 
24
24
  import numpy as np
25
25
 
26
- from ..datapoint.annotation import CategoryAnnotation, ContainerAnnotation, ImageAnnotation, SummaryAnnotation
26
+ from ..datapoint.annotation import DEFAULT_CATEGORY_ID, CategoryAnnotation, ContainerAnnotation, ImageAnnotation
27
27
  from ..datapoint.box import BoundingBox, local_to_global_coords, rescale_coords
28
28
  from ..datapoint.image import Image
29
29
  from ..extern.base import DetectionResult
@@ -44,7 +44,7 @@ class DatapointManager:
44
44
 
45
45
  def __init__(self, service_id: str, model_id: Optional[str] = None) -> None:
46
46
  self._datapoint: Optional[Image] = None
47
- self._cache_anns: Dict[str, ImageAnnotation] = {}
47
+ self._cache_anns: dict[str, ImageAnnotation] = {}
48
48
  self.datapoint_is_passed: bool = False
49
49
  self.category_id_mapping: Optional[Mapping[int, int]] = None
50
50
  self.service_id = service_id
@@ -155,7 +155,7 @@ class DatapointManager:
155
155
  ann = ImageAnnotation(
156
156
  category_name=detect_result.class_name,
157
157
  bounding_box=box,
158
- category_id=str(detect_result.class_id),
158
+ category_id=detect_result.class_id,
159
159
  score=detect_result.score,
160
160
  service_id=self.service_id,
161
161
  model_id=self.model_id,
@@ -174,7 +174,7 @@ class DatapointManager:
174
174
  raise ValueError("image cannot be None")
175
175
  ann.image.set_embedding(parent_ann.annotation_id, ann.bounding_box)
176
176
  ann.image.set_embedding(self.datapoint.image_id, ann_global_box)
177
- parent_ann.dump_relationship(Relationships.child, ann.annotation_id)
177
+ parent_ann.dump_relationship(Relationships.CHILD, ann.annotation_id)
178
178
 
179
179
  self.datapoint.dump(ann)
180
180
  self._cache_anns[ann.annotation_id] = ann
@@ -189,7 +189,7 @@ class DatapointManager:
189
189
  def set_category_annotation(
190
190
  self,
191
191
  category_name: ObjectTypes,
192
- category_id: Optional[Union[str, int]],
192
+ category_id: Optional[int],
193
193
  sub_cat_key: ObjectTypes,
194
194
  annotation_id: str,
195
195
  score: Optional[float] = None,
@@ -216,7 +216,7 @@ class DatapointManager:
216
216
  ) as annotation_context:
217
217
  cat_ann = CategoryAnnotation(
218
218
  category_name=category_name,
219
- category_id=str(category_id),
219
+ category_id=category_id if category_id is not None else DEFAULT_CATEGORY_ID,
220
220
  score=score,
221
221
  service_id=self.service_id,
222
222
  model_id=self.model_id,
@@ -230,10 +230,10 @@ class DatapointManager:
230
230
  def set_container_annotation(
231
231
  self,
232
232
  category_name: ObjectTypes,
233
- category_id: Optional[Union[str, int]],
233
+ category_id: Optional[int],
234
234
  sub_cat_key: ObjectTypes,
235
235
  annotation_id: str,
236
- value: Union[str, List[str]],
236
+ value: Union[str, list[str]],
237
237
  score: Optional[float] = None,
238
238
  ) -> Optional[str]:
239
239
  """
@@ -260,7 +260,7 @@ class DatapointManager:
260
260
  ) as annotation_context:
261
261
  cont_ann = ContainerAnnotation(
262
262
  category_name=category_name,
263
- category_id=str(category_id),
263
+ category_id=category_id if category_id is not None else DEFAULT_CATEGORY_ID,
264
264
  value=value,
265
265
  score=score,
266
266
  service_id=self.service_id,
@@ -299,8 +299,6 @@ class DatapointManager:
299
299
  else:
300
300
  image = self.datapoint
301
301
  assert image is not None, image
302
- if image.summary is None:
303
- image.summary = SummaryAnnotation()
304
302
 
305
303
  ann: Union[CategoryAnnotation, ContainerAnnotation]
306
304
  with MappingContextManager(
@@ -316,7 +314,7 @@ class DatapointManager:
316
314
  if summary_value is not None:
317
315
  ann = ContainerAnnotation(
318
316
  category_name=summary_name,
319
- category_id=str(summary_number) if summary_number is not None else "",
317
+ category_id=summary_number if summary_number else DEFAULT_CATEGORY_ID,
320
318
  value=summary_value,
321
319
  score=summary_score,
322
320
  service_id=self.service_id,
@@ -326,7 +324,7 @@ class DatapointManager:
326
324
  else:
327
325
  ann = CategoryAnnotation(
328
326
  category_name=summary_name,
329
- category_id=str(summary_number) if summary_number is not None else "",
327
+ category_id=summary_number if summary_number is not None else DEFAULT_CATEGORY_ID,
330
328
  score=summary_score,
331
329
  service_id=self.service_id,
332
330
  model_id=self.model_id,
@@ -19,21 +19,33 @@
19
19
  """
20
20
  Module for the base class for building pipelines
21
21
  """
22
+ from __future__ import annotations
23
+
22
24
  from abc import ABC, abstractmethod
23
25
  from collections import defaultdict
24
- from copy import deepcopy
25
- from typing import Any, Callable, DefaultDict, Dict, List, Mapping, Optional, Set, Union
26
+ from dataclasses import dataclass, field
27
+ from typing import Any, Mapping, Optional, Union
26
28
  from uuid import uuid1
27
29
 
28
30
  from ..dataflow import DataFlow, MapData
29
31
  from ..datapoint.image import Image
30
- from ..extern.base import ImageTransformer, ObjectDetector, PdfMiner, TextRecognizer
31
32
  from ..utils.context import timed_operation
32
- from ..utils.detection_types import JsonDict
33
33
  from ..utils.identifier import get_uuid_from_str
34
+ from ..utils.settings import ObjectTypes
34
35
  from .anngen import DatapointManager
35
36
 
36
37
 
38
+ @dataclass(frozen=True)
39
+ class MetaAnnotation:
40
+ """A immutable dataclass that stores information about what `Image` are being
41
+ modified through a pipeline compoenent."""
42
+
43
+ image_annotations: tuple[ObjectTypes, ...] = field(default=())
44
+ sub_categories: dict[ObjectTypes, set[ObjectTypes]] = field(default_factory=dict)
45
+ relationships: dict[ObjectTypes, set[ObjectTypes]] = field(default_factory=dict)
46
+ summaries: tuple[ObjectTypes, ...] = field(default=())
47
+
48
+
37
49
  class PipelineComponent(ABC):
38
50
  """
39
51
  Base class for pipeline components. Pipeline components are the parts that make up a pipeline. They contain the
@@ -54,15 +66,14 @@ class PipelineComponent(ABC):
54
66
  planned.
55
67
  """
56
68
 
57
- def __init__(self, name: str):
69
+ def __init__(self, name: str, model_id: Optional[str] = None) -> None:
58
70
  """
59
71
  :param name: The name of the pipeline component. The name will be used to identify a pipeline component in a
60
72
  pipeline. Use something that describe the task of the pipeline.
61
73
  """
62
74
  self.name = name
63
75
  self.service_id = self.get_service_id()
64
- self._meta_has_all_types()
65
- self.dp_manager = DatapointManager(self.service_id)
76
+ self.dp_manager = DatapointManager(self.service_id, model_id)
66
77
  self.timer_on = False
67
78
 
68
79
  @abstractmethod
@@ -108,14 +119,14 @@ class PipelineComponent(ABC):
108
119
  return MapData(df, self.pass_datapoint)
109
120
 
110
121
  @abstractmethod
111
- def clone(self) -> "PipelineComponent":
122
+ def clone(self) -> PipelineComponent:
112
123
  """
113
124
  Clone an instance
114
125
  """
115
126
  raise NotImplementedError()
116
127
 
117
128
  @abstractmethod
118
- def get_meta_annotation(self) -> JsonDict:
129
+ def get_meta_annotation(self) -> MetaAnnotation:
119
130
  """
120
131
  Get a dict of list of annotation type. The dict must contain
121
132
 
@@ -127,96 +138,30 @@ class PipelineComponent(ABC):
127
138
  """
128
139
  raise NotImplementedError()
129
140
 
130
- def _meta_has_all_types(self) -> None:
131
- if not {"image_annotations", "sub_categories", "relationships", "summaries"}.issubset(
132
- set(self.get_meta_annotation().keys())
133
- ):
134
- raise TypeError(
135
- f" 'get_meta_annotation' must return dict with all required keys. "
136
- f"Got {self.get_meta_annotation().keys()}"
137
- )
138
-
139
141
  def get_service_id(self) -> str:
140
142
  """
141
143
  Get the generating model
142
144
  """
143
145
  return get_uuid_from_str(self.name)[:8]
144
146
 
145
-
146
- class PredictorPipelineComponent(PipelineComponent, ABC):
147
- """
148
- Lightweight abstract pipeline component class with `predictor`. Object detectors that only read in images as
149
- numpy array and return `DetectResult`s are currently permitted.
150
- """
151
-
152
- def __init__(
153
- self,
154
- name: str,
155
- predictor: Union[ObjectDetector, PdfMiner, TextRecognizer],
156
- ) -> None:
147
+ def clear_predictor(self) -> None:
157
148
  """
158
- :param name: Will be passed to base class
159
- :param predictor: An Object detector for predicting
149
+ Clear the predictor of the pipeline component if it has one. Needed for model updates during training.
160
150
  """
161
- self.predictor = predictor
162
- super().__init__(name)
163
- self.dp_manager = DatapointManager(self.service_id, self.predictor.model_id)
151
+ raise NotImplementedError(
152
+ "Maybe you forgot to implement this method in your pipeline component. This might "
153
+ "be the case when you run evaluation during training and need to update the "
154
+ "trained model in your pipeline component."
155
+ )
164
156
 
165
- @abstractmethod
166
- def clone(self) -> "PredictorPipelineComponent":
167
- raise NotImplementedError()
168
-
169
-
170
- class LanguageModelPipelineComponent(PipelineComponent, ABC):
171
- """
172
- Abstract pipeline component class with two attributes `tokenizer` and `language_model` .
173
- """
174
-
175
- def __init__(
176
- self,
177
- name: str,
178
- tokenizer: Any,
179
- mapping_to_lm_input_func: Callable[..., Callable[[Image], Optional[Any]]],
180
- ):
157
+ def has_predictor(self) -> bool:
181
158
  """
182
- :param name: Will be passed to base class
183
- :param tokenizer: Tokenizer, typing allows currently anything. This will be changed in the future
184
- :param mapping_to_lm_input_func: Function mapping image to layout language model features
159
+ Check if the pipeline component has a predictor
185
160
  """
186
-
187
- self.tokenizer = tokenizer
188
- super().__init__(name)
189
- self.mapping_to_lm_input_func = mapping_to_lm_input_func
190
-
191
- @abstractmethod
192
- def clone(self) -> "LanguageModelPipelineComponent":
193
- """
194
- Clone an instance
195
- """
196
- raise NotImplementedError()
197
-
198
-
199
- class ImageTransformPipelineComponent(PipelineComponent, ABC):
200
- """
201
- Abstract pipeline component class with one model to transform images. This component is meant to be used at the
202
- beginning of a pipeline
203
- """
204
-
205
- def __init__(self, name: str, transform_predictor: ImageTransformer):
206
- """
207
- :param name: Will be passed to base class
208
- :param transform_predictor: An `ImageTransformer` for image transformation
209
- """
210
-
211
- self.transform_predictor = transform_predictor
212
- super().__init__(name)
213
-
214
- @abstractmethod
215
- def clone(self) -> "ImageTransformPipelineComponent":
216
- """
217
- Clone an instance
218
- """
219
- raise NotImplementedError()
161
+ if hasattr(self, "predictor"):
162
+ if self.predictor is not None:
163
+ return True
164
+ return False
220
165
 
221
166
 
222
167
  class Pipeline(ABC):
@@ -262,7 +207,7 @@ class Pipeline(ABC):
262
207
  df = pipe.analyze(input = "path/to/dir") # session_id is generated automatically
263
208
  """
264
209
 
265
- def __init__(self, pipeline_component_list: List[PipelineComponent]) -> None:
210
+ def __init__(self, pipeline_component_list: list[PipelineComponent]) -> None:
266
211
  """
267
212
  :param pipeline_component_list: A list of pipeline components.
268
213
  """
@@ -305,7 +250,7 @@ class Pipeline(ABC):
305
250
  """
306
251
  raise NotImplementedError()
307
252
 
308
- def get_meta_annotation(self) -> JsonDict:
253
+ def get_meta_annotation(self) -> MetaAnnotation:
309
254
  """
310
255
  Collects meta annotations from all pipeline components and summarizes the returned results
311
256
 
@@ -313,23 +258,24 @@ class Pipeline(ABC):
313
258
  names and generated sub categories), relationships (dict with category names and generated
314
259
  relationships) as well as summaries (list with sub categories)
315
260
  """
316
- pipeline_populations: Dict[str, Union[List[str], DefaultDict[str, Set[str]]]] = {
317
- "image_annotations": [],
318
- "sub_categories": defaultdict(set),
319
- "relationships": defaultdict(set),
320
- "summaries": [],
321
- }
261
+ image_annotations: list[ObjectTypes] = []
262
+ sub_categories = defaultdict(set)
263
+ relationships = defaultdict(set)
264
+ summaries: list[ObjectTypes] = []
322
265
  for component in self.pipe_component_list:
323
- meta_anns = deepcopy(component.get_meta_annotation())
324
- pipeline_populations["image_annotations"].extend(meta_anns["image_annotations"]) # type: ignore
325
- for key, value in meta_anns["sub_categories"].items():
326
- pipeline_populations["sub_categories"][key].update(value)
327
- for key, value in meta_anns["relationships"].items():
328
- pipeline_populations["relationships"][key].update(value)
329
- pipeline_populations["summaries"].extend(meta_anns["summaries"]) # type: ignore
330
- pipeline_populations["sub_categories"] = dict(pipeline_populations["sub_categories"]) # type: ignore
331
- pipeline_populations["relationships"] = dict(pipeline_populations["relationships"]) # type: ignore
332
- return pipeline_populations
266
+ meta_anns = component.get_meta_annotation()
267
+ image_annotations.extend(meta_anns.image_annotations)
268
+ for key, value in meta_anns.sub_categories.items():
269
+ sub_categories[key].update(value)
270
+ for key, value in meta_anns.relationships.items():
271
+ relationships[key].update(value)
272
+ summaries.extend(meta_anns.summaries)
273
+ return MetaAnnotation(
274
+ image_annotations=tuple(image_annotations),
275
+ sub_categories=dict(sub_categories),
276
+ relationships=dict(relationships),
277
+ summaries=tuple(summaries),
278
+ )
333
279
 
334
280
  def get_pipeline_info(
335
281
  self, service_id: Optional[str] = None, name: Optional[str] = None