Label Studio 前端(LSF)集成参考:初始化选项、事件系统与标注 API 回调完全指南
【免费下载链接】label-studioLabel Studio is a multi-type data labeling and annotation tool with standardized output format项目地址: https://gitcode.com/GitHub_Trending/la/label-studio
本篇技术指南以 Label Studio 前端(Label Studio Frontend,简称 LSF)为核心,系统讲解如何将其嵌入自定义标注后端、如何通过初始化选项控制标注界面、如何利用内置事件系统监听标注生命周期,以及如何使用(已被事件系统取代的)历史回调 API。读完本文,你将掌握new LabelStudio()的完整选项清单、任务/用户数据结构、全部可用事件及参数签名,并能在自己的数据科学或机器学习工作流中直接落地集成。
注意:自 Label Studio 1.11.0 起,LSF 已不再作为独立分发包对外提供,如需在 Label Studio 内使用前端库,可参阅仓库内的 web/libs/editor/README.md。本文所述 API 均基于当前仓库 web/libs/editor 中前端源码的实现。
LSF 是什么:驱动整个标注流程的前端模块
LSF 是 Label Studio 生态中的核心前端模块,它既提供标注界面(UI),也内置了统一标注格式的数据层。根据 web/libs/editor/README.md 的说明,Label Studio 中的每一次人工标注都是由 LSF 完成的,因此理解 LSF 的集成方式,就等于理解了 Label Studio 标注能力的底层机制。
在仓库中,LSF 的源码位于 web/libs/editor/src,核心入口类LabelStudio定义于 LabelStudio.tsx。从源码可以看出,该类:
- 构造函数接收
root(DOM 元素或元素 id)和userOptions,并将默认选项与用户选项合并; - 根据
instanceOptions.reactVersion自动选择 React 17(createAppV17)或 React 18(createAppV18)渲染路径; - 通过
configureStore(this.options, this.events)创建 MobX 状态树(store),这也是 LSF.init.md 中提到的初始化主流程LabelStudio -> constructor -> createApp -> configureStore -> initializeStore; - 提供
on()/off()方法用于事件订阅与退订,其底层基于EventInvoker类实现(见 web/libs/editor/src/utils/events.ts)。
本地开发与测试
如果你想在本仓库中运行、调试 LSF,需在web目录或其子目录下执行以下脚本(来自 web/libs/editor/README.md):
| 命令 | 用途 |
|---|---|
bun run lsf:watch | 持续构建 LSF,开发时可实时观察改动在 Label Studio 环境中的效果 |
bun run lsf:serve | 以独立模式运行 LSF,访问 http://localhost:3000 使用独立版应用 |
bun run lsf:integration | 运行 Cypress 集成测试(需先启动bun run lsf:serve) |
bun run lsf:integration:ui | 以 UI 模式运行集成测试,便于可视化调试 |
bun run lsf:unit | 运行 LSF 单元测试 |
初始化 LSF
在页面中初始化 LSF 只需一行代码:
var labelStudio = new LabelStudio("editor", options);其中"editor"是挂载元素(或元素 id),options是初始化选项对象。以下列出 LSF 1.0.0 版本识别并支持的全部初始化选项。
初始化选项详解
config
- 默认值:
null - 类型:
string
标注界面的 XML 配置,它决定了标注界面上显示哪些控件、标签类型以及标签与任务data字段之间的绑定关系。配置依赖任务对象中的data字段。该配置本质上是 Label Studio 的自定义标签体系(如Text、Choices、RectangleLabels、Image等),仓库中的标签文档见 docs/source/tags。
interfaces
- 默认值:见 web/libs/editor/src/defaultOptions.js,即下列列表全部启用
- 类型:
array
需要展示的 UI 元素集合,用于按需裁剪标注界面。可用值如下:
| 接口名 | 作用 |
|---|---|
panel | 为当前任务启用导航面板,含撤销(undo)、重做(redo)和重置(reset)按钮 |
update | 提交后显示"更新当前任务"按钮 |
submit | 显示提交或更新当前标注的按钮 |
skip | 显示跳过当前任务的按钮 |
controls | 启用包含submit、update、skip的控制面板 |
infobar | 信息按钮 |
topbar | 显示 Label Studio UI 顶层条目的标注界面 |
instruction | 打开说明的按钮 |
side-column | 在 UI 左侧或右侧显示一列 |
annotations:history | 标注历史按钮 |
annotations:tabs | 标注标签页按钮 |
annotations:menu | 标注菜单按钮 |
annotations:current | 当前标注按钮 |
annotations:add-new | 新增标注按钮 |
annotations:delete | 删除当前标注按钮 |
annotations:view-all | 查看全部标注按钮 |
predictions:tabs | 显示预测标签页 |
predictions:menu | 显示预测菜单 |
auto-annotation | 显示自动标注 |
edit-history | 显示编辑历史 |
源码佐证:默认选项在 defaultOptions.js 中定义,除了文档列出的全部接口外,还额外包含
predictions:delete。这些选项最终作为AppStore的初始值传入(参见 LabelStudio.tsx 中LSFOptions类型定义)。
messages
- 默认值:
null - 类型:
object
不同操作对应的界面消息文案:
{ DONE: "Done!", NO_COMP_LEFT: "No more annotations", NO_NEXT_TASK: "No more data available for labeling", NO_ACCESS: "You don't have access to this task" }DONE:任务提交到服务器后显示NO_COMP_LEFT:没有更多标注时显示NO_NEXT_TASK:没有下一个可加载任务时显示NO_ACCESS:无法访问给定任务时显示
description
- 默认值:
No description - 类型:
string
当前任务的描述文本,对应界面中的说明(instructions)入口。从 LSF.init.md 中可以看到,官方在"待改进清单"里提出过将description选项重命名为instructions的计划,说明它本质上是任务标注说明。
task
- 默认值:
null - 类型:
object
任务数据,结构如下:
{ id: 1, data: { text: "Labeling text..." }, annotations: [], predictions: [] }字段说明:
id:整数类型,默认null,任务唯一标识。data:任务原始数据,即标注界面读取并展示的数据源,与config中的 XML 标签绑定。annotations:数组类型,任务的标注列表。具体结构参见导出文档中的原始 JSON 格式(Label Studio JSON format of annotated tasks一节),result数组内是区域/结果对象。predictions:数组类型,预测列表,结构与标注(annotations)相似。用于预标注(pre-labeling)场景,相关内容可参考 docs/source/guide/predictions.md。
源码佐证:
AppStore初始化时会遍历任务的每个预测调用addPrediction、selectPrediction、deserializeResults,遍历每个标注调用addAnnotation、selectAnnotation等,最终setInitialValues、setHistory并触发storageInitialized(参见 LSF.init.md 的initializeStore小节,以及 AppStore.js 中对应实现)。
user
- 默认值:
null - 类型:
object
当前用户数据:
{ "pk": 1, "firstName": "Stanley", "lastName": "Kubrick" }字段说明:
pk:数字类型,用户主键。firstName:字符串类型,名。lastName:字符串类型,姓。
此外,从 LabelStudio.tsx 的类型定义可知,options还支持keymap(自定义快捷键映射,通过Hotkey.setKeymap生效)、users(用户数组)以及settings.forceBottomPanel等扩展选项。
LSF 事件系统
LSF 内置了事件系统,允许你随时监听事件并触发自定义动作。实例初始化完成后即可订阅或退订事件。
事件订阅与退订
订阅事件:
const callback = () => { console.log("Event triggered"); }; labelStudio.on("event", callback);退订事件:
const callback = () => { console.log("Event triggered"); }; labelStudio.off("event", callback);注意:要成功退订,必须向
off方法传入与订阅时相同的回调函数引用。若调用off(eventName)而不传回调,则会移除该事件的所有监听器(见 LabelStudio.tsx)。
事件系统底层实现
从源码看,事件系统的核心是EventInvoker类(web/libs/editor/src/utils/events.ts):
- 内部使用
Map<string, Set<Callback>>存储事件名到回调集合的映射,同一事件可挂多个回调,重复添加同一回调会被去重; invoke(eventName, ...args)会并发执行该事件的全部回调(Promise.all);invokeFirst只执行第一个注册的回调;removeAll清空某事件的全部监听器。
LabelStudio实例的on/off方法正是委托给EventInvoker实现的。另外,源码还通过supportLegacyEvents()将onSubmitAnnotation这类历史回调自动转换并注册为同名事件(camelCase(key.replace(/^on/, ""))),这就是新旧两套 API 能共存的底层机制(见 LabelStudio.tsx)。
可用事件全览
顶层事件
顶层事件不关联 LSF 的任何内部实体。
labelStudioLoad
Label Studio 实例加载完成时触发。
警告:该事件在插件中不生效。
事件处理器参数
| 参数 | 类型 | 描述 |
|---|---|---|
labelStudio | Object | Label Studio 实例 |
storageInitialized
内部存储初始化完成时触发。
警告:该事件在插件中不生效。
事件处理器参数
| 参数 | 类型 | 描述 |
|---|---|---|
labelStudio | Object | Label Studio 实例 |
源码佐证:
AppStore#initializeStore是 LSF 的核心初始化方法,它在完成预测/标注的反序列化、历史初始化后设置initialized = true并触发storageInitialized(参见 LSF.init.md)。
任务事件
skipTask
用户点击"Skip(跳过)"按钮时触发。
事件处理器参数
| 参数 | 类型 | 描述 |
|---|---|---|
labelStudio | Object | Label Studio 实例 |
payload | Object | 跳过动作时发送的附加数据 |
unskipTask
用户点击"Cancel Skip(取消跳过)"按钮时触发。
| 参数 | 类型 | 描述 |
|---|---|---|
labelStudio | Object | Label Studio 实例 |
nextTask
用户点击"Next(右箭头)"按钮时触发。
| 参数 | 类型 | 描述 |
|---|---|---|
labelStudio | Object | Label Studio 实例 |
taskId | Number? | 历史中下一个任务的 ID |
annotationId | Number? | 要选中的任务内标注 ID |
prevTask
用户点击"Previous(左箭头)"按钮时触发。
| 参数 | 类型 | 描述 |
|---|---|---|
labelStudio | Object | Label Studio 实例 |
taskId | Number? | 历史中上一个任务的 ID |
annotationId | Number? | 要选中的任务内标注 ID |
submitDraft
草稿被发送到服务器时触发。
| 参数 | 类型 | 描述 |
|---|---|---|
labelStudio | Object | Label Studio 实例 |
annotation | Object | 当前标注 |
params | Object? | 随草稿发送的额外参数 |
标注事件
beforeSaveAnnotation
标注即将因submit或update动作而被保存时触发。若该事件的回调返回false,将阻止标注保存。
| 参数 | 类型 | 描述 |
|---|---|---|
labelStudio | Object | Label Studio 实例 |
annotation | Object | 当前标注 |
payload | Object | 附加信息 |
payload.event | string | 指示即将执行的事件名(如submitAnnotation、updateAnnotation等) |
submitAnnotation
标注被提交时触发。
| 参数 | 类型 | 描述 |
|---|---|---|
labelStudio | Object | Label Studio 实例 |
annotation | Object | 当前标注 |
updateAnnotation
标注被更新时触发。
| 参数 | 类型 | 描述 |
|---|---|---|
labelStudio | Object | Label Studio 实例 |
annotation | Object | 当前标注 |
selectAnnotation
标注被选中时触发。
| 参数 | 类型 | 描述 |
|---|---|---|
annotation | Object | 当前标注 |
previousAnnotation | Object | 之前的标注 |
payload | Object? | 附加信息 |
payload.fromViewAll | boolean | 若 ViewAll 刚刚被关闭则为true |
deleteAnnotation
标注被删除时触发。
| 参数 | 类型 | 描述 |
|---|---|---|
labelStudio | Object | Label Studio 实例 |
annotation | Object | 当前标注 |
groundTruth
标注被设为 Ground Truth(点击星标按钮)时触发。
| 参数 | 类型 | 描述 |
|---|---|---|
store | Object | Label Studio 实例 |
labelStudio | Object | Label Studio 实例 |
params | Object | 附加参数 |
params.isDirty | Boolean | 标注若被修改过则为true |
params.entity | Object | 当前标注 |
selectHistory
在标注历史中选择某一步时触发。
| 参数 | 类型 | 描述 |
|---|---|---|
labelStudio | Object | Label Studio 实例 |
annotation | Object | 当前标注 |
historyItem | Object | 当前历史项 |
区域(Region)事件
区域是分割类任务(如图像分割、音频分割)中的特殊实体。
entityCreate
区域被创建时触发。
| 参数 | 类型 | 描述 |
|---|---|---|
region | Object | 新创建的区域 |
entityDelete
区域被删除时触发。
| 参数 | 类型 | 描述 |
|---|---|---|
region | Object | 被删除的区域 |
区域事件的回调参数只有
region,与任务/标注事件不同,不包含labelStudio实例参数。
回调 API(已弃用)
回调(Callbacks)可用于基于用户与界面的交互执行动作,例如 label-studio 服务器使用回调与 API 通信。将回调与其他选项一起在初始化实例时传入。它们已由上述事件系统取代,但在历史版本中承担了与事件相同的职责。
源码佐证:历史回调清单定义于 web/libs/editor/src/core/External.js,除文档列出的回调外还包括
onDeletePrediction、onUnskipTask、onTaskLoad、onSelectAnnotation、onAcceptAnnotation、onRejectAnnotation、onStorageInitialized、onSubmitDraft、onNextTask、onPrevTask等。如上文所述,这些回调在实例化时会被自动转换为同名事件注册。
onSubmitAnnotation
类型:function
点击submit按钮时调用。ls是 label studio 实例,annotation是当前标注的值。
onSubmitAnnotation: function(ls, annotation) { console.log(annotation) }onUpdateAnnotation
类型:function
点击update按钮时调用。ls是 label studio 实例,annotation是当前标注的值。
onUpdateAnnotation: function(ls, annotation) { console.log(result) }onDeleteAnnotation
类型:function
点击delete按钮时调用。ls是 label studio 实例,annotation是当前标注的值。
onDeleteAnnotation: function(ls, annotation) { console.log(result) }onEntityCreate
类型:function
新区域被标注时调用,例如创建了一个新的 bbox。region是被创建的对象。
onEntityCreate: function(region) { console.log(region) }onEntityDelete
类型:function
已有区域被删除时调用。region是被删除的对象本身。
onEntityDelete: function(region) { console.log(region) }onSkipTask
类型:function
点击skip按钮时调用。ls是 label studio 实例。
onSkipTask: function(ls) { console.log(result) }onLabelStudioLoad
类型:function
Label Studio 完全加载并准备好标注时调用。ls是 label studio 实例。
onLabelStudioLoad: function(ls) { console.log(result) }LSF 1.0.0 的破坏性变更
LSF 1.0.0 与更早版本不兼容。如果使用 LSF 搭配自定义后端,必须按以下映射关系修改使用的 API 回调:
| 0.9.1 及更早版本的回调 | 1.0.0 中的重命名回调 |
|---|---|
onSubmitCompletion | onSubmitAnnotation |
onUpdateCompletion | onUpdateAnnotation |
onDeleteCompletion | onDeleteAnnotation |
同时,如果你依赖 Label Studio 已完成任务的特定格式,其标注格式(原始 JSON 格式)也随 1.0.0 更新。更新后的格式以annotations/predictions数组及result结果对象为核心结构,相关说明见导出文档中的Label Studio JSON format of annotated tasks一节(docs/source/guide/export.md)。
实战集成示例
结合以上内容,一个完整的集成片段如下:
const options = { config: ` <View> <Text name="text" value="$text"/> <Choices name="label" toName="text" choice="single"> <Choice value="Positive"/> <Choice value="Negative"/> </Choices> </View> `, interfaces: ["panel", "update", "submit", "skip", "controls", "topbar"], task: { id: 1, data: { text: "Labeling text..." }, annotations: [], predictions: [], }, user: { pk: 1, firstName: "Stanley", lastName: "Kubrick" }, }; const labelStudio = new LabelStudio("editor", options); // 事件订阅:保存前校验 labelStudio.on("beforeSaveAnnotation", (ls, annotation, payload) => { if (!annotation.regions?.length) { alert("请至少标注一个区域后再提交"); return false; // 阻止保存 } }); // 事件订阅:提交后与后端同步 labelStudio.on("submitAnnotation", (ls, annotation) => { syncWithBackend(annotation); });该示例演示了:通过config定义基于任务data字段的 XML 标注配置;通过interfaces裁剪 UI;通过task传入任务与空标注/预测列表;通过user记录操作者;最后利用beforeSaveAnnotation做保存前校验(返回false拦截)、利用submitAnnotation做提交后同步。若需与历史版本兼容,也可改用onSubmitAnnotation: function(ls, annotation) {...}形式的回调,二者在实例化时会映射到同一套事件机制。
【免费下载链接】label-studioLabel Studio is a multi-type data labeling and annotation tool with standardized output format项目地址: https://gitcode.com/GitHub_Trending/la/label-studio
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考