Browse Source

Merge pull request #1632 from doccano/enhancement/refactorProjectModel

[Enhancement] refactor project model and serializer
pull/1633/head
Hiroki Nakayama 2 years ago
committed by GitHub
parent
commit
69511c3ad0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 119 additions and 68 deletions
  1. 94
      backend/api/models.py
  2. 10
      backend/api/serializers.py
  3. 4
      backend/api/views/auto_labeling.py
  4. 79
      frontend/domain/models/project/project.ts

94
backend/api/models.py

@ -1,7 +1,7 @@
import abc
import random import random
import string import string
import uuid import uuid
from typing import Literal
from auto_labeling_pipeline.models import RequestModelFactory from auto_labeling_pipeline.models import RequestModelFactory
from django.contrib.auth.models import User from django.contrib.auth.models import User
@ -39,8 +39,30 @@ class Project(PolymorphicModel):
collaborative_annotation = models.BooleanField(default=False) collaborative_annotation = models.BooleanField(default=False)
single_class_classification = 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): def __str__(self):
return self.name return self.name
@ -48,40 +70,82 @@ class Project(PolymorphicModel):
class TextClassificationProject(Project): 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): class SequenceLabelingProject(Project):
allow_overlapping = models.BooleanField(default=False) allow_overlapping = models.BooleanField(default=False)
grapheme_mode = 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): 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): 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): 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): 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(): def generate_random_hex_color():

10
backend/api/serializers.py

@ -173,11 +173,21 @@ class ProjectSerializer(serializers.ModelSerializer):
'random_order', 'random_order',
'collaborative_annotation', 'collaborative_annotation',
'single_class_classification', 'single_class_classification',
'is_text_project',
'can_define_label',
'can_define_relation',
'can_define_category',
'can_define_span',
'tags' 'tags'
) )
read_only_fields = ( read_only_fields = (
'updated_at', 'updated_at',
'users', 'users',
'is_text_project',
'can_define_label',
'can_define_relation',
'can_define_category',
'can_define_span',
'tags' 'tags'
) )

4
backend/api/views/auto_labeling.py

@ -142,7 +142,7 @@ class AutoLabelingConfigParameterTest(APIView):
def prepare_example(self): def prepare_example(self):
text = self.request.data['text'] text = self.request.data['text']
if self.project.is_task_of('text'):
if self.project.is_text_project:
return text return text
else: else:
tu = TemporaryUpload.objects.get(upload_id=text) tu = TemporaryUpload.objects.get(upload_id=text)
@ -221,7 +221,7 @@ class AutoLabelingAnnotation(generics.CreateAPIView):
def get_example(self, project): def get_example(self, project):
example = get_object_or_404(Example, pk=self.kwargs['example_id']) 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 return example.text
else: else:
return str(example.filename) return str(example.filename)

79
frontend/domain/models/project/project.ts

@ -17,6 +17,11 @@ export class ProjectReadItem {
public allow_overlapping: boolean, public allow_overlapping: boolean,
public grapheme_mode: boolean, public grapheme_mode: boolean,
public tags: Object[], 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( static valueOf(
@ -34,7 +39,12 @@ export class ProjectReadItem {
resourcetype, resourcetype,
allow_overlapping, allow_overlapping,
grapheme_mode, grapheme_mode,
tags
tags,
is_text_project,
can_define_label,
can_define_relation,
can_define_span,
can_define_category,
}: }:
{ {
id: number, id: number,
@ -50,7 +60,12 @@ export class ProjectReadItem {
resourcetype: string, resourcetype: string,
allow_overlapping: boolean, allow_overlapping: boolean,
grapheme_mode: 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 { ): ProjectReadItem {
return new ProjectReadItem( return new ProjectReadItem(
@ -67,7 +82,12 @@ export class ProjectReadItem {
resourcetype, resourcetype,
allow_overlapping, allow_overlapping,
grapheme_mode, 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() { get canDefineLabel() {
const allowedProjectTypes = [
'DocumentClassification',
'SequenceLabeling',
'IntentDetectionAndSlotFilling',
'ImageClassification'
]
return allowedProjectTypes.includes(this.project_type)
return this.can_define_label
} }
get canDefineRelation() { get canDefineRelation() {
const allowedProjectTypes = [
'SequenceLabeling'
]
return allowedProjectTypes.includes(this.project_type)
return this.can_define_relation
} }
get isTextProject() { get isTextProject() {
const allowedProjectTypes = [
'DocumentClassification',
'SequenceLabeling',
'Seq2seq',
'IntentDetectionAndSlotFilling'
]
return allowedProjectTypes.includes(this.project_type)
return this.is_text_project
} }
get hasCategory(): boolean { get hasCategory(): boolean {
const allowedProjectTypes = [
'DocumentClassification',
'IntentDetectionAndSlotFilling',
'ImageClassification'
]
return allowedProjectTypes.includes(this.project_type)
return this.can_define_category
} }
get hasSpan(): boolean { 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
} }
} }

Loading…
Cancel
Save