rapidata 2.3.1__py3-none-any.whl → 2.4.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.
Potentially problematic release.
This version of rapidata might be problematic. Click here for more details.
- rapidata/__init__.py +1 -1
- rapidata/api_client/__init__.py +2 -0
- rapidata/api_client/api/rapid_api.py +268 -0
- rapidata/api_client/models/__init__.py +2 -0
- rapidata/api_client/models/add_validation_rapid_model.py +9 -2
- rapidata/api_client/models/add_validation_text_rapid_model.py +9 -2
- rapidata/api_client/models/query_validation_rapids_result.py +7 -3
- rapidata/api_client/models/rapid_issue.py +41 -0
- rapidata/api_client/models/report_model.py +103 -0
- rapidata/api_client_README.md +3 -0
- rapidata/rapidata_client/assets/_media_asset.py +0 -1
- rapidata/rapidata_client/selection/rapidata_selections.py +11 -1
- rapidata/rapidata_client/validation/rapidata_validation_set.py +2 -291
- rapidata/rapidata_client/validation/rapids/rapids.py +72 -125
- rapidata/rapidata_client/validation/rapids/rapids_manager.py +206 -42
- rapidata/rapidata_client/validation/validation_set_manager.py +108 -69
- {rapidata-2.3.1.dist-info → rapidata-2.4.0.dist-info}/METADATA +1 -1
- {rapidata-2.3.1.dist-info → rapidata-2.4.0.dist-info}/RECORD +20 -20
- rapidata/rapidata_client/validation/_validation_rapid_parts.py +0 -61
- rapidata/rapidata_client/validation/_validation_set_builder.py +0 -481
- {rapidata-2.3.1.dist-info → rapidata-2.4.0.dist-info}/LICENSE +0 -0
- {rapidata-2.3.1.dist-info → rapidata-2.4.0.dist-info}/WHEEL +0 -0
|
@@ -1,17 +1,14 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from rapidata.api_client import AttachCategoryTruth, BoundingBoxTruth, BoxShape, ClassifyPayload, ComparePayload, CompareTruth, LinePayload, LocateBoxTruth, LocatePayload, ScrubPayload, ScrubRange, ScrubTruth, TranscriptionPayload, TranscriptionTruth, TranscriptionWord
|
|
1
3
|
from rapidata.rapidata_client.assets.data_type_enum import RapidataDataTypes
|
|
2
|
-
from rapidata.rapidata_client.validation.rapids.rapids import (
|
|
3
|
-
ClassificationRapid,
|
|
4
|
-
CompareRapid,
|
|
5
|
-
SelectWordsRapid,
|
|
6
|
-
LocateRapid,
|
|
7
|
-
DrawRapid,
|
|
8
|
-
TimestampRapid)
|
|
9
4
|
from rapidata.rapidata_client.assets import MediaAsset, TextAsset, MultiAsset
|
|
10
5
|
from rapidata.rapidata_client.metadata import Metadata
|
|
11
6
|
from rapidata.rapidata_client.validation.rapids.box import Box
|
|
12
7
|
|
|
13
8
|
from typing import Sequence
|
|
14
9
|
|
|
10
|
+
from rapidata.rapidata_client.validation.rapids.rapids import Rapid
|
|
11
|
+
|
|
15
12
|
class RapidsManager:
|
|
16
13
|
"""
|
|
17
14
|
Can be used to build different types of rapids. That can then be added to Validation sets
|
|
@@ -26,7 +23,8 @@ class RapidsManager:
|
|
|
26
23
|
truths: list[str],
|
|
27
24
|
data_type: str = RapidataDataTypes.MEDIA,
|
|
28
25
|
metadata: Sequence[Metadata] = [],
|
|
29
|
-
|
|
26
|
+
explanation: str | None = None,
|
|
27
|
+
) -> Rapid:
|
|
30
28
|
"""Build a classification rapid
|
|
31
29
|
|
|
32
30
|
Args:
|
|
@@ -45,13 +43,24 @@ class RapidsManager:
|
|
|
45
43
|
else:
|
|
46
44
|
raise ValueError(f"Unsupported data type: {data_type}")
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
if not all(truth in answer_options for truth in truths):
|
|
47
|
+
raise ValueError("Truths must be part of the answer options")
|
|
48
|
+
|
|
49
|
+
payload = ClassifyPayload(
|
|
50
|
+
_t="ClassifyPayload", possibleCategories=answer_options, title=instruction
|
|
51
|
+
)
|
|
52
|
+
model_truth = AttachCategoryTruth(
|
|
53
|
+
correctCategories=truths, _t="AttachCategoryTruth"
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
return Rapid(
|
|
51
57
|
asset=asset,
|
|
52
|
-
truths=truths,
|
|
53
58
|
metadata=metadata,
|
|
54
|
-
|
|
59
|
+
explanation=explanation,
|
|
60
|
+
payload=payload,
|
|
61
|
+
truth=model_truth,
|
|
62
|
+
randomCorrectProbability=len(truths) / len(answer_options)
|
|
63
|
+
)
|
|
55
64
|
|
|
56
65
|
def compare_rapid(self,
|
|
57
66
|
instruction: str,
|
|
@@ -59,7 +68,8 @@ class RapidsManager:
|
|
|
59
68
|
datapoint: list[str],
|
|
60
69
|
data_type: str = RapidataDataTypes.MEDIA,
|
|
61
70
|
metadata: Sequence[Metadata] = [],
|
|
62
|
-
|
|
71
|
+
explanation: str | None = None,
|
|
72
|
+
) -> Rapid:
|
|
63
73
|
"""Build a compare rapid
|
|
64
74
|
|
|
65
75
|
Args:
|
|
@@ -78,12 +88,23 @@ class RapidsManager:
|
|
|
78
88
|
raise ValueError(f"Unsupported data type: {data_type}")
|
|
79
89
|
|
|
80
90
|
asset = MultiAsset(assets)
|
|
91
|
+
|
|
92
|
+
payload = ComparePayload(_t="ComparePayload", criteria=instruction)
|
|
93
|
+
# take only last part of truth path
|
|
94
|
+
truth = os.path.basename(truth)
|
|
95
|
+
model_truth = CompareTruth(_t="CompareTruth", winnerId=truth)
|
|
81
96
|
|
|
82
|
-
|
|
83
|
-
|
|
97
|
+
if len(asset) != 2:
|
|
98
|
+
raise ValueError("Compare rapid requires exactly two media paths")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
return Rapid(
|
|
84
102
|
asset=asset,
|
|
85
|
-
truth=
|
|
103
|
+
truth=model_truth,
|
|
86
104
|
metadata=metadata,
|
|
105
|
+
payload=payload,
|
|
106
|
+
explanation=explanation,
|
|
107
|
+
randomCorrectProbability= 1 / len(asset.assets)
|
|
87
108
|
)
|
|
88
109
|
|
|
89
110
|
def select_words_rapid(self,
|
|
@@ -94,7 +115,8 @@ class RapidsManager:
|
|
|
94
115
|
required_precision: float = 1,
|
|
95
116
|
required_completeness: float = 1,
|
|
96
117
|
metadata: Sequence[Metadata] = [],
|
|
97
|
-
|
|
118
|
+
explanation: str | None = None,
|
|
119
|
+
) -> Rapid:
|
|
98
120
|
"""Build a select words rapid
|
|
99
121
|
|
|
100
122
|
Args:
|
|
@@ -108,23 +130,44 @@ class RapidsManager:
|
|
|
108
130
|
"""
|
|
109
131
|
|
|
110
132
|
asset = MediaAsset(datapoint)
|
|
133
|
+
transcription_words = [
|
|
134
|
+
TranscriptionWord(word=word, wordIndex=i)
|
|
135
|
+
for i, word in enumerate(sentence)
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
correct_transcription_words: list[TranscriptionWord] = []
|
|
139
|
+
for index in truths:
|
|
140
|
+
correct_transcription_words.append(
|
|
141
|
+
TranscriptionWord(word=transcription_words[index].word, wordIndex=index)
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
payload = TranscriptionPayload(
|
|
145
|
+
_t="TranscriptionPayload", title=instruction, transcription=transcription_words
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
model_truth = TranscriptionTruth(
|
|
149
|
+
_t="TranscriptionTruth",
|
|
150
|
+
correctWords=correct_transcription_words,
|
|
151
|
+
requiredPrecision=required_precision,
|
|
152
|
+
requiredCompleteness=required_completeness,
|
|
153
|
+
)
|
|
111
154
|
|
|
112
|
-
return
|
|
113
|
-
|
|
114
|
-
|
|
155
|
+
return Rapid(
|
|
156
|
+
payload=payload,
|
|
157
|
+
truth=model_truth,
|
|
115
158
|
asset=asset,
|
|
116
|
-
sentence=sentence,
|
|
117
|
-
required_precision=required_precision,
|
|
118
|
-
required_completeness=required_completeness,
|
|
119
159
|
metadata=metadata,
|
|
120
|
-
|
|
160
|
+
explanation=explanation,
|
|
161
|
+
randomCorrectProbability= len(correct_transcription_words) / len(transcription_words)
|
|
162
|
+
)
|
|
121
163
|
|
|
122
164
|
def locate_rapid(self,
|
|
123
165
|
instruction: str,
|
|
124
166
|
truths: list[Box],
|
|
125
167
|
datapoint: str,
|
|
126
168
|
metadata: Sequence[Metadata] = [],
|
|
127
|
-
|
|
169
|
+
explanation: str | None = None,
|
|
170
|
+
) -> Rapid:
|
|
128
171
|
"""Build a locate rapid
|
|
129
172
|
|
|
130
173
|
Args:
|
|
@@ -135,12 +178,35 @@ class RapidsManager:
|
|
|
135
178
|
"""
|
|
136
179
|
|
|
137
180
|
asset = MediaAsset(datapoint)
|
|
181
|
+
payload = LocatePayload(
|
|
182
|
+
_t="LocatePayload", target=instruction
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
img_dimensions = asset.get_image_dimension()
|
|
186
|
+
|
|
187
|
+
if not img_dimensions:
|
|
188
|
+
raise ValueError("Failed to get image dimensions")
|
|
189
|
+
|
|
190
|
+
model_truth = LocateBoxTruth(
|
|
191
|
+
_t="LocateBoxTruth",
|
|
192
|
+
boundingBoxes=[BoxShape(
|
|
193
|
+
_t="BoxShape",
|
|
194
|
+
xMin=truth.x_min / img_dimensions[0] * 100,
|
|
195
|
+
xMax=truth.x_max / img_dimensions[0] * 100,
|
|
196
|
+
yMax=truth.y_max / img_dimensions[1] * 100,
|
|
197
|
+
yMin=truth.y_min / img_dimensions[1] * 100,
|
|
198
|
+
) for truth in truths]
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
coverage = self._calculate_boxes_coverage(truths, img_dimensions[0], img_dimensions[1])
|
|
138
202
|
|
|
139
|
-
return
|
|
140
|
-
|
|
141
|
-
|
|
203
|
+
return Rapid(
|
|
204
|
+
payload=payload,
|
|
205
|
+
truth=model_truth,
|
|
142
206
|
asset=asset,
|
|
143
207
|
metadata=metadata,
|
|
208
|
+
explanation=explanation,
|
|
209
|
+
randomCorrectProbability=coverage
|
|
144
210
|
)
|
|
145
211
|
|
|
146
212
|
def draw_rapid(self,
|
|
@@ -148,7 +214,8 @@ class RapidsManager:
|
|
|
148
214
|
truths: list[Box],
|
|
149
215
|
datapoint: str,
|
|
150
216
|
metadata: Sequence[Metadata] = [],
|
|
151
|
-
|
|
217
|
+
explanation: str | None = None
|
|
218
|
+
) -> Rapid:
|
|
152
219
|
"""Build a draw rapid
|
|
153
220
|
|
|
154
221
|
Args:
|
|
@@ -160,19 +227,42 @@ class RapidsManager:
|
|
|
160
227
|
|
|
161
228
|
asset = MediaAsset(datapoint)
|
|
162
229
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
230
|
+
payload = LinePayload(
|
|
231
|
+
_t="LinePayload", target=instruction
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
img_dimensions = asset.get_image_dimension()
|
|
235
|
+
|
|
236
|
+
if not img_dimensions:
|
|
237
|
+
raise ValueError("Failed to get image dimensions")
|
|
238
|
+
|
|
239
|
+
model_truth = BoundingBoxTruth(
|
|
240
|
+
_t="BoundingBoxTruth",
|
|
241
|
+
xMax=truths[0].x_max / img_dimensions[0],
|
|
242
|
+
xMin=truths[0].x_min / img_dimensions[0],
|
|
243
|
+
yMax=truths[0].y_max / img_dimensions[1],
|
|
244
|
+
yMin=truths[0].y_min / img_dimensions[1],
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
coverage = self._calculate_boxes_coverage(truths, img_dimensions[0], img_dimensions[1])
|
|
248
|
+
|
|
249
|
+
return Rapid(
|
|
250
|
+
payload=payload,
|
|
251
|
+
truth=model_truth,
|
|
252
|
+
asset=asset,
|
|
253
|
+
metadata=metadata,
|
|
254
|
+
explanation=explanation,
|
|
255
|
+
randomCorrectProbability=coverage
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
170
259
|
def timestamp_rapid(self,
|
|
171
260
|
instruction: str,
|
|
172
261
|
truths: list[tuple[int, int]],
|
|
173
262
|
datapoint: str,
|
|
174
|
-
metadata: Sequence[Metadata] = []
|
|
175
|
-
|
|
263
|
+
metadata: Sequence[Metadata] = [],
|
|
264
|
+
explanation: str | None = None
|
|
265
|
+
) -> Rapid:
|
|
176
266
|
"""Build a timestamp rapid
|
|
177
267
|
|
|
178
268
|
Args:
|
|
@@ -184,12 +274,86 @@ class RapidsManager:
|
|
|
184
274
|
"""
|
|
185
275
|
|
|
186
276
|
asset = MediaAsset(datapoint)
|
|
277
|
+
|
|
278
|
+
for truth in truths:
|
|
279
|
+
if len(truth) != 2:
|
|
280
|
+
raise ValueError("The truths per datapoint must be a tuple of exactly two integers.")
|
|
281
|
+
if truth[0] > truth[1]:
|
|
282
|
+
raise ValueError("The start of the interval must be smaller than the end of the interval.")
|
|
283
|
+
|
|
284
|
+
payload = ScrubPayload(
|
|
285
|
+
_t="ScrubPayload",
|
|
286
|
+
target=instruction
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
model_truth = ScrubTruth(
|
|
290
|
+
_t="ScrubTruth",
|
|
291
|
+
validRanges=[ScrubRange(
|
|
292
|
+
start=truth[0],
|
|
293
|
+
end=truth[1]
|
|
294
|
+
) for truth in truths]
|
|
295
|
+
)
|
|
187
296
|
|
|
188
|
-
return
|
|
189
|
-
|
|
190
|
-
|
|
297
|
+
return Rapid(
|
|
298
|
+
payload=payload,
|
|
299
|
+
truth=model_truth,
|
|
191
300
|
asset=asset,
|
|
192
301
|
metadata=metadata,
|
|
302
|
+
explanation=explanation,
|
|
303
|
+
randomCorrectProbability=self._calculate_coverage_ratio(asset.get_duration(), truths),
|
|
193
304
|
)
|
|
194
305
|
|
|
306
|
+
def _calculate_boxes_coverage(self, boxes: list[Box], image_width: int, image_height: int) -> float:
|
|
307
|
+
if not boxes:
|
|
308
|
+
return 0.0
|
|
309
|
+
# Convert all coordinates to integers for pixel-wise coverage
|
|
310
|
+
pixels = set()
|
|
311
|
+
for box in boxes:
|
|
312
|
+
for x in range(int(box.x_min), int(box.x_max + 1)):
|
|
313
|
+
for y in range(int(box.y_min), int(box.y_max + 1)):
|
|
314
|
+
if 0 <= x < image_width and 0 <= y < image_height:
|
|
315
|
+
pixels.add((x,y))
|
|
316
|
+
|
|
317
|
+
total_covered = len(pixels)
|
|
318
|
+
return total_covered / (image_width * image_height)
|
|
319
|
+
|
|
320
|
+
def _calculate_coverage_ratio(self, total_duration: int, subsections: list[tuple[int, int]]) -> float:
|
|
321
|
+
"""
|
|
322
|
+
Calculate the ratio of total_duration that is covered by subsections, handling overlaps.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
total_duration: The total duration to consider
|
|
326
|
+
subsections: List of tuples containing (start, end) times
|
|
327
|
+
|
|
328
|
+
Returns:
|
|
329
|
+
float: Ratio of coverage (0 to 1)
|
|
330
|
+
"""
|
|
331
|
+
if not subsections:
|
|
332
|
+
return 0.0
|
|
333
|
+
|
|
334
|
+
# Sort subsections by start time and clamp to valid range
|
|
335
|
+
sorted_ranges = sorted(
|
|
336
|
+
(max(0, start), min(end, total_duration))
|
|
337
|
+
for start, end in subsections
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
# Merge overlapping ranges
|
|
341
|
+
merged_ranges = []
|
|
342
|
+
current_range = list(sorted_ranges[0])
|
|
343
|
+
|
|
344
|
+
for next_start, next_end in sorted_ranges[1:]:
|
|
345
|
+
current_start, current_end = current_range
|
|
346
|
+
|
|
347
|
+
# If ranges overlap or are adjacent
|
|
348
|
+
if next_start <= current_end:
|
|
349
|
+
current_range[1] = max(current_end, next_end)
|
|
350
|
+
else:
|
|
351
|
+
merged_ranges.append(current_range)
|
|
352
|
+
current_range = [next_start, next_end]
|
|
353
|
+
|
|
354
|
+
merged_ranges.append(current_range)
|
|
355
|
+
|
|
356
|
+
# Calculate total coverage
|
|
357
|
+
total_coverage = sum(end - start for start, end in merged_ranges)
|
|
195
358
|
|
|
359
|
+
return total_coverage / total_duration
|