You've already forked DataMate
修复部分功能 (#138)
* feature: 版本统一 * feature: 定时同步时默认值展示异常,增加提示 * feature: 修复数据归集搜索 * feature: 优化标注模板查询 * feature: 屏蔽webhook功能
This commit is contained in:
@@ -21,5 +21,5 @@ public class CollectionTaskPagingQuery extends PagingQuery {
|
||||
/**
|
||||
* 任务名称
|
||||
*/
|
||||
private String name;
|
||||
private String keyword;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,8 @@ public class CollectionTaskController{
|
||||
Page<CollectionTask> page = new Page<>(query.getPage(), query.getSize());
|
||||
LambdaQueryWrapper<CollectionTask> wrapper = new LambdaQueryWrapper<CollectionTask>()
|
||||
.eq(query.getStatus() != null, CollectionTask::getStatus, query.getStatus())
|
||||
.like(StringUtils.isNotBlank(query.getName()), CollectionTask::getName, query.getName());
|
||||
.like(StringUtils.isNotBlank(query.getKeyword()), CollectionTask::getName, query.getKeyword())
|
||||
.orderByDesc(CollectionTask::getCreatedAt);
|
||||
return ResponseEntity.ok(CollectionTaskConverter.INSTANCE.toResponse(taskService.getTasks(page, wrapper)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ services:
|
||||
|
||||
milvus:
|
||||
container_name: milvus-standalone
|
||||
image: milvusdb/milvus:v2.6.2
|
||||
image: milvusdb/milvus:v2.6.5
|
||||
command: ["milvus", "run", "standalone"]
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
|
||||
@@ -111,7 +111,9 @@ export default function useFetchData<T>(
|
||||
// 同时执行主要数据获取和额外的轮询函数
|
||||
const promises = [
|
||||
fetchFunc({
|
||||
...filter,
|
||||
...Object.fromEntries(
|
||||
Object.entries(filter).filter(([_, value]) => value != null && value.length > 0)
|
||||
),
|
||||
...extraParams,
|
||||
keyword,
|
||||
type: getFirstOfArray(filter?.type) || undefined,
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
Table,
|
||||
Space,
|
||||
Tag,
|
||||
message,
|
||||
Input,
|
||||
Select,
|
||||
Tooltip,
|
||||
Popconfirm,
|
||||
Card,
|
||||
@@ -16,7 +14,6 @@ import {
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
EyeOutlined,
|
||||
FilterOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import type { ColumnsType } from "antd/es/table";
|
||||
import {
|
||||
@@ -26,23 +23,38 @@ import {
|
||||
import type { AnnotationTemplate } from "../annotation.model";
|
||||
import TemplateForm from "./TemplateForm.tsx";
|
||||
import TemplateDetail from "./TemplateDetail.tsx";
|
||||
|
||||
const { Search } = Input;
|
||||
const { Option } = Select;
|
||||
import {SearchControls} from "@/components/SearchControls.tsx";
|
||||
import useFetchData from "@/hooks/useFetchData.ts";
|
||||
import {
|
||||
AnnotationTypeMap,
|
||||
ClassificationMap,
|
||||
DataTypeMap,
|
||||
TemplateTypeMap
|
||||
} from "@/pages/DataAnnotation/annotation.const.tsx";
|
||||
|
||||
const TemplateList: React.FC = () => {
|
||||
const [templates, setTemplates] = useState<AnnotationTemplate[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [page, setPage] = useState(1);
|
||||
const [size, setSize] = useState(10);
|
||||
|
||||
// Filters
|
||||
const [searchText, setSearchText] = useState("");
|
||||
const [categoryFilter, setCategoryFilter] = useState<string | undefined>();
|
||||
const [dataTypeFilter, setDataTypeFilter] = useState<string | undefined>();
|
||||
const [labelingTypeFilter, setLabelingTypeFilter] = useState<string | undefined>();
|
||||
const [builtInFilter, setBuiltInFilter] = useState<boolean | undefined>();
|
||||
const filterOptions = [
|
||||
{
|
||||
key: "category",
|
||||
label: "分类",
|
||||
options: [...Object.values(ClassificationMap)],
|
||||
},
|
||||
{
|
||||
key: "dataType",
|
||||
label: "数据类型",
|
||||
options: [...Object.values(DataTypeMap)],
|
||||
},
|
||||
{
|
||||
key: "labelingType",
|
||||
label: "标注类型",
|
||||
options: [...Object.values(AnnotationTypeMap)],
|
||||
},
|
||||
{
|
||||
key: "builtIn",
|
||||
label: "模板类型",
|
||||
options: [...Object.values(TemplateTypeMap)],
|
||||
},
|
||||
];
|
||||
|
||||
// Modals
|
||||
const [isFormVisible, setIsFormVisible] = useState(false);
|
||||
@@ -50,35 +62,16 @@ const TemplateList: React.FC = () => {
|
||||
const [selectedTemplate, setSelectedTemplate] = useState<AnnotationTemplate | undefined>();
|
||||
const [formMode, setFormMode] = useState<"create" | "edit">("create");
|
||||
|
||||
useEffect(() => {
|
||||
fetchTemplates();
|
||||
}, [page, size, categoryFilter, dataTypeFilter, labelingTypeFilter, builtInFilter]);
|
||||
|
||||
const fetchTemplates = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const params: any = {
|
||||
page,
|
||||
size,
|
||||
};
|
||||
|
||||
if (categoryFilter) params.category = categoryFilter;
|
||||
if (dataTypeFilter) params.dataType = dataTypeFilter;
|
||||
if (labelingTypeFilter) params.labelingType = labelingTypeFilter;
|
||||
if (builtInFilter !== undefined) params.builtIn = builtInFilter;
|
||||
|
||||
const response = await queryAnnotationTemplatesUsingGet(params);
|
||||
if (response.code === 200 && response.data) {
|
||||
setTemplates(response.data.content || []);
|
||||
setTotal(response.data.total || 0);
|
||||
}
|
||||
} catch (error) {
|
||||
message.error("获取模板列表失败");
|
||||
console.error(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
const {
|
||||
loading,
|
||||
tableData,
|
||||
pagination,
|
||||
searchParams,
|
||||
setSearchParams,
|
||||
fetchData,
|
||||
handleFiltersChange,
|
||||
handleKeywordChange,
|
||||
} = useFetchData(queryAnnotationTemplatesUsingGet, undefined, undefined, undefined, undefined, 0);
|
||||
|
||||
const handleCreate = () => {
|
||||
setFormMode("create");
|
||||
@@ -102,7 +95,7 @@ const TemplateList: React.FC = () => {
|
||||
const response = await deleteAnnotationTemplateByIdUsingDelete(templateId);
|
||||
if (response.code === 200) {
|
||||
message.success("模板删除成功");
|
||||
fetchTemplates();
|
||||
fetchData();
|
||||
} else {
|
||||
message.error(response.message || "删除模板失败");
|
||||
}
|
||||
@@ -114,15 +107,7 @@ const TemplateList: React.FC = () => {
|
||||
|
||||
const handleFormSuccess = () => {
|
||||
setIsFormVisible(false);
|
||||
fetchTemplates();
|
||||
};
|
||||
|
||||
const handleClearFilters = () => {
|
||||
setCategoryFilter(undefined);
|
||||
setDataTypeFilter(undefined);
|
||||
setLabelingTypeFilter(undefined);
|
||||
setBuiltInFilter(undefined);
|
||||
setSearchText("");
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const getCategoryColor = (category: string) => {
|
||||
@@ -143,7 +128,6 @@ const TemplateList: React.FC = () => {
|
||||
key: "name",
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
filteredValue: searchText ? [searchText] : null,
|
||||
onFilter: (value, record) =>
|
||||
record.name.toLowerCase().includes(value.toString().toLowerCase()) ||
|
||||
(record.description?.toLowerCase().includes(value.toString().toLowerCase()) ?? false),
|
||||
@@ -269,78 +253,22 @@ const TemplateList: React.FC = () => {
|
||||
},
|
||||
];
|
||||
|
||||
const hasActiveFilters = categoryFilter || dataTypeFilter || labelingTypeFilter || builtInFilter !== undefined;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
{/* Search, Filters and Buttons in one row */}
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
{/* Left side: Search and Filters */}
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<Search
|
||||
placeholder="搜索模板..."
|
||||
allowClear
|
||||
style={{ width: 300 }}
|
||||
value={searchText}
|
||||
onChange={(e) => setSearchText(e.target.value)}
|
||||
<SearchControls
|
||||
searchTerm={searchParams.keyword}
|
||||
onSearchChange={handleKeywordChange}
|
||||
searchPlaceholder="搜索任务名称、描述"
|
||||
filters={filterOptions}
|
||||
onFiltersChange={handleFiltersChange}
|
||||
showViewToggle={true}
|
||||
onReload={fetchData}
|
||||
onClearFilters={() => setSearchParams({ ...searchParams, filter: {} })}
|
||||
/>
|
||||
|
||||
<Select
|
||||
placeholder="分类"
|
||||
allowClear
|
||||
style={{ width: 140 }}
|
||||
value={categoryFilter}
|
||||
onChange={setCategoryFilter}
|
||||
>
|
||||
<Option value="computer-vision">计算机视觉</Option>
|
||||
<Option value="nlp">自然语言处理</Option>
|
||||
<Option value="audio">音频</Option>
|
||||
<Option value="quality-control">质量控制</Option>
|
||||
<Option value="custom">自定义</Option>
|
||||
</Select>
|
||||
|
||||
<Select
|
||||
placeholder="数据类型"
|
||||
allowClear
|
||||
style={{ width: 120 }}
|
||||
value={dataTypeFilter}
|
||||
onChange={setDataTypeFilter}
|
||||
>
|
||||
<Option value="image">图像</Option>
|
||||
<Option value="text">文本</Option>
|
||||
<Option value="audio">音频</Option>
|
||||
<Option value="video">视频</Option>
|
||||
</Select>
|
||||
|
||||
<Select
|
||||
placeholder="标注类型"
|
||||
allowClear
|
||||
style={{ width: 140 }}
|
||||
value={labelingTypeFilter}
|
||||
onChange={setLabelingTypeFilter}
|
||||
>
|
||||
<Option value="classification">分类</Option>
|
||||
<Option value="object-detection">目标检测</Option>
|
||||
<Option value="segmentation">分割</Option>
|
||||
<Option value="ner">命名实体识别</Option>
|
||||
</Select>
|
||||
|
||||
<Select
|
||||
placeholder="模板类型"
|
||||
allowClear
|
||||
style={{ width: 120 }}
|
||||
value={builtInFilter}
|
||||
onChange={setBuiltInFilter}
|
||||
>
|
||||
<Option value={true}>系统内置</Option>
|
||||
<Option value={false}>自定义</Option>
|
||||
</Select>
|
||||
|
||||
{hasActiveFilters && (
|
||||
<Button icon={<FilterOutlined />} onClick={handleClearFilters}>
|
||||
清空筛选
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Right side: Create button */}
|
||||
@@ -354,20 +282,10 @@ const TemplateList: React.FC = () => {
|
||||
<Card>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={templates}
|
||||
dataSource={tableData}
|
||||
rowKey="id"
|
||||
loading={loading}
|
||||
pagination={{
|
||||
current: page,
|
||||
pageSize: size,
|
||||
total: total,
|
||||
showSizeChanger: true,
|
||||
showTotal: (total) => `共 ${total} 个模板`,
|
||||
onChange: (page, pageSize) => {
|
||||
setPage(page);
|
||||
setSize(pageSize);
|
||||
},
|
||||
}}
|
||||
pagination={pagination}
|
||||
scroll={{ x: 1400, y: "calc(100vh - 24rem)" }}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import { get, post, put, del, download } from "@/utils/request";
|
||||
import { get, post, put, del } from "@/utils/request";
|
||||
|
||||
// 标注任务管理相关接口
|
||||
export function queryAnnotationTasksUsingGet(params?: any) {
|
||||
return get("/api/annotation/project", params);
|
||||
}
|
||||
|
||||
// 获取应用配置(包含 Label Studio 基础 URL)
|
||||
export function getConfigUsingGet() {
|
||||
return get("/api/annotation/about");
|
||||
}
|
||||
|
||||
export function createAnnotationTaskUsingPost(data: any) {
|
||||
return post("/api/annotation/project", data);
|
||||
}
|
||||
@@ -18,80 +13,11 @@ export function syncAnnotationTaskUsingPost(data: any) {
|
||||
return post(`/api/annotation/task/sync`, data);
|
||||
}
|
||||
|
||||
export function queryAnnotationTaskByIdUsingGet(mappingId: string | number) {
|
||||
return get(`/api/annotation/project/${mappingId}`);
|
||||
}
|
||||
|
||||
// 根据源 datasetId 查询映射关系(分页)
|
||||
export function queryMappingsBySourceUsingGet(datasetId: string, params?: any) {
|
||||
return get(`/api/annotation/project/by-source/${datasetId}`, params);
|
||||
}
|
||||
export function deleteAnnotationTaskByIdUsingDelete(mappingId: string) {
|
||||
// Backend expects mapping UUID as path parameter
|
||||
return del(`/api/annotation/project/${mappingId}`);
|
||||
}
|
||||
|
||||
// 智能预标注相关接口
|
||||
export function preAnnotateUsingPost(data: any) {
|
||||
return post("/api/v1/annotation/pre-annotate", data);
|
||||
}
|
||||
|
||||
// 标注数据管理接口
|
||||
export function queryAnnotationDataUsingGet(
|
||||
taskId: string | number,
|
||||
params?: any
|
||||
) {
|
||||
return get(`/api/v1/annotation/tasks/${taskId}/data`, params);
|
||||
}
|
||||
|
||||
export function submitAnnotationUsingPost(taskId: string | number, data: any) {
|
||||
return post(`/api/v1/annotation/tasks/${taskId}/annotations`, data);
|
||||
}
|
||||
|
||||
export function updateAnnotationUsingPut(
|
||||
taskId: string | number,
|
||||
annotationId: string | number,
|
||||
data: any
|
||||
) {
|
||||
return put(
|
||||
`/api/v1/annotation/tasks/${taskId}/annotations/${annotationId}`,
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
export function deleteAnnotationUsingDelete(
|
||||
taskId: string | number,
|
||||
annotationId: string | number
|
||||
) {
|
||||
return del(`/api/v1/annotation/tasks/${taskId}/annotations/${annotationId}`);
|
||||
}
|
||||
|
||||
// 标注任务执行控制
|
||||
export function startAnnotationTaskUsingPost(taskId: string | number) {
|
||||
return post(`/api/v1/annotation/tasks/${taskId}/start`);
|
||||
}
|
||||
|
||||
export function pauseAnnotationTaskUsingPost(taskId: string | number) {
|
||||
return post(`/api/v1/annotation/tasks/${taskId}/pause`);
|
||||
}
|
||||
|
||||
export function resumeAnnotationTaskUsingPost(taskId: string | number) {
|
||||
return post(`/api/v1/annotation/tasks/${taskId}/resume`);
|
||||
}
|
||||
|
||||
export function completeAnnotationTaskUsingPost(taskId: string | number) {
|
||||
return post(`/api/v1/annotation/tasks/${taskId}/complete`);
|
||||
}
|
||||
|
||||
// 标注任务统计信息
|
||||
export function getAnnotationTaskStatisticsUsingGet(taskId: string | number) {
|
||||
return get(`/api/v1/annotation/tasks/${taskId}/statistics`);
|
||||
}
|
||||
|
||||
export function getAnnotationStatisticsUsingGet(params?: any) {
|
||||
return get("/api/v1/annotation/statistics", params);
|
||||
}
|
||||
|
||||
// 标签配置管理
|
||||
export function getTagConfigUsingGet() {
|
||||
return get("/api/annotation/tags/config");
|
||||
@@ -106,173 +32,15 @@ export function createAnnotationTemplateUsingPost(data: any) {
|
||||
return post("/api/annotation/template", data);
|
||||
}
|
||||
|
||||
export function queryAnnotationTemplateByIdUsingGet(
|
||||
templateId: string | number
|
||||
) {
|
||||
return get(`/api/v1/annotation/templates/${templateId}`);
|
||||
}
|
||||
|
||||
export function updateAnnotationTemplateByIdUsingPut(
|
||||
templateId: string | number,
|
||||
data: any
|
||||
) {
|
||||
return put(`/api/v1/annotation/templates/${templateId}`, data);
|
||||
return put(`/api/annotation/template/${templateId}`, data);
|
||||
}
|
||||
|
||||
export function deleteAnnotationTemplateByIdUsingDelete(
|
||||
templateId: string | number
|
||||
) {
|
||||
return del(`/api/v1/annotation/templates/${templateId}`);
|
||||
}
|
||||
|
||||
// 主动学习相关接口
|
||||
export function queryActiveLearningCandidatesUsingGet(
|
||||
taskId: string | number,
|
||||
params?: any
|
||||
) {
|
||||
return get(
|
||||
`/api/v1/annotation/tasks/${taskId}/active-learning/candidates`,
|
||||
params
|
||||
);
|
||||
}
|
||||
|
||||
export function submitActiveLearningFeedbackUsingPost(
|
||||
taskId: string | number,
|
||||
data: any
|
||||
) {
|
||||
return post(
|
||||
`/api/v1/annotation/tasks/${taskId}/active-learning/feedback`,
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
export function updateActiveLearningModelUsingPost(
|
||||
taskId: string | number,
|
||||
data: any
|
||||
) {
|
||||
return post(
|
||||
`/api/v1/annotation/tasks/${taskId}/active-learning/update-model`,
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
// 标注质量控制
|
||||
export function validateAnnotationsUsingPost(
|
||||
taskId: string | number,
|
||||
data: any
|
||||
) {
|
||||
return post(`/api/v1/annotation/tasks/${taskId}/validate`, data);
|
||||
}
|
||||
|
||||
export function getAnnotationQualityReportUsingGet(taskId: string | number) {
|
||||
return get(`/api/v1/annotation/tasks/${taskId}/quality-report`);
|
||||
}
|
||||
|
||||
// 标注数据导入导出
|
||||
export function exportAnnotationsUsingPost(taskId: string | number, data: any) {
|
||||
return post(`/api/v1/annotation/tasks/${taskId}/export`, data);
|
||||
}
|
||||
|
||||
export function importAnnotationsUsingPost(taskId: string | number, data: any) {
|
||||
return post(`/api/v1/annotation/tasks/${taskId}/import`, data);
|
||||
}
|
||||
|
||||
export function downloadAnnotationsUsingGet(
|
||||
taskId: string | number,
|
||||
filename?: string
|
||||
) {
|
||||
return download(
|
||||
`/api/v1/annotation/tasks/${taskId}/download`,
|
||||
null,
|
||||
filename
|
||||
);
|
||||
}
|
||||
|
||||
// 标注者管理
|
||||
export function queryAnnotatorsUsingGet(params?: any) {
|
||||
return get("/api/v1/annotation/annotators", params);
|
||||
}
|
||||
|
||||
export function assignAnnotatorUsingPost(taskId: string | number, data: any) {
|
||||
return post(`/api/v1/annotation/tasks/${taskId}/assign`, data);
|
||||
}
|
||||
|
||||
export function getAnnotatorStatisticsUsingGet(annotatorId: string | number) {
|
||||
return get(`/api/v1/annotation/annotators/${annotatorId}/statistics`);
|
||||
}
|
||||
|
||||
// 标注配置管理
|
||||
export function getAnnotationConfigUsingGet(taskId: string | number) {
|
||||
return get(`/api/v1/annotation/tasks/${taskId}/config`);
|
||||
}
|
||||
|
||||
export function updateAnnotationConfigUsingPut(
|
||||
taskId: string | number,
|
||||
data: any
|
||||
) {
|
||||
return put(`/api/v1/annotation/tasks/${taskId}/config`, data);
|
||||
}
|
||||
|
||||
// 标注类型和标签管理
|
||||
export function queryAnnotationTypesUsingGet() {
|
||||
return get("/api/v1/annotation/types");
|
||||
}
|
||||
|
||||
export function queryAnnotationLabelsUsingGet(taskId: string | number) {
|
||||
return get(`/api/v1/annotation/tasks/${taskId}/labels`);
|
||||
}
|
||||
|
||||
export function createAnnotationLabelUsingPost(
|
||||
taskId: string | number,
|
||||
data: any
|
||||
) {
|
||||
return post(`/api/v1/annotation/tasks/${taskId}/labels`, data);
|
||||
}
|
||||
|
||||
export function updateAnnotationLabelUsingPut(
|
||||
taskId: string | number,
|
||||
labelId: string | number,
|
||||
data: any
|
||||
) {
|
||||
return put(`/api/v1/annotation/tasks/${taskId}/labels/${labelId}`, data);
|
||||
}
|
||||
|
||||
export function deleteAnnotationLabelUsingDelete(
|
||||
taskId: string | number,
|
||||
labelId: string | number
|
||||
) {
|
||||
return del(`/api/v1/annotation/tasks/${taskId}/labels/${labelId}`);
|
||||
}
|
||||
|
||||
// 批量操作
|
||||
export function batchAssignAnnotatorsUsingPost(data: any) {
|
||||
return post("/api/v1/annotation/tasks/batch-assign", data);
|
||||
}
|
||||
|
||||
export function batchUpdateTaskStatusUsingPost(data: any) {
|
||||
return post("/api/v1/annotation/tasks/batch-update-status", data);
|
||||
}
|
||||
|
||||
export function batchDeleteTasksUsingPost(data: { taskIds: string[] }) {
|
||||
return post("/api/v1/annotation/tasks/batch-delete", data);
|
||||
}
|
||||
|
||||
// 标注进度跟踪
|
||||
export function getAnnotationProgressUsingGet(taskId: string | number) {
|
||||
return get(`/api/v1/annotation/tasks/${taskId}/progress`);
|
||||
}
|
||||
|
||||
// 标注审核
|
||||
export function submitAnnotationReviewUsingPost(
|
||||
taskId: string | number,
|
||||
data: any
|
||||
) {
|
||||
return post(`/api/v1/annotation/tasks/${taskId}/review`, data);
|
||||
}
|
||||
|
||||
export function getAnnotationReviewResultsUsingGet(
|
||||
taskId: string | number,
|
||||
params?: any
|
||||
) {
|
||||
return get(`/api/v1/annotation/tasks/${taskId}/reviews`, params);
|
||||
}
|
||||
return del(`/api/annotation/template/${templateId}`);
|
||||
}
|
||||
@@ -1,13 +1,9 @@
|
||||
import { StickyNote } from "lucide-react";
|
||||
import { AnnotationTaskStatus } from "./annotation.model";
|
||||
import {AnnotationTaskStatus, AnnotationType, Classification, DataType, TemplateType} from "./annotation.model";
|
||||
import {
|
||||
CheckCircleOutlined,
|
||||
ClockCircleOutlined,
|
||||
CloseCircleOutlined,
|
||||
CustomerServiceOutlined,
|
||||
FileTextOutlined,
|
||||
PictureOutlined,
|
||||
VideoCameraOutlined,
|
||||
} from "@ant-design/icons";
|
||||
|
||||
export const AnnotationTaskStatusMap = {
|
||||
@@ -70,3 +66,75 @@ export function mapAnnotationTask(task: any) {
|
||||
statistics: statsArray,
|
||||
};
|
||||
}
|
||||
|
||||
export const DataTypeMap = {
|
||||
[DataType.TEXT]: {
|
||||
label: "文本",
|
||||
value: DataType.TEXT
|
||||
},
|
||||
[DataType.IMAGE]: {
|
||||
label: "图片",
|
||||
value: DataType.IMAGE
|
||||
},
|
||||
[DataType.AUDIO]: {
|
||||
label: "音频",
|
||||
value: DataType.AUDIO
|
||||
},
|
||||
[DataType.VIDEO]: {
|
||||
label: "视频",
|
||||
value: DataType.VIDEO
|
||||
},
|
||||
}
|
||||
|
||||
export const ClassificationMap = {
|
||||
[Classification.COMPUTER_VERSION]: {
|
||||
label: "计算机视觉",
|
||||
value: Classification.COMPUTER_VERSION
|
||||
},
|
||||
[Classification.NLP]: {
|
||||
label: "自然语言处理",
|
||||
value: Classification.NLP
|
||||
},
|
||||
[Classification.AUDIO]: {
|
||||
label: "音频",
|
||||
value: Classification.AUDIO
|
||||
},
|
||||
[Classification.QUALITY_CONTROL]: {
|
||||
label: "质量控制",
|
||||
value: Classification.QUALITY_CONTROL
|
||||
},
|
||||
[Classification.CUSTOM]: {
|
||||
label: "自定义",
|
||||
value: Classification.CUSTOM
|
||||
},
|
||||
}
|
||||
|
||||
export const AnnotationTypeMap = {
|
||||
[AnnotationType.CLASSIFICATION]: {
|
||||
label: "分类",
|
||||
value: AnnotationType.CLASSIFICATION
|
||||
},
|
||||
[AnnotationType.OBJECT_DETECTION]: {
|
||||
label: "目标检测",
|
||||
value: AnnotationType.OBJECT_DETECTION
|
||||
},
|
||||
[AnnotationType.SEGMENTATION]: {
|
||||
label: "分割",
|
||||
value: AnnotationType.SEGMENTATION
|
||||
},
|
||||
[AnnotationType.NER]: {
|
||||
label: "命名实体识别",
|
||||
value: AnnotationType.NER
|
||||
},
|
||||
}
|
||||
|
||||
export const TemplateTypeMap = {
|
||||
[TemplateType.SYSTEM]: {
|
||||
label: "系统内置",
|
||||
value: TemplateType.SYSTEM
|
||||
},
|
||||
[TemplateType.CUSTOM]: {
|
||||
label: "自定义",
|
||||
value: TemplateType.CUSTOM
|
||||
},
|
||||
}
|
||||
@@ -78,3 +78,30 @@ export interface AnnotationTemplateListResponse {
|
||||
size: number;
|
||||
totalPages: number;
|
||||
}
|
||||
|
||||
export enum DataType {
|
||||
TEXT = "text",
|
||||
IMAGE = "image",
|
||||
AUDIO = "audio",
|
||||
VIDEO = "video",
|
||||
}
|
||||
|
||||
export enum Classification {
|
||||
COMPUTER_VERSION = "computer-vision",
|
||||
NLP = "nlp",
|
||||
AUDIO = "audio",
|
||||
QUALITY_CONTROL = "quality-control",
|
||||
CUSTOM = "custom"
|
||||
}
|
||||
|
||||
export enum AnnotationType {
|
||||
CLASSIFICATION = "classification",
|
||||
OBJECT_DETECTION = "object-detection",
|
||||
SEGMENTATION = "segmentation",
|
||||
NER = "ner"
|
||||
}
|
||||
|
||||
export enum TemplateType {
|
||||
SYSTEM = "true",
|
||||
CUSTOM = "false"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useState } from "react";
|
||||
import { Input, Button, Radio, Form, InputNumber, App, Select } from "antd";
|
||||
import { Input, Button, Radio, Form, App, Select } from "antd";
|
||||
import { Link, useNavigate } from "react-router";
|
||||
import { ArrowLeft } from "lucide-react";
|
||||
import { createTaskUsingPost } from "../collection.apis";
|
||||
@@ -76,7 +76,7 @@ export default function CollectionTaskCreate() {
|
||||
createDataset: false,
|
||||
});
|
||||
const [scheduleExpression, setScheduleExpression] = useState({
|
||||
type: SyncMode.SCHEDULED,
|
||||
type: "once",
|
||||
time: "00:00",
|
||||
cronExpression: "0 0 0 * * ?",
|
||||
});
|
||||
@@ -388,6 +388,7 @@ export default function CollectionTaskCreate() {
|
||||
name="createDataset"
|
||||
required
|
||||
rules={[{ required: true, message: "请选择是否创建数据集" }]}
|
||||
tooltip={"支持后续在【数据管理】中手动创建数据集并关联至此任务。"}
|
||||
>
|
||||
<Radio.Group
|
||||
value={isCreateDataset}
|
||||
|
||||
@@ -218,6 +218,19 @@ export default function DatasetManagementPage() {
|
||||
key: "type",
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
render: (status: any) => {
|
||||
return (
|
||||
<Tag icon={status?.icon} color={status?.color}>
|
||||
{status?.label}
|
||||
</Tag>
|
||||
);
|
||||
},
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: "大小",
|
||||
dataIndex: "size",
|
||||
@@ -230,12 +243,12 @@ export default function DatasetManagementPage() {
|
||||
key: "fileCount",
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: "创建者",
|
||||
dataIndex: "createdBy",
|
||||
key: "createdBy",
|
||||
width: 120,
|
||||
},
|
||||
// {
|
||||
// title: "创建者",
|
||||
// dataIndex: "createdBy",
|
||||
// key: "createdBy",
|
||||
// width: 120,
|
||||
// },
|
||||
{
|
||||
title: "存储路径",
|
||||
dataIndex: "targetLocation",
|
||||
@@ -255,26 +268,6 @@ export default function DatasetManagementPage() {
|
||||
key: "updatedAt",
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: "描述",
|
||||
dataIndex: "description",
|
||||
key: "description",
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
render: (status: any) => {
|
||||
return (
|
||||
<Tag icon={status?.icon} color={status?.color}>
|
||||
{status?.label}
|
||||
</Tag>
|
||||
);
|
||||
},
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "actions",
|
||||
@@ -372,7 +365,7 @@ export default function DatasetManagementPage() {
|
||||
<SearchControls
|
||||
searchTerm={searchParams.keyword}
|
||||
onSearchChange={handleKeywordChange}
|
||||
searchPlaceholder="搜索数据集名称、描述或标签..."
|
||||
searchPlaceholder="搜索数据集名称、描述"
|
||||
filters={filterOptions}
|
||||
onFiltersChange={handleFiltersChange}
|
||||
onClearFilters={() => setSearchParams({ ...searchParams, filter: {} })}
|
||||
|
||||
@@ -21,12 +21,13 @@ export default function WelcomePage() {
|
||||
// 检查接口连通性的函数
|
||||
const checkDeerFlowDeploy = async (): Promise<boolean> => {
|
||||
try {
|
||||
const response = await fetch('/deer-flow-backend/config', { // 替换为你的实际接口地址
|
||||
const response = await fetch('/deer-flow-backend/config', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
timeout: 5000, // 5秒超时
|
||||
cache: 'no-store'
|
||||
});
|
||||
|
||||
// 检查 HTTP 状态码在 200-299 范围内
|
||||
|
||||
@@ -36,6 +36,8 @@ export default function SettingsPage() {
|
||||
key: "webhook-config",
|
||||
icon: <ApiOutlined />,
|
||||
label: "Webhook",
|
||||
disabled: true,
|
||||
title: "暂未开放"
|
||||
},
|
||||
]}
|
||||
selectedKeys={[activeTab]}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:18-alpine AS builder
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
Reference in New Issue
Block a user