Skip to content

Commit 8e79aa5

Browse files
sbatcheldermakseq
andauthored
feat: Cache Labels for Taxonomy (#7383)
Co-authored-by: Max Tkachenko <makseq@gmail.com>
1 parent 944e140 commit 8e79aa5

File tree

1 file changed

+29
-10
lines changed

1 file changed

+29
-10
lines changed

label_studio/data_manager/actions/cache_labels.py

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from core.permissions import AllPermissions
77
from core.redis import start_job_async_or_sync
8+
from label_studio_sdk.label_interface import LabelInterface
89
from tasks.models import Annotation, Prediction, Task
910

1011
logger = logging.getLogger(__name__)
@@ -18,6 +19,8 @@ def cache_labels_job(project, queryset, **kwargs):
1819
source_class = Annotation if source == 'annotations' else Prediction
1920
control_tag = request_data.get('custom_control_tag') or request_data.get('control_tag')
2021
with_counters = request_data.get('with_counters', 'Yes').lower() == 'yes'
22+
label_interface = LabelInterface(project.label_config)
23+
label_interface_tags = {tag.name: tag for tag in label_interface.find_tags('control')}
2124

2225
if source == 'annotations':
2326
column_name = 'cache'
@@ -38,7 +41,7 @@ def cache_labels_job(project, queryset, **kwargs):
3841
task_labels = []
3942
annotations = source_class.objects.filter(task=task).only('result')
4043
for annotation in annotations:
41-
labels = extract_labels(annotation, control_tag)
44+
labels = extract_labels(annotation, control_tag, label_interface_tags)
4245
task_labels.extend(labels)
4346

4447
# cache labels in separate data column
@@ -57,20 +60,36 @@ def cache_labels_job(project, queryset, **kwargs):
5760
return {'response_code': 200, 'detail': f'Updated {len(tasks)} tasks'}
5861

5962

60-
def extract_labels(annotation, control_tag):
63+
def extract_labels(annotation, control_tag, label_interface_tags=None):
6164
labels = []
6265
for region in annotation.result:
6366
# find regions with specific control tag name or just all regions if control tag is None
6467
if (control_tag is None or region['from_name'] == control_tag) and 'value' in region:
65-
# scan value for a field with list of strings,
66-
# as bonus it will work with textareas too
68+
# scan value for a field with list of strings (eg choices, textareas)
69+
# or taxonomy (list of string-lists)
6770
for key in region['value']:
68-
if (
69-
isinstance(region['value'][key], list)
70-
and region['value'][key]
71-
and isinstance(region['value'][key][0], str)
72-
):
73-
labels.extend(region['value'][key])
71+
if region['value'][key] and isinstance(region['value'][key], list):
72+
73+
if key == 'taxonomy':
74+
showFullPath = 'true'
75+
pathSeparator = '/'
76+
if label_interface_tags is not None and region['from_name'] in label_interface_tags:
77+
# if from_name is not a custom_control tag, then we can try to fetch taxonomy formatting params
78+
label_interface_tag = label_interface_tags[region['from_name']]
79+
showFullPath = label_interface_tag.attr.get('showFullPath', 'false')
80+
pathSeparator = label_interface_tag.attr.get('pathSeparator', '/')
81+
82+
if showFullPath == 'false':
83+
for elems in region['value'][key]:
84+
labels.append(elems[-1]) # just the leaf node of a taxonomy selection
85+
else:
86+
for elems in region['value'][key]:
87+
labels.append(pathSeparator.join(elems)) # the full delimited taxonomy path
88+
89+
# other control tag types like Choices & TextAreas
90+
elif isinstance(region['value'][key][0], str):
91+
labels.extend(region['value'][key])
92+
7493
break
7594
return labels
7695

0 commit comments

Comments
 (0)