You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

127 lines
3.2 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. import abc
  2. from typing import Any, Dict, Optional
  3. from pydantic import BaseModel, validator
  4. from projects.models import Project
  5. from label_types.models import LabelType, CategoryType, SpanType
  6. from labels.models import Category, Span, TextLabel as TL
  7. class Label(BaseModel, abc.ABC):
  8. @abc.abstractmethod
  9. def has_name(self) -> bool:
  10. raise NotImplementedError()
  11. @property
  12. @abc.abstractmethod
  13. def name(self) -> str:
  14. raise NotImplementedError()
  15. @classmethod
  16. def parse(cls, obj: Any):
  17. raise NotImplementedError()
  18. @abc.abstractmethod
  19. def create(self, project: Project) -> Optional[LabelType]:
  20. raise NotImplementedError()
  21. @abc.abstractmethod
  22. def create_annotation(self, user, example, mapping):
  23. raise NotImplementedError
  24. def __hash__(self):
  25. return hash(tuple(self.dict()))
  26. class CategoryLabel(Label):
  27. label: str
  28. @validator("label")
  29. def label_is_not_empty(cls, value: str):
  30. if value:
  31. return value
  32. else:
  33. raise ValueError("is not empty.")
  34. def has_name(self) -> bool:
  35. return True
  36. @property
  37. def name(self) -> str:
  38. return self.label
  39. @classmethod
  40. def parse(cls, obj: Any):
  41. if isinstance(obj, str):
  42. return cls(label=obj)
  43. elif isinstance(obj, int):
  44. return cls(label=str(obj))
  45. else:
  46. raise TypeError(f"{obj} is not str.")
  47. def create(self, project: Project) -> Optional[LabelType]:
  48. return CategoryType(text=self.label, project=project)
  49. def create_annotation(self, user, example, mapping: Dict[str, LabelType]):
  50. return Category(user=user, example=example, label=mapping[self.label])
  51. class SpanLabel(Label):
  52. label: str
  53. start_offset: int
  54. end_offset: int
  55. def has_name(self) -> bool:
  56. return True
  57. @property
  58. def name(self) -> str:
  59. return self.label
  60. @classmethod
  61. def parse(cls, obj: Any):
  62. if isinstance(obj, list) or isinstance(obj, tuple):
  63. columns = ["start_offset", "end_offset", "label"]
  64. obj = zip(columns, obj)
  65. return cls.parse_obj(obj)
  66. elif isinstance(obj, dict):
  67. return cls.parse_obj(obj)
  68. else:
  69. raise TypeError(f"{obj} is invalid type.")
  70. def create(self, project: Project) -> Optional[LabelType]:
  71. return SpanType(text=self.label, project=project)
  72. def create_annotation(self, user, example, mapping: Dict[str, LabelType]):
  73. return Span(
  74. user=user,
  75. example=example,
  76. start_offset=self.start_offset,
  77. end_offset=self.end_offset,
  78. label=mapping[self.label],
  79. )
  80. class TextLabel(Label):
  81. text: str
  82. def has_name(self) -> bool:
  83. return False
  84. @property
  85. def name(self) -> str:
  86. return self.text
  87. @classmethod
  88. def parse(cls, obj: Any):
  89. if isinstance(obj, str) and obj:
  90. return cls(text=obj)
  91. else:
  92. raise TypeError(f"{obj} is not str or empty.")
  93. def create(self, project: Project) -> Optional[LabelType]:
  94. return None
  95. def create_annotation(self, user, example, mapping):
  96. return TL(user=user, example=example, text=self.text)