diff --git a/ami/exports/views.py b/ami/exports/views.py index 65e1ae030..b6802aeee 100644 --- a/ami/exports/views.py +++ b/ami/exports/views.py @@ -49,12 +49,12 @@ def create(self, request, *args, **kwargs): collection = SourceImageCollection.objects.get(pk=collection_id) except SourceImageCollection.DoesNotExist: return Response( - {"error": "Collection does not exist."}, + {"error": "Capture set does not exist."}, status=status.HTTP_400_BAD_REQUEST, ) if collection.project != project: return Response( - {"error": "Collection does not belong to the selected project."}, + {"error": "Capture set does not belong to the selected project."}, status=status.HTTP_400_BAD_REQUEST, ) @@ -73,7 +73,7 @@ def create(self, request, *args, **kwargs): data_export.save() data_export.update_record_count() - job_name = f"Export occurrences{f' for collection {collection.pk}' if collection else ''}" + job_name = f"Export occurrences{f' for capture set {collection.pk}' if collection else ''}" job = Job.objects.create( name=job_name, project=project, diff --git a/ami/jobs/models.py b/ami/jobs/models.py index 94c1fdbe8..8acb718cd 100644 --- a/ami/jobs/models.py +++ b/ami/jobs/models.py @@ -657,13 +657,13 @@ def run(cls, job: "Job"): class SourceImageCollectionPopulateJob(JobType): - name = "Populate captures collection" + name = "Populate capture set" key = "populate_captures_collection" @classmethod def run(cls, job: "Job"): """ - Run the populate source image collection job. + Run the populate capture set job. This is meant to be called by an async task, not directly. """ @@ -675,9 +675,9 @@ def run(cls, job: "Job"): job.save() if not job.source_image_collection: - raise ValueError("No source image collection provided") + raise ValueError("No capture set provided") - job.logger.info(f"Populating source image collection {job.source_image_collection}") + job.logger.info(f"Populating capture set {job.source_image_collection}") job.update_status(JobState.STARTED) job.started_at = datetime.datetime.now() job.finished_at = None @@ -690,11 +690,11 @@ def run(cls, job: "Job"): job.save() job.source_image_collection.populate_sample(job=job) - job.logger.info(f"Finished populating source image collection {job.source_image_collection}") + job.logger.info(f"Finished populating capture set {job.source_image_collection}") job.save() captures_added = job.source_image_collection.images.count() - job.logger.info(f"Added {captures_added} captures to source image collection {job.source_image_collection}") + job.logger.info(f"Added {captures_added} captures to capture set {job.source_image_collection}") job.progress.update_stage( cls.key, diff --git a/ami/jobs/serializers.py b/ami/jobs/serializers.py index fc2fcf8be..fed4d58fa 100644 --- a/ami/jobs/serializers.py +++ b/ami/jobs/serializers.py @@ -81,7 +81,7 @@ class JobListSerializer(DefaultSerializer): source="source_image_single", ) source_image_collection_id = serializers.PrimaryKeyRelatedField( - label="Source Image Collection", + label="Capture Set", write_only=True, required=False, allow_null=True, diff --git a/ami/main/admin.py b/ami/main/admin.py index 1ffc6d5fc..0605c238e 100644 --- a/ami/main/admin.py +++ b/ami/main/admin.py @@ -638,14 +638,14 @@ def image_count(self, obj) -> int: def populate_collection(self, request: HttpRequest, queryset: QuerySet[SourceImageCollection]) -> None: for collection in queryset: collection.populate_sample() - self.message_user(request, f"Populated {queryset.count()} collection(s).") + self.message_user(request, f"Populated {queryset.count()} capture set(s).") @admin.action() def populate_collection_async(self, request: HttpRequest, queryset: QuerySet[SourceImageCollection]) -> None: queued_tasks = [tasks.populate_collection.apply_async([collection.pk]) for collection in queryset] self.message_user( request, - f"Populating {len(queued_tasks)} collection(s) background tasks: {queued_tasks}.", + f"Populating {len(queued_tasks)} capture set(s) background tasks: {queued_tasks}.", ) @admin.action(description="Run Small Size Filter post-processing task (async)") @@ -653,7 +653,7 @@ def run_small_size_filter(self, request: HttpRequest, queryset: QuerySet[SourceI jobs = [] for collection in queryset: job = Job.objects.create( - name=f"Post-processing: SmallSizeFilter on Collection {collection.pk}", + name=f"Post-processing: SmallSizeFilter on Capture Set {collection.pk}", project=collection.project, job_type_key="post_processing", params={ @@ -666,7 +666,7 @@ def run_small_size_filter(self, request: HttpRequest, queryset: QuerySet[SourceI job.enqueue() jobs.append(job.pk) - self.message_user(request, f"Queued Small Size Filter for {queryset.count()} collection(s). Jobs: {jobs}") + self.message_user(request, f"Queued Small Size Filter for {queryset.count()} capture set(s). Jobs: {jobs}") actions = [ populate_collection, diff --git a/ami/main/api/views.py b/ami/main/api/views.py index 75951535a..34f4466ce 100644 --- a/ami/main/api/views.py +++ b/ami/main/api/views.py @@ -681,7 +681,7 @@ def add_adjacent_captures(self, queryset: QuerySet) -> QuerySet: @action(detail=True, methods=["post"], name="star") def star(self, _request, pk=None) -> Response: """ - Add a source image to the project's starred images collection. + Add a capture to the project's starred images capture set. """ source_image: SourceImage = self.get_object() if source_image and source_image.deployment and source_image.deployment.project: @@ -694,7 +694,7 @@ def star(self, _request, pk=None) -> Response: @action(detail=True, methods=["post"], name="unstar") def unstar(self, _request, pk=None) -> Response: """ - Remove a source image from the project's starred images collection. + Remove a capture from the project's starred images capture set. """ source_image: SourceImage = self.get_object() if source_image and source_image.deployment and source_image.deployment.project: @@ -707,7 +707,7 @@ def unstar(self, _request, pk=None) -> Response: class SourceImageCollectionViewSet(DefaultViewSet, ProjectMixin): """ - Endpoint for viewing collections or samples of source images. + Endpoint for viewing capture sets or samples of captures. """ queryset = ( @@ -766,26 +766,26 @@ def get_queryset(self) -> QuerySet: @action(detail=True, methods=["post"], name="populate") def populate(self, request, pk=None): """ - Populate a collection with source images using the configured sampling method and arguments. + Populate a capture set with captures using the configured sampling method and arguments. """ collection: SourceImageCollection = self.get_object() if collection: from ami.jobs.models import Job, SourceImageCollectionPopulateJob - assert collection.project, "Collection must be associated with a project" + assert collection.project, "Capture set must be associated with a project" job = Job.objects.create( - name=f"Populate captures for collection {collection.pk}", + name=f"Populate captures for capture set {collection.pk}", project=collection.project, source_image_collection=collection, job_type_key=SourceImageCollectionPopulateJob.key, ) job.enqueue() - msg = f"Populating captures for collection {collection.pk} in background." + msg = f"Populating captures for capture set {collection.pk} in background." logger.info(msg) return Response({"job_id": job.pk, "project_id": collection.project.pk}) else: - raise api_exceptions.ValidationError(detail="Invalid collection requested") + raise api_exceptions.ValidationError(detail="Invalid capture set requested") def _get_source_image(self): """ @@ -812,7 +812,7 @@ def _serialize_source_image(self, source_image): @action(detail=True, methods=["post"], name="add") def add(self, request, pk=None): """ - Add a source image to a collection. + Add a capture to a capture set. """ collection: SourceImageCollection = self.get_object() source_image = self._get_source_image() @@ -828,7 +828,7 @@ def add(self, request, pk=None): @action(detail=True, methods=["post"], name="remove") def remove(self, request, pk=None): """ - Remove a source image from a collection. + Remove a capture from a capture set. """ collection = self.get_object() source_image = self._get_source_image() @@ -991,7 +991,7 @@ def filter_queryset(self, request, queryset, view): class OccurrenceCollectionFilter(filters.BaseFilterBackend): """ - Filter occurrences by the collection their detections source images belong to. + Filter occurrences by the capture set their detections' captures belong to. """ query_params = ["collection_id", "collection"] # @TODO remove "collection" param when UI is updated @@ -1158,7 +1158,7 @@ def filter_queryset(self, request, queryset, view): class TaxonCollectionFilter(filters.BaseFilterBackend): """ - Filter taxa by the collection their occurrences belong to. + Filter taxa by the capture set their occurrences belong to. """ query_param = "collection" @@ -1260,7 +1260,7 @@ def get_queryset(self) -> QuerySet["Occurrence"]: ), OpenApiParameter( name="collection_id", - description="Filter occurrences by the collection their detections' source images belong to.", + description="Filter occurrences by the capture set their detections' captures belong to.", required=False, type=OpenApiTypes.INT, ), diff --git a/ami/main/models.py b/ami/main/models.py index 2de69f815..1adc855ac 100644 --- a/ami/main/models.py +++ b/ami/main/models.py @@ -148,7 +148,7 @@ def get_or_create_default_collection(project: "Project") -> "SourceImageCollecti project=project, method="full", ) - logger.info(f"Created default collection for project {project}") + logger.info(f"Created default capture set for project {project}") return collection diff --git a/ami/tasks.py b/ami/tasks.py index 47abfbd09..bc4400e47 100644 --- a/ami/tasks.py +++ b/ami/tasks.py @@ -77,12 +77,13 @@ def write_tasks(label_studio_config_id: int) -> int: def populate_collection(collection_id: int) -> None: from ami.main.models import SourceImageCollection - collection = SourceImageCollection.objects.get(id=collection_id) - if collection: - logger.info(f"Populating collection {collection}") - collection.populate_sample() - else: - logger.error(f"SourceImageCollection with id {collection_id} not found") + try: + collection = SourceImageCollection.objects.get(id=collection_id) + except SourceImageCollection.DoesNotExist: + logger.error(f"Capture set with id {collection_id} not found") + return + logger.info(f"Populating capture set {collection}") + collection.populate_sample() # Task to group images into events @@ -90,13 +91,14 @@ def populate_collection(collection_id: int) -> None: def regroup_events(deployment_id: int) -> None: from ami.main.models import Deployment, group_images_into_events - deployment = Deployment.objects.get(id=deployment_id) - if deployment: - logger.info(f"Grouping captures for {deployment}") - events = group_images_into_events(deployment) - logger.info(f"{deployment } now has {len(events)} events") - else: + try: + deployment = Deployment.objects.get(id=deployment_id) + except Deployment.DoesNotExist: logger.error(f"Deployment with id {deployment_id} not found") + return + logger.info(f"Grouping captures for {deployment}") + events = group_images_into_events(deployment) + logger.info(f"{deployment} now has {len(events)} events") @celery_app.task(soft_time_limit=one_hour, time_limit=one_hour + 60)