Skip to content

Commit 0ca9cd6

Browse files
chore: use start frame instead of frame
1 parent a838513 commit 0ca9cd6

File tree

4 files changed

+46
-46
lines changed

4 files changed

+46
-46
lines changed

libs/labelbox/src/labelbox/data/annotation_types/audio.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ class AudioClassificationAnnotation(ClassificationAnnotation):
2222
name (Optional[str]): Name of the classification
2323
feature_schema_id (Optional[Cuid]): Feature schema identifier
2424
value (Union[Text, Checklist, Radio]): Classification value
25-
frame (int): The frame index in milliseconds (e.g., 2500 = 2.5 seconds)
25+
start_frame (int): The frame index in milliseconds (e.g., 2500 = 2.5 seconds)
2626
end_frame (Optional[int]): End frame in milliseconds (for time ranges)
2727
segment_index (Optional[int]): Index of audio segment this annotation belongs to
2828
extra (Dict[str, Any]): Additional metadata
2929
"""
3030

31-
frame: int
31+
start_frame: int
3232
end_frame: Optional[int] = None
3333
segment_index: Optional[int] = None
3434

@@ -49,15 +49,15 @@ class AudioObjectAnnotation(
4949
name (Optional[str]): Name of the annotation
5050
feature_schema_id (Optional[Cuid]): Feature schema identifier
5151
value (Union[TextEntity, Geometry]): Localization or text content
52-
frame (int): The frame index in milliseconds (e.g., 10000 = 10.0 seconds)
52+
start_frame (int): The frame index in milliseconds (e.g., 10000 = 10.0 seconds)
5353
end_frame (Optional[int]): End frame in milliseconds (for time ranges)
5454
keyframe (bool): Whether this is a keyframe annotation (default: True)
5555
segment_index (Optional[int]): Index of audio segment this annotation belongs to
5656
classifications (Optional[List[ClassificationAnnotation]]): Optional sub-classifications
5757
extra (Dict[str, Any]): Additional metadata
5858
"""
5959

60-
frame: int
60+
start_frame: int
6161
end_frame: Optional[int] = None
6262
keyframe: bool = True
6363
segment_index: Optional[int] = None

libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ def to_common(
421421
for frame in annotation.frames:
422422
for idx in range(frame.start, frame.end + 1, 1):
423423
# Check if this is an audio annotation by looking at the extra data
424-
# Audio annotations will have frame/end_frame in extra, video annotations won't
424+
# Audio annotations will have start_frame/end_frame in extra, video annotations won't
425425
if (
426426
hasattr(annotation, "extra")
427427
and annotation.extra

libs/labelbox/src/labelbox/data/serialization/ndjson/label.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def _get_consecutive_frames(
8989
@classmethod
9090
def _get_audio_frame_ranges(cls, annotation_group: List[Union[AudioClassificationAnnotation, AudioObjectAnnotation]]) -> List[Tuple[int, int]]:
9191
"""Get frame ranges for audio annotations (simpler than video segments)"""
92-
return [(ann.frame, getattr(ann, 'end_frame', None) or ann.frame) for ann in annotation_group]
92+
return [(ann.start_frame, getattr(ann, 'end_frame', None) or ann.start_frame) for ann in annotation_group]
9393

9494
@classmethod
9595
def _has_changing_values(cls, annotation_group: List[AudioClassificationAnnotation]) -> bool:
@@ -109,7 +109,7 @@ def _create_multi_value_annotation(cls, annotation_group: List[AudioClassificati
109109
frame_mapping = {}
110110

111111
for ann in annotation_group:
112-
start, end = ann.frame, getattr(ann, 'end_frame', None) or ann.frame
112+
start, end = ann.start_frame, getattr(ann, 'end_frame', None) or ann.start_frame
113113
frames_data.append({"start": start, "end": end})
114114
frame_mapping[str(start)] = ann.value.answer
115115

@@ -199,7 +199,7 @@ def _create_video_annotations(
199199
for annotation in annotation_group:
200200
if (
201201
annotation.keyframe
202-
and start_frame <= annotation.frame <= end_frame
202+
and start_frame <= annotation.start_frame <= end_frame
203203
):
204204
segment.append(annotation)
205205
segments.append(segment)

libs/labelbox/tests/data/annotation_types/test_audio.py

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
def test_audio_classification_creation():
1616
"""Test creating audio classification with direct frame specification"""
1717
annotation = AudioClassificationAnnotation(
18-
frame=2500, # 2.5 seconds in milliseconds
18+
start_frame=2500, # 2.5 seconds in milliseconds
1919
name="speaker_id",
2020
value=Radio(answer=ClassificationAnswer(name="john")),
2121
)
2222

23-
assert annotation.frame == 2500
23+
assert annotation.start_frame == 2500
2424
assert annotation.end_frame is None
2525
assert annotation.segment_index is None
2626
assert annotation.name == "speaker_id"
@@ -31,41 +31,41 @@ def test_audio_classification_creation():
3131
def test_audio_classification_with_time_range():
3232
"""Test creating audio classification with start and end frames"""
3333
annotation = AudioClassificationAnnotation(
34-
frame=2500, # Start at 2.5 seconds
34+
start_frame=2500, # Start at 2.5 seconds
3535
end_frame=4100, # End at 4.1 seconds
3636
name="speaker_id",
3737
value=Radio(answer=ClassificationAnswer(name="john")),
3838
)
3939

40-
assert annotation.frame == 2500
40+
assert annotation.start_frame == 2500
4141
assert annotation.end_frame == 4100
4242
assert annotation.name == "speaker_id"
4343

4444

4545
def test_audio_classification_creation_with_segment():
4646
"""Test creating audio classification with segment index"""
4747
annotation = AudioClassificationAnnotation(
48-
frame=10000,
48+
start_frame=10000,
4949
end_frame=15000,
5050
name="language",
5151
value=Radio(answer=ClassificationAnswer(name="english")),
5252
segment_index=1,
5353
)
5454

55-
assert annotation.frame == 10000
55+
assert annotation.start_frame == 10000
5656
assert annotation.end_frame == 15000
5757
assert annotation.segment_index == 1
5858

5959

6060
def test_audio_classification_text_type():
6161
"""Test creating audio classification with Text value"""
6262
annotation = AudioClassificationAnnotation(
63-
frame=5000, # 5.0 seconds
63+
start_frame=5000, # 5.0 seconds
6464
name="quality",
6565
value=Text(answer="excellent"),
6666
)
6767

68-
assert annotation.frame == 5000
68+
assert annotation.start_frame == 5000
6969
assert annotation.name == "quality"
7070
assert isinstance(annotation.value, Text)
7171
assert annotation.value.answer == "excellent"
@@ -74,15 +74,15 @@ def test_audio_classification_text_type():
7474
def test_audio_object_creation():
7575
"""Test creating audio object annotation"""
7676
annotation = AudioObjectAnnotation(
77-
frame=10000,
77+
start_frame=10000,
7878
end_frame=12500,
7979
name="transcription",
8080
value=lb_types.TextEntity(
8181
start=0, end=11
8282
), # "Hello world" has 11 characters
8383
)
8484

85-
assert annotation.frame == 10000
85+
assert annotation.start_frame == 10000
8686
assert annotation.end_frame == 12500
8787
assert annotation.keyframe is True
8888
assert annotation.segment_index is None
@@ -95,13 +95,13 @@ def test_audio_object_creation():
9595
def test_audio_object_creation_with_classifications():
9696
"""Test creating audio object with sub-classifications"""
9797
sub_classification = AudioClassificationAnnotation(
98-
frame=10000,
98+
start_frame=10000,
9999
name="confidence",
100100
value=Radio(answer=ClassificationAnswer(name="high")),
101101
)
102102

103103
annotation = AudioObjectAnnotation(
104-
frame=10000,
104+
start_frame=10000,
105105
end_frame=12500,
106106
name="transcription",
107107
value=lb_types.TextEntity(start=0, end=11),
@@ -110,20 +110,20 @@ def test_audio_object_creation_with_classifications():
110110

111111
assert len(annotation.classifications) == 1
112112
assert annotation.classifications[0].name == "confidence"
113-
assert annotation.classifications[0].frame == 10000
113+
assert annotation.classifications[0].start_frame == 10000
114114

115115

116116
def test_audio_object_direct_creation():
117117
"""Test creating audio object directly with various options"""
118118
annotation = AudioObjectAnnotation(
119-
frame=7500, # 7.5 seconds
119+
start_frame=7500, # 7.5 seconds
120120
name="sound_event",
121121
value=lb_types.TextEntity(start=0, end=11),
122122
keyframe=False,
123123
segment_index=2,
124124
)
125125

126-
assert annotation.frame == 7500
126+
assert annotation.start_frame == 7500
127127
assert annotation.end_frame is None
128128
assert annotation.keyframe is False
129129
assert annotation.segment_index == 2
@@ -136,27 +136,27 @@ def test_frame_precision():
136136

137137
for milliseconds in test_cases:
138138
annotation = AudioClassificationAnnotation(
139-
frame=milliseconds,
139+
start_frame=milliseconds,
140140
end_frame=milliseconds + 1000,
141141
name="test",
142142
value=Text(answer="test"),
143143
)
144-
assert annotation.frame == milliseconds
144+
assert annotation.start_frame == milliseconds
145145
assert annotation.end_frame == milliseconds + 1000
146146

147147

148148
def test_audio_label_integration():
149149
"""Test audio annotations work with Label container"""
150150
# Create audio annotations
151151
speaker_annotation = AudioClassificationAnnotation(
152-
frame=1000,
152+
start_frame=1000,
153153
end_frame=2000,
154154
name="speaker",
155155
value=Radio(answer=ClassificationAnswer(name="john")),
156156
)
157157

158158
transcription_annotation = AudioObjectAnnotation(
159-
frame=1000,
159+
start_frame=1000,
160160
end_frame=2000,
161161
name="transcription",
162162
value=lb_types.TextEntity(start=0, end=5),
@@ -194,7 +194,7 @@ def test_audio_annotation_validation():
194194
# Test frame must be int
195195
with pytest.raises(ValueError):
196196
AudioClassificationAnnotation(
197-
frame="invalid", # Should be int
197+
start_frame="invalid", # Should be int
198198
name="test",
199199
value=Text(answer="test"),
200200
)
@@ -205,7 +205,7 @@ def test_audio_annotation_extra_fields():
205205
extra_data = {"source": "automatic", "confidence_score": 0.95}
206206

207207
annotation = AudioClassificationAnnotation(
208-
frame=3000, name="quality", value=Text(answer="good"), extra=extra_data
208+
start_frame=3000, name="quality", value=Text(answer="good"), extra=extra_data
209209
)
210210

211211
assert annotation.extra["source"] == "automatic"
@@ -215,7 +215,7 @@ def test_audio_annotation_extra_fields():
215215
def test_audio_annotation_feature_schema():
216216
"""Test audio annotations with feature schema IDs"""
217217
annotation = AudioClassificationAnnotation(
218-
frame=4000,
218+
start_frame=4000,
219219
name="language",
220220
value=Radio(answer=ClassificationAnswer(name="spanish")),
221221
feature_schema_id="1234567890123456789012345",
@@ -228,14 +228,14 @@ def test_audio_annotation_mixed_types():
228228
"""Test label with mixed audio and other annotation types"""
229229
# Audio annotation
230230
audio_annotation = AudioClassificationAnnotation(
231-
frame=2000,
231+
start_frame=2000,
232232
name="speaker",
233233
value=Radio(answer=ClassificationAnswer(name="john")),
234234
)
235235

236236
# Video annotation
237237
video_annotation = lb_types.VideoClassificationAnnotation(
238-
frame=10, name="quality", value=Text(answer="good")
238+
start_frame=10, name="quality", value=Text(answer="good")
239239
)
240240

241241
# Image annotation
@@ -280,7 +280,7 @@ def test_audio_annotation_mixed_types():
280280
def test_audio_annotation_serialization():
281281
"""Test audio annotations can be serialized to dict"""
282282
annotation = AudioClassificationAnnotation(
283-
frame=6000,
283+
start_frame=6000,
284284
end_frame=8000,
285285
name="emotion",
286286
value=Radio(answer=ClassificationAnswer(name="happy")),
@@ -317,7 +317,7 @@ def test_audio_annotation_from_dict():
317317

318318
annotation = AudioClassificationAnnotation(**annotation_data)
319319

320-
assert annotation.frame == 7000
320+
assert annotation.start_frame == 7000
321321
assert annotation.end_frame == 9000
322322
assert annotation.name == "topic"
323323
assert annotation.segment_index == 2
@@ -328,32 +328,32 @@ def test_audio_annotation_edge_cases():
328328
"""Test audio annotation edge cases"""
329329
# Test very long audio (many hours)
330330
long_annotation = AudioClassificationAnnotation(
331-
frame=3600000, # 1 hour in milliseconds
331+
start_frame=3600000, # 1 hour in milliseconds
332332
end_frame=7200000, # 2 hours in milliseconds
333333
name="long_audio",
334334
value=Text(answer="very long"),
335335
)
336336

337-
assert long_annotation.frame == 3600000
337+
assert long_annotation.start_frame == 3600000
338338
assert long_annotation.end_frame == 7200000
339339

340340
# Test very short audio (milliseconds)
341341
short_annotation = AudioClassificationAnnotation(
342-
frame=1, # 1 millisecond
342+
start_frame=1, # 1 millisecond
343343
end_frame=2, # 2 milliseconds
344344
name="short_audio",
345345
value=Text(answer="very short"),
346346
)
347347

348-
assert short_annotation.frame == 1
348+
assert short_annotation.start_frame == 1
349349
assert short_annotation.end_frame == 2
350350

351351
# Test zero time
352352
zero_annotation = AudioClassificationAnnotation(
353-
frame=0, name="zero_time", value=Text(answer="zero")
353+
start_frame=0, name="zero_time", value=Text(answer="zero")
354354
)
355355

356-
assert zero_annotation.frame == 0
356+
assert zero_annotation.start_frame == 0
357357
assert zero_annotation.end_frame is None
358358

359359

@@ -368,7 +368,7 @@ def test_temporal_annotation_grouping():
368368
end_frame = start_frame + 900 # 900ms duration each
369369

370370
annotation = AudioClassificationAnnotation(
371-
frame=start_frame,
371+
start_frame=start_frame,
372372
end_frame=end_frame,
373373
name="tokens", # Same name for grouping
374374
value=Text(answer=token),
@@ -380,8 +380,8 @@ def test_temporal_annotation_grouping():
380380
assert all(ann.name == "tokens" for ann in annotations)
381381
assert annotations[0].value.answer == "Hello"
382382
assert annotations[1].value.answer == "world"
383-
assert annotations[0].frame == 0
384-
assert annotations[1].frame == 1000
383+
assert annotations[0].start_frame == 0
384+
assert annotations[1].start_frame == 1000
385385
assert annotations[0].end_frame == 900
386386
assert annotations[1].end_frame == 1900
387387

@@ -390,7 +390,7 @@ def test_audio_object_types():
390390
"""Test different types of audio object annotations"""
391391
# Text entity (transcription)
392392
text_obj = AudioObjectAnnotation(
393-
frame=1000,
393+
start_frame=1000,
394394
name="transcription",
395395
value=TextEntity(start=0, end=5), # "hello"
396396
)
@@ -401,7 +401,7 @@ def test_audio_object_types():
401401

402402
# Test with keyframe and segment settings
403403
keyframe_obj = AudioObjectAnnotation(
404-
frame=2000,
404+
start_frame=2000,
405405
end_frame=3000,
406406
name="segment",
407407
value=TextEntity(start=10, end=15),
@@ -411,5 +411,5 @@ def test_audio_object_types():
411411

412412
assert keyframe_obj.keyframe is True
413413
assert keyframe_obj.segment_index == 1
414-
assert keyframe_obj.frame == 2000
414+
assert keyframe_obj.start_frame == 2000
415415
assert keyframe_obj.end_frame == 3000

0 commit comments

Comments
 (0)