You've already forked DataMate
Compare commits
2 Commits
f6788756d3
...
4a3e466210
| Author | SHA1 | Date | |
|---|---|---|---|
| 4a3e466210 | |||
| 5d8d25ca8c |
@@ -192,6 +192,7 @@ const stableStringify = (value: unknown) => {
|
|||||||
|
|
||||||
const buildAnnotationSnapshot = (annotation?: Record<string, unknown>) => {
|
const buildAnnotationSnapshot = (annotation?: Record<string, unknown>) => {
|
||||||
if (!annotation) return "";
|
if (!annotation) return "";
|
||||||
|
if (isAnnotationResultEmpty(annotation)) return "";
|
||||||
const cleaned: Record<string, unknown> = { ...annotation };
|
const cleaned: Record<string, unknown> = { ...annotation };
|
||||||
delete cleaned.updated_at;
|
delete cleaned.updated_at;
|
||||||
delete cleaned.updatedAt;
|
delete cleaned.updatedAt;
|
||||||
@@ -717,11 +718,13 @@ export default function LabelStudioTextEditor() {
|
|||||||
const annotationRecord = annotation as Record<string, unknown>;
|
const annotationRecord = annotation as Record<string, unknown>;
|
||||||
const currentTask = tasks.find((item) => item.fileId === String(fileId));
|
const currentTask = tasks.find((item) => item.fileId === String(fileId));
|
||||||
const currentStatus = currentTask?.annotationStatus;
|
const currentStatus = currentTask?.annotationStatus;
|
||||||
const hasExistingAnnotation = !!currentTask?.hasAnnotation;
|
|
||||||
let resolvedStatus: AnnotationResultStatus;
|
let resolvedStatus: AnnotationResultStatus;
|
||||||
if (isAnnotationResultEmpty(annotationRecord)) {
|
if (isAnnotationResultEmpty(annotationRecord)) {
|
||||||
if (currentStatus === AnnotationResultStatus.ANNOTATED || (hasExistingAnnotation && !currentStatus)) {
|
if (
|
||||||
resolvedStatus = AnnotationResultStatus.ANNOTATED;
|
currentStatus === AnnotationResultStatus.NO_ANNOTATION ||
|
||||||
|
currentStatus === AnnotationResultStatus.NOT_APPLICABLE
|
||||||
|
) {
|
||||||
|
resolvedStatus = currentStatus;
|
||||||
} else {
|
} else {
|
||||||
const selectedStatus = await confirmEmptyAnnotationStatus();
|
const selectedStatus = await confirmEmptyAnnotationStatus();
|
||||||
if (!selectedStatus) return false;
|
if (!selectedStatus) return false;
|
||||||
@@ -1033,6 +1036,15 @@ export default function LabelStudioTextEditor() {
|
|||||||
[segmentTreeData]
|
[segmentTreeData]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const inProgressSegmentedCount = useMemo(() => {
|
||||||
|
if (tasks.length === 0) return 0;
|
||||||
|
return tasks.reduce((count, item) => {
|
||||||
|
const summary = resolveSegmentSummary(item);
|
||||||
|
if (!summary) return count;
|
||||||
|
return summary.done < summary.total ? count + 1 : count;
|
||||||
|
}, 0);
|
||||||
|
}, [tasks]);
|
||||||
|
|
||||||
const handleSegmentSelect = useCallback((keys: Array<string | number>) => {
|
const handleSegmentSelect = useCallback((keys: Array<string | number>) => {
|
||||||
const [first] = keys;
|
const [first] = keys;
|
||||||
if (first === undefined || first === null) return;
|
if (first === undefined || first === null) return;
|
||||||
@@ -1214,8 +1226,13 @@ export default function LabelStudioTextEditor() {
|
|||||||
className="border-r border-gray-200 bg-gray-50 flex flex-col transition-all duration-200 min-h-0"
|
className="border-r border-gray-200 bg-gray-50 flex flex-col transition-all duration-200 min-h-0"
|
||||||
style={{ width: sidebarCollapsed ? 0 : 240, overflow: "hidden" }}
|
style={{ width: sidebarCollapsed ? 0 : 240, overflow: "hidden" }}
|
||||||
>
|
>
|
||||||
<div className="px-3 py-2 border-b border-gray-200 bg-white font-medium text-sm">
|
<div className="px-3 py-2 border-b border-gray-200 bg-white font-medium text-sm flex items-center justify-between gap-2">
|
||||||
文件列表
|
<span>文件列表</span>
|
||||||
|
{segmented && (
|
||||||
|
<Tag color="orange" style={{ margin: 0 }}>
|
||||||
|
标注中 {inProgressSegmentedCount}
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 min-h-0 overflow-auto">
|
<div className="flex-1 min-h-0 overflow-auto">
|
||||||
<List
|
<List
|
||||||
|
|||||||
@@ -10,27 +10,35 @@ import {
|
|||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import { SearchControls } from "@/components/SearchControls";
|
import { SearchControls } from "@/components/SearchControls";
|
||||||
import CardView from "@/components/CardView";
|
import CardView from "@/components/CardView";
|
||||||
import type { AnnotationTask } from "../annotation.model";
|
|
||||||
import useFetchData from "@/hooks/useFetchData";
|
import useFetchData from "@/hooks/useFetchData";
|
||||||
import {
|
import {
|
||||||
deleteAnnotationTaskByIdUsingDelete,
|
deleteAnnotationTaskByIdUsingDelete,
|
||||||
queryAnnotationTasksUsingGet,
|
queryAnnotationTasksUsingGet,
|
||||||
} from "../annotation.api";
|
} from "../annotation.api";
|
||||||
import { mapAnnotationTask } from "../annotation.const";
|
import { mapAnnotationTask, type AnnotationTaskListItem } from "../annotation.const";
|
||||||
import CreateAnnotationTask from "../Create/components/CreateAnnotationTaskDialog";
|
import CreateAnnotationTask from "../Create/components/CreateAnnotationTaskDialog";
|
||||||
import ExportAnnotationDialog from "./ExportAnnotationDialog";
|
import ExportAnnotationDialog from "./ExportAnnotationDialog";
|
||||||
import { ColumnType } from "antd/es/table";
|
import { ColumnType } from "antd/es/table";
|
||||||
import { TemplateList } from "../Template";
|
import { TemplateList } from "../Template";
|
||||||
// Note: DevelopmentInProgress intentionally not used here
|
// Note: DevelopmentInProgress intentionally not used here
|
||||||
|
|
||||||
|
type AnnotationTaskRowKey = string | number;
|
||||||
|
type AnnotationTaskOperation = {
|
||||||
|
key: string;
|
||||||
|
label: string;
|
||||||
|
icon: JSX.Element;
|
||||||
|
danger?: boolean;
|
||||||
|
onClick: (task: AnnotationTaskListItem) => void;
|
||||||
|
};
|
||||||
|
|
||||||
export default function DataAnnotation() {
|
export default function DataAnnotation() {
|
||||||
// return <DevelopmentInProgress showTime="2025.10.30" />;
|
// return <DevelopmentInProgress showTime="2025.10.30" />;
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [activeTab, setActiveTab] = useState("tasks");
|
const [activeTab, setActiveTab] = useState("tasks");
|
||||||
const [viewMode, setViewMode] = useState<"list" | "card">("list");
|
const [viewMode, setViewMode] = useState<"list" | "card">("list");
|
||||||
const [showCreateDialog, setShowCreateDialog] = useState(false);
|
const [showCreateDialog, setShowCreateDialog] = useState(false);
|
||||||
const [exportTask, setExportTask] = useState<AnnotationTask | null>(null);
|
const [exportTask, setExportTask] = useState<AnnotationTaskListItem | null>(null);
|
||||||
const [editTask, setEditTask] = useState<AnnotationTask | null>(null);
|
const [editTask, setEditTask] = useState<AnnotationTaskListItem | null>(null);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
loading,
|
loading,
|
||||||
@@ -40,13 +48,13 @@ export default function DataAnnotation() {
|
|||||||
fetchData,
|
fetchData,
|
||||||
handleFiltersChange,
|
handleFiltersChange,
|
||||||
handleKeywordChange,
|
handleKeywordChange,
|
||||||
} = useFetchData(queryAnnotationTasksUsingGet, mapAnnotationTask, 30000, true, [], 0);
|
} = useFetchData<AnnotationTaskListItem>(queryAnnotationTasksUsingGet, mapAnnotationTask, 30000, true, [], 0);
|
||||||
|
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState<(string | number)[]>([]);
|
const [selectedRowKeys, setSelectedRowKeys] = useState<AnnotationTaskRowKey[]>([]);
|
||||||
const [selectedRows, setSelectedRows] = useState<any[]>([]);
|
const [selectedRows, setSelectedRows] = useState<AnnotationTaskListItem[]>([]);
|
||||||
|
|
||||||
const handleAnnotate = (task: AnnotationTask) => {
|
const handleAnnotate = (task: AnnotationTaskListItem) => {
|
||||||
const projectId = (task as any)?.id;
|
const projectId = task.id;
|
||||||
if (!projectId) {
|
if (!projectId) {
|
||||||
message.error("无法进入标注:缺少标注项目ID");
|
message.error("无法进入标注:缺少标注项目ID");
|
||||||
return;
|
return;
|
||||||
@@ -54,15 +62,15 @@ export default function DataAnnotation() {
|
|||||||
navigate(`/data/annotation/annotate/${projectId}`);
|
navigate(`/data/annotation/annotate/${projectId}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleExport = (task: AnnotationTask) => {
|
const handleExport = (task: AnnotationTaskListItem) => {
|
||||||
setExportTask(task);
|
setExportTask(task);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEdit = (task: AnnotationTask) => {
|
const handleEdit = (task: AnnotationTaskListItem) => {
|
||||||
setEditTask(task);
|
setEditTask(task);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = (task: AnnotationTask) => {
|
const handleDelete = (task: AnnotationTaskListItem) => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: `确认删除标注任务「${task.name}」吗?`,
|
title: `确认删除标注任务「${task.name}」吗?`,
|
||||||
content: "删除标注任务不会删除对应数据集,但会删除该任务的所有标注结果。",
|
content: "删除标注任务不会删除对应数据集,但会删除该任务的所有标注结果。",
|
||||||
@@ -110,7 +118,7 @@ export default function DataAnnotation() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const operations = [
|
const operations: AnnotationTaskOperation[] = [
|
||||||
{
|
{
|
||||||
key: "annotate",
|
key: "annotate",
|
||||||
label: "标注",
|
label: "标注",
|
||||||
@@ -142,7 +150,7 @@ export default function DataAnnotation() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const columns: ColumnType<any>[] = [
|
const columns: ColumnType<AnnotationTaskListItem>[] = [
|
||||||
{
|
{
|
||||||
title: "任务名称",
|
title: "任务名称",
|
||||||
dataIndex: "name",
|
dataIndex: "name",
|
||||||
@@ -173,7 +181,7 @@ export default function DataAnnotation() {
|
|||||||
key: "annotatedCount",
|
key: "annotatedCount",
|
||||||
width: 100,
|
width: 100,
|
||||||
align: "center" as const,
|
align: "center" as const,
|
||||||
render: (value: number, record: any) => {
|
render: (value: number, record: AnnotationTaskListItem) => {
|
||||||
const total = record.totalCount || 0;
|
const total = record.totalCount || 0;
|
||||||
const annotated = value || 0;
|
const annotated = value || 0;
|
||||||
const percent = total > 0 ? Math.round((annotated / total) * 100) : 0;
|
const percent = total > 0 ? Math.round((annotated / total) * 100) : 0;
|
||||||
@@ -184,6 +192,23 @@ export default function DataAnnotation() {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "标注中",
|
||||||
|
dataIndex: "inProgressCount",
|
||||||
|
key: "inProgressCount",
|
||||||
|
width: 100,
|
||||||
|
align: "center" as const,
|
||||||
|
render: (value: number, record: AnnotationTaskListItem) => {
|
||||||
|
const segmentationEnabled =
|
||||||
|
record.segmentationEnabled ?? record.segmentation_enabled;
|
||||||
|
if (!segmentationEnabled) return "-";
|
||||||
|
const resolved =
|
||||||
|
Number.isFinite(value)
|
||||||
|
? value
|
||||||
|
: record.inProgressCount ?? record.in_progress_count ?? 0;
|
||||||
|
return resolved;
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "创建时间",
|
title: "创建时间",
|
||||||
dataIndex: "createdAt",
|
dataIndex: "createdAt",
|
||||||
@@ -202,14 +227,14 @@ export default function DataAnnotation() {
|
|||||||
fixed: "right" as const,
|
fixed: "right" as const,
|
||||||
width: 150,
|
width: 150,
|
||||||
dataIndex: "actions",
|
dataIndex: "actions",
|
||||||
render: (_: any, task: any) => (
|
render: (_value: unknown, task: AnnotationTaskListItem) => (
|
||||||
<div className="flex items-center justify-center space-x-1">
|
<div className="flex items-center justify-center space-x-1">
|
||||||
{operations.map((operation) => (
|
{operations.map((operation) => (
|
||||||
<Button
|
<Button
|
||||||
key={operation.key}
|
key={operation.key}
|
||||||
type="text"
|
type="text"
|
||||||
icon={operation.icon}
|
icon={operation.icon}
|
||||||
onClick={() => (operation?.onClick as any)?.(task)}
|
onClick={() => operation.onClick(task)}
|
||||||
title={operation.label}
|
title={operation.label}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@@ -282,9 +307,9 @@ export default function DataAnnotation() {
|
|||||||
pagination={pagination}
|
pagination={pagination}
|
||||||
rowSelection={{
|
rowSelection={{
|
||||||
selectedRowKeys,
|
selectedRowKeys,
|
||||||
onChange: (keys, rows) => {
|
onChange: (keys: AnnotationTaskRowKey[], rows: AnnotationTaskListItem[]) => {
|
||||||
setSelectedRowKeys(keys as (string | number)[]);
|
setSelectedRowKeys(keys);
|
||||||
setSelectedRows(rows as any[]);
|
setSelectedRows(rows);
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
scroll={{ x: "max-content", y: "calc(100vh - 24rem)" }}
|
scroll={{ x: "max-content", y: "calc(100vh - 24rem)" }}
|
||||||
@@ -293,7 +318,7 @@ export default function DataAnnotation() {
|
|||||||
) : (
|
) : (
|
||||||
<CardView
|
<CardView
|
||||||
data={tableData}
|
data={tableData}
|
||||||
operations={operations as any}
|
operations={operations}
|
||||||
pagination={pagination}
|
pagination={pagination}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
/>
|
/>
|
||||||
@@ -327,4 +352,4 @@ export default function DataAnnotation() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,64 @@ import {
|
|||||||
CloseCircleOutlined,
|
CloseCircleOutlined,
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
|
|
||||||
|
type AnnotationTaskStatistics = {
|
||||||
|
accuracy?: number | string;
|
||||||
|
averageTime?: number | string;
|
||||||
|
reviewCount?: number | string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type AnnotationTaskPayload = {
|
||||||
|
id?: string;
|
||||||
|
labelingProjId?: string;
|
||||||
|
labelingProjectId?: string;
|
||||||
|
projId?: string;
|
||||||
|
labeling_project_id?: string;
|
||||||
|
name?: string;
|
||||||
|
description?: string;
|
||||||
|
datasetId?: string;
|
||||||
|
datasetName?: string;
|
||||||
|
dataset_name?: string;
|
||||||
|
totalCount?: number;
|
||||||
|
total_count?: number;
|
||||||
|
annotatedCount?: number;
|
||||||
|
annotated_count?: number;
|
||||||
|
inProgressCount?: number;
|
||||||
|
in_progress_count?: number;
|
||||||
|
segmentationEnabled?: boolean;
|
||||||
|
segmentation_enabled?: boolean;
|
||||||
|
createdAt?: string;
|
||||||
|
created_at?: string;
|
||||||
|
updatedAt?: string;
|
||||||
|
updated_at?: string;
|
||||||
|
status?: string;
|
||||||
|
statistics?: AnnotationTaskStatistics;
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AnnotationTaskListItem = {
|
||||||
|
id?: string;
|
||||||
|
labelingProjId?: string;
|
||||||
|
projId?: string;
|
||||||
|
name?: string;
|
||||||
|
description?: string;
|
||||||
|
datasetId?: string;
|
||||||
|
datasetName?: string;
|
||||||
|
totalCount?: number;
|
||||||
|
annotatedCount?: number;
|
||||||
|
inProgressCount?: number;
|
||||||
|
segmentationEnabled?: boolean;
|
||||||
|
createdAt?: string;
|
||||||
|
updatedAt?: string;
|
||||||
|
icon?: JSX.Element;
|
||||||
|
iconColor?: string;
|
||||||
|
status?: {
|
||||||
|
label: string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
statistics?: { label: string; value: string | number }[];
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
export const AnnotationTaskStatusMap = {
|
export const AnnotationTaskStatusMap = {
|
||||||
[AnnotationTaskStatus.ACTIVE]: {
|
[AnnotationTaskStatus.ACTIVE]: {
|
||||||
label: "活跃",
|
label: "活跃",
|
||||||
@@ -27,9 +85,11 @@ export const AnnotationTaskStatusMap = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export function mapAnnotationTask(task: any) {
|
export function mapAnnotationTask(task: AnnotationTaskPayload): AnnotationTaskListItem {
|
||||||
// Normalize labeling project id from possible backend field names
|
// Normalize labeling project id from possible backend field names
|
||||||
const labelingProjId = task?.labelingProjId || task?.labelingProjectId || task?.projId || task?.labeling_project_id || "";
|
const labelingProjId = task?.labelingProjId || task?.labelingProjectId || task?.projId || task?.labeling_project_id || "";
|
||||||
|
const segmentationEnabled = task?.segmentationEnabled ?? task?.segmentation_enabled ?? false;
|
||||||
|
const inProgressCount = task?.inProgressCount ?? task?.in_progress_count ?? 0;
|
||||||
|
|
||||||
const statsArray = task?.statistics
|
const statsArray = task?.statistics
|
||||||
? [
|
? [
|
||||||
@@ -45,6 +105,8 @@ export function mapAnnotationTask(task: any) {
|
|||||||
// provide consistent field for components
|
// provide consistent field for components
|
||||||
labelingProjId,
|
labelingProjId,
|
||||||
projId: labelingProjId,
|
projId: labelingProjId,
|
||||||
|
segmentationEnabled,
|
||||||
|
inProgressCount,
|
||||||
name: task.name,
|
name: task.name,
|
||||||
description: task.description || "",
|
description: task.description || "",
|
||||||
datasetName: task.datasetName || task.dataset_name || "-",
|
datasetName: task.datasetName || task.dataset_name || "-",
|
||||||
@@ -478,4 +540,4 @@ export const TemplateTypeMap = {
|
|||||||
label: "自定义",
|
label: "自定义",
|
||||||
value: TemplateType.CUSTOM
|
value: TemplateType.CUSTOM
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ class DatasetMappingResponse(BaseModel):
|
|||||||
)
|
)
|
||||||
total_count: int = Field(0, alias="totalCount", description="数据集总数据量")
|
total_count: int = Field(0, alias="totalCount", description="数据集总数据量")
|
||||||
annotated_count: int = Field(0, alias="annotatedCount", description="已标注数据量")
|
annotated_count: int = Field(0, alias="annotatedCount", description="已标注数据量")
|
||||||
|
in_progress_count: int = Field(0, alias="inProgressCount", description="分段标注中数据量")
|
||||||
created_at: datetime = Field(..., alias="createdAt", description="创建时间")
|
created_at: datetime = Field(..., alias="createdAt", description="创建时间")
|
||||||
updated_at: Optional[datetime] = Field(None, alias="updatedAt", description="更新时间")
|
updated_at: Optional[datetime] = Field(None, alias="updatedAt", description="更新时间")
|
||||||
deleted_at: Optional[datetime] = Field(None, alias="deletedAt", description="删除时间")
|
deleted_at: Optional[datetime] = Field(None, alias="deletedAt", description="删除时间")
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import uuid
|
|||||||
|
|
||||||
from app.core.logging import get_logger
|
from app.core.logging import get_logger
|
||||||
from app.db.models import LabelingProject, AnnotationTemplate, AnnotationResult, LabelingProjectFile
|
from app.db.models import LabelingProject, AnnotationTemplate, AnnotationResult, LabelingProjectFile
|
||||||
|
from app.db.models.annotation_management import ANNOTATION_STATUS_IN_PROGRESS
|
||||||
from app.db.models.dataset_management import Dataset, DatasetFiles
|
from app.db.models.dataset_management import Dataset, DatasetFiles
|
||||||
from app.module.annotation.schema import (
|
from app.module.annotation.schema import (
|
||||||
DatasetMappingCreateRequest,
|
DatasetMappingCreateRequest,
|
||||||
@@ -40,7 +41,7 @@ class DatasetMappingService:
|
|||||||
self,
|
self,
|
||||||
project_id: str,
|
project_id: str,
|
||||||
dataset_id: str
|
dataset_id: str
|
||||||
) -> Tuple[int, int]:
|
) -> Tuple[int, int, int]:
|
||||||
"""
|
"""
|
||||||
获取项目的统计数据
|
获取项目的统计数据
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ class DatasetMappingService:
|
|||||||
dataset_id: 数据集ID
|
dataset_id: 数据集ID
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
(total_count, annotated_count) 元组
|
(total_count, annotated_count, in_progress_count) 元组
|
||||||
"""
|
"""
|
||||||
# 获取标注项目快照数据量(只统计快照内的文件)
|
# 获取标注项目快照数据量(只统计快照内的文件)
|
||||||
total_result = await self.db.execute(
|
total_result = await self.db.execute(
|
||||||
@@ -71,7 +72,16 @@ class DatasetMappingService:
|
|||||||
)
|
)
|
||||||
annotated_count = int(annotated_result.scalar() or 0)
|
annotated_count = int(annotated_result.scalar() or 0)
|
||||||
|
|
||||||
return total_count, annotated_count
|
# 获取分段标注中数据量(标注状态为 IN_PROGRESS)
|
||||||
|
in_progress_result = await self.db.execute(
|
||||||
|
select(func.count(func.distinct(AnnotationResult.file_id))).where(
|
||||||
|
AnnotationResult.project_id == project_id,
|
||||||
|
AnnotationResult.annotation_status == ANNOTATION_STATUS_IN_PROGRESS,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
in_progress_count = int(in_progress_result.scalar() or 0)
|
||||||
|
|
||||||
|
return total_count, annotated_count, in_progress_count
|
||||||
|
|
||||||
async def _to_response_from_row(
|
async def _to_response_from_row(
|
||||||
self,
|
self,
|
||||||
@@ -110,7 +120,7 @@ class DatasetMappingService:
|
|||||||
logger.debug(f"Included template details for template_id: {template_id}")
|
logger.debug(f"Included template details for template_id: {template_id}")
|
||||||
|
|
||||||
# 获取统计数据
|
# 获取统计数据
|
||||||
total_count, annotated_count = await self._get_project_stats(
|
total_count, annotated_count, in_progress_count = await self._get_project_stats(
|
||||||
mapping.id, mapping.dataset_id
|
mapping.id, mapping.dataset_id
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -127,6 +137,7 @@ class DatasetMappingService:
|
|||||||
"segmentation_enabled": segmentation_enabled,
|
"segmentation_enabled": segmentation_enabled,
|
||||||
"total_count": total_count,
|
"total_count": total_count,
|
||||||
"annotated_count": annotated_count,
|
"annotated_count": annotated_count,
|
||||||
|
"in_progress_count": in_progress_count,
|
||||||
"created_at": mapping.created_at,
|
"created_at": mapping.created_at,
|
||||||
"updated_at": mapping.updated_at,
|
"updated_at": mapping.updated_at,
|
||||||
"deleted_at": mapping.deleted_at,
|
"deleted_at": mapping.deleted_at,
|
||||||
@@ -177,9 +188,9 @@ class DatasetMappingService:
|
|||||||
logger.debug(f"Included template details for template_id: {template_id}")
|
logger.debug(f"Included template details for template_id: {template_id}")
|
||||||
|
|
||||||
# 获取统计数据
|
# 获取统计数据
|
||||||
total_count, annotated_count = 0, 0
|
total_count, annotated_count, in_progress_count = 0, 0, 0
|
||||||
if dataset_id:
|
if dataset_id:
|
||||||
total_count, annotated_count = await self._get_project_stats(
|
total_count, annotated_count, in_progress_count = await self._get_project_stats(
|
||||||
mapping.id, dataset_id
|
mapping.id, dataset_id
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -197,6 +208,7 @@ class DatasetMappingService:
|
|||||||
"segmentation_enabled": segmentation_enabled,
|
"segmentation_enabled": segmentation_enabled,
|
||||||
"total_count": total_count,
|
"total_count": total_count,
|
||||||
"annotated_count": annotated_count,
|
"annotated_count": annotated_count,
|
||||||
|
"in_progress_count": in_progress_count,
|
||||||
"created_at": mapping.created_at,
|
"created_at": mapping.created_at,
|
||||||
"updated_at": mapping.updated_at,
|
"updated_at": mapping.updated_at,
|
||||||
"deleted_at": mapping.deleted_at,
|
"deleted_at": mapping.deleted_at,
|
||||||
|
|||||||
Reference in New Issue
Block a user