From 86ad772e935220f99465817cf1238bee6449d19c Mon Sep 17 00:00:00 2001 From: Andreas Divaris Date: Thu, 3 Aug 2023 08:15:48 -0700 Subject: [PATCH 1/5] feat: LSDV-5222: Add ids to labels to allow for persistence of custom label weights when changing label names --- label_studio/projects/models.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/label_studio/projects/models.py b/label_studio/projects/models.py index b4fbd6e665f4..a92f36b8a9f2 100644 --- a/label_studio/projects/models.py +++ b/label_studio/projects/models.py @@ -592,10 +592,33 @@ def get_updated_weights(self): control_type = outputs[control_name]['type'] if control_type in exclude_control_types: continue + + def get_label_id(label): + # Get label id from the 'labels_attrs' field, return None if 'id' is missing + return outputs[control_name]['labels_attrs'].get(label, {}).get('id') + + def get_label_data(label): + # Check if id exists for this label + label_id = get_label_id(label) + if label_id is not None: + # If id exists, try to fetch weight using id + weight = self.control_weights.get(control_name, {}).get('labels', {}).get(label_id, {}).get( + 'weight') + else: + # If id does not exist, fall back to using label name to fetch weight + weight = self.control_weights.get(control_name, {}).get('labels', {}).get(label, 1.0) + try: + weight = weight['weight'] + except TypeError: # in this case weight is already a float + pass + # Return a dictionary with the label's name and its weight + return {'name': label, 'weight': weight if weight is not None else 1.0} + control_weights[control_name] = { 'overall': self.control_weights.get(control_name, {}).get('overall') or 1.0, 'type': control_type, - 'labels': {label: self.control_weights.get(control_name, {}).get('labels', {}).get(label) or 1.0 for label in outputs[control_name].get('labels', [])}, + 'labels': {get_label_id(label) or label: get_label_data(label) for label in + outputs[control_name].get('labels', [])}, } return control_weights From 45c4cfa6d0d477516c330302203a80663ac6f6ea Mon Sep 17 00:00:00 2001 From: Andreas Divaris Date: Fri, 4 Aug 2023 16:39:30 -0700 Subject: [PATCH 2/5] Revert changes related to using a label id and add fix for resetting labels set to 0 --- label_studio/projects/models.py | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/label_studio/projects/models.py b/label_studio/projects/models.py index a92f36b8a9f2..8b5c284153dc 100644 --- a/label_studio/projects/models.py +++ b/label_studio/projects/models.py @@ -593,31 +593,13 @@ def get_updated_weights(self): if control_type in exclude_control_types: continue - def get_label_id(label): - # Get label id from the 'labels_attrs' field, return None if 'id' is missing - return outputs[control_name]['labels_attrs'].get(label, {}).get('id') - - def get_label_data(label): - # Check if id exists for this label - label_id = get_label_id(label) - if label_id is not None: - # If id exists, try to fetch weight using id - weight = self.control_weights.get(control_name, {}).get('labels', {}).get(label_id, {}).get( - 'weight') - else: - # If id does not exist, fall back to using label name to fetch weight - weight = self.control_weights.get(control_name, {}).get('labels', {}).get(label, 1.0) - try: - weight = weight['weight'] - except TypeError: # in this case weight is already a float - pass - # Return a dictionary with the label's name and its weight - return {'name': label, 'weight': weight if weight is not None else 1.0} + def get_label(label): + return self.control_weights.get(control_name, {}).get('labels', {}).get(label) control_weights[control_name] = { 'overall': self.control_weights.get(control_name, {}).get('overall') or 1.0, 'type': control_type, - 'labels': {get_label_id(label) or label: get_label_data(label) for label in + 'labels': {label: get_label(label) if get_label(label) is not None else 1.0 for label in outputs[control_name].get('labels', [])}, } return control_weights From bb2114c19078f7c4127a9ea47682d2fed23e98ba Mon Sep 17 00:00:00 2001 From: Andreas Divaris Date: Mon, 7 Aug 2023 15:51:06 -0700 Subject: [PATCH 3/5] Update get_label so it doesn't have to be called twice in comprehension --- label_studio/projects/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/label_studio/projects/models.py b/label_studio/projects/models.py index 8b5c284153dc..cc24cb1eb566 100644 --- a/label_studio/projects/models.py +++ b/label_studio/projects/models.py @@ -594,13 +594,13 @@ def get_updated_weights(self): continue def get_label(label): - return self.control_weights.get(control_name, {}).get('labels', {}).get(label) + label_value = self.control_weights.get(control_name, {}).get('labels', {}).get(label) + return label_value if label_value is not None else 1.0 control_weights[control_name] = { 'overall': self.control_weights.get(control_name, {}).get('overall') or 1.0, 'type': control_type, - 'labels': {label: get_label(label) if get_label(label) is not None else 1.0 for label in - outputs[control_name].get('labels', [])}, + 'labels': {label: get_label(label) for label in outputs[control_name].get('labels', [])}, } return control_weights From 15a1087bd684fb0f2438bc8d391ea699b60c82c5 Mon Sep 17 00:00:00 2001 From: Andreas Divaris Date: Tue, 8 Aug 2023 15:09:14 -0700 Subject: [PATCH 4/5] Update so overall section is also covered when it is set to 0 --- label_studio/projects/models.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/label_studio/projects/models.py b/label_studio/projects/models.py index cc24cb1eb566..b44bd3fd11e2 100644 --- a/label_studio/projects/models.py +++ b/label_studio/projects/models.py @@ -588,19 +588,22 @@ def get_updated_weights(self): outputs = self.get_parsed_config(autosave_cache=False) control_weights = {} exclude_control_types = ('Filter',) + + def get_value(key, subkey=None): + value = self.control_weights.get(control_name, {}).get(key, {}) + if subkey: + value = value.get(subkey) + return value if value is not None else 1.0 + for control_name in outputs: control_type = outputs[control_name]['type'] if control_type in exclude_control_types: continue - def get_label(label): - label_value = self.control_weights.get(control_name, {}).get('labels', {}).get(label) - return label_value if label_value is not None else 1.0 - control_weights[control_name] = { - 'overall': self.control_weights.get(control_name, {}).get('overall') or 1.0, + 'overall': get_value('overall'), 'type': control_type, - 'labels': {label: get_label(label) for label in outputs[control_name].get('labels', [])}, + 'labels': {label: get_value('labels', label) for label in outputs[control_name].get('labels', [])}, } return control_weights From 0937b1717f8b5b16cbf1887a88966644bc7280e7 Mon Sep 17 00:00:00 2001 From: Andreas Divaris Date: Thu, 10 Aug 2023 12:37:47 -0700 Subject: [PATCH 5/5] Fix fetching of overall weight as there are subtle issues with the default values --- label_studio/projects/models.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/label_studio/projects/models.py b/label_studio/projects/models.py index 85a933347517..4a84735e4768 100644 --- a/label_studio/projects/models.py +++ b/label_studio/projects/models.py @@ -590,11 +590,18 @@ def get_updated_weights(self): control_weights = {} exclude_control_types = ('Filter',) - def get_value(key, subkey=None): - value = self.control_weights.get(control_name, {}).get(key, {}) - if subkey: - value = value.get(subkey) - return value if value is not None else 1.0 + def get_label(label): + label_value = self.control_weights.get(control_name, {}).get('labels', {}).get(label) + return label_value if label_value is not None else 1.0 + + def get_overall(name): + weights = self.control_weights.get(name, None) + if not weights: + return 1.0 + else: + weight = weights.get('overall', None) + return weight if weight is not None else 1.0 + for control_name in outputs: control_type = outputs[control_name]['type'] @@ -602,9 +609,9 @@ def get_value(key, subkey=None): continue control_weights[control_name] = { - 'overall': get_value('overall'), + 'overall': get_overall(control_name), 'type': control_type, - 'labels': {label: get_value('labels', label) for label in outputs[control_name].get('labels', [])}, + 'labels': {label: get_label(label) for label in outputs[control_name].get('labels', [])}, } return control_weights