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: