mirror of https://github.com/doccano/doccano.git
Browse Source
Merge pull request #1646 from doccano/enhancement/separateAutoLabelingApp
Merge pull request #1646 from doccano/enhancement/separateAutoLabelingApp
[Enhancement] Separate auto labeling apppull/1647/head
Hiroki Nakayama
2 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 299 additions and 202 deletions
Split View
Diff Options
-
2Pipfile
-
18backend/api/admin.py
-
30backend/api/exceptions.py
-
26backend/api/migrations/0030_delete_autolabelingconfig.py
-
30backend/api/models.py
-
53backend/api/serializers.py
-
5backend/api/tests/api/test_annotation.py
-
3backend/api/tests/api/test_document.py
-
3backend/api/tests/api/test_label.py
-
7backend/api/tests/api/utils.py
-
5backend/api/tests/test_filters.py
-
6backend/api/tests/test_models.py
-
49backend/api/urls.py
-
1backend/app/settings.py
-
1backend/app/urls.py
-
0backend/auto_labeling/__init__.py
-
17backend/auto_labeling/admin.py
-
6backend/auto_labeling/apps.py
-
29backend/auto_labeling/exceptions.py
-
37backend/auto_labeling/migrations/0001_initial.py
-
0backend/auto_labeling/migrations/__init__.py
-
34backend/auto_labeling/models.py
-
55backend/auto_labeling/serializers.py
-
0backend/auto_labeling/tests/__init__.py
-
16backend/auto_labeling/tests/test_views.py
-
53backend/auto_labeling/urls.py
-
13backend/auto_labeling/views.py
-
2backend/members/tests.py
@ -0,0 +1,26 @@ |
|||
# Generated by Django 3.2.11 on 2022-01-20 04:17 |
|||
|
|||
from django.db import migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('api', '0029_auto_20220119_2333'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.SeparateDatabaseAndState( |
|||
state_operations=[ |
|||
migrations.DeleteModel( |
|||
name='AutoLabelingConfig', |
|||
), |
|||
], |
|||
database_operations=[ |
|||
migrations.AlterModelTable( |
|||
name='AutoLabelingConfig', |
|||
table='auto_labeling_autolabelingconfig' |
|||
) |
|||
] |
|||
) |
|||
] |
@ -0,0 +1,17 @@ |
|||
from django.contrib import admin |
|||
|
|||
from .models import AutoLabelingConfig |
|||
|
|||
|
|||
class AutoLabelingConfigAdmin(admin.ModelAdmin): |
|||
list_display = ('project', 'model_name', 'model_attrs',) |
|||
ordering = ('project',) |
|||
|
|||
def get_readonly_fields(self, request, obj=None): |
|||
if obj: |
|||
return ["model_name"] |
|||
else: |
|||
return [] |
|||
|
|||
|
|||
admin.site.register(AutoLabelingConfig, AutoLabelingConfigAdmin) |
@ -0,0 +1,6 @@ |
|||
from django.apps import AppConfig |
|||
|
|||
|
|||
class AutoLabelingConfig(AppConfig): |
|||
default_auto_field = 'django.db.models.BigAutoField' |
|||
name = 'auto_labeling' |
@ -0,0 +1,29 @@ |
|||
from rest_framework import status |
|||
from rest_framework.exceptions import APIException, PermissionDenied, ValidationError |
|||
|
|||
|
|||
class AutoLabelingException(APIException): |
|||
status_code = status.HTTP_400_BAD_REQUEST |
|||
default_detail = 'Auto labeling not allowed for the document with labels.' |
|||
|
|||
|
|||
class AutoLabelingPermissionDenied(PermissionDenied): |
|||
default_detail = 'You do not have permission to perform auto labeling.' \ |
|||
'Please ask the project administrators to add you.' |
|||
|
|||
|
|||
class URLConnectionError(ValidationError): |
|||
default_detail = 'Failed to establish a connection. Please check the URL or network.' |
|||
|
|||
|
|||
class AWSTokenError(ValidationError): |
|||
default_detail = 'The security token included in the request is invalid.' |
|||
|
|||
|
|||
class SampleDataException(ValidationError): |
|||
default_detail = 'The response is empty. Maybe the sample data is not appropriate.' \ |
|||
'Please specify another sample data which returns at least one label.' |
|||
|
|||
|
|||
class TemplateMappingError(ValidationError): |
|||
default_detail = 'The response cannot be mapped. You might need to change the template.' |
@ -0,0 +1,37 @@ |
|||
# Generated by Django 3.2.11 on 2022-01-20 04:17 |
|||
|
|||
from django.db import migrations, models |
|||
import django.db.models.deletion |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
initial = True |
|||
|
|||
dependencies = [ |
|||
('api', '0030_delete_autolabelingconfig'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.SeparateDatabaseAndState( |
|||
state_operations=[ |
|||
migrations.CreateModel( |
|||
name='AutoLabelingConfig', |
|||
fields=[ |
|||
('id', |
|||
models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|||
('model_name', models.CharField(max_length=100)), |
|||
('model_attrs', models.JSONField(default=dict)), |
|||
('template', models.TextField(default='')), |
|||
('label_mapping', models.JSONField(blank=True, default=dict)), |
|||
('default', models.BooleanField(default=False)), |
|||
('created_at', models.DateTimeField(auto_now_add=True)), |
|||
('updated_at', models.DateTimeField(auto_now=True)), |
|||
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, |
|||
related_name='auto_labeling_config', to='api.project')), |
|||
], |
|||
), |
|||
], |
|||
database_operations=[] |
|||
) |
|||
] |
@ -0,0 +1,34 @@ |
|||
from auto_labeling_pipeline.models import RequestModelFactory |
|||
from django.core.exceptions import ValidationError |
|||
from django.db import models |
|||
|
|||
from api.models import Project |
|||
|
|||
|
|||
class AutoLabelingConfig(models.Model): |
|||
model_name = models.CharField(max_length=100) |
|||
model_attrs = models.JSONField(default=dict) |
|||
template = models.TextField(default='') |
|||
label_mapping = models.JSONField(default=dict, blank=True) |
|||
project = models.ForeignKey( |
|||
to=Project, |
|||
on_delete=models.CASCADE, |
|||
related_name='auto_labeling_config' |
|||
) |
|||
default = models.BooleanField(default=False) |
|||
created_at = models.DateTimeField(auto_now_add=True) |
|||
updated_at = models.DateTimeField(auto_now=True) |
|||
|
|||
def __str__(self): |
|||
return self.model_name |
|||
|
|||
def clean_fields(self, exclude=None): |
|||
super().clean_fields(exclude=exclude) |
|||
try: |
|||
RequestModelFactory.find(self.model_name) |
|||
except NameError: |
|||
message = f'The specified model name {self.model_name} does not exist.' |
|||
raise ValidationError(message) |
|||
except Exception: |
|||
message = 'The attributes does not match the model.' |
|||
raise ValidationError(message) |
@ -0,0 +1,55 @@ |
|||
from auto_labeling_pipeline.models import RequestModelFactory |
|||
from rest_framework import serializers |
|||
|
|||
from api.models import DOCUMENT_CLASSIFICATION, SEQUENCE_LABELING, SEQ2SEQ, SPEECH2TEXT, \ |
|||
IMAGE_CLASSIFICATION |
|||
from api.serializers import CategorySerializer, SpanSerializer, TextLabelSerializer |
|||
from .models import AutoLabelingConfig |
|||
|
|||
|
|||
class AutoLabelingConfigSerializer(serializers.ModelSerializer): |
|||
|
|||
class Meta: |
|||
model = AutoLabelingConfig |
|||
fields = ('id', 'model_name', 'model_attrs', 'template', 'label_mapping', 'default') |
|||
read_only_fields = ('created_at', 'updated_at') |
|||
|
|||
def validate_model_name(self, value): |
|||
try: |
|||
RequestModelFactory.find(value) |
|||
except NameError: |
|||
raise serializers.ValidationError(f'The specified model name {value} does not exist.') |
|||
return value |
|||
|
|||
def valid_label_mapping(self, value): |
|||
if isinstance(value, dict): |
|||
return value |
|||
else: |
|||
raise serializers.ValidationError(f'The {value} is not a dictionary. Please specify it as a dictionary.') |
|||
|
|||
def validate(self, data): |
|||
try: |
|||
RequestModelFactory.create(data['model_name'], data['model_attrs']) |
|||
except Exception: |
|||
model = RequestModelFactory.find(data['model_name']) |
|||
schema = model.schema() |
|||
required_fields = ', '.join(schema['required']) if 'required' in schema else '' |
|||
raise serializers.ValidationError( |
|||
'The attributes does not match the model.' |
|||
'You need to correctly specify the required fields: {}'.format(required_fields) |
|||
) |
|||
return data |
|||
|
|||
|
|||
def get_annotation_serializer(task: str): |
|||
mapping = { |
|||
DOCUMENT_CLASSIFICATION: CategorySerializer, |
|||
SEQUENCE_LABELING: SpanSerializer, |
|||
SEQ2SEQ: TextLabelSerializer, |
|||
SPEECH2TEXT: TextLabelSerializer, |
|||
IMAGE_CLASSIFICATION: CategorySerializer, |
|||
} |
|||
try: |
|||
return mapping[task] |
|||
except KeyError: |
|||
raise ValueError(f'{task} is not implemented.') |
@ -0,0 +1,53 @@ |
|||
from django.urls import path |
|||
|
|||
from .views import (AutoLabelingConfigDetail, AutoLabelingConfigTest, AutoLabelingAnnotation, AutoLabelingMappingTest, |
|||
AutoLabelingTemplateListAPI, AutoLabelingTemplateDetailAPI, AutoLabelingConfigList, |
|||
AutoLabelingConfigParameterTest, AutoLabelingTemplateTest) |
|||
|
|||
urlpatterns = [ |
|||
path( |
|||
route='auto-labeling-templates', |
|||
view=AutoLabelingTemplateListAPI.as_view(), |
|||
name='auto_labeling_templates' |
|||
), |
|||
path( |
|||
route='auto-labeling-templates/<str:option_name>', |
|||
view=AutoLabelingTemplateDetailAPI.as_view(), |
|||
name='auto_labeling_template' |
|||
), |
|||
path( |
|||
route='auto-labeling-configs', |
|||
view=AutoLabelingConfigList.as_view(), |
|||
name='auto_labeling_configs' |
|||
), |
|||
path( |
|||
route='auto-labeling-configs/<int:config_id>', |
|||
view=AutoLabelingConfigDetail.as_view(), |
|||
name='auto_labeling_config' |
|||
), |
|||
path( |
|||
route='auto-labeling-config-testing', |
|||
view=AutoLabelingConfigTest.as_view(), |
|||
name='auto_labeling_config_test' |
|||
), |
|||
path( |
|||
route='examples/<int:example_id>/auto-labeling', |
|||
view=AutoLabelingAnnotation.as_view(), |
|||
name='auto_labeling_annotation' |
|||
), |
|||
path( |
|||
route='auto-labeling-parameter-testing', |
|||
view=AutoLabelingConfigParameterTest.as_view(), |
|||
name='auto_labeling_parameter_testing' |
|||
), |
|||
path( |
|||
route='auto-labeling-template-testing', |
|||
view=AutoLabelingTemplateTest.as_view(), |
|||
name='auto_labeling_template_test' |
|||
), |
|||
path( |
|||
route='auto-labeling-mapping-testing', |
|||
view=AutoLabelingMappingTest.as_view(), |
|||
name='auto_labeling_mapping_test' |
|||
) |
|||
] |
Write
Preview
Loading…
Cancel
Save