From fae65162efe29aefbdba35972d76b0f62ddff94f Mon Sep 17 00:00:00 2001 From: Hironsan Date: Fri, 14 Jan 2022 09:53:10 +0900 Subject: [PATCH 1/4] Add is_text_project property to Project model --- backend/api/models.py | 35 +++++++++++++++++++----------- backend/api/views/auto_labeling.py | 4 ++-- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/backend/api/models.py b/backend/api/models.py index 58699dd4..61c12cd6 100644 --- a/backend/api/models.py +++ b/backend/api/models.py @@ -1,3 +1,4 @@ +import abc import random import string import uuid @@ -39,7 +40,9 @@ class Project(PolymorphicModel): collaborative_annotation = models.BooleanField(default=False) single_class_classification = models.BooleanField(default=False) - def is_task_of(self, task: Literal['text', 'image', 'speech']): + @property + @abc.abstractmethod + def is_text_project(self) -> bool: raise NotImplementedError() def __str__(self): @@ -48,40 +51,46 @@ class Project(PolymorphicModel): class TextClassificationProject(Project): - def is_task_of(self, task: Literal['text', 'image', 'speech']): - return task == 'text' + @property + def is_text_project(self) -> bool: + return True class SequenceLabelingProject(Project): allow_overlapping = models.BooleanField(default=False) grapheme_mode = models.BooleanField(default=False) - def is_task_of(self, task: Literal['text', 'image', 'speech']): - return task == 'text' + @property + def is_text_project(self) -> bool: + return True class Seq2seqProject(Project): - def is_task_of(self, task: Literal['text', 'image', 'speech']): - return task == 'text' + @property + def is_text_project(self) -> bool: + return True class IntentDetectionAndSlotFillingProject(Project): - def is_task_of(self, task: Literal['text', 'image', 'speech']): - return task == 'text' + @property + def is_text_project(self) -> bool: + return True class Speech2textProject(Project): - def is_task_of(self, task: Literal['text', 'image', 'speech']): - return task == 'speech' + @property + def is_text_project(self) -> bool: + return False class ImageClassificationProject(Project): - def is_task_of(self, task: Literal['text', 'image', 'speech']): - return task == 'image' + @property + def is_text_project(self) -> bool: + return False def generate_random_hex_color(): diff --git a/backend/api/views/auto_labeling.py b/backend/api/views/auto_labeling.py index 6f9bbc31..137c0e17 100644 --- a/backend/api/views/auto_labeling.py +++ b/backend/api/views/auto_labeling.py @@ -142,7 +142,7 @@ class AutoLabelingConfigParameterTest(APIView): def prepare_example(self): text = self.request.data['text'] - if self.project.is_task_of('text'): + if self.project.is_text_project: return text else: tu = TemporaryUpload.objects.get(upload_id=text) @@ -221,7 +221,7 @@ class AutoLabelingAnnotation(generics.CreateAPIView): def get_example(self, project): example = get_object_or_404(Example, pk=self.kwargs['example_id']) - if project.is_task_of('text'): + if project.is_text_project: return example.text else: return str(example.filename) From 06be25d336454b0b3ccb3e4ec9e83eac1fd89273 Mon Sep 17 00:00:00 2001 From: Hironsan Date: Fri, 14 Jan 2022 10:11:18 +0900 Subject: [PATCH 2/4] Add is_text_project field to ProjectSerializer --- backend/api/models.py | 2 +- backend/api/serializers.py | 2 ++ frontend/domain/models/project/project.ts | 21 ++++++++++----------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/backend/api/models.py b/backend/api/models.py index 61c12cd6..fd268e94 100644 --- a/backend/api/models.py +++ b/backend/api/models.py @@ -43,7 +43,7 @@ class Project(PolymorphicModel): @property @abc.abstractmethod def is_text_project(self) -> bool: - raise NotImplementedError() + return False def __str__(self): return self.name diff --git a/backend/api/serializers.py b/backend/api/serializers.py index 8fa2bac6..c873b136 100644 --- a/backend/api/serializers.py +++ b/backend/api/serializers.py @@ -173,11 +173,13 @@ class ProjectSerializer(serializers.ModelSerializer): 'random_order', 'collaborative_annotation', 'single_class_classification', + 'is_text_project', 'tags' ) read_only_fields = ( 'updated_at', 'users', + 'is_text_project', 'tags' ) diff --git a/frontend/domain/models/project/project.ts b/frontend/domain/models/project/project.ts index e0bb3ca0..2c3c1e1a 100644 --- a/frontend/domain/models/project/project.ts +++ b/frontend/domain/models/project/project.ts @@ -17,6 +17,7 @@ export class ProjectReadItem { public allow_overlapping: boolean, public grapheme_mode: boolean, public tags: Object[], + public is_text_project: boolean, ) {} static valueOf( @@ -34,7 +35,8 @@ export class ProjectReadItem { resourcetype, allow_overlapping, grapheme_mode, - tags + tags, + is_text_project }: { id: number, @@ -50,7 +52,8 @@ export class ProjectReadItem { resourcetype: string, allow_overlapping: boolean, grapheme_mode: boolean, - tags: Object[] + tags: Object[], + is_text_project: boolean } ): ProjectReadItem { return new ProjectReadItem( @@ -67,7 +70,8 @@ export class ProjectReadItem { resourcetype, allow_overlapping, grapheme_mode, - tags + tags, + is_text_project ) } @@ -102,13 +106,7 @@ export class ProjectReadItem { } get isTextProject() { - const allowedProjectTypes = [ - 'DocumentClassification', - 'SequenceLabeling', - 'Seq2seq', - 'IntentDetectionAndSlotFilling' - ] - return allowedProjectTypes.includes(this.project_type) + return this.is_text_project } get hasCategory(): boolean { @@ -143,7 +141,8 @@ export class ProjectReadItem { resourcetype: this.resourcetype, allow_overlapping: this.allow_overlapping, grapheme_mode: this.grapheme_mode, - tags: this.tags + tags: this.tags, + is_text_project: this.is_text_project } } } From 80074942a968e4a5932850469fbd1772bd7eed47 Mon Sep 17 00:00:00 2001 From: Hironsan Date: Fri, 14 Jan 2022 10:21:45 +0900 Subject: [PATCH 3/4] Add can_define_label method to project model --- backend/api/models.py | 29 +++++++++++++++++++++++ backend/api/serializers.py | 2 ++ frontend/domain/models/project/project.ts | 21 ++++++++-------- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/backend/api/models.py b/backend/api/models.py index fd268e94..e79288e4 100644 --- a/backend/api/models.py +++ b/backend/api/models.py @@ -45,6 +45,11 @@ class Project(PolymorphicModel): def is_text_project(self) -> bool: return False + @property + @abc.abstractmethod + def can_define_label(self) -> bool: + return False + def __str__(self): return self.name @@ -55,6 +60,10 @@ class TextClassificationProject(Project): def is_text_project(self) -> bool: return True + @property + def can_define_label(self) -> bool: + return True + class SequenceLabelingProject(Project): allow_overlapping = models.BooleanField(default=False) @@ -64,6 +73,10 @@ class SequenceLabelingProject(Project): def is_text_project(self) -> bool: return True + @property + def can_define_label(self) -> bool: + return True + class Seq2seqProject(Project): @@ -71,6 +84,10 @@ class Seq2seqProject(Project): def is_text_project(self) -> bool: return True + @property + def can_define_label(self) -> bool: + return False + class IntentDetectionAndSlotFillingProject(Project): @@ -78,6 +95,10 @@ class IntentDetectionAndSlotFillingProject(Project): def is_text_project(self) -> bool: return True + @property + def can_define_label(self) -> bool: + return True + class Speech2textProject(Project): @@ -85,6 +106,10 @@ class Speech2textProject(Project): def is_text_project(self) -> bool: return False + @property + def can_define_label(self) -> bool: + return False + class ImageClassificationProject(Project): @@ -92,6 +117,10 @@ class ImageClassificationProject(Project): def is_text_project(self) -> bool: return False + @property + def can_define_label(self) -> bool: + return True + def generate_random_hex_color(): return f'#{random.randint(0, 0xFFFFFF):06x}' diff --git a/backend/api/serializers.py b/backend/api/serializers.py index c873b136..c09b4b66 100644 --- a/backend/api/serializers.py +++ b/backend/api/serializers.py @@ -174,12 +174,14 @@ class ProjectSerializer(serializers.ModelSerializer): 'collaborative_annotation', 'single_class_classification', 'is_text_project', + 'can_define_label', 'tags' ) read_only_fields = ( 'updated_at', 'users', 'is_text_project', + 'can_define_label', 'tags' ) diff --git a/frontend/domain/models/project/project.ts b/frontend/domain/models/project/project.ts index 2c3c1e1a..01bb21ee 100644 --- a/frontend/domain/models/project/project.ts +++ b/frontend/domain/models/project/project.ts @@ -18,6 +18,7 @@ export class ProjectReadItem { public grapheme_mode: boolean, public tags: Object[], public is_text_project: boolean, + public can_define_label: boolean, ) {} static valueOf( @@ -36,7 +37,8 @@ export class ProjectReadItem { allow_overlapping, grapheme_mode, tags, - is_text_project + is_text_project, + can_define_label, }: { id: number, @@ -53,7 +55,8 @@ export class ProjectReadItem { allow_overlapping: boolean, grapheme_mode: boolean, tags: Object[], - is_text_project: boolean + is_text_project: boolean, + can_define_label: boolean } ): ProjectReadItem { return new ProjectReadItem( @@ -71,7 +74,8 @@ export class ProjectReadItem { allow_overlapping, grapheme_mode, tags, - is_text_project + is_text_project, + can_define_label ) } @@ -89,13 +93,7 @@ export class ProjectReadItem { } get canDefineLabel() { - const allowedProjectTypes = [ - 'DocumentClassification', - 'SequenceLabeling', - 'IntentDetectionAndSlotFilling', - 'ImageClassification' - ] - return allowedProjectTypes.includes(this.project_type) + return this.can_define_label } get canDefineRelation() { @@ -142,7 +140,8 @@ export class ProjectReadItem { allow_overlapping: this.allow_overlapping, grapheme_mode: this.grapheme_mode, tags: this.tags, - is_text_project: this.is_text_project + is_text_project: this.is_text_project, + can_define_label: this.can_define_label } } } From 9cb7abd3b6f217e67b52e92e0a43389001cd39b2 Mon Sep 17 00:00:00 2001 From: Hironsan Date: Fri, 14 Jan 2022 10:37:19 +0900 Subject: [PATCH 4/4] Add can_define_relation/span/category method to project model --- backend/api/models.py | 46 ++++++++++++++----- backend/api/serializers.py | 6 +++ frontend/domain/models/project/project.ts | 55 +++++++---------------- 3 files changed, 59 insertions(+), 48 deletions(-) diff --git a/backend/api/models.py b/backend/api/models.py index e79288e4..9ba82249 100644 --- a/backend/api/models.py +++ b/backend/api/models.py @@ -2,7 +2,6 @@ import abc import random import string import uuid -from typing import Literal from auto_labeling_pipeline.models import RequestModelFactory from django.contrib.auth.models import User @@ -46,8 +45,23 @@ class Project(PolymorphicModel): return False @property - @abc.abstractmethod def can_define_label(self) -> bool: + """Whether or not the project can define label(ignoring the type of label)""" + return False + + @property + def can_define_relation(self) -> bool: + """Whether or not the project can define relation.""" + return False + + @property + def can_define_category(self) -> bool: + """Whether or not the project can define category.""" + return False + + @property + def can_define_span(self) -> bool: + """Whether or not the project can define span.""" return False def __str__(self): @@ -64,6 +78,10 @@ class TextClassificationProject(Project): def can_define_label(self) -> bool: return True + @property + def can_define_category(self) -> bool: + return True + class SequenceLabelingProject(Project): allow_overlapping = models.BooleanField(default=False) @@ -77,6 +95,10 @@ class SequenceLabelingProject(Project): def can_define_label(self) -> bool: return True + @property + def can_define_span(self) -> bool: + return True + class Seq2seqProject(Project): @@ -84,10 +106,6 @@ class Seq2seqProject(Project): def is_text_project(self) -> bool: return True - @property - def can_define_label(self) -> bool: - return False - class IntentDetectionAndSlotFillingProject(Project): @@ -99,6 +117,14 @@ class IntentDetectionAndSlotFillingProject(Project): def can_define_label(self) -> bool: return True + @property + def can_define_category(self) -> bool: + return True + + @property + def can_define_span(self) -> bool: + return True + class Speech2textProject(Project): @@ -106,10 +132,6 @@ class Speech2textProject(Project): def is_text_project(self) -> bool: return False - @property - def can_define_label(self) -> bool: - return False - class ImageClassificationProject(Project): @@ -121,6 +143,10 @@ class ImageClassificationProject(Project): def can_define_label(self) -> bool: return True + @property + def can_define_category(self) -> bool: + return True + def generate_random_hex_color(): return f'#{random.randint(0, 0xFFFFFF):06x}' diff --git a/backend/api/serializers.py b/backend/api/serializers.py index c09b4b66..c4f00c0b 100644 --- a/backend/api/serializers.py +++ b/backend/api/serializers.py @@ -175,6 +175,9 @@ class ProjectSerializer(serializers.ModelSerializer): 'single_class_classification', 'is_text_project', 'can_define_label', + 'can_define_relation', + 'can_define_category', + 'can_define_span', 'tags' ) read_only_fields = ( @@ -182,6 +185,9 @@ class ProjectSerializer(serializers.ModelSerializer): 'users', 'is_text_project', 'can_define_label', + 'can_define_relation', + 'can_define_category', + 'can_define_span', 'tags' ) diff --git a/frontend/domain/models/project/project.ts b/frontend/domain/models/project/project.ts index 01bb21ee..a6f70048 100644 --- a/frontend/domain/models/project/project.ts +++ b/frontend/domain/models/project/project.ts @@ -19,6 +19,9 @@ export class ProjectReadItem { public tags: Object[], public is_text_project: boolean, public can_define_label: boolean, + public can_define_relation: boolean, + public can_define_span: boolean, + public can_define_category: boolean, ) {} static valueOf( @@ -39,6 +42,9 @@ export class ProjectReadItem { tags, is_text_project, can_define_label, + can_define_relation, + can_define_span, + can_define_category, }: { id: number, @@ -56,7 +62,10 @@ export class ProjectReadItem { grapheme_mode: boolean, tags: Object[], is_text_project: boolean, - can_define_label: boolean + can_define_label: boolean, + can_define_relation: boolean, + can_define_span: boolean, + can_define_category: boolean } ): ProjectReadItem { return new ProjectReadItem( @@ -75,7 +84,10 @@ export class ProjectReadItem { grapheme_mode, tags, is_text_project, - can_define_label + can_define_label, + can_define_relation, + can_define_span, + can_define_category ) } @@ -97,10 +109,7 @@ export class ProjectReadItem { } get canDefineRelation() { - const allowedProjectTypes = [ - 'SequenceLabeling' - ] - return allowedProjectTypes.includes(this.project_type) + return this.can_define_relation } get isTextProject() { @@ -108,41 +117,11 @@ export class ProjectReadItem { } get hasCategory(): boolean { - const allowedProjectTypes = [ - 'DocumentClassification', - 'IntentDetectionAndSlotFilling', - 'ImageClassification' - ] - return allowedProjectTypes.includes(this.project_type) + return this.can_define_category } get hasSpan(): boolean { - const allowedProjectTypes = [ - 'IntentDetectionAndSlotFilling', - 'SequenceLabeling' - ] - return allowedProjectTypes.includes(this.project_type) - } - - toObject(): Object { - return { - id: this.id, - name: this.name, - description: this.description, - guideline: this.guideline, - users: this.users, - project_type: this.project_type, - updated_at: this.updated_at, - random_order: this.random_order, - collaborative_annotation: this.collaborative_annotation, - single_class_classification: this.single_class_classification, - resourcetype: this.resourcetype, - allow_overlapping: this.allow_overlapping, - grapheme_mode: this.grapheme_mode, - tags: this.tags, - is_text_project: this.is_text_project, - can_define_label: this.can_define_label - } + return this.can_define_span } }