fix(label): label result

This commit is contained in:
2026-02-27 16:08:42 +08:00
parent 6a19edbdfc
commit a901dcf36b
4 changed files with 436 additions and 297 deletions

View File

@@ -14,7 +14,12 @@ import { processVideo } from "@/app/component/label/video2image/processVideo"
import { Box, Flex, LoadingOverlay, Stack } from "@mantine/core" import { Box, Flex, LoadingOverlay, Stack } from "@mantine/core"
import { showNotification } from "@mantine/notifications" import { showNotification } from "@mantine/notifications"
import { getLabelResult, getServerImage } from "./api/label" import { getLabelResult, getServerImage } from "./api/label"
import { Comment, WorkLoad } from "./api/label/typing" import {
Comment,
ImageObjects,
LabelResult,
WorkLoad,
} from "./api/label/typing"
import { getProjectDetail } from "./api/project" import { getProjectDetail } from "./api/project"
import { Project } from "./api/project/typing" import { Project } from "./api/project/typing"
import { getTaskList, getTaskWorkFlow } from "./api/task" import { getTaskList, getTaskWorkFlow } from "./api/task"
@@ -91,6 +96,29 @@ const normalizeNamePrefix = (name: string) => {
return value || "video" return value || "video"
} }
interface ResultImageEntry {
frameName: string
imageObjects: ImageObjects
}
const expandLabelResultImages = (item: LabelResult): ResultImageEntry[] => {
if (item.image_objects) {
return [
{
frameName: item.data_name,
imageObjects: item.image_objects,
},
]
}
if (!item.video_objects) return []
return Object.entries(item.video_objects).map(([frameName, imageObjects]) => {
return {
frameName,
imageObjects,
}
})
}
interface LabelProps { interface LabelProps {
headerHeight: number headerHeight: number
leftWidth: number leftWidth: number
@@ -237,84 +265,95 @@ const LabelPage = ({
const normalizeVideoTaskData = useCallback( const normalizeVideoTaskData = useCallback(
async (detail: Task.DataProps) => { async (detail: Task.DataProps) => {
try { const sourceNames = detail.data_name
const sourceNames = detail.data_name .map((item) => item?.name?.[0] || "")
.map((item) => item?.name?.[0] || "") .filter((name) => !!name)
.filter((name) => !!name) if (!sourceNames.length || !projectId || !taskId) return detail
if (!sourceNames.length || !projectId) return detail
const taskDataType = Number( const taskDataType = Number(
(detail as { [key: string]: any })?.data_type ?? (detail as { [key: string]: any })?.data_type ??
(detail as { [key: string]: any })?.task_data_type ?? (detail as { [key: string]: any })?.task_data_type ??
-1 -1
) )
const isVideoTask = const isVideoTask =
taskDataType === 2 || taskDataType === 2 ||
sourceNames.some((name) => videoExtPattern.test(name)) taskDataType === 7 ||
if (!isVideoTask) return detail sourceNames.some((name) => videoExtPattern.test(name))
if (!isVideoTask) return detail
const imagesMap = new Map(useImagesStore.getState().images) const imagesMap = new Map(useImagesStore.getState().images)
let imageMapUpdated = false const frameMapUpdates = new Map<string, string[]>()
const normalizedDataName: Task.DataProps["data_name"] = [] let imageMapUpdated = false
const normalizedDataName: Task.DataProps["data_name"] = []
for (const videoName of sourceNames) { for (const videoName of sourceNames) {
const cacheKey = `${projectId}:${taskId}:${videoName}` const cacheKey = `${projectId}:${taskId}:${videoName}`
let frameNames = let frameNames =
useVideoFrameStore.getState().videoFrames.get(cacheKey) ?? [] useVideoFrameStore.getState().videoFrames.get(cacheKey) ?? []
const hasAllCachedFrames = const hasAllCachedFrames =
frameNames.length > 0 && frameNames.length > 0 &&
frameNames.every((frameName) => { frameNames.every((frameName) => {
const cache = imagesMap.get(frameName) const cache = imagesMap.get(frameName)
return typeof cache === "string" && cache.length > 0 return typeof cache === "string" && cache.length > 0
}) })
if (!hasAllCachedFrames) { if (!hasAllCachedFrames) {
let frameData: Awaited<ReturnType<typeof processVideo>> = []
try {
const base64Video = await getServerImage({ const base64Video = await getServerImage({
data_names: [videoName], data_names: [videoName],
data_type: 2, data_type: 2,
project_id: projectId, project_id: projectId,
}) })
const frameData = await processVideo({ frameData = await processVideo({
base64Data: String(base64Video || ""), base64Data: String(base64Video || ""),
fileName: videoName, fileName: videoName,
namePrefix: normalizeNamePrefix( namePrefix: normalizeNamePrefix(
`${projectId}_${taskId}_${videoName.replace(/\.[^.]+$/, "")}` `${projectId}_${taskId}_${videoName.replace(/\.[^.]+$/, "")}`
), ),
}) })
frameNames = frameData.map((frame) => frame.name) } catch (error) {
frameData.forEach((frame) => { const message = error instanceof Error ? error.message : "未知错误"
imagesMap.set(frame.name, frame.dataUrl) throw new Error(`视频帧生成失败:${videoName}${message}`)
})
imageMapUpdated = true
useVideoFrameStore.getState().setVideoFrames(cacheKey, frameNames)
} }
frameNames = frameData.map((frame) => frame.name)
frameNames.forEach((frameName) => { if (!frameNames.length) {
normalizedDataName.push({ throw new Error(`视频帧生成失败:${videoName}`)
name: [frameName] as [string], }
related_images: [], frameData.forEach((frame) => {
}) imagesMap.set(frame.name, frame.dataUrl)
}) })
imageMapUpdated = true
frameMapUpdates.set(cacheKey, frameNames)
} }
if (imageMapUpdated) { if (!frameNames.length) {
useImagesStore.getState().setImages(imagesMap) throw new Error(`视频帧映射为空:${videoName}`)
} }
if (!normalizedDataName.length) return detail
return { frameNames.forEach((frameName) => {
...detail, normalizedDataName.push({
data_name: normalizedDataName, name: [frameName] as [string],
} related_images: [],
} catch (error) { })
console.log(error)
showNotification({
color: "red",
title: "视频解码失败",
message: "视频帧生成失败,已回退到原始数据",
}) })
return detail }
if (!normalizedDataName.length) {
throw new Error("未生成可用视频帧")
}
if (imageMapUpdated) {
useImagesStore.getState().setImages(imagesMap)
}
frameMapUpdates.forEach((frameNames, cacheKey) => {
useVideoFrameStore.getState().setVideoFrames(cacheKey, frameNames)
})
return {
...detail,
data_name: normalizedDataName,
} }
}, },
[projectId, taskId] [projectId, taskId]
@@ -385,6 +424,9 @@ const LabelPage = ({
// 获取并处理当前任务标注结果数据 // 获取并处理当前任务标注结果数据
const dataRes = await getLabelResult(taskId) const dataRes = await getLabelResult(taskId)
const { results } = dataRes const { results } = dataRes
const resultImageEntries = results.flatMap((item) =>
expandLabelResultImages(item)
)
let currentWorkTime = 0 let currentWorkTime = 0
if (label_status === 2) { if (label_status === 2) {
@@ -411,75 +453,75 @@ const LabelPage = ({
review_key_frame_size: {}, review_key_frame_size: {},
question_size: {}, question_size: {},
} }
results.forEach((item) => { resultImageEntries.forEach(({ frameName, imageObjects }) => {
const { image_objects } = item const { annotations, images, key_frame, desc } = imageObjects
if (image_objects) { const rasterName = frameName || images.file_name
const { annotations, images, key_frame, desc } = image_objects if (rasterName) {
usePaperStore usePaperStore
.getState() .getState()
.setRasterSize(images.file_name, [images.width, images.height]) .setRasterSize(rasterName, [images.width, images.height])
annotations.forEach((annotation) => { }
let reviewed = false annotations.forEach((annotation) => {
const { comment, prelabel, uid } = annotation let reviewed = false
if (prelabel) const { comment, prelabel, uid } = annotation
workLoad.prelabel_modify_size[uid] if (prelabel)
? workLoad.prelabel_modify_size[uid]++ workLoad.prelabel_modify_size[uid]
: (workLoad.prelabel_modify_size[uid] = 1) ? workLoad.prelabel_modify_size[uid]++
else : (workLoad.prelabel_modify_size[uid] = 1)
workLoad.object_size[uid] else
? workLoad.object_size[uid]++ workLoad.object_size[uid]
: (workLoad.object_size[uid] = 1) ? workLoad.object_size[uid]++
if (comment) { : (workLoad.object_size[uid] = 1)
comment.forEach((c) => { if (comment) {
if (c.comment_type > 0 && c.uid === user_id) reviewed = true comment.forEach((c) => {
if (c.comment_type === 2 && c.uid === user_id) if (c.comment_type > 0 && c.uid === user_id) reviewed = true
workLoad.comment_size++ if (c.comment_type === 2 && c.uid === user_id)
}) workLoad.comment_size++
} })
if (reviewed) workLoad.review_size++
})
if (key_frame) {
if (label_status === 2) {
let id = image_objects.label1_uid!
if (id)
workLoad.key_frame_size[id]
? workLoad.key_frame_size[id]++
: (workLoad.key_frame_size[id] = 1)
} else if (label_status === 4) {
let id = image_objects.review1_uid!
if (id)
workLoad.review_key_frame_size[id]
? workLoad.review_key_frame_size[id]++
: (workLoad.review_key_frame_size[id] = 1)
} else if (label_status === 6) {
let id = image_objects.review2_uid!
if (id)
workLoad.review_key_frame_size[id]
? workLoad.review_key_frame_size[id]++
: (workLoad.review_key_frame_size[id] = 1)
}
} }
if (useDescToolsStore.getState().qaOperations.length) { if (reviewed) workLoad.review_size++
if (desc) { })
const { other_desc } = desc if (key_frame) {
const descData = other_desc ? JSON.parse(other_desc) : {} if (label_status === 2) {
Object.values(descData).forEach((questionArr: any) => { let id = imageObjects.label1_uid!
questionArr.forEach((q: any) => { if (id)
const v: any = Object.values(q)[0] workLoad.key_frame_size[id]
if (v.uid) { ? workLoad.key_frame_size[id]++
workLoad.question_size[v.uid] : (workLoad.key_frame_size[id] = 1)
? workLoad.question_size[v.uid]++ } else if (label_status === 4) {
: (workLoad.question_size[v.uid] = 1) let id = imageObjects.review1_uid!
} if (id)
if (v.tag) { workLoad.review_key_frame_size[id]
const uid = usePermissionStore.getState().user_id ? workLoad.review_key_frame_size[id]++
workLoad.review_question_size[uid] : (workLoad.review_key_frame_size[id] = 1)
? workLoad.review_question_size[uid]++ } else if (label_status === 6) {
: (workLoad.review_question_size[uid] = 1) let id = imageObjects.review2_uid!
} if (id)
}) workLoad.review_key_frame_size[id]
? workLoad.review_key_frame_size[id]++
: (workLoad.review_key_frame_size[id] = 1)
}
}
if (useDescToolsStore.getState().qaOperations.length) {
if (desc) {
const { other_desc } = desc
const descData = other_desc ? JSON.parse(other_desc) : {}
Object.values(descData).forEach((questionArr: any) => {
questionArr.forEach((q: any) => {
const v: any = Object.values(q)[0]
if (v.uid) {
workLoad.question_size[v.uid]
? workLoad.question_size[v.uid]++
: (workLoad.question_size[v.uid] = 1)
}
if (v.tag) {
const uid = usePermissionStore.getState().user_id
workLoad.review_question_size[uid]
? workLoad.review_question_size[uid]++
: (workLoad.review_question_size[uid] = 1)
}
}) })
} })
} }
} }
}) })
@@ -492,180 +534,178 @@ const LabelPage = ({
// 重置 PathGroupIds // 重置 PathGroupIds
useRightToolsStore.getState().setPathGroupIds([]) useRightToolsStore.getState().setPathGroupIds([])
// 生成标注结果 // 生成标注结果
results.forEach((item) => { resultImageEntries.forEach(({ frameName, imageObjects }) => {
const { data_name, image_objects } = item const key = frameName
if (image_objects) { if (!key) return
const categoryMap = new Map() const categoryMap = new Map()
const { annotations, image_groups, desc } = image_objects const { annotations, image_groups, desc } = imageObjects
// 赋值用过的 id // 赋值用过的 id
annotations.map((annotation) => { annotations.map((annotation) => {
useRightToolsStore.getState().pushPathId(annotation.id) useRightToolsStore.getState().pushPathId(annotation.id)
})
// 赋值用过的 groupId
image_groups &&
Object.keys(image_groups)?.map((groupId) => {
useRightToolsStore.getState().pushPathGroupId(+groupId)
}) })
// 赋值用过的 groupId annotations.forEach((annotation) => {
image_groups && const { id, category_id, comment } = annotation
Object.keys(image_groups)?.map((groupId) => { let current_comment: Comment[] = []
useRightToolsStore.getState().pushPathGroupId(+groupId) if (comment) {
}) current_comment = flowCommentArr.map((c) => {
annotations.forEach((annotation) => { const { turn, times } = c
const { id, category_id, comment } = annotation let modified_comment = null
let current_comment: Comment[] = [] comment.forEach((item) => {
if (comment) { if (item.turn === turn && item.times === times)
current_comment = flowCommentArr.map((c) => { modified_comment = item
const { turn, times } = c
let modified_comment = null
comment.forEach((item) => {
if (item.turn === turn && item.times === times)
modified_comment = item
})
return modified_comment ? modified_comment : c
}) })
} else { return modified_comment ? modified_comment : c
current_comment = [...flowCommentArr] })
} } else {
let detail: any = { current_comment = [...flowCommentArr]
...annotation,
comment: current_comment,
}
// group info
if (image_groups) {
const key = findGroupKey(image_groups as any, id)
if (key !== -1) detail.parentGroupId = key
}
const categoryKey = `${category_id}`
let arr = categoryMap.has(categoryKey)
? categoryMap.get(categoryKey)
: []
if (annotation.rect) {
// arr.push([id, getRectPoints(annotation.rect), detail, []]);
arr.push([id, [getRectPoints(annotation.rect)], detail, []])
}
if (annotation.line_segment) {
arr.push([
id,
annotation.line_segment.map((item) => getSegmentPoints(item)),
detail,
[],
])
}
if (annotation.segmentation) {
arr.push([
id,
// getSegmentPoints(annotation.segmentation[0]),
annotation.segmentation.map((item) => getSegmentPoints(item)),
detail,
annotation.hollow_segmentation?.map((item) =>
getSegmentPoints(item)
) || [],
])
}
if (annotation.key_points) {
arr.push([
id,
// getSegmentPoints(annotation.segmentation[0]),
[
getSegmentPoints(
annotation.key_points.map((item) => item.point)
),
],
Object.assign(detail, {
circles: annotation.key_points,
}),
[],
])
}
categoryMap.set(categoryKey, arr)
})
const key = data_name
taskLabelData.set(key, categoryMap)
// 关键帧信息
const keyFrame = {
key_frame: image_objects.key_frame || false,
label1_ts: image_objects.label1_ts || 0,
label1_uid: image_objects.label1_uid || 0,
review1_ts: image_objects.review1_ts || 0,
review1_uid: image_objects.review1_uid || 0,
review2_ts: image_objects.review2_ts || 0,
review2_uid: image_objects.review2_uid || 0,
} }
useBottomToolsStore.getState().setKeyFrameData(key, keyFrame) let detail: any = {
// 大语言模型 两种数据情况 ...annotation,
if (useDescToolsStore.getState().qaOperations.length) { comment: current_comment,
if (desc) {
const { other_desc } = desc
let current_data: any = {}
const descData = other_desc ? JSON.parse(other_desc) : {}
Object.entries(descData).forEach(
([label_class, questionArr]: any) => {
let arr = questionArr.map((question: any) => {
let [name, val]: any = Object.entries(question)[0]
return {
[name]: {
...val,
value: val.value
? `${val.value}${splitWord}${val.value}`
: undefined,
comment: val.comment
? `${val.comment}${splitWord}${val.comment}`
: undefined,
},
}
})
current_data[label_class] = arr
}
)
const qaData = useDescToolsStore.getState().qaData
// 无文本描述时 赋予预设值
if (JSON.stringify(current_data) === "{}") {
current_data = qaData.get("init")
}
const qaMap = structuredClone(qaData)
qaMap.set(key, current_data)
useDescToolsStore.getState().setQaData(qaMap)
}
} else if (useDescToolsStore.getState().descOperations.length) {
if (desc) {
const { meta_operation, other_desc } = desc
const currentMetaMap = structuredClone(
useDescToolsStore.getState().metaData
)
currentMetaMap.set(key, meta_operation || [])
useDescToolsStore.getState().setMetaData(currentMetaMap)
const currentDescMap = structuredClone(
useDescToolsStore.getState().descData
)
let descMap = new Map()
const descData = other_desc ? JSON.parse(other_desc) : {}
console.log(descData)
Object.entries(descData).forEach(
([label_class, { value, is_correct, comment }]: any) => {
descMap.set(label_class, {
value:
(typeof value === "string"
? `${value}${splitWord}${value}`
: value) || undefined,
is_correct: is_correct || undefined,
comment: comment || undefined,
})
}
)
currentDescMap.set(key, descMap)
useDescToolsStore.getState().setDescData(currentDescMap)
}
} }
image_groups && // group info
pathGroupData.set( if (image_groups) {
key, const key = findGroupKey(image_groups as any, id)
new Map( if (key !== -1) detail.parentGroupId = key
Object.entries(image_groups).map(([key, value]: any) => [ }
key * 1, const categoryKey = `${category_id}`
value, let arr = categoryMap.has(categoryKey)
]) ? categoryMap.get(categoryKey)
) : []
) if (annotation.rect) {
// arr.push([id, getRectPoints(annotation.rect), detail, []]);
arr.push([id, [getRectPoints(annotation.rect)], detail, []])
}
if (annotation.line_segment) {
arr.push([
id,
annotation.line_segment.map((item) => getSegmentPoints(item)),
detail,
[],
])
}
if (annotation.segmentation) {
arr.push([
id,
// getSegmentPoints(annotation.segmentation[0]),
annotation.segmentation.map((item) => getSegmentPoints(item)),
detail,
annotation.hollow_segmentation?.map((item) =>
getSegmentPoints(item)
) || [],
])
}
if (annotation.key_points) {
arr.push([
id,
// getSegmentPoints(annotation.segmentation[0]),
[
getSegmentPoints(
annotation.key_points.map((item) => item.point)
),
],
Object.assign(detail, {
circles: annotation.key_points,
}),
[],
])
}
categoryMap.set(categoryKey, arr)
})
taskLabelData.set(key, categoryMap)
// 关键帧信息
const keyFrame = {
key_frame: imageObjects.key_frame || false,
label1_ts: imageObjects.label1_ts || 0,
label1_uid: imageObjects.label1_uid || 0,
review1_ts: imageObjects.review1_ts || 0,
review1_uid: imageObjects.review1_uid || 0,
review2_ts: imageObjects.review2_ts || 0,
review2_uid: imageObjects.review2_uid || 0,
} }
useBottomToolsStore.getState().setKeyFrameData(key, keyFrame)
// 大语言模型 两种数据情况
if (useDescToolsStore.getState().qaOperations.length) {
if (desc) {
const { other_desc } = desc
let current_data: any = {}
const descData = other_desc ? JSON.parse(other_desc) : {}
Object.entries(descData).forEach(
([label_class, questionArr]: any) => {
let arr = questionArr.map((question: any) => {
let [name, val]: any = Object.entries(question)[0]
return {
[name]: {
...val,
value: val.value
? `${val.value}${splitWord}${val.value}`
: undefined,
comment: val.comment
? `${val.comment}${splitWord}${val.comment}`
: undefined,
},
}
})
current_data[label_class] = arr
}
)
const qaData = useDescToolsStore.getState().qaData
// 无文本描述时 赋予预设值
if (JSON.stringify(current_data) === "{}") {
current_data = qaData.get("init")
}
const qaMap = structuredClone(qaData)
qaMap.set(key, current_data)
useDescToolsStore.getState().setQaData(qaMap)
}
} else if (useDescToolsStore.getState().descOperations.length) {
if (desc) {
const { meta_operation, other_desc } = desc
const currentMetaMap = structuredClone(
useDescToolsStore.getState().metaData
)
currentMetaMap.set(key, meta_operation || [])
useDescToolsStore.getState().setMetaData(currentMetaMap)
const currentDescMap = structuredClone(
useDescToolsStore.getState().descData
)
let descMap = new Map()
const descData = other_desc ? JSON.parse(other_desc) : {}
console.log(descData)
Object.entries(descData).forEach(
([label_class, { value, is_correct, comment }]: any) => {
descMap.set(label_class, {
value:
(typeof value === "string"
? `${value}${splitWord}${value}`
: value) || undefined,
is_correct: is_correct || undefined,
comment: comment || undefined,
})
}
)
currentDescMap.set(key, descMap)
useDescToolsStore.getState().setDescData(currentDescMap)
}
}
image_groups &&
pathGroupData.set(
key,
new Map(
Object.entries(image_groups).map(([key, value]: any) => [
key * 1,
value,
])
)
)
}) })
setLabel(taskLabelData) setLabel(taskLabelData)
// 获取任务详情时设置状态栈初始值 // 获取任务详情时设置状态栈初始值
@@ -675,9 +715,18 @@ const LabelPage = ({
} catch (err) { } catch (err) {
console.log(err) console.log(err)
setOldWorkLoad(null) setOldWorkLoad(null)
setTaskDetail(undefined)
useBottomToolsStore.getState().setAllItems([])
setLabel(new Map()) setLabel(new Map())
setStateStack([]) setStateStack([])
useRightToolsStore.getState().setPathGroupMap(new Map()) useRightToolsStore.getState().setPathGroupMap(new Map())
if (err instanceof Error && err.message.includes("视频")) {
showNotification({
color: "red",
title: "视频解码失败",
message: err.message,
})
}
} finally { } finally {
usePaperStore.getState().setLoadingData(false) usePaperStore.getState().setLoadingData(false)
} }

View File

@@ -1,6 +1,9 @@
export interface LabelResult { export interface LabelResult {
data_name: string data_name: string
image_objects?: ImageObjects image_objects?: ImageObjects
video_objects?: {
[key: string]: ImageObjects
}
pc_box_objects?: { [key: string]: any }[] pc_box_objects?: { [key: string]: any }[]
pc_segment_objects?: { [key: string]: any }[] pc_segment_objects?: { [key: string]: any }[]
pc_vegetation_objects?: { [key: string]: any }[] pc_vegetation_objects?: { [key: string]: any }[]
@@ -129,6 +132,7 @@ export interface DataList {
data_name: string data_name: string
data_type: string data_type: string
image_data?: string image_data?: string
video_data?: string
pointcloud_data?: PointcloudDatum[] pointcloud_data?: PointcloudDatum[]
[property: string]: any [property: string]: any
} }

View File

@@ -3,7 +3,6 @@ export namespace Task {
id: number id: number
create_date: string create_date: string
data_type?: number data_type?: number
task_data_type?: number
data_name: { data_name: {
name: [string] name: [string]
related_images: [] related_images: []

View File

@@ -82,6 +82,7 @@ import {
useKeyEventStore, useKeyEventStore,
useLabelStore, useLabelStore,
useObjectStore, useObjectStore,
useVideoFrameStore,
} from "../store" } from "../store"
import { useBackUrlStore, usePermissionStore } from "../store/auth" import { useBackUrlStore, usePermissionStore } from "../store/auth"
import { useBottomToolsStore } from "../useBottomToolsStore" import { useBottomToolsStore } from "../useBottomToolsStore"
@@ -450,7 +451,7 @@ const TopTools = (
} }
const { label_status, data_name } = taskDetail! const { label_status, data_name } = taskDetail!
let results = data_name.map((item, imageId) => { const frameResults = data_name.map((item, imageId) => {
const name = item.name?.[0] const name = item.name?.[0]
let finalData: LabelResult = { let finalData: LabelResult = {
data_name: name, data_name: name,
@@ -637,6 +638,90 @@ const TopTools = (
finalData.image_objects = image_objects finalData.image_objects = image_objects
return finalData return finalData
}) })
let saveResults: LabelResult[] = frameResults
if (projectDetail?.label_type === 7) {
const frameNamesFromTask = data_name
.map((item) => item.name?.[0] || "")
.filter((name) => !!name)
const frameNameSet = new Set(frameNamesFromTask)
const frameStore = useVideoFrameStore.getState().videoFrames
const taskVideoPrefix = `${taskDetail!.project_id}:${taskDetail!.id}:`
const videoFrameEntries = Array.from(frameStore.entries()).filter(
([key]) => key.startsWith(taskVideoPrefix)
)
if (!videoFrameEntries.length) {
throw new Error("视频帧映射缺失,无法保存,请刷新任务后重试")
}
const videoFrameMap = new Map<string, string[]>()
videoFrameEntries.forEach(([key, frameNames]) => {
const videoName = key.slice(taskVideoPrefix.length)
if (!videoName) return
videoFrameMap.set(
videoName,
(frameNames || []).filter((frameName) =>
frameNameSet.has(frameName)
)
)
})
if (!videoFrameMap.size) {
throw new Error("视频帧映射无效,无法保存,请刷新任务后重试")
}
const videoNames = Array.from(videoFrameMap.keys())
const frameToVideoMap = new Map<string, string>()
videoFrameMap.forEach((frameNames, videoName) => {
frameNames.forEach((frameName) => {
frameToVideoMap.set(frameName, videoName)
})
})
const unresolvedFrames = frameNamesFromTask.filter(
(frameName) => !frameToVideoMap.has(frameName)
)
if (unresolvedFrames.length) {
throw new Error(
`视频帧映射缺失,无法保存,请刷新任务后重试: ${unresolvedFrames.slice(0, 5).join(", ")}`
)
}
const frameResultMap = new Map<string, ImageObjects>()
frameResults.forEach((item) => {
if (item.image_objects) {
frameResultMap.set(item.data_name, item.image_objects)
}
})
const groupedVideoObjects = new Map<
string,
{ [key: string]: ImageObjects }
>()
frameResultMap.forEach((imageObjects, frameName) => {
const videoName = frameToVideoMap.get(frameName)
if (!videoName) return
if (!groupedVideoObjects.has(videoName)) {
groupedVideoObjects.set(videoName, {})
}
groupedVideoObjects.get(videoName)![frameName] = imageObjects
})
saveResults = videoNames
.map((videoName) => {
const videoObjects = groupedVideoObjects.get(videoName)
if (!videoObjects || !Object.keys(videoObjects).length) return null
return {
data_name: videoName,
video_objects: videoObjects,
} as LabelResult
})
.filter((item): item is LabelResult => !!item)
if (!saveResults.length) {
throw new Error("视频任务保存结果为空")
}
}
const workTime = { const workTime = {
label_work_time: labelTime.label, label_work_time: labelTime.label,
first_review_work_time: labelTime.review1, first_review_work_time: labelTime.review1,
@@ -653,7 +738,7 @@ const TopTools = (
} }
const workLoad: WorkLoad = JSON.parse(JSON.stringify(initialWorkLoad)) const workLoad: WorkLoad = JSON.parse(JSON.stringify(initialWorkLoad))
workLoad.work_time = time ? time - oldWorkLoad.work_time : 0 workLoad.work_time = time ? time - oldWorkLoad.work_time : 0
results.forEach((item) => { frameResults.forEach((item) => {
const { image_objects } = item const { image_objects } = item
if (image_objects) { if (image_objects) {
const { annotations, key_frame, desc } = image_objects const { annotations, key_frame, desc } = image_objects
@@ -744,12 +829,9 @@ const TopTools = (
let params: RequestLabelResult = { let params: RequestLabelResult = {
uid: user_id, uid: user_id,
task_id: taskDetail?.id || 0, task_id: taskDetail?.id || 0,
results: results, results: saveResults,
...defaultObj, ...defaultObj,
} }
results.forEach((item) => {
console.log(item.image_objects)
})
console.log(params, workLoad) console.log(params, workLoad)
await saveLabelResult(params) await saveLabelResult(params)
notifications.show({ notifications.show({
@@ -760,6 +842,11 @@ const TopTools = (
updateOldWorkLoad(workLoad) updateOldWorkLoad(workLoad)
} catch (error: any) { } catch (error: any) {
console.log(error) console.log(error)
notifications.hide("save")
notifications.show({
color: "red",
message: error?.message || "保存失败",
})
} }
}, [ }, [
labelCategories, labelCategories,