Skip to content

Commit 81bffbf

Browse files
committed
Batch process annotattions and prevent duplicates
1 parent 221df9f commit 81bffbf

1 file changed

Lines changed: 65 additions & 27 deletions

File tree

‎bats_ai/core/management/commands/copy_batbot_pulse_annotations.py‎

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,41 +17,79 @@
1717

1818
logger = logging.getLogger(__name__)
1919

20+
COPY_COMMENT = "Copy of batbot pulse annotation"
21+
2022

2123
@click.command()
2224
@click.argument("username")
23-
def copy_batbot_pulse_annotations(username: str):
25+
@click.option("--batch-size", default=5000)
26+
def copy_batbot_pulse_annotations(username: str, batch_size: int = 5000):
2427
logger.info("Finding user with username %s...", username)
2528
new_owner = User.objects.filter(username=username).first()
2629
if not new_owner:
2730
raise CommandError(f"No user found with username {username}")
2831

2932
logger.info("Finding all pulse annotations created by batbot...")
30-
batbot_pulse_annotations = list(
31-
Annotations.objects.filter(model=BATBOT_ANNOTATION_MODEL).prefetch_related("species")
33+
batbot_pulse_annotations = (
34+
Annotations.objects.filter(model=BATBOT_ANNOTATION_MODEL)
35+
.order_by("recording_id")
36+
.iterator(chunk_size=batch_size)
3237
)
3338

34-
copies = [
35-
Annotations(
36-
recording=original.recording,
37-
owner=new_owner,
38-
start_time=original.start_time,
39-
end_time=original.end_time,
40-
low_freq=original.low_freq,
41-
high_freq=original.high_freq,
42-
type=original.type,
43-
comments="Copy of batbot pulse annotation",
44-
model="",
45-
confidence=original.confidence,
46-
)
47-
for original in batbot_pulse_annotations
48-
]
49-
50-
logger.info("Saving %d new annotations...", len(copies))
51-
created = Annotations.objects.bulk_create(copies)
52-
53-
logger.info("Copying species info...")
54-
for original, copy in zip(batbot_pulse_annotations, created, strict=True):
55-
copy.species.set(original.species.all())
56-
57-
logger.info("Done")
39+
total_count = 0
40+
41+
copies = []
42+
current_recording_id = None
43+
skip_recording = False
44+
for original in batbot_pulse_annotations:
45+
if original.recording_id != current_recording_id:
46+
current_recording_id = original.recording_id
47+
# This check attempts to prevent multiple runs of this command
48+
# from creating redundant copies for the given user. This is not
49+
# perfect, since it relies on the editable "comments" field, and
50+
# lazily checks for the existence of any annotation for the given
51+
# recording that was created by a run of this command. There are 2
52+
# existing concerns that are unlikely to cause trouble in the short
53+
# term, but should be noted:
54+
#
55+
# 1. "comments" are editable. If a user edits all the comments
56+
# for their copied annotations for a given recording, a re-run of
57+
# this command will duplicate the annotations again.
58+
#
59+
# 2. If a run of this command is interrupted and a strict subset of
60+
# annotations for a given recording has been saved, then whichever annotations
61+
# for that recording have not been copied WILL NOT be copied by a subsequent run.
62+
copied_already = Annotations.objects.filter(
63+
owner=new_owner, comments=COPY_COMMENT, recording_id=current_recording_id
64+
).exists()
65+
skip_recording = copied_already
66+
if skip_recording:
67+
continue
68+
else:
69+
# Create a new annotation object and add it to copies
70+
copies.append(
71+
Annotations(
72+
recording_id=original.recording_id,
73+
owner=new_owner,
74+
start_time=original.start_time,
75+
end_time=original.end_time,
76+
low_freq=original.low_freq,
77+
high_freq=original.high_freq,
78+
type=original.type,
79+
comments=COPY_COMMENT,
80+
model="",
81+
confidence=original.confidence,
82+
)
83+
)
84+
if len(copies) >= batch_size:
85+
logger.info("Saving %d copied annotations...", len(copies))
86+
total_count += len(copies)
87+
Annotations.objects.bulk_create(copies)
88+
copies = []
89+
90+
if len(copies) > 0:
91+
logger.info("Saving %d copied annotations...", len(copies))
92+
total_count += len(copies)
93+
Annotations.objects.bulk_create(copies)
94+
95+
logger.info("Done. Copied %d annotations.", total_count)

0 commit comments

Comments
 (0)