diff --git a/frontend/public/lsf/lsf.html b/frontend/public/lsf/lsf.html index b7f3d2d..5d7f846 100644 --- a/frontend/public/lsf/lsf.html +++ b/frontend/public/lsf/lsf.html @@ -9,9 +9,11 @@ body { height: 100%; margin: 0; + overflow: hidden; } #label-studio { height: 100vh; + overflow: auto; } diff --git a/runtime/datamate-python/app/module/annotation/schema/template.py b/runtime/datamate-python/app/module/annotation/schema/template.py index 27bd770..e82fec0 100644 --- a/runtime/datamate-python/app/module/annotation/schema/template.py +++ b/runtime/datamate-python/app/module/annotation/schema/template.py @@ -14,6 +14,8 @@ class LabelDefinition(BaseModel): options: Optional[List[str]] = Field(None, description="选项列表(用于choices类型)") labels: Optional[List[str]] = Field(None, description="标签列表(用于rectanglelabels等类型)") required: bool = Field(False, description="是否必填") + choice: Optional[str] = Field(None, description="Choices 选择模式: single/multiple") + show_inline: Optional[bool] = Field(None, alias="showInline", description="Choices 是否行内显示") description: Optional[str] = Field(None, description="标签描述") model_config = ConfigDict(populate_by_name=True) diff --git a/runtime/datamate-python/app/module/annotation/service/editor.py b/runtime/datamate-python/app/module/annotation/service/editor.py index 749ea71..ac04257 100644 --- a/runtime/datamate-python/app/module/annotation/service/editor.py +++ b/runtime/datamate-python/app/module/annotation/service/editor.py @@ -251,6 +251,18 @@ class AnnotationEditorService: if not isinstance(stored.get("id"), int): stored["id"] = self._make_ls_annotation_id(project_id, file_id) task["annotations"] = [stored] + else: + # 提供一个空 annotation,避免前端在没有选中 annotation 时无法产生 result + empty_ann_id = self._make_ls_annotation_id(project_id, file_id) + task["annotations"] = [ + { + "id": empty_ann_id, + "task": ls_task_id, + "result": [], + "created_at": datetime.utcnow().isoformat() + "Z", + "updated_at": datetime.utcnow().isoformat() + "Z", + } + ] return EditorTaskResponse( task=task, diff --git a/runtime/datamate-python/app/module/annotation/service/template.py b/runtime/datamate-python/app/module/annotation/service/template.py index d2fa52d..61abeb5 100644 --- a/runtime/datamate-python/app/module/annotation/service/template.py +++ b/runtime/datamate-python/app/module/annotation/service/template.py @@ -35,8 +35,20 @@ class AnnotationTemplateService: Label Studio XML字符串 """ tag_config = LabelStudioTagConfig() + control_types = tag_config.get_control_types() xml_parts = [''] + def normalize_control_type(raw: Optional[str]) -> str: + if not raw: + return "Choices" + if raw in control_types: + return raw + raw_lower = raw.lower() + for ct in control_types: + if ct.lower() == raw_lower: + return ct + return raw + # 生成对象定义 for obj in config.objects: obj_attrs = [ @@ -47,16 +59,17 @@ class AnnotationTemplateService: # 生成标签定义 for label in config.labels: - label_attrs = [ - f'name="{label.from_name}"', - f'toName="{label.to_name}"' - ] + label_attrs = [f'name="{label.from_name}"', f'toName="{label.to_name}"'] # 添加可选属性 if label.required: label_attrs.append('required="true"') - tag_type = label.type.capitalize() if label.type else "Choices" + tag_type = normalize_control_type(label.type) + if tag_type == "Choices" and label.choice: + label_attrs.append(f'choice="{label.choice}"') + if tag_type == "Choices" and label.show_inline is not None: + label_attrs.append(f'showInline="{"true" if label.show_inline else "false"}"') # 检查是否需要子元素 if label.options or label.labels: