diff --git a/runtime/datamate-python/app/module/annotation/service/template.py b/runtime/datamate-python/app/module/annotation/service/template.py index 61abeb5..9e36950 100644 --- a/runtime/datamate-python/app/module/annotation/service/template.py +++ b/runtime/datamate-python/app/module/annotation/service/template.py @@ -36,7 +36,7 @@ class AnnotationTemplateService: """ tag_config = LabelStudioTagConfig() control_types = tag_config.get_control_types() - xml_parts = [''] + text_object_types = {"Text", "Paragraphs", "ParagraphLabels", "HyperText", "Markdown"} def normalize_control_type(raw: Optional[str]) -> str: if not raw: @@ -49,15 +49,19 @@ class AnnotationTemplateService: return ct return raw + is_text_template = any((obj.type in text_object_types) for obj in config.objects) + # 生成对象定义 + object_parts: List[str] = [] for obj in config.objects: obj_attrs = [ f'name="{obj.name}"', f'value="{obj.value}"' ] - xml_parts.append(f' <{obj.type} {" ".join(obj_attrs)}/>') + object_parts.append(f' <{obj.type} {" ".join(obj_attrs)}/>') # 生成标签定义 + control_parts: List[str] = [] for label in config.labels: label_attrs = [f'name="{label.from_name}"', f'toName="{label.to_name}"'] @@ -74,7 +78,7 @@ class AnnotationTemplateService: # 检查是否需要子元素 if label.options or label.labels: choices = label.options or label.labels or [] - xml_parts.append(f' <{tag_type} {" ".join(label_attrs)}>') + control_parts.append(f' <{tag_type} {" ".join(label_attrs)}>') # 从配置获取子元素标签名 child_tag = tag_config.get_child_tag(tag_type) @@ -83,12 +87,29 @@ class AnnotationTemplateService: child_tag = "Label" for choice in choices: - xml_parts.append(f' <{child_tag} value="{choice}"/>') - xml_parts.append(f' ') + control_parts.append(f' <{child_tag} value="{choice}"/>') + control_parts.append(f' ') else: # 处理简单标签类型(不需要子元素) - xml_parts.append(f' <{tag_type} {" ".join(label_attrs)}/>') + control_parts.append(f' <{tag_type} {" ".join(label_attrs)}/>') + if is_text_template: + # 长文本优化:将标签控件固定在右侧(sticky),避免需要滚动到页面底部才能看到控件 + xml_parts = [ + '', + ' ', + *object_parts, + ' ', + ' ', + *control_parts, + ' ', + '', + ] + return '\n'.join(xml_parts) + + xml_parts = [''] + xml_parts.extend(object_parts) + xml_parts.extend(control_parts) xml_parts.append('') return '\n'.join(xml_parts) diff --git a/runtime/datamate-python/app/module/annotation/utils/config_validator.py b/runtime/datamate-python/app/module/annotation/utils/config_validator.py index 2612cd6..f818fa3 100644 --- a/runtime/datamate-python/app/module/annotation/utils/config_validator.py +++ b/runtime/datamate-python/app/module/annotation/utils/config_validator.py @@ -35,13 +35,13 @@ class LabelStudioConfigValidator: # 检查是否有对象定义 object_types = config.get_object_types() - objects = [child for child in root if child.tag in object_types] + objects = [elem for elem in root.iter() if elem is not root and elem.tag in object_types] if not objects: return False, "No data objects (Image, Text, etc.) found" # 检查是否有控件定义 control_types = config.get_control_types() - controls = [child for child in root if child.tag in control_types] + controls = [elem for elem in root.iter() if elem is not root and elem.tag in control_types] if not controls: return False, "No annotation controls found"