Skip to content
Snippets Groups Projects
Commit 3d43ede7 authored by Erwan Rouchet's avatar Erwan Rouchet
Browse files

Merge branch 'create-transcriptions-list-elements' into 'master'

Add a parameter to serialize transcription elements in CreateElementTranscriptions

See merge request !863
parents d9680e36 c4339e35
No related branches found
No related tags found
1 merge request!863Add a parameter to serialize transcription elements in CreateElementTranscriptions
......@@ -13,7 +13,7 @@ from arkindex.documents.serializers.ml import (
ClassificationsSerializer, ClassificationCreateSerializer, ClassificationSerializer,
TranscriptionsSerializer, TranscriptionSerializer, TranscriptionCreateSerializer,
DataSourceStatsSerializer, ClassificationsSelectionSerializer, ClassificationMode,
CountMLClassSerializer, MLClassSerializer, ElementTranscriptionsBulkSerializer,
CountMLClassSerializer, MLClassSerializer, ElementTranscriptionsBulkSerializer, AnnotatedElementSerializer
)
from arkindex.images.importer import build_transcriptions, save_transcriptions
from arkindex.images.models import Zone
......@@ -126,6 +126,35 @@ class ElementTranscriptionsBulk(CreateAPIView):
'description': 'Create multiple sub elements with their transcriptions on a common parent in one transaction',
'operationId': 'CreateElementTranscriptions',
'tags': ['transcriptions'],
'responses': {
'201': {
'description': 'Created',
'content': {
'application/json': {
'examples': [{
'summary': 'return_elements = false',
'value': {
'element_type': 'string',
'transcription_type': 'string',
'source': 'string',
'transcriptions': {
'polygon': [[]],
'text': 'string',
'score': 0
},
'return_elements': False
}
}, {
'summary': 'return_elements = true',
'value': [{
'id': 'string',
'created': True
}]
}]
}
}
}
}
}
def get_object(self):
......@@ -144,6 +173,20 @@ class ElementTranscriptionsBulk(CreateAPIView):
context['element'] = self.get_object()
return context
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
annotations = self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
if serializer.validated_data['return_elements']:
# Re-serialize the annotated sub-elements
data = AnnotatedElementSerializer(annotations, many=True).data
else:
data = serializer.data
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
@transaction.atomic
def perform_create(self, serializer):
elt_type = serializer.validated_data['element_type']
......@@ -170,6 +213,7 @@ class ElementTranscriptionsBulk(CreateAPIView):
image_id=image.id,
polygon=annotation['polygon'],
)
existing_zones[annotation['polygon']] = annotation['zone']
missing_zones.append(annotation['zone'])
Zone.objects.bulk_create(missing_zones)
......@@ -198,6 +242,9 @@ class ElementTranscriptionsBulk(CreateAPIView):
type=elt_type,
name=next_path_ordering + 1
)
# Specify the annotated element has been created
annotation['created'] = True
children[annotation['zone'].id] = annotation['element']
missing_elements.append(annotation['element'])
for parent_path in paths:
new_path = parent_path.path + [self.element.id]
......@@ -229,6 +276,9 @@ class ElementTranscriptionsBulk(CreateAPIView):
# Index in ES
reindex_start(element=self.element, transcriptions=True, elements=True)
# Return ordered annotations
return annotations
class TranscriptionBulk(CreateAPIView, UpdateAPIView):
'''
......
......@@ -328,6 +328,14 @@ class ElementTranscriptionsBulkSerializer(serializers.Serializer):
allow_empty=False,
help_text='A list of transcriptions with their text, score and element zone'
)
return_elements = serializers.BooleanField(
default=False,
help_text=(
'Return a list of annotations containing an `element` field with basic element informations '
'and a `created` field specifying if the element has been created for the annotation. '
'Elements are ordered corresponding to the `transcriptions` field and may be duplicated.'
)
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
......@@ -342,6 +350,16 @@ class ElementTranscriptionsBulkSerializer(serializers.Serializer):
return source
class AnnotatedElementSerializer(serializers.Serializer):
"""
Returns annotated element IDs specifying if they have been created
to hold a transcription.
"""
id = serializers.UUIDField(source='element.id')
# Specify if the element has been created for the annotation
created = serializers.BooleanField(default=False)
class ClassificationBulkSerializer(serializers.Serializer):
"""
Single classification serializer for bulk insertion
......
......@@ -273,3 +273,64 @@ class TestBulkElementTranscriptions(FixtureAPITestCase):
'score': ['This field is required.']
}]
})
@patch('arkindex.project.serializer_fields.MLTool.get')
@override_settings(ARKINDEX_FEATURES={'search': False})
def test_bulk_transcriptions_return_ordered_elements(self, ml_get_mock):
"""
return_elements field allows to serialize an ordered list of sub-elements holding the transcriptions
Returned elements may be duplicated in case the same zone is used for multiple transcriptions
"""
ml_get_mock.return_value.type = self.src.type
ml_get_mock.return_value.slug = self.src.slug
ml_get_mock.return_value.name = self.src.name
ml_get_mock.return_value.version = self.src.revision
self.src.internal = True
self.src.save()
transcriptions = [
([[13, 37], [133, 37], [133, 137], [13, 137], [13, 37]], 'stuck', 0.13),
([[13, 37], [133, 37], [133, 137], [13, 137], [13, 37]], 'stick', 0.33),
([[24, 42], [64, 42], [64, 142], [24, 142], [24, 42]], 'stock', 0.37),
# The existing line has the smallest ordering
(self.line.zone.polygon, 'stack', 0.42),
]
data = {
'element_type': 'text_line',
'transcription_type': 'line',
'source': self.src.slug,
'transcriptions': [{
'polygon': poly,
'text': text,
'score': score
} for poly, text, score in transcriptions],
'return_elements': True
}
self.client.force_login(self.internal_user)
with self.assertNumQueries(19):
response = self.client.post(
reverse('api:element-transcriptions-bulk', kwargs={'pk': self.page.id}),
format='json',
data=data
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
created_elts = Element.objects.get_descending(self.page.id).exclude(id=self.line.id)
self.assertEqual(created_elts.count(), 2)
first_elt = created_elts.get(transcriptions__text='stuck')
second_elt = created_elts.get(transcriptions__text='stock')
self.assertListEqual(response.json(), [{
'id': str(first_elt.id),
'created': True
}, {
'id': str(first_elt.id),
'created': False
}, {
'id': str(second_elt.id),
'created': True
}, {
'id': str(self.line.id),
'created': False
}])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment