indico_toolkit 6.14.0__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.
- indico_toolkit/__init__.py +24 -0
- indico_toolkit/association/__init__.py +15 -0
- indico_toolkit/association/association.py +65 -0
- indico_toolkit/association/extracted_tokens.py +106 -0
- indico_toolkit/association/line_items.py +189 -0
- indico_toolkit/association/positioning.py +301 -0
- indico_toolkit/association/splitting.py +41 -0
- indico_toolkit/auto_populate/__init__.py +3 -0
- indico_toolkit/auto_populate/populator.py +362 -0
- indico_toolkit/auto_populate/types.py +66 -0
- indico_toolkit/auto_review/__init__.py +6 -0
- indico_toolkit/auto_review/auto_review_functions.py +123 -0
- indico_toolkit/auto_review/auto_reviewer.py +62 -0
- indico_toolkit/client.py +35 -0
- indico_toolkit/errors.py +32 -0
- indico_toolkit/etloutput/__init__.py +210 -0
- indico_toolkit/etloutput/cell.py +47 -0
- indico_toolkit/etloutput/errors.py +16 -0
- indico_toolkit/etloutput/etloutput.py +110 -0
- indico_toolkit/etloutput/range.py +30 -0
- indico_toolkit/etloutput/table.py +44 -0
- indico_toolkit/etloutput/token.py +25 -0
- indico_toolkit/indico_wrapper/__init__.py +15 -0
- indico_toolkit/indico_wrapper/dataset.py +114 -0
- indico_toolkit/indico_wrapper/doc_extraction.py +79 -0
- indico_toolkit/indico_wrapper/download.py +193 -0
- indico_toolkit/indico_wrapper/indico_wrapper.py +119 -0
- indico_toolkit/indico_wrapper/modelop.py +200 -0
- indico_toolkit/indico_wrapper/reviewer.py +111 -0
- indico_toolkit/indico_wrapper/workflow.py +231 -0
- indico_toolkit/metrics/__init__.py +11 -0
- indico_toolkit/metrics/compare_ground_truth.py +123 -0
- indico_toolkit/metrics/compare_models.py +180 -0
- indico_toolkit/metrics/metrics.py +373 -0
- indico_toolkit/metrics/plotting.py +102 -0
- indico_toolkit/ocr/__init__.py +9 -0
- indico_toolkit/ocr/customocr_object.py +42 -0
- indico_toolkit/ocr/ondoc_object.py +93 -0
- indico_toolkit/ocr/standard_object.py +54 -0
- indico_toolkit/pipelines/__init__.py +3 -0
- indico_toolkit/pipelines/file_processing.py +157 -0
- indico_toolkit/polling/__init__.py +8 -0
- indico_toolkit/polling/autoreview.py +204 -0
- indico_toolkit/polling/downstream.py +145 -0
- indico_toolkit/polling/queries.py +68 -0
- indico_toolkit/py.typed +0 -0
- indico_toolkit/results/__init__.py +104 -0
- indico_toolkit/results/document.py +78 -0
- indico_toolkit/results/errors.py +4 -0
- indico_toolkit/results/model.py +60 -0
- indico_toolkit/results/normalization.py +159 -0
- indico_toolkit/results/predictionlist.py +395 -0
- indico_toolkit/results/predictions/__init__.py +88 -0
- indico_toolkit/results/predictions/box.py +58 -0
- indico_toolkit/results/predictions/citation.py +47 -0
- indico_toolkit/results/predictions/classification.py +50 -0
- indico_toolkit/results/predictions/documentextraction.py +160 -0
- indico_toolkit/results/predictions/extraction.py +35 -0
- indico_toolkit/results/predictions/formextraction.py +121 -0
- indico_toolkit/results/predictions/group.py +29 -0
- indico_toolkit/results/predictions/prediction.py +41 -0
- indico_toolkit/results/predictions/span.py +43 -0
- indico_toolkit/results/predictions/summarization.py +103 -0
- indico_toolkit/results/predictions/unbundling.py +51 -0
- indico_toolkit/results/result.py +152 -0
- indico_toolkit/results/review.py +32 -0
- indico_toolkit/results/utilities.py +73 -0
- indico_toolkit/retry.py +94 -0
- indico_toolkit/snapshots/__init__.py +3 -0
- indico_toolkit/snapshots/snapshot.py +340 -0
- indico_toolkit/structure/__init__.py +3 -0
- indico_toolkit/structure/create_structure.py +232 -0
- indico_toolkit/structure/queries.py +119 -0
- indico_toolkit/structure/utils.py +16 -0
- indico_toolkit/types/__init__.py +12 -0
- indico_toolkit/types/classification.py +92 -0
- indico_toolkit/types/extractions.py +227 -0
- indico_toolkit/types/predictions.py +28 -0
- indico_toolkit/types/workflow_object.py +133 -0
- indico_toolkit-6.14.0.dist-info/LICENSE +21 -0
- indico_toolkit-6.14.0.dist-info/METADATA +144 -0
- indico_toolkit-6.14.0.dist-info/RECORD +83 -0
- indico_toolkit-6.14.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Classes, functions, and abstractions for Indico IPA"""
|
|
2
|
+
|
|
3
|
+
from .client import create_client
|
|
4
|
+
from .errors import (
|
|
5
|
+
ToolkitAuthError,
|
|
6
|
+
ToolkitError,
|
|
7
|
+
ToolkitInputError,
|
|
8
|
+
ToolkitInstantiationError,
|
|
9
|
+
ToolkitPopulationError,
|
|
10
|
+
ToolkitStaggeredLoopError,
|
|
11
|
+
ToolkitStatusError,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = (
|
|
15
|
+
"create_client",
|
|
16
|
+
"ToolkitAuthError",
|
|
17
|
+
"ToolkitError",
|
|
18
|
+
"ToolkitInputError",
|
|
19
|
+
"ToolkitInstantiationError",
|
|
20
|
+
"ToolkitPopulationError",
|
|
21
|
+
"ToolkitStaggeredLoopError",
|
|
22
|
+
"ToolkitStatusError",
|
|
23
|
+
)
|
|
24
|
+
__version__ = "6.14.0"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from .association import Association, sequences_exact, sequences_overlap
|
|
2
|
+
from .extracted_tokens import ExtractedTokens
|
|
3
|
+
from .line_items import LineItems
|
|
4
|
+
from .positioning import Positioning
|
|
5
|
+
from .splitting import split_prediction
|
|
6
|
+
|
|
7
|
+
__all__ = (
|
|
8
|
+
"Association",
|
|
9
|
+
"ExtractedTokens",
|
|
10
|
+
"LineItems",
|
|
11
|
+
"Positioning",
|
|
12
|
+
"sequences_exact",
|
|
13
|
+
"sequences_overlap",
|
|
14
|
+
"split_prediction",
|
|
15
|
+
)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
from typing import Dict, List, Union
|
|
4
|
+
|
|
5
|
+
from ..types import Extractions
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Association(ABC):
|
|
9
|
+
"""
|
|
10
|
+
Base class for matching tokens to extraction predictions.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, predictions: Union[List[dict], Extractions]):
|
|
14
|
+
self._predictions = self.validate_prediction_formatting(predictions)
|
|
15
|
+
self._mapped_positions = []
|
|
16
|
+
self._manually_added_preds = []
|
|
17
|
+
self._errored_predictions = []
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def match_pred_to_token(self):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
@staticmethod
|
|
24
|
+
def sort_predictions_by_start_index(predictions: List[dict]) -> List[dict]:
|
|
25
|
+
return sorted(predictions, key=lambda x: x["start"])
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def mapped_positions_by_page(self) -> Dict[int, List[dict]]:
|
|
29
|
+
"""
|
|
30
|
+
Return mapped positions by page on which they first appear
|
|
31
|
+
"""
|
|
32
|
+
page_map = defaultdict(list)
|
|
33
|
+
for position in self._mapped_positions:
|
|
34
|
+
page_map[position["page_num"]].append(position)
|
|
35
|
+
return page_map
|
|
36
|
+
|
|
37
|
+
def validate_prediction_formatting(
|
|
38
|
+
self, predictions: Union[List[dict], Extractions]
|
|
39
|
+
) -> List[dict]:
|
|
40
|
+
if isinstance(predictions, Extractions):
|
|
41
|
+
predictions = predictions.to_list()
|
|
42
|
+
return predictions
|
|
43
|
+
|
|
44
|
+
def _is_manually_added_pred(self, prediction: dict) -> bool:
|
|
45
|
+
return Extractions.is_manually_added_prediction(prediction)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def sequences_overlap(x: dict, y: dict) -> bool:
|
|
49
|
+
"""
|
|
50
|
+
Boolean return value indicates whether or not seqs overlap
|
|
51
|
+
"""
|
|
52
|
+
return x["start"] < y["end"] and y["start"] < x["end"]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def sequences_exact(x: dict, y: dict) -> bool:
|
|
56
|
+
"""
|
|
57
|
+
Boolean return value indicates whether or not seqs are exact
|
|
58
|
+
"""
|
|
59
|
+
return x["start"] == y["start"] and x["end"] == y["end"]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _check_if_token_match_found(pred: dict, no_match_indicator: bool):
|
|
63
|
+
if no_match_indicator:
|
|
64
|
+
pred["error"] = "No matching token found for extraction"
|
|
65
|
+
raise ValueError(f"Couldn't match a token to this prediction:\n{pred}")
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from typing import List, Union
|
|
2
|
+
|
|
3
|
+
from ..types import Extractions
|
|
4
|
+
from .association import Association, _check_if_token_match_found, sequences_overlap
|
|
5
|
+
|
|
6
|
+
# TODO: add test that 'errored_predictions' actually works with ValueErrors
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ExtractedTokens(Association):
|
|
10
|
+
"""
|
|
11
|
+
Class to collect all extracted tokens, e.g. to enable highlighting of source
|
|
12
|
+
document
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, predictions: Union[List[dict], Extractions]):
|
|
16
|
+
super().__init__(predictions)
|
|
17
|
+
|
|
18
|
+
def match_pred_to_token(self, pred: dict, ocr_tokens: List[dict], pred_index: int):
|
|
19
|
+
"""
|
|
20
|
+
Append matching token positions to self.mapped_positions, if no matches for
|
|
21
|
+
pred, raise ValueError
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
pred (dict): Indico extraction model prediction
|
|
25
|
+
ocr_tokens (List[dict]): List of OCR tokens
|
|
26
|
+
pred_index (int): unique number for each prediction so that tokens can be
|
|
27
|
+
linked to it
|
|
28
|
+
|
|
29
|
+
Raises:
|
|
30
|
+
ValueError: No matching token was found
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
[int]: index in ocr tokens where prediction matched
|
|
34
|
+
"""
|
|
35
|
+
no_match = True
|
|
36
|
+
match_token_index = 0
|
|
37
|
+
pred["prediction_index"] = pred_index
|
|
38
|
+
for ind, token in enumerate(ocr_tokens):
|
|
39
|
+
if sequences_overlap(token["doc_offset"], pred):
|
|
40
|
+
self._add_pred_meta_to_token(token, pred, pred_index)
|
|
41
|
+
self._remove_unneeded_token_keys(token)
|
|
42
|
+
self._mapped_positions.append(token)
|
|
43
|
+
match_token_index = ind
|
|
44
|
+
no_match = False
|
|
45
|
+
elif token["doc_offset"]["start"] > pred["end"]:
|
|
46
|
+
break
|
|
47
|
+
_check_if_token_match_found(pred, no_match)
|
|
48
|
+
return match_token_index
|
|
49
|
+
|
|
50
|
+
def collect_tokens(self, ocr_tokens: List[dict], raise_for_no_match: bool = True):
|
|
51
|
+
"""
|
|
52
|
+
Collect all extracted tokens and with pred text and label added to dictionaries
|
|
53
|
+
Args:
|
|
54
|
+
ocr_tokens (List[dict]): Tokens from 'ondocument' OCR config output
|
|
55
|
+
raise_for_no_match (bool): raise exception if a matching token isn't found for a
|
|
56
|
+
prediction
|
|
57
|
+
"""
|
|
58
|
+
self._separate_manually_added_predictions()
|
|
59
|
+
self._predictions = self.sort_predictions_by_start_index(self._predictions)
|
|
60
|
+
match_index = 0
|
|
61
|
+
for pred_ind, pred in enumerate(self._predictions):
|
|
62
|
+
try:
|
|
63
|
+
match_index = self.match_pred_to_token(
|
|
64
|
+
pred, ocr_tokens[match_index:], pred_ind
|
|
65
|
+
)
|
|
66
|
+
except ValueError as e:
|
|
67
|
+
if raise_for_no_match:
|
|
68
|
+
raise ValueError(e)
|
|
69
|
+
else:
|
|
70
|
+
print(f"Ignoring Error: {e}")
|
|
71
|
+
self._errored_predictions.append(pred)
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def extracted_tokens(self) -> List[dict]:
|
|
75
|
+
return self._mapped_positions
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def predictions(self) -> Extractions:
|
|
79
|
+
return Extractions(
|
|
80
|
+
self._predictions + self._errored_predictions + self._manually_added_preds
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def unmapped_predictions(self) -> Extractions:
|
|
85
|
+
return Extractions(self._errored_predictions + self._manually_added_preds)
|
|
86
|
+
|
|
87
|
+
def _remove_unneeded_token_keys(
|
|
88
|
+
self, token: dict, keys: List[str] = ["style", "block_offset", "page_offset"]
|
|
89
|
+
):
|
|
90
|
+
for key in keys:
|
|
91
|
+
token.pop(key, None)
|
|
92
|
+
|
|
93
|
+
def _separate_manually_added_predictions(self):
|
|
94
|
+
predictions = []
|
|
95
|
+
for pred in self._predictions:
|
|
96
|
+
if self._is_manually_added_pred(pred):
|
|
97
|
+
pred["error"] = "Can't match tokens for manually added prediction"
|
|
98
|
+
self._manually_added_preds.append(pred)
|
|
99
|
+
else:
|
|
100
|
+
predictions.append(pred)
|
|
101
|
+
self._predictions = predictions
|
|
102
|
+
|
|
103
|
+
def _add_pred_meta_to_token(self, token: dict, pred: dict, pred_index: int):
|
|
104
|
+
token["label"] = pred["label"]
|
|
105
|
+
token["text"] = pred["text"]
|
|
106
|
+
token["prediction_index"] = pred_index
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""Associate row items"""
|
|
2
|
+
|
|
3
|
+
from collections import defaultdict
|
|
4
|
+
from copy import deepcopy
|
|
5
|
+
from typing import Iterable, List, Union
|
|
6
|
+
|
|
7
|
+
from ..types import Extractions
|
|
8
|
+
from .association import Association, _check_if_token_match_found, sequences_overlap
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LineItems(Association):
|
|
12
|
+
"""
|
|
13
|
+
Class for associating line items given extraction predictions and ondocument OCR
|
|
14
|
+
tokens
|
|
15
|
+
|
|
16
|
+
Example Usage:
|
|
17
|
+
|
|
18
|
+
litems = LineItems(
|
|
19
|
+
predictions=[{"label": "line_date", "start": 12, "text": "1/2/2021".....}],
|
|
20
|
+
line_item_fields=["line_value", "line_date"],
|
|
21
|
+
)
|
|
22
|
+
litems.get_bounding_boxes(ocr_tokens=[{"postion"...,},])
|
|
23
|
+
litems.assign_row_number()
|
|
24
|
+
|
|
25
|
+
# Get your updated predictions
|
|
26
|
+
print(litems.updated_predictions)
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
predictions: Union[List[dict], Extractions],
|
|
32
|
+
line_item_fields: Iterable[str],
|
|
33
|
+
):
|
|
34
|
+
"""
|
|
35
|
+
Args:
|
|
36
|
+
predictions (List[dict]): List of extraction predictions
|
|
37
|
+
line_item_fields (Iterable[str]): Fields/labels to include as line item values,
|
|
38
|
+
other values will not be assigned a row_number.
|
|
39
|
+
"""
|
|
40
|
+
self.predictions = self.validate_prediction_formatting(predictions)
|
|
41
|
+
self.line_item_fields: Iterable[str] = line_item_fields
|
|
42
|
+
self._mapped_positions: List[dict] = []
|
|
43
|
+
self._unmapped_positions: List[dict] = []
|
|
44
|
+
self._errored_predictions: List[dict] = []
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def updated_predictions(self) -> Extractions:
|
|
48
|
+
return Extractions(
|
|
49
|
+
self._mapped_positions
|
|
50
|
+
+ self._unmapped_positions
|
|
51
|
+
+ self._errored_predictions
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
@staticmethod
|
|
55
|
+
def match_pred_to_token(pred: dict, ocr_tokens: List[dict]):
|
|
56
|
+
"""
|
|
57
|
+
Match and add bounding box metadata to prediction.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
pred (dict): Indico extraction model prediction
|
|
61
|
+
ocr_tokens (List[dict]): List of OCR tokens
|
|
62
|
+
|
|
63
|
+
Raises:
|
|
64
|
+
ValueError: No matching token was found
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
[int]: index in ocr tokens where prediction matched
|
|
68
|
+
"""
|
|
69
|
+
no_match = True
|
|
70
|
+
match_token_index = 0
|
|
71
|
+
for ind, token in enumerate(ocr_tokens):
|
|
72
|
+
if no_match and sequences_overlap(token["doc_offset"], pred):
|
|
73
|
+
_add_bounding_metadata_to_pred(pred, token)
|
|
74
|
+
no_match = False
|
|
75
|
+
match_token_index = ind
|
|
76
|
+
elif sequences_overlap(token["doc_offset"], pred):
|
|
77
|
+
_update_bounding_metadata_for_pred(pred, token)
|
|
78
|
+
elif token["doc_offset"]["start"] > pred["end"]:
|
|
79
|
+
break
|
|
80
|
+
_check_if_token_match_found(pred, no_match)
|
|
81
|
+
return match_token_index
|
|
82
|
+
|
|
83
|
+
def get_bounding_boxes(
|
|
84
|
+
self, ocr_tokens: List[dict], raise_for_no_match: bool = True
|
|
85
|
+
):
|
|
86
|
+
"""
|
|
87
|
+
Adds keys for bounding box top/bottom/left/right and page number to line item
|
|
88
|
+
predictions
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
ocr_tokens (List[dict]): Tokens from 'ondocument' OCR config output
|
|
92
|
+
raise_for_no_match (bool): raise exception if a matching token isn't found for a
|
|
93
|
+
prediction
|
|
94
|
+
"""
|
|
95
|
+
predictions = deepcopy(self.predictions)
|
|
96
|
+
predictions = self._remove_unneeded_predictions(predictions)
|
|
97
|
+
predictions = self.sort_predictions_by_start_index(predictions)
|
|
98
|
+
match_index = 0
|
|
99
|
+
for pred in predictions:
|
|
100
|
+
try:
|
|
101
|
+
match_index = self.match_pred_to_token(pred, ocr_tokens[match_index:])
|
|
102
|
+
self._mapped_positions.append(pred)
|
|
103
|
+
except ValueError as e:
|
|
104
|
+
if raise_for_no_match:
|
|
105
|
+
raise e
|
|
106
|
+
else:
|
|
107
|
+
print(f"Ignoring Error: {e}")
|
|
108
|
+
self._errored_predictions.append(pred)
|
|
109
|
+
|
|
110
|
+
def assign_row_number(self):
|
|
111
|
+
"""
|
|
112
|
+
Adds a row_number:int key/val pair based on bounding box position and page
|
|
113
|
+
|
|
114
|
+
Updates:
|
|
115
|
+
self._mapped_positions (list of dicts): predictions with row_number added
|
|
116
|
+
"""
|
|
117
|
+
self._mapped_positions = sorted(
|
|
118
|
+
self._mapped_positions,
|
|
119
|
+
key=lambda x: (x["page_num"], x["bbTop"], x["bbLeft"]),
|
|
120
|
+
)
|
|
121
|
+
starting_pred = self._get_first_valid_line_item_pred()
|
|
122
|
+
max_bot = starting_pred["bbBot"]
|
|
123
|
+
page_number = starting_pred["page_num"]
|
|
124
|
+
row_number = 1
|
|
125
|
+
for pred in self._mapped_positions:
|
|
126
|
+
# if the top of one box equals the bottom of another, we still want a new
|
|
127
|
+
# line
|
|
128
|
+
if pred["bbTop"] >= max_bot or pred["page_num"] != page_number:
|
|
129
|
+
row_number += 1
|
|
130
|
+
page_number = pred["page_num"]
|
|
131
|
+
max_bot = pred["bbBot"]
|
|
132
|
+
else:
|
|
133
|
+
max_bot = max(pred["bbBot"], max_bot)
|
|
134
|
+
pred["row_number"] = row_number
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def grouped_line_items(self) -> List[List[dict]]:
|
|
138
|
+
"""
|
|
139
|
+
After row number has been assigned to predictions, returns line item predictions
|
|
140
|
+
as a list of lists where each list is a row.
|
|
141
|
+
"""
|
|
142
|
+
rows = defaultdict(list)
|
|
143
|
+
for pred in self._mapped_positions:
|
|
144
|
+
rows[pred["row_number"]].append(pred)
|
|
145
|
+
return list(rows.values())
|
|
146
|
+
|
|
147
|
+
def _remove_unneeded_predictions(self, predictions: List[dict]) -> List[dict]:
|
|
148
|
+
"""
|
|
149
|
+
Remove predictions that are not line item fields or don't have valid start/end
|
|
150
|
+
index data
|
|
151
|
+
"""
|
|
152
|
+
valid_line_item_preds = []
|
|
153
|
+
for pred in predictions:
|
|
154
|
+
if not self.is_line_item_pred(pred):
|
|
155
|
+
self._unmapped_positions.append(pred)
|
|
156
|
+
elif self._is_manually_added_pred(pred):
|
|
157
|
+
pred["error"] = "Can't match tokens for manually added prediction"
|
|
158
|
+
self._errored_predictions.append(pred)
|
|
159
|
+
else:
|
|
160
|
+
valid_line_item_preds.append(pred)
|
|
161
|
+
return valid_line_item_preds
|
|
162
|
+
|
|
163
|
+
def is_line_item_pred(self, pred: dict):
|
|
164
|
+
if pred["label"] in self.line_item_fields:
|
|
165
|
+
return True
|
|
166
|
+
return False
|
|
167
|
+
|
|
168
|
+
def _get_first_valid_line_item_pred(self) -> dict:
|
|
169
|
+
if len(self._mapped_positions) == 0:
|
|
170
|
+
raise RuntimeError(
|
|
171
|
+
"Whoops! You have no line_item_fields predictions. "
|
|
172
|
+
"Did you run get_bounding_boxes?"
|
|
173
|
+
)
|
|
174
|
+
return self._mapped_positions[0]
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _add_bounding_metadata_to_pred(pred: dict, token: dict):
|
|
178
|
+
pred["bbTop"] = token["position"]["bbTop"]
|
|
179
|
+
pred["bbBot"] = token["position"]["bbBot"]
|
|
180
|
+
pred["bbLeft"] = token["position"]["bbLeft"]
|
|
181
|
+
pred["bbRight"] = token["position"]["bbRight"]
|
|
182
|
+
pred["page_num"] = token["page_num"]
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _update_bounding_metadata_for_pred(pred: dict, token: dict):
|
|
186
|
+
pred["bbTop"] = min(token["position"]["bbTop"], pred["bbTop"])
|
|
187
|
+
pred["bbBot"] = max(token["position"]["bbBot"], pred["bbBot"])
|
|
188
|
+
pred["bbLeft"] = min(token["position"]["bbLeft"], pred["bbLeft"])
|
|
189
|
+
pred["bbRight"] = max(token["position"]["bbRight"], pred["bbRight"])
|