bonus-ui/src/views/dataCenter/annotationTask/child/customLabelStudio.vue

228 lines
6.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="label-studio-annotator">
<div id="label-studio" class="annotation-container"></div>
</div>
</template>
<script>
import LabelStudio from 'label-studio';
import '@/assets/styles/labelStudio.scss';
import { manualAnnotate } from '../../../../api/dataCenter/annotationTask';
export default {
name: 'LabelStudioAnnotator',
props: {
fileUrl: { type: String, required: true },
taskId: { type: Number, required: true },
config: { type: String, required: true },
id: { type: Number, required: true },
itemIndex: { type: Number, required: true },
fileAnnotationStatus: { type: String, required: true },
annotations: {
type: Array,
default: () => [] // 默认值为空数组
}
},
computed: {
index: {
get() {
return this.itemIndex;
},
set(value) {
this.$parent.updateItemIndex(value,this.label); // 更新父组件的索引
}
}
},
data() {
return {
label:null,
labelStudio: null,
annotationsList: [] // 用于存储当前标注的结果
};
},
watch: {
fileUrl: 'resetLabelStudio' // 当文件地址变化时重置LabelStudio
},
mounted() {
this.initLabelStudio(); // 组件挂载完成后初始化LabelStudio
},
methods: {
// 处理返回的标注数据
getAnnotations() {
return [{
result: this.annotations.map(annotation => ({
type: "rectanglelabels",
from_name: "label",
to_name: "image",
value: {
rectanglelabels: [annotation.label],
x: annotation.x,
y: annotation.y,
width: annotation.width,
height: annotation.height
}
}))
}];
},
// 初始化 LabelStudio
initLabelStudio() {
this.cleanupLabelStudio(); // 清理之前的实例
const task = {
id: this.id,
data: { image: this.fileUrl },
};
if (this.annotations) {
task.annotations = this.getAnnotations();
}
let interfaces = [];
if (this.fileAnnotationStatus === '2'){
interfaces = ["controls"];
}else {
interfaces = ["panel","update", "submit", "controls"];
}
this.$nextTick(() => {
const labelStudioElement = document.getElementById('label-studio');
if (!labelStudioElement) {
console.error('Label Studio element not found');
return;
}
this.labelStudio = new LabelStudio('label-studio', {
config: this.config,
interfaces: interfaces,
user: { pk: 1, firstName: '标注者', lastName: '用户' },
task,
onLabelStudioLoad: (LS) => {
if (!LS.annotationStore.selectedAnnotation) {
const annotation = LS.annotationStore.addAnnotation({ userGenerate: true });
LS.annotationStore.selectAnnotation(annotation.id);
}
this.changeButtonText(LS);
},
onSubmitAnnotation: (LS, annotation) => this.handleAnnotationSubmit(LS, annotation, task),
//onUpdateAnnotation:(LS, annotation) => this.handleAnnotationSubmit(LS, annotation, task),
});
});
},
// 提交标注结果
async handleAnnotationSubmit(LS, annotation, task) {
const results = annotation.serializeAnnotation();
console.log(results)
if (results.length === 0) return;
const formattedAnnotations = results.map(result => {
if (result.type === 'rectanglelabels') {
return {
label: result.value.rectanglelabels[0],
x: result.value.x,
y: result.value.y,
width: result.value.width,
height: result.value.height
};
}
return result;
});
const data = {
annotationResult: JSON.stringify(formattedAnnotations),
taskId: this.taskId,
fileId: this.id
};
try {
await manualAnnotate(data);
this.annotationsList.push({
taskId: task.id,
annotation: JSON.stringify(formattedAnnotations),
url: this.fileUrl
});
this.label = JSON.stringify(formattedAnnotations)
this.index++; // 更新索引
} catch (error) {
console.error('Failed to submit annotation:', error);
} finally {
this.cleanupLabelStudio(); // 清理 LabelStudio 实例
}
},
changeButtonText(LS) {
const buttons = {
'Undo': '撤销',
'Redo': '重做',
'Reset': '重置',
'Submit': '提交',
'Update':'更新'
};
const updateButtonText = (element) => {
const buttonElements = element.querySelectorAll('button');
buttonElements.forEach((button) => {
const text = button.textContent.trim();
if (buttons[text]) {
button.textContent = buttons[text];
}
});
};
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
updateButtonText(node);
}
});
}
});
});
observer.observe(document.body, { childList: true, subtree: true });
updateButtonText(document.body);
},
// 重置 LabelStudio
resetLabelStudio() {
this.cleanupLabelStudio();
this.initLabelStudio(); // 重新初始化
},
// 清理 LabelStudio 实例
cleanupLabelStudio() {
if (this.labelStudio && this.labelStudio.destroy) {
this.labelStudio.destroy();
}
const labelStudioElement = document.getElementById('label-studio');
if (labelStudioElement) {
labelStudioElement.innerHTML = ''; // 清空容器
}
this.labelStudio = null; // 置空实例
}
}
};
</script>
<style lang="scss">
.label-studio-annotator{
width: 100%;
height: 100%;
}
.annotation-container{
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
>div{
width: 100%;
height: 100%;
padding: 5px;
}
}
</style>