|
@ -2,7 +2,7 @@ import abc |
|
|
import uuid |
|
|
import uuid |
|
|
from typing import Any, Optional |
|
|
from typing import Any, Optional |
|
|
|
|
|
|
|
|
from pydantic import UUID4, BaseModel, validator |
|
|
|
|
|
|
|
|
from pydantic import UUID4, BaseModel, ConstrainedStr, NonNegativeInt, root_validator |
|
|
|
|
|
|
|
|
from .label_types import LabelTypes |
|
|
from .label_types import LabelTypes |
|
|
from examples.models import Example |
|
|
from examples.models import Example |
|
@ -15,6 +15,10 @@ from labels.models import TextLabel as TextLabelModel |
|
|
from projects.models import Project |
|
|
from projects.models import Project |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NonEmptyStr(ConstrainedStr): |
|
|
|
|
|
min_length = 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Label(BaseModel, abc.ABC): |
|
|
class Label(BaseModel, abc.ABC): |
|
|
id: int = -1 |
|
|
id: int = -1 |
|
|
uuid: UUID4 |
|
|
uuid: UUID4 |
|
@ -45,18 +49,11 @@ class Label(BaseModel, abc.ABC): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CategoryLabel(Label): |
|
|
class CategoryLabel(Label): |
|
|
label: str |
|
|
|
|
|
|
|
|
label: NonEmptyStr |
|
|
|
|
|
|
|
|
def __lt__(self, other): |
|
|
def __lt__(self, other): |
|
|
return self.label < other.label |
|
|
return self.label < other.label |
|
|
|
|
|
|
|
|
@validator("label") |
|
|
|
|
|
def label_is_not_empty(cls, value: str): |
|
|
|
|
|
if value: |
|
|
|
|
|
return value |
|
|
|
|
|
else: |
|
|
|
|
|
raise ValueError("is not empty.") |
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
@classmethod |
|
|
def parse(cls, example_uuid: UUID4, obj: Any): |
|
|
def parse(cls, example_uuid: UUID4, obj: Any): |
|
|
return cls(example_uuid=example_uuid, label=obj) |
|
|
return cls(example_uuid=example_uuid, label=obj) |
|
@ -65,17 +62,24 @@ class CategoryLabel(Label): |
|
|
return CategoryType(text=self.label, project=project) |
|
|
return CategoryType(text=self.label, project=project) |
|
|
|
|
|
|
|
|
def create(self, user, example: Example, types: LabelTypes, **kwargs): |
|
|
def create(self, user, example: Example, types: LabelTypes, **kwargs): |
|
|
return CategoryModel(uuid=self.uuid, user=user, example=example, label=types.get_by_text(self.label)) |
|
|
|
|
|
|
|
|
return CategoryModel(uuid=self.uuid, user=user, example=example, label=types[self.label]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SpanLabel(Label): |
|
|
class SpanLabel(Label): |
|
|
label: str |
|
|
|
|
|
start_offset: int |
|
|
|
|
|
end_offset: int |
|
|
|
|
|
|
|
|
label: NonEmptyStr |
|
|
|
|
|
start_offset: NonNegativeInt |
|
|
|
|
|
end_offset: NonNegativeInt |
|
|
|
|
|
|
|
|
def __lt__(self, other): |
|
|
def __lt__(self, other): |
|
|
return self.start_offset < other.start_offset |
|
|
return self.start_offset < other.start_offset |
|
|
|
|
|
|
|
|
|
|
|
@root_validator |
|
|
|
|
|
def check_start_offset_is_less_than_end_offset(cls, values): |
|
|
|
|
|
start_offset, end_offset = values.get("start_offset"), values.get("end_offset") |
|
|
|
|
|
if start_offset >= end_offset: |
|
|
|
|
|
raise ValueError("start_offset must be less than end_offset.") |
|
|
|
|
|
return values |
|
|
|
|
|
|
|
|
@classmethod |
|
|
@classmethod |
|
|
def parse(cls, example_uuid: UUID4, obj: Any): |
|
|
def parse(cls, example_uuid: UUID4, obj: Any): |
|
|
if isinstance(obj, list) or isinstance(obj, tuple): |
|
|
if isinstance(obj, list) or isinstance(obj, tuple): |
|
@ -96,23 +100,16 @@ class SpanLabel(Label): |
|
|
example=example, |
|
|
example=example, |
|
|
start_offset=self.start_offset, |
|
|
start_offset=self.start_offset, |
|
|
end_offset=self.end_offset, |
|
|
end_offset=self.end_offset, |
|
|
label=types.get_by_text(self.label), |
|
|
|
|
|
|
|
|
label=types[self.label], |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TextLabel(Label): |
|
|
class TextLabel(Label): |
|
|
text: str |
|
|
|
|
|
|
|
|
text: NonEmptyStr |
|
|
|
|
|
|
|
|
def __lt__(self, other): |
|
|
def __lt__(self, other): |
|
|
return self.text < other.text |
|
|
return self.text < other.text |
|
|
|
|
|
|
|
|
@validator("text") |
|
|
|
|
|
def text_is_not_empty(cls, value: str): |
|
|
|
|
|
if value: |
|
|
|
|
|
return value |
|
|
|
|
|
else: |
|
|
|
|
|
raise ValueError("is not empty.") |
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
@classmethod |
|
|
def parse(cls, example_uuid: UUID4, obj: Any): |
|
|
def parse(cls, example_uuid: UUID4, obj: Any): |
|
|
return cls(example_uuid=example_uuid, text=obj) |
|
|
return cls(example_uuid=example_uuid, text=obj) |
|
@ -127,7 +124,7 @@ class TextLabel(Label): |
|
|
class RelationLabel(Label): |
|
|
class RelationLabel(Label): |
|
|
from_id: int |
|
|
from_id: int |
|
|
to_id: int |
|
|
to_id: int |
|
|
type: str |
|
|
|
|
|
|
|
|
type: NonEmptyStr |
|
|
|
|
|
|
|
|
def __lt__(self, other): |
|
|
def __lt__(self, other): |
|
|
return self.from_id < other.from_id |
|
|
return self.from_id < other.from_id |
|
@ -144,7 +141,7 @@ class RelationLabel(Label): |
|
|
uuid=self.uuid, |
|
|
uuid=self.uuid, |
|
|
user=user, |
|
|
user=user, |
|
|
example=example, |
|
|
example=example, |
|
|
type=types.get_by_text(self.type), |
|
|
|
|
|
|
|
|
type=types[self.type], |
|
|
from_id=kwargs["id_to_span"][self.from_id], |
|
|
from_id=kwargs["id_to_span"][self.from_id], |
|
|
to_id=kwargs["id_to_span"][self.to_id], |
|
|
to_id=kwargs["id_to_span"][self.to_id], |
|
|
) |
|
|
) |