diff --git a/backend/api/models.py b/backend/api/models.py index 58699dd4..9ba82249 100644 --- a/backend/api/models.py +++ b/backend/api/models.py @@ -1,7 +1,7 @@ +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 @@ -39,8 +39,30 @@ 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']): - raise NotImplementedError() + @property + @abc.abstractmethod + def is_text_project(self) -> bool: + return False + + @property + 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): return self.name @@ -48,40 +70,82 @@ 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 + + @property + 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) 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 + + @property + def can_define_label(self) -> bool: + return True + + @property + def can_define_span(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 + + @property + 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): - 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 + + @property + def can_define_label(self) -> bool: + return True + + @property + def can_define_category(self) -> bool: + return True def generate_random_hex_color(): diff --git a/backend/api/serializers.py b/backend/api/serializers.py index 8fa2bac6..c4f00c0b 100644 --- a/backend/api/serializers.py +++ b/backend/api/serializers.py @@ -173,11 +173,21 @@ class ProjectSerializer(serializers.ModelSerializer): 'random_order', 'collaborative_annotation', 'single_class_classification', + 'is_text_project', + 'can_define_label', + 'can_define_relation', + 'can_define_category', + 'can_define_span', 'tags' ) read_only_fields = ( 'updated_at', 'users', + 'is_text_project', + 'can_define_label', + 'can_define_relation', + 'can_define_category', + 'can_define_span', 'tags' ) 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) diff --git a/frontend/domain/models/project/project.ts b/frontend/domain/models/project/project.ts index e0bb3ca0..a6f70048 100644 --- a/frontend/domain/models/project/project.ts +++ b/frontend/domain/models/project/project.ts @@ -17,6 +17,11 @@ export class ProjectReadItem { public allow_overlapping: boolean, public grapheme_mode: boolean, 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( @@ -34,7 +39,12 @@ export class ProjectReadItem { resourcetype, allow_overlapping, grapheme_mode, - tags + tags, + is_text_project, + can_define_label, + can_define_relation, + can_define_span, + can_define_category, }: { id: number, @@ -50,7 +60,12 @@ export class ProjectReadItem { resourcetype: string, allow_overlapping: boolean, grapheme_mode: boolean, - tags: Object[] + tags: Object[], + is_text_project: boolean, + can_define_label: boolean, + can_define_relation: boolean, + can_define_span: boolean, + can_define_category: boolean } ): ProjectReadItem { return new ProjectReadItem( @@ -67,7 +82,12 @@ export class ProjectReadItem { resourcetype, allow_overlapping, grapheme_mode, - tags + tags, + is_text_project, + can_define_label, + can_define_relation, + can_define_span, + can_define_category ) } @@ -85,66 +105,23 @@ export class ProjectReadItem { } get canDefineLabel() { - const allowedProjectTypes = [ - 'DocumentClassification', - 'SequenceLabeling', - 'IntentDetectionAndSlotFilling', - 'ImageClassification' - ] - return allowedProjectTypes.includes(this.project_type) + return this.can_define_label } get canDefineRelation() { - const allowedProjectTypes = [ - 'SequenceLabeling' - ] - return allowedProjectTypes.includes(this.project_type) + return this.can_define_relation } get isTextProject() { - const allowedProjectTypes = [ - 'DocumentClassification', - 'SequenceLabeling', - 'Seq2seq', - 'IntentDetectionAndSlotFilling' - ] - return allowedProjectTypes.includes(this.project_type) + return this.is_text_project } 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 - } + return this.can_define_span } }