diff --git a/.github/workflows/all.yml b/.github/workflows/all.yml index ddab4fe41..b792792a9 100644 --- a/.github/workflows/all.yml +++ b/.github/workflows/all.yml @@ -181,9 +181,6 @@ jobs: - name: Build working-directory: frontend run: npm run build - - name: Typescript compilation - working-directory: frontend - run: npx tsc # ── Playwright tests ─────────────────────────────── - name: Run Playwright tests diff --git a/backend/api/migrations/0007_remove_annotation_analysis.py b/backend/api/migrations/0007_remove_annotation_analysis.py new file mode 100644 index 000000000..5cc48f033 --- /dev/null +++ b/backend/api/migrations/0007_remove_annotation_analysis.py @@ -0,0 +1,17 @@ +# Generated by Django 3.2.25 on 2026-05-29 09:08 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("api", "0006_spectrogramanalysis_frequency_scale_parts"), + ] + + operations = [ + migrations.RemoveField( + model_name="annotation", + name="analysis", + ), + ] diff --git a/backend/api/models/annotation/annotation.py b/backend/api/models/annotation/annotation.py index 44054216c..53e4d238f 100644 --- a/backend/api/models/annotation/annotation.py +++ b/backend/api/models/annotation/annotation.py @@ -12,7 +12,7 @@ from .confidence import Confidence from .detector_configuration import DetectorConfiguration from .label import Label -from ..data import Spectrogram, SpectrogramAnalysis +from ..data import Spectrogram class AnnotationQuerySet(ExtendedQuerySet): @@ -176,11 +176,6 @@ class Meta: on_delete=models.CASCADE, related_name="annotations", ) - analysis = models.ForeignKey( - SpectrogramAnalysis, - on_delete=models.CASCADE, - related_name="annotations", - ) detector_configuration = models.ForeignKey( DetectorConfiguration, diff --git a/backend/api/serializers/annotation.py b/backend/api/serializers/annotation.py index c062749e2..ef28c7a8e 100644 --- a/backend/api/serializers/annotation.py +++ b/backend/api/serializers/annotation.py @@ -14,7 +14,6 @@ Label, Confidence, AnnotationValidation, - SpectrogramAnalysis, AnnotationComment, ) from backend.aplose.models import ExpertiseLevel @@ -80,9 +79,6 @@ def get_fields(self): fields["spectrogram"].queryset = Spectrogram.objects.filter( analysis__in=campaign.analysis.all() ).distinct() - fields["analysis"].queryset = SpectrogramAnalysis.objects.filter( - id__in=campaign.analysis.values_list("id", flat=True) - ) if campaign.confidence_set is not None: fields["confidence"] = serializers.SlugRelatedField( queryset=campaign.confidence_set.confidence_indicators.all(), diff --git a/backend/api/tests/fixtures/annotation/annotation.yaml b/backend/api/tests/fixtures/annotation/annotation.yaml index 642a66f7f..ef1940987 100644 --- a/backend/api/tests/fixtures/annotation/annotation.yaml +++ b/backend/api/tests/fixtures/annotation/annotation.yaml @@ -12,7 +12,6 @@ annotation_phase: 1 confidence: 1 spectrogram: 7 - analysis: 1 created_at: 2010-11-02 00:00:00+00:00 last_updated_at: 2010-11-02 00:00:00+00:00 is_update_of: @@ -30,7 +29,6 @@ annotation_phase: 1 confidence: 2 spectrogram: 7 - analysis: 1 created_at: 2010-11-02 00:00:00+00:00 last_updated_at: 2010-11-02 00:00:00+00:00 is_update_of: @@ -48,7 +46,6 @@ annotation_phase: 1 confidence: 1 spectrogram: 7 - analysis: 1 created_at: 2010-11-02 00:00:00+00:00 last_updated_at: 2010-11-02 00:00:00+00:00 is_update_of: @@ -66,7 +63,6 @@ annotation_phase: 1 confidence: 1 spectrogram: 8 - analysis: 1 created_at: 2010-11-02 00:00:00+00:00 last_updated_at: 2010-11-02 00:00:00+00:00 is_update_of: @@ -84,7 +80,6 @@ annotation_phase: 1 confidence: 1 spectrogram: 8 - analysis: 1 created_at: 2010-11-02 00:00:00+00:00 last_updated_at: 2010-11-02 00:00:00+00:00 is_update_of: @@ -102,7 +97,6 @@ annotation_phase: 1 confidence: 2 spectrogram: 8 - analysis: 1 created_at: 2010-11-02 00:00:00+00:00 last_updated_at: 2010-11-02 00:00:00+00:00 is_update_of: @@ -120,7 +114,6 @@ annotation_phase: 1 confidence: 1 spectrogram: 1 - analysis: 1 created_at: 2010-11-02 00:00:00+00:00 last_updated_at: 2010-11-02 00:00:00+00:00 is_update_of: @@ -138,7 +131,6 @@ annotator: 1 confidence: 1 spectrogram: 1 - analysis: 1 created_at: 2010-11-02 00:00:00+00:00 last_updated_at: 2010-11-02 00:00:00+00:00 is_update_of: @@ -157,7 +149,6 @@ confidence: 2 spectrogram: 1 acoustic_features: 1 - analysis: 1 created_at: 2010-11-02 00:00:00+00:00 last_updated_at: 2010-11-02 00:00:00+00:00 is_update_of: @@ -174,7 +165,6 @@ annotation_phase: 4 confidence: 2 spectrogram: 1 - analysis: 1 created_at: 2010-11-02 00:00:00+00:00 last_updated_at: 2010-11-02 00:00:00+00:00 is_update_of: @@ -191,7 +181,6 @@ annotation_phase: 5 confidence: 2 spectrogram: 1 - analysis: 1 created_at: 2010-11-02 00:00:00+00:00 last_updated_at: 2010-11-02 00:00:00+00:00 is_update_of: 10 \ No newline at end of file diff --git a/backend/api/tests/schema/annotation/update_annotations.py b/backend/api/tests/schema/annotation/update_annotations.py index 051c205fa..dc1ca7e13 100644 --- a/backend/api/tests/schema/annotation/update_annotations.py +++ b/backend/api/tests/schema/annotation/update_annotations.py @@ -41,7 +41,6 @@ "startFrequency": None, "endFrequency": None, "acousticFeatures": None, - "analysis": "1", "annotationPhase": "1", } box_annotation = { @@ -60,7 +59,6 @@ "hasHarmonics": True, "trend": "Modulated", }, - "analysis": "1", "annotationPhase": "1", } @@ -112,7 +110,6 @@ def test_connected_annotator_add_presence(self): self.assertEqual(new_annotation.type, Annotation.Type.WEAK) self.assertEqual(new_annotation.label.name, "Boat") self.assertEqual(new_annotation.confidence.label, "confident") - self.assertEqual(new_annotation.analysis_id, 1) self.assertEqual(new_annotation.spectrogram_id, 9) self.assertEqual(new_annotation.annotator_id, 4) self.assertIsNone(new_annotation.acoustic_features) @@ -132,7 +129,6 @@ def test_connected_annotator_add_box(self): self.assertEqual(new_annotation.start_time, 0.0) self.assertEqual(new_annotation.label.name, "Boat") self.assertEqual(new_annotation.confidence.label, "confident") - self.assertEqual(new_annotation.analysis_id, 1) self.assertEqual(new_annotation.spectrogram_id, 9) self.assertEqual(new_annotation.annotator_id, 4) self.assertEqual(new_annotation.acoustic_features.start_frequency, 10.0) @@ -163,7 +159,6 @@ def test_connected_annotator_update_presence_to_box(self): self.assertEqual(new_annotation.start_time, 0.0) self.assertEqual(new_annotation.label.name, "Boat") self.assertEqual(new_annotation.confidence.label, "confident") - self.assertEqual(new_annotation.analysis_id, 1) self.assertEqual(new_annotation.spectrogram_id, 9) self.assertEqual(new_annotation.annotator_id, 4) self.assertEqual(new_annotation.acoustic_features.start_frequency, 10.0) @@ -275,7 +270,6 @@ def test_connected_annotator_does_not_exists(self): **presence_annotation, "label": "DCall", # label exist in different label set "confidence": "test", - "analysis": "-1", } ], }, @@ -285,7 +279,6 @@ def test_connected_annotator_does_not_exists(self): errors = json.loads(response.content)["data"]["updateAnnotations"]["errors"] self.assertEqual(errors[0][0]["field"], "label") self.assertEqual(errors[0][1]["field"], "confidence") - self.assertEqual(errors[0][2]["field"], "analysis") def test_connected_annotator_min_value(self): previous_count = Annotation.objects.count() diff --git a/backend/api/tests/schema/annotation_spectrogram/annotation_spectrogram_by_id.py b/backend/api/tests/schema/annotation_spectrogram/annotation_spectrogram_by_id.py index eccb2dd3f..b63fcf65f 100644 --- a/backend/api/tests/schema/annotation_spectrogram/annotation_spectrogram_by_id.py +++ b/backend/api/tests/schema/annotation_spectrogram/annotation_spectrogram_by_id.py @@ -92,9 +92,6 @@ relativeMaxFrequencyCount hasHarmonics } - analysis { - id - } } } } diff --git a/backend/api/tests/serializers/annotation.py b/backend/api/tests/serializers/annotation.py index f809eda19..d9f8c2d49 100644 --- a/backend/api/tests/serializers/annotation.py +++ b/backend/api/tests/serializers/annotation.py @@ -7,7 +7,6 @@ AnnotationPhase, Annotation, AcousticFeatures, - SpectrogramAnalysis, ) from backend.api.serializers import AnnotationSerializer from backend.aplose.models import User @@ -33,7 +32,6 @@ "validations": [], "comments": [], "acoustic_features": None, - "analysis": 1, } box_result = { "label": "Boat", @@ -46,7 +44,6 @@ "validations": [], "comments": [], "acoustic_features": features, - "analysis": 1, } USER_ID = 4 @@ -86,7 +83,7 @@ def test_presence(self): self.assertEqual(instance.type, Annotation.Type.WEAK) self.assertEqual(instance.label.name, "Boat") self.assertEqual(instance.confidence.label, "confident") - self.assertEqual(instance.analysis_id, PHASE_ID) + self.assertEqual(instance.annotation_phase_id, PHASE_ID) self.assertEqual(instance.spectrogram_id, SPECTROGRAM_ID) self.assertEqual(instance.annotator_id, USER_ID) self.assertIsNone(instance.acoustic_features) @@ -103,7 +100,7 @@ def test_box(self): self.assertEqual(instance.start_time, 0.0) self.assertEqual(instance.label.name, "Boat") self.assertEqual(instance.confidence.label, "confident") - self.assertEqual(instance.analysis_id, PHASE_ID) + self.assertEqual(instance.annotation_phase_id, PHASE_ID) self.assertEqual(instance.spectrogram_id, SPECTROGRAM_ID) self.assertEqual(instance.annotator_id, USER_ID) self.assertEqual(instance.acoustic_features.start_frequency, 10.0) @@ -131,7 +128,6 @@ def test_required(self): self.assertFalse(serializer.is_valid(raise_exception=False)) self.assertEqual(serializer.errors["label"][0].code, "required") self.assertEqual(serializer.errors["confidence"][0].code, "required") - self.assertEqual(serializer.errors["analysis"][0].code, "required") def test_null(self): serializer = self._get_serializer( @@ -143,7 +139,6 @@ def test_null(self): "annotator": None, "detector_configuration": None, "label": None, - "analysis": None, "confidence": None, # Cannot be null since campaign has a confidence indicator set "comments": [], "validations": [], @@ -155,12 +150,10 @@ def test_null(self): [ "label", "confidence", - "analysis", ], ) self.assertEqual(serializer.errors["label"][0].code, "null") self.assertEqual(serializer.errors["confidence"][0].code, "null") - self.assertEqual(serializer.errors["analysis"][0].code, "null") def test_null_confidence_in_campaign_without_confidence(self): serializer = self._get_serializer( @@ -177,13 +170,11 @@ def test_does_not_exist(self): { "label": "DCall", # label exist in different label set "confidence": "test", - "analysis": -1, } ) self.assertFalse(serializer.is_valid(raise_exception=False)) self.assertEqual(serializer.errors["label"][0].code, "does_not_exist") self.assertEqual(serializer.errors["confidence"][0].code, "does_not_exist") - self.assertEqual(serializer.errors["analysis"][0].code, "does_not_exist") def test_min_value(self): serializer = self._get_serializer( @@ -227,12 +218,10 @@ def setUp(self): annotator = ( AnnotationFileRange.objects.filter(annotation_phase=phase).first().annotator ) - analysis: SpectrogramAnalysis = phase.annotation_campaign.analysis.first() features_instance = AcousticFeatures.objects.create(**features) self.instance = Annotation.objects.create( annotation_phase=phase, - analysis=analysis, - spectrogram=analysis.spectrograms.first(), + spectrogram=phase.annotation_campaign.spectrograms.first(), annotator=annotator, label=phase.annotation_campaign.label_set.labels.first(), confidence=phase.annotation_campaign.confidence_set.confidence_indicators.first(), @@ -271,7 +260,7 @@ def test_presence(self): self.assertEqual(instance.type, Annotation.Type.WEAK) self.assertEqual(instance.label.name, "Boat") self.assertEqual(instance.confidence.label, "confident") - self.assertEqual(instance.analysis_id, PHASE_ID) + self.assertEqual(instance.annotation_phase_id, PHASE_ID) self.assertEqual(instance.spectrogram_id, SPECTROGRAM_ID) self.assertEqual(instance.annotator_id, USER_ID) self.assertIsNone(instance.acoustic_features) @@ -288,7 +277,7 @@ def test_box(self): self.assertEqual(instance.start_time, 0.0) self.assertEqual(instance.label.name, "Boat") self.assertEqual(instance.confidence.label, "confident") - self.assertEqual(instance.analysis_id, PHASE_ID) + self.assertEqual(instance.annotation_phase_id, PHASE_ID) self.assertEqual(instance.spectrogram_id, SPECTROGRAM_ID) self.assertEqual(instance.annotator_id, USER_ID) self.assertEqual(instance.acoustic_features.start_frequency, 10.0) @@ -321,7 +310,6 @@ def test_box_update_label(self): serializer = AnnotationSerializer( data={ "is_update_of": 1, - "analysis": 1, "label": "Mysticetes", "confidence": "confident", "start_time": 0.0, diff --git a/backend/api/tests/view/annotation/import_csv/bellow_frequency.csv b/backend/api/tests/view/annotation/import_csv/bellow_frequency.csv index 5847ed1b6..8bd2138e1 100644 --- a/backend/api/tests/view/annotation/import_csv/bellow_frequency.csv +++ b/backend/api/tests/view/annotation/import_csv/bellow_frequency.csv @@ -1,2 +1,2 @@ -dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,analysis,detector_configuration__configuration -Dataset,-1,-1,click,nnini,2012-10-03T10:00:00.800+00:00,2012-10-03T10:00:01.800+00:00,1,sure,1,1,test +dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,detector_configuration__configuration +Dataset,-1,-1,click,nnini,2012-10-03T10:00:00.800+00:00,2012-10-03T10:00:01.800+00:00,1,sure,1,test diff --git a/backend/api/tests/view/annotation/import_csv/box_one_file_annotation.csv b/backend/api/tests/view/annotation/import_csv/box_one_file_annotation.csv index fe82333a6..32a38d909 100644 --- a/backend/api/tests/view/annotation/import_csv/box_one_file_annotation.csv +++ b/backend/api/tests/view/annotation/import_csv/box_one_file_annotation.csv @@ -1,2 +1,2 @@ -dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,analysis,detector_configuration__configuration -Dataset,100,200,click,nnini,2012-10-03T10:00:00.800+00:00,2012-10-03T10:00:01.800+00:00,1,sure,1,1,test +dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,detector_configuration__configuration +Dataset,100,200,click,nnini,2012-10-03T10:00:00.800+00:00,2012-10-03T10:00:01.800+00:00,1,sure,1,test diff --git a/backend/api/tests/view/annotation/import_csv/box_two_files_annotation.csv b/backend/api/tests/view/annotation/import_csv/box_two_files_annotation.csv index 3ce23a297..889f030c3 100644 --- a/backend/api/tests/view/annotation/import_csv/box_two_files_annotation.csv +++ b/backend/api/tests/view/annotation/import_csv/box_two_files_annotation.csv @@ -1,2 +1,2 @@ -dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,analysis,detector_configuration__configuration -Dataset,100,200,click,nnini,2012-10-03T10:00:00.800+00:00,2012-10-03T11:00:08+00:00,1,sure,1,1,test +dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,detector_configuration__configuration +Dataset,100,200,click,nnini,2012-10-03T10:00:00.800+00:00,2012-10-03T11:00:08+00:00,1,sure,1,test diff --git a/backend/api/tests/view/annotation/import_csv/incorrect_time.csv b/backend/api/tests/view/annotation/import_csv/incorrect_time.csv index b56806eee..e9f3126d7 100644 --- a/backend/api/tests/view/annotation/import_csv/incorrect_time.csv +++ b/backend/api/tests/view/annotation/import_csv/incorrect_time.csv @@ -1,2 +1,2 @@ -dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,analysis,detector_configuration__configuration -Dataset,100,200,click,nnini,2032-10-03T10:00:00+00:00,2032-10-03T10:15:00+00:00,1,sure,1,1,test +dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,detector_configuration__configuration +Dataset,100,200,click,nnini,2032-10-03T10:00:00+00:00,2032-10-03T10:15:00+00:00,1,sure,1,test diff --git a/backend/api/tests/view/annotation/import_csv/over_frequency.csv b/backend/api/tests/view/annotation/import_csv/over_frequency.csv index 4db71e682..ae6c62117 100644 --- a/backend/api/tests/view/annotation/import_csv/over_frequency.csv +++ b/backend/api/tests/view/annotation/import_csv/over_frequency.csv @@ -1,2 +1,2 @@ -dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,analysis,detector_configuration__configuration -Dataset,300000,400000,click,nnini,2012-10-03T10:00:00.800+00:00,2012-10-03T10:00:01.800+00:00,1,sure,1,1,test +dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,detector_configuration__configuration +Dataset,300000,400000,click,nnini,2012-10-03T10:00:00.800+00:00,2012-10-03T10:00:01.800+00:00,1,sure,1,test diff --git a/backend/api/tests/view/annotation/import_csv/point_annotation.csv b/backend/api/tests/view/annotation/import_csv/point_annotation.csv index ea76dea37..9d45e126d 100644 --- a/backend/api/tests/view/annotation/import_csv/point_annotation.csv +++ b/backend/api/tests/view/annotation/import_csv/point_annotation.csv @@ -1,2 +1,2 @@ -dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,analysis,detector_configuration__configuration -Dataset,100,100,click,nnini,2012-10-03T10:00:00.800+00:00,2012-10-03T10:00:00.800+00:00,1,sure,1,1,test +dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,detector_configuration__configuration +Dataset,100,100,click,nnini,2012-10-03T10:00:00.800+00:00,2012-10-03T10:00:00.800+00:00,1,sure,1,test diff --git a/backend/api/tests/view/annotation/import_csv/point_annotation_no_end_frequency.csv b/backend/api/tests/view/annotation/import_csv/point_annotation_no_end_frequency.csv index 83e231705..8c7c4eb30 100644 --- a/backend/api/tests/view/annotation/import_csv/point_annotation_no_end_frequency.csv +++ b/backend/api/tests/view/annotation/import_csv/point_annotation_no_end_frequency.csv @@ -1,2 +1,2 @@ -dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,analysis,detector_configuration__configuration -Dataset,100,,click,nnini,2012-10-03T10:00:00.800+00:00,2012-10-03T10:00:00.800+00:00,1,sure,1,1,test +dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,detector_configuration__configuration +Dataset,100,,click,nnini,2012-10-03T10:00:00.800+00:00,2012-10-03T10:00:00.800+00:00,1,sure,1,test diff --git a/backend/api/tests/view/annotation/import_csv/weak_one_file_annotation.csv b/backend/api/tests/view/annotation/import_csv/weak_one_file_annotation.csv index 4833da549..ef7a3b818 100644 --- a/backend/api/tests/view/annotation/import_csv/weak_one_file_annotation.csv +++ b/backend/api/tests/view/annotation/import_csv/weak_one_file_annotation.csv @@ -1,2 +1,2 @@ -dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,analysis,detector_configuration__configuration -Dataset,0,240,click,nnini,2012-10-03T10:00:00+00:00,2012-10-03T10:15:00+00:00,0,sure,1,1,test +dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,detector_configuration__configuration +Dataset,0,240,click,nnini,2012-10-03T10:00:00+00:00,2012-10-03T10:15:00+00:00,0,sure,1,test diff --git a/backend/api/tests/view/annotation/import_csv/weak_two_files_annotation.csv b/backend/api/tests/view/annotation/import_csv/weak_two_files_annotation.csv index 60739a91b..239f07d50 100644 --- a/backend/api/tests/view/annotation/import_csv/weak_two_files_annotation.csv +++ b/backend/api/tests/view/annotation/import_csv/weak_two_files_annotation.csv @@ -1,2 +1,2 @@ -dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,analysis,detector_configuration__configuration -Dataset,0,240,click,nnini,2012-10-03T10:00:00+00:00,2012-10-03T11:10:00+00:00,0,sure,1,1,test +dataset,start_frequency,end_frequency,label__name,detector__name,start_datetime,end_datetime,is_box,confidence__label,confidence__level,detector_configuration__configuration +Dataset,0,240,click,nnini,2012-10-03T10:00:00+00:00,2012-10-03T11:10:00+00:00,0,sure,1,test diff --git a/backend/api/tests/view/annotation/import_for_phase.py b/backend/api/tests/view/annotation/import_for_phase.py index d43ff83a5..705d45bc0 100644 --- a/backend/api/tests/view/annotation/import_for_phase.py +++ b/backend/api/tests/view/annotation/import_for_phase.py @@ -391,10 +391,12 @@ def test_campaign_owner_box_one_file(self): self.log_client(User.objects.get(username="user1")) url, phase_id, task_id = self._get_url() old_count = Annotation.objects.count() + print("before", Annotation.objects.all()) response = self.upload_csv_file_as_string( url, f"{os.path.dirname(os.path.realpath(__file__))}/import_csv/box_one_file_annotation.csv", ) + print("after", Annotation.objects.all()) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(Annotation.objects.count(), old_count + 1) self.assertEqual( diff --git a/backend/api/views/annotation.py b/backend/api/views/annotation.py index aa1b768b4..c099421af 100644 --- a/backend/api/views/annotation.py +++ b/backend/api/views/annotation.py @@ -4,6 +4,7 @@ from typing import Optional from django.db import transaction +from django.db.models import Max from django_extension.filters import get_boolean_query_param from django_extension.schema.errors import ForbiddenError, NotFoundError from rest_framework import viewsets, permissions, status, serializers @@ -15,7 +16,6 @@ Annotation, AnnotationPhase, Spectrogram, - SpectrogramAnalysis, DetectorConfiguration, Detector, AnnotationCampaign, @@ -72,19 +72,21 @@ def import_for_phase( status=status.HTTP_404_NOT_FOUND, ) + max_fft = phase.annotation_campaign.analysis.aggregate( + Max("fft__sampling_frequency") + )["fft__sampling_frequency__max"] reader = csv.DictReader(StringIO(request.data["data"])) annotations = [] for row in reader: - analysis: Optional[SpectrogramAnalysis] = SpectrogramAnalysis.objects.get( - pk=row["analysis"] - ) - - spectrograms = Spectrogram.objects.filter_matches_time_range( - start=datetime.fromisoformat(row["start_datetime"]), - end=datetime.fromisoformat(row["end_datetime"]), - ).filter( - analysis__dataset_id=phase.annotation_campaign.dataset_id, - analysis=analysis, + spectrograms = ( + Spectrogram.objects.filter_matches_time_range( + start=datetime.fromisoformat(row["start_datetime"]), + end=datetime.fromisoformat(row["end_datetime"]), + ) + .filter( + analysis__dataset_id=phase.annotation_campaign.dataset_id, + ) + .distinct() ) if not spectrograms.exists(): @@ -97,7 +99,7 @@ def import_for_phase( for s in spectrograms: annotation = self._get_annotation_for_spectrogram( - phase, analysis, s, row + phase, s, row, max_fft ) if annotation is not None: annotations.append(annotation) @@ -128,11 +130,7 @@ def import_for_phase( return Response(status=status.HTTP_201_CREATED) def _get_annotation_for_spectrogram( - self, - phase: AnnotationPhase, - analysis: SpectrogramAnalysis, - s: Spectrogram, - row: str, + self, phase: AnnotationPhase, s: Spectrogram, row: str, max_fft: int ) -> Optional[dict]: campaign: AnnotationCampaign = phase.annotation_campaign confidence = None @@ -148,7 +146,6 @@ def _get_annotation_for_spectrogram( "confidence": confidence, "annotation_phase": phase.id, "annotator": None, - "analysis": analysis, "annotator_expertise_level": None, "is_update_of": None, "detector_configuration": DetectorConfiguration.objects.get_or_create( @@ -168,7 +165,7 @@ def _get_annotation_for_spectrogram( ) none_end_frequency = ( annotation["end_frequency"] is None - or float(row["end_frequency"]) == analysis.fft.sampling_frequency / 2 + or float(row["end_frequency"]) == max_fft / 2 ) if ( @@ -199,7 +196,6 @@ def _get_annotation_for_spectrogram( return { **annotation, "spectrogram": annotation["spectrogram"].id, - "analysis": annotation["analysis"].id, "detector_configuration": annotation["detector_configuration"].id, } diff --git a/frontend/src/api/annotation-task/annotation-task.graphql b/frontend/src/api/annotation-task/annotation-task.graphql index 67b3fc8ac..9b43b4b24 100644 --- a/frontend/src/api/annotation-task/annotation-task.graphql +++ b/frontend/src/api/annotation-task/annotation-task.graphql @@ -210,9 +210,6 @@ query getAnnotationTask( frequencyJumpsCount hasDeterministicChaos } - analysis { - id - } } } annotationsToCheck { @@ -275,9 +272,6 @@ query getAnnotationTask( frequencyJumpsCount hasDeterministicChaos } - analysis { - id - } } } } diff --git a/frontend/src/api/annotation/api.ts b/frontend/src/api/annotation/api.ts index 5ffc8f0f8..c3442521a 100644 --- a/frontend/src/api/annotation/api.ts +++ b/frontend/src/api/annotation/api.ts @@ -10,7 +10,6 @@ const keys: (keyof ImportAnnotation)[] = [ 'label__name', 'confidence__label', 'confidence__level', - 'analysis', 'detector__name', 'detector_configuration__configuration', ]; diff --git a/frontend/src/api/annotation/types.ts b/frontend/src/api/annotation/types.ts index ae50148c1..abf14770b 100644 --- a/frontend/src/api/annotation/types.ts +++ b/frontend/src/api/annotation/types.ts @@ -9,9 +9,6 @@ export type ImportAnnotation = { /** [0 ; samplingFrequency/2] */ end_frequency?: number; - /** SpectrogramAnalysisNode.id */ - analysis: string | number; - label__name: string confidence__label?: string confidence__level?: number diff --git a/frontend/src/features/Annotator/Annotation/conversions.ts b/frontend/src/features/Annotator/Annotation/conversions.ts index b91761ec7..49d30ac5f 100644 --- a/frontend/src/features/Annotator/Annotation/conversions.ts +++ b/frontend/src/features/Annotator/Annotation/conversions.ts @@ -13,7 +13,6 @@ import { type DetectorConfigurationNode, type DetectorNode, type Maybe, - type SpectrogramAnalysisNode, type UserNode, } from '@/api'; import { type Annotation, type Features, type Validation } from './slice'; @@ -88,7 +87,6 @@ type Node = results: Maybe>[], }>, label: Pick, - analysis: Pick, annotationPhase: Pick } @@ -111,7 +109,6 @@ export function convertGqlToAnnotation(annotation: Node, startTime: annotation.startTime === null ? undefined : annotation.startTime, confidence: annotation.confidence?.label, detectorConfiguration: annotation.detectorConfiguration?.id, - analysis: annotation.analysis.id, } as Annotation } diff --git a/frontend/src/features/Annotator/Annotation/slice.ts b/frontend/src/features/Annotator/Annotation/slice.ts index 953213ba2..c21b1f5c8 100644 --- a/frontend/src/features/Annotator/Annotation/slice.ts +++ b/frontend/src/features/Annotator/Annotation/slice.ts @@ -7,12 +7,9 @@ import { AnnotationValidationSerializerInput, getAnnotationTaskFulfilled, GetAnnotationTaskQuery, - getCampaignFulfilled, - type GetCampaignQuery, getCurrentUserFulfilled, type GetCurrentUserQuery, } from '@/api'; -import { type Analysis, getDefaultAnalysisID, setAnalysis } from '@/features/Annotator/Analysis/slice'; import type { GetAnnotationTaskQueryVariables } from '@/api/annotation-task/annotation-task.generated'; import { convertGqlToAnnotations } from '@/features/Annotator/Annotation/conversions'; @@ -38,7 +35,6 @@ type AnnotationState = { id?: number; tempAnnotation?: TempAnnotation; - _analysisID?: string; _campaignID?: string _userID?: string } @@ -48,8 +44,8 @@ const initialState: AnnotationState = { id: undefined, tempAnnotation: undefined, - _analysisID: undefined, _campaignID: undefined, + _userID: undefined, } export const AnnotatorAnnotationSlice = createSlice({ @@ -63,13 +59,8 @@ export const AnnotatorAnnotationSlice = createSlice({ state.id = undefined }, addAnnotation: (state, action: { payload: Omit }) => { - if (!state._analysisID || state.allAnnotations.some(a => a.id === action.payload.id)) return; - const annotation: Annotation = { - ...action.payload, - analysis: state._analysisID, - } - state.allAnnotations = [ ...state.allAnnotations, annotation ]; - action.payload = annotation; + if (state.allAnnotations.some(a => a.id === action.payload.id)) return; + state.allAnnotations = [ ...state.allAnnotations, action.payload ]; }, updateAnnotation: (state, action: { payload: Partial & Pick }) => { const annotation: Annotation | undefined = state.allAnnotations.find(a => a.id === action.payload.id); @@ -78,9 +69,6 @@ export const AnnotatorAnnotationSlice = createSlice({ ...annotation, ...action.payload, } - if (state._analysisID) { - action.payload = { ...action.payload, analysis: state._analysisID } - } state.allAnnotations = state.allAnnotations.map(a => a.id === action.payload.id ? action.payload as Annotation : a) }, removeAnnotation: (state, action: { payload: Annotation }) => { @@ -94,14 +82,6 @@ export const AnnotatorAnnotationSlice = createSlice({ }, }, extraReducers: builder => { - builder.addCase(setAnalysis, (state: AnnotationState, action: { payload: Analysis }) => { - state._analysisID = action.payload?.id; - }) - builder.addMatcher(getCampaignFulfilled, (state: AnnotationState, action: { - payload: GetCampaignQuery - }) => { - state._analysisID = getDefaultAnalysisID({ data: action.payload, id: state._analysisID }) - }) builder.addMatcher(getCurrentUserFulfilled, (state: AnnotationState, action: { payload: GetCurrentUserQuery }) => { diff --git a/frontend/src/features/ImportAnnotations/AnalysisSelect.tsx b/frontend/src/features/ImportAnnotations/AnalysisSelect.tsx deleted file mode 100644 index 6f53b87b9..000000000 --- a/frontend/src/features/ImportAnnotations/AnalysisSelect.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React, { Fragment } from 'react'; -import { useCurrentCampaign } from '@/api'; -import { useImportAnnotationsContext } from '@/features/ImportAnnotations/context'; -import { type Item, Select } from '@/components/form'; -import { IonNote } from '@ionic/react'; - -export const AnalysisSelect: React.FC = () => { - const { allAnalysis } = useCurrentCampaign(); - const { - analysisID, - analysis, - setAnalysisID, - } = useImportAnnotationsContext() - - if (!allAnalysis) return - if (allAnalysis.length === 1) return Annotations belong to analysis { analysis?.name } - return