You've already forked DataMate
init datamate
This commit is contained in:
330
frontend/src/mock/annotation.tsx
Normal file
330
frontend/src/mock/annotation.tsx
Normal file
@@ -0,0 +1,330 @@
|
||||
import { BarChart, Circle, Grid, ImageIcon, Layers, Maximize, MousePointer, Move, Square, Target, Crop, RotateCcw, FileText, Tag, Heart, HelpCircle, BookOpen, MessageSquare, Users, Zap, Globe, Scissors } from "lucide-react";
|
||||
|
||||
// Define the AnnotationTask type if not imported from elsewhere
|
||||
interface AnnotationTask {
|
||||
id: string
|
||||
name: string
|
||||
completed: string
|
||||
completedCount: number
|
||||
skippedCount: number
|
||||
totalCount: number
|
||||
annotators: Array<{
|
||||
id: string
|
||||
name: string
|
||||
avatar?: string
|
||||
}>
|
||||
text: string
|
||||
status: "completed" | "in_progress" | "pending" | "skipped"
|
||||
project: string
|
||||
type: "图像分类" | "文本分类" | "目标检测" | "NER" | "语音识别" | "视频分析"
|
||||
datasetType: "text" | "image" | "video" | "audio"
|
||||
progress: number
|
||||
}
|
||||
|
||||
|
||||
export const mockTasks: AnnotationTask[] = [
|
||||
{
|
||||
id: "12345678",
|
||||
name: "图像分类标注任务",
|
||||
completed: "2024年1月20日 20:40",
|
||||
completedCount: 1,
|
||||
skippedCount: 0,
|
||||
totalCount: 2,
|
||||
annotators: [
|
||||
{ id: "1", name: "张三", avatar: "/placeholder-user.jpg" },
|
||||
{ id: "2", name: "李四", avatar: "/placeholder-user.jpg" },
|
||||
],
|
||||
text: "对产品图像进行分类标注,包含10个类别",
|
||||
status: "completed",
|
||||
project: "图像分类",
|
||||
type: "图像分类",
|
||||
datasetType: "image",
|
||||
progress: 100,
|
||||
},
|
||||
{
|
||||
id: "12345679",
|
||||
name: "文本情感分析标注",
|
||||
completed: "2024年1月20日 20:40",
|
||||
completedCount: 2,
|
||||
skippedCount: 0,
|
||||
totalCount: 2,
|
||||
annotators: [
|
||||
{ id: "1", name: "王五", avatar: "/placeholder-user.jpg" },
|
||||
{ id: "2", name: "赵六", avatar: "/placeholder-user.jpg" },
|
||||
],
|
||||
text: "对用户评论进行情感倾向标注",
|
||||
status: "completed",
|
||||
project: "文本分类",
|
||||
type: "文本分类",
|
||||
datasetType: "text",
|
||||
progress: 100,
|
||||
},
|
||||
{
|
||||
id: "12345680",
|
||||
name: "目标检测标注任务",
|
||||
completed: "2024年1月20日 20:40",
|
||||
completedCount: 1,
|
||||
skippedCount: 0,
|
||||
totalCount: 2,
|
||||
annotators: [{ id: "1", name: "孙七", avatar: "/placeholder-user.jpg" }],
|
||||
text: "对交通场景图像进行目标检测标注",
|
||||
status: "in_progress",
|
||||
project: "目标检测",
|
||||
type: "目标检测",
|
||||
datasetType: "image",
|
||||
progress: 50,
|
||||
},
|
||||
{
|
||||
id: "12345681",
|
||||
name: "命名实体识别标注",
|
||||
completed: "2024年1月20日 20:40",
|
||||
completedCount: 1,
|
||||
skippedCount: 0,
|
||||
totalCount: 2,
|
||||
annotators: [{ id: "1", name: "周八", avatar: "/placeholder-user.jpg" }],
|
||||
text: "对新闻文本进行命名实体识别标注",
|
||||
status: "in_progress",
|
||||
project: "NER",
|
||||
type: "NER",
|
||||
datasetType: "text",
|
||||
progress: 75,
|
||||
},
|
||||
{
|
||||
id: "12345682",
|
||||
name: "语音识别标注任务",
|
||||
completed: "2024年1月20日 20:40",
|
||||
completedCount: 1,
|
||||
skippedCount: 0,
|
||||
totalCount: 2,
|
||||
annotators: [{ id: "1", name: "吴九", avatar: "/placeholder-user.jpg" }],
|
||||
text: "对语音数据进行转录和标注",
|
||||
status: "in_progress",
|
||||
project: "语音识别",
|
||||
type: "语音识别",
|
||||
datasetType: "audio",
|
||||
progress: 25,
|
||||
},
|
||||
{
|
||||
id: "12345683",
|
||||
name: "视频动作识别标注",
|
||||
completed: "2024年1月20日 20:40",
|
||||
completedCount: 0,
|
||||
skippedCount: 2,
|
||||
totalCount: 2,
|
||||
annotators: [
|
||||
{ id: "1", name: "陈十", avatar: "/placeholder-user.jpg" },
|
||||
{ id: "2", name: "林十一", avatar: "/placeholder-user.jpg" },
|
||||
],
|
||||
text: "对视频中的人体动作进行识别和标注",
|
||||
status: "skipped",
|
||||
project: "视频分析",
|
||||
type: "视频分析",
|
||||
datasetType: "video",
|
||||
progress: 0,
|
||||
},
|
||||
]
|
||||
|
||||
// Define the Template type
|
||||
type Template = {
|
||||
id: string;
|
||||
name: string;
|
||||
category: string;
|
||||
description: string;
|
||||
type: string;
|
||||
preview?: string;
|
||||
icon: React.ReactNode;
|
||||
};
|
||||
|
||||
// 扩展的预制模板数据
|
||||
export const mockTemplates: Template[] = [
|
||||
// 计算机视觉模板
|
||||
{
|
||||
id: "cv-1",
|
||||
name: "目标检测",
|
||||
category: "Computer Vision",
|
||||
description: "使用边界框标注图像中的目标对象",
|
||||
type: "image",
|
||||
preview: "/placeholder.svg?height=120&width=180&text=Object+Detection",
|
||||
icon: <Square className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "cv-2",
|
||||
name: "语义分割(多边形)",
|
||||
category: "Computer Vision",
|
||||
description: "使用多边形精确标注图像中的区域",
|
||||
type: "image",
|
||||
preview: "/placeholder.svg?height=120&width=180&text=Polygon+Segmentation",
|
||||
icon: <Layers className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "cv-3",
|
||||
name: "语义分割(掩码)",
|
||||
category: "Computer Vision",
|
||||
description: "使用像素级掩码标注图像区域",
|
||||
type: "image",
|
||||
preview: "/placeholder.svg?height=120&width=180&text=Mask+Segmentation",
|
||||
icon: <Circle className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "cv-4",
|
||||
name: "关键点标注",
|
||||
category: "Computer Vision",
|
||||
description: "标注图像中的关键点位置",
|
||||
type: "image",
|
||||
preview: "/placeholder.svg?height=120&width=180&text=Keypoint+Labeling",
|
||||
icon: <MousePointer className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "cv-5",
|
||||
name: "图像分类",
|
||||
category: "Computer Vision",
|
||||
description: "为整个图像分配类别标签",
|
||||
type: "image",
|
||||
preview: "/placeholder.svg?height=120&width=180&text=Image+Classification",
|
||||
icon: <ImageIcon className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "cv-6",
|
||||
name: "实例分割",
|
||||
category: "Computer Vision",
|
||||
description: "区分同类别的不同实例对象",
|
||||
type: "image",
|
||||
preview: "/placeholder.svg?height=120&width=180&text=Instance+Segmentation",
|
||||
icon: <Target className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "cv-7",
|
||||
name: "全景分割",
|
||||
category: "Computer Vision",
|
||||
description: "结合语义分割和实例分割的全景标注",
|
||||
type: "image",
|
||||
preview: "/placeholder.svg?height=120&width=180&text=Panoptic+Segmentation",
|
||||
icon: <Grid className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "cv-8",
|
||||
name: "3D目标检测",
|
||||
category: "Computer Vision",
|
||||
description: "在3D空间中标注目标对象的位置和方向",
|
||||
type: "image",
|
||||
preview: "/placeholder.svg?height=120&width=180&text=3D+Object+Detection",
|
||||
icon: <Maximize className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "cv-9",
|
||||
name: "图像配对",
|
||||
category: "Computer Vision",
|
||||
description: "标注图像之间的对应关系",
|
||||
type: "image",
|
||||
preview: "/placeholder.svg?height=120&width=180&text=Image+Matching",
|
||||
icon: <Move className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "cv-10",
|
||||
name: "图像质量评估",
|
||||
category: "Computer Vision",
|
||||
description: "评估和标注图像质量等级",
|
||||
type: "image",
|
||||
preview: "/placeholder.svg?height=120&width=180&text=Quality+Assessment",
|
||||
icon: <BarChart className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "cv-11",
|
||||
name: "图像裁剪标注",
|
||||
category: "Computer Vision",
|
||||
description: "标注图像中需要裁剪的区域",
|
||||
type: "image",
|
||||
preview: "/placeholder.svg?height=120&width=180&text=Image+Cropping",
|
||||
icon: <Crop className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "cv-12",
|
||||
name: "图像旋转标注",
|
||||
category: "Computer Vision",
|
||||
description: "标注图像的正确方向角度",
|
||||
type: "image",
|
||||
preview: "/placeholder.svg?height=120&width=180&text=Image+Rotation",
|
||||
icon: <RotateCcw className="w-4 h-4" />,
|
||||
},
|
||||
// 自然语言处理模板
|
||||
{
|
||||
id: "nlp-1",
|
||||
name: "文本分类",
|
||||
category: "Natural Language Processing",
|
||||
description: "为文本分配类别标签",
|
||||
type: "text",
|
||||
icon: <FileText className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "nlp-2",
|
||||
name: "命名实体识别",
|
||||
category: "Natural Language Processing",
|
||||
description: "识别和标注文本中的实体",
|
||||
type: "text",
|
||||
icon: <Tag className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "nlp-3",
|
||||
name: "情感分析",
|
||||
category: "Natural Language Processing",
|
||||
description: "标注文本的情感倾向",
|
||||
type: "text",
|
||||
icon: <Heart className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "nlp-4",
|
||||
name: "问答标注",
|
||||
category: "Natural Language Processing",
|
||||
description: "标注问题和答案对",
|
||||
type: "text",
|
||||
icon: <HelpCircle className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "nlp-5",
|
||||
name: "文本摘要",
|
||||
category: "Natural Language Processing",
|
||||
description: "为长文本创建摘要标注",
|
||||
type: "text",
|
||||
icon: <BookOpen className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "nlp-6",
|
||||
name: "对话标注",
|
||||
category: "Natural Language Processing",
|
||||
description: "标注对话中的意图和实体",
|
||||
type: "text",
|
||||
icon: <MessageSquare className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "nlp-7",
|
||||
name: "关系抽取",
|
||||
category: "Natural Language Processing",
|
||||
description: "标注实体之间的关系",
|
||||
type: "text",
|
||||
icon: <Users className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "nlp-8",
|
||||
name: "文本相似度",
|
||||
category: "Natural Language Processing",
|
||||
description: "标注文本之间的相似度",
|
||||
type: "text",
|
||||
icon: <Zap className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "nlp-9",
|
||||
name: "语言检测",
|
||||
category: "Natural Language Processing",
|
||||
description: "识别和标注文本的语言类型",
|
||||
type: "text",
|
||||
icon: <Globe className="w-4 h-4" />,
|
||||
},
|
||||
{
|
||||
id: "nlp-10",
|
||||
name: "文本纠错",
|
||||
category: "Natural Language Processing",
|
||||
description: "标注文本中的错误并提供修正",
|
||||
type: "text",
|
||||
icon: <Scissors className="w-4 h-4" />,
|
||||
},
|
||||
]
|
||||
56
frontend/src/mock/cleansing.tsx
Normal file
56
frontend/src/mock/cleansing.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import {
|
||||
DatabaseOutlined,
|
||||
BarChartOutlined,
|
||||
FileTextOutlined,
|
||||
ThunderboltOutlined,
|
||||
PictureOutlined,
|
||||
CalculatorOutlined,
|
||||
SwapOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { FileImage, FileText, Music, Repeat, Video } from "lucide-react";
|
||||
|
||||
// 模板类型选项
|
||||
export const templateTypes = [
|
||||
{
|
||||
value: "text",
|
||||
label: "文本",
|
||||
icon: FileText,
|
||||
description: "处理文本数据的清洗模板",
|
||||
},
|
||||
{
|
||||
value: "image",
|
||||
label: "图片",
|
||||
icon: FileImage,
|
||||
description: "处理图像数据的清洗模板",
|
||||
},
|
||||
{
|
||||
value: "video",
|
||||
label: "视频",
|
||||
icon: Video,
|
||||
description: "处理视频数据的清洗模板",
|
||||
},
|
||||
{
|
||||
value: "audio",
|
||||
label: "音频",
|
||||
icon: Music,
|
||||
description: "处理音频数据的清洗模板",
|
||||
},
|
||||
{
|
||||
value: "image-to-text",
|
||||
label: "图片转文本",
|
||||
icon: Repeat,
|
||||
description: "图像识别转文本的处理模板",
|
||||
},
|
||||
];
|
||||
|
||||
// 算子分类
|
||||
export const OPERATOR_CATEGORIES = {
|
||||
data: { name: "数据清洗", icon: <DatabaseOutlined />, color: "#1677ff" },
|
||||
ml: { name: "机器学习", icon: <ThunderboltOutlined />, color: "#722ed1" },
|
||||
vision: { name: "计算机视觉", icon: <PictureOutlined />, color: "#52c41a" },
|
||||
nlp: { name: "自然语言处理", icon: <FileTextOutlined />, color: "#faad14" },
|
||||
analysis: { name: "数据分析", icon: <BarChartOutlined />, color: "#f5222d" },
|
||||
transform: { name: "数据转换", icon: <SwapOutlined />, color: "#13c2c2" },
|
||||
io: { name: "输入输出", icon: <FileTextOutlined />, color: "#595959" },
|
||||
math: { name: "数学计算", icon: <CalculatorOutlined />, color: "#fadb14" },
|
||||
};
|
||||
290
frontend/src/mock/evaluation.tsx
Normal file
290
frontend/src/mock/evaluation.tsx
Normal file
@@ -0,0 +1,290 @@
|
||||
// 预设评估维度配置
|
||||
export const presetEvaluationDimensions: EvaluationDimension[] = [
|
||||
{
|
||||
id: "answer_relevance",
|
||||
name: "回答相关性",
|
||||
description: "评估回答内容是否针对问题,是否切中要点",
|
||||
category: "accuracy",
|
||||
isEnabled: true,
|
||||
},
|
||||
{
|
||||
id: "content_quality",
|
||||
name: "内容质量",
|
||||
description: "评估内容的准确性、完整性和可读性",
|
||||
category: "quality",
|
||||
isEnabled: true,
|
||||
},
|
||||
{
|
||||
id: "information_completeness",
|
||||
name: "信息完整性",
|
||||
description: "评估信息是否完整,无缺失关键内容",
|
||||
category: "completeness",
|
||||
isEnabled: true,
|
||||
},
|
||||
{
|
||||
id: "language_fluency",
|
||||
name: "语言流畅性",
|
||||
description: "评估语言表达是否流畅自然",
|
||||
category: "quality",
|
||||
isEnabled: true,
|
||||
},
|
||||
{
|
||||
id: "factual_accuracy",
|
||||
name: "事实准确性",
|
||||
description: "评估内容中事实信息的准确性",
|
||||
category: "accuracy",
|
||||
isEnabled: true,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
export const sliceOperators: SliceOperator[] = [
|
||||
{
|
||||
id: "paragraph-split",
|
||||
name: "段落分割",
|
||||
description: "按段落自然分割文档",
|
||||
type: "text",
|
||||
icon: "📄",
|
||||
params: { minLength: 50, maxLength: 1000 },
|
||||
},
|
||||
{
|
||||
id: "sentence-split",
|
||||
name: "句子分割",
|
||||
description: "按句子边界分割文档",
|
||||
type: "text",
|
||||
icon: "📝",
|
||||
params: { maxSentences: 5, overlap: 1 },
|
||||
},
|
||||
{
|
||||
id: "semantic-split",
|
||||
name: "语义分割",
|
||||
description: "基于语义相似度智能分割",
|
||||
type: "semantic",
|
||||
icon: "🧠",
|
||||
params: { threshold: 0.7, windowSize: 3 },
|
||||
},
|
||||
{
|
||||
id: "length-split",
|
||||
name: "长度分割",
|
||||
description: "按固定字符长度分割",
|
||||
type: "text",
|
||||
icon: "📏",
|
||||
params: { chunkSize: 512, overlap: 50 },
|
||||
},
|
||||
{
|
||||
id: "structure-split",
|
||||
name: "结构化分割",
|
||||
description: "按文档结构(标题、章节)分割",
|
||||
type: "structure",
|
||||
icon: "🏗️",
|
||||
params: { preserveHeaders: true, minSectionLength: 100 },
|
||||
},
|
||||
{
|
||||
id: "table-extract",
|
||||
name: "表格提取",
|
||||
description: "提取并单独处理表格内容",
|
||||
type: "structure",
|
||||
icon: "📊",
|
||||
params: { includeHeaders: true, mergeRows: false },
|
||||
},
|
||||
{
|
||||
id: "code-extract",
|
||||
name: "代码提取",
|
||||
description: "识别并提取代码块",
|
||||
type: "custom",
|
||||
icon: "💻",
|
||||
params: { languages: ["python", "javascript", "sql"], preserveIndentation: true },
|
||||
},
|
||||
{
|
||||
id: "qa-extract",
|
||||
name: "问答提取",
|
||||
description: "自动识别问答格式内容",
|
||||
type: "semantic",
|
||||
icon: "❓",
|
||||
params: { confidenceThreshold: 0.8, generateAnswers: true },
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
export const mockTasks: EvaluationTask[] = [
|
||||
{
|
||||
id: "1",
|
||||
name: "客服对话数据质量评估",
|
||||
datasetId: "1",
|
||||
datasetName: "客服对话数据集",
|
||||
evaluationType: "model",
|
||||
status: "completed",
|
||||
score: 85,
|
||||
progress: 100,
|
||||
createdAt: "2024-01-15 14:30",
|
||||
completedAt: "2024-01-15 14:45",
|
||||
description: "评估客服对话数据的质量,包括对话完整性、回复准确性等维度",
|
||||
dimensions: ["answer_relevance", "content_quality", "information_completeness"],
|
||||
customDimensions: [],
|
||||
sliceConfig: {
|
||||
threshold: 0.8,
|
||||
sampleCount: 100,
|
||||
method: "语义分割",
|
||||
},
|
||||
modelConfig: {
|
||||
url: "https://api.openai.com/v1/chat/completions",
|
||||
apiKey: "sk-***",
|
||||
prompt: "请从数据质量、标签准确性、标注一致性三个维度评估这个客服对话数据集...",
|
||||
temperature: 0.3,
|
||||
maxTokens: 2000,
|
||||
},
|
||||
metrics: {
|
||||
accuracy: 88,
|
||||
completeness: 92,
|
||||
consistency: 78,
|
||||
relevance: 85,
|
||||
},
|
||||
issues: [
|
||||
{ type: "重复数据", count: 23, severity: "medium" },
|
||||
{ type: "格式错误", count: 5, severity: "high" },
|
||||
{ type: "内容不完整", count: 12, severity: "low" },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "产品评论人工评估",
|
||||
datasetId: "2",
|
||||
datasetName: "产品评论数据集",
|
||||
evaluationType: "manual",
|
||||
status: "pending",
|
||||
progress: 0,
|
||||
createdAt: "2024-01-15 15:20",
|
||||
description: "人工评估产品评论数据的情感标注准确性",
|
||||
dimensions: ["content_quality", "factual_accuracy"],
|
||||
customDimensions: [
|
||||
{
|
||||
id: "custom_1",
|
||||
name: "情感极性准确性",
|
||||
description: "评估情感标注的极性(正面/负面/中性)准确性",
|
||||
category: "custom",
|
||||
isCustom: true,
|
||||
isEnabled: true,
|
||||
},
|
||||
],
|
||||
sliceConfig: {
|
||||
threshold: 0.7,
|
||||
sampleCount: 50,
|
||||
method: "段落分割",
|
||||
},
|
||||
metrics: {
|
||||
accuracy: 0,
|
||||
completeness: 0,
|
||||
consistency: 0,
|
||||
relevance: 0,
|
||||
},
|
||||
issues: [],
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "新闻分类数据评估",
|
||||
datasetId: "4",
|
||||
datasetName: "新闻分类数据集",
|
||||
evaluationType: "manual",
|
||||
status: "running",
|
||||
progress: 65,
|
||||
createdAt: "2024-01-15 16:10",
|
||||
description: "人工评估新闻分类数据集的标注质量",
|
||||
dimensions: ["content_quality", "information_completeness", "factual_accuracy"],
|
||||
customDimensions: [],
|
||||
sliceConfig: {
|
||||
threshold: 0.9,
|
||||
sampleCount: 80,
|
||||
method: "句子分割",
|
||||
},
|
||||
metrics: {
|
||||
accuracy: 82,
|
||||
completeness: 78,
|
||||
consistency: 85,
|
||||
relevance: 80,
|
||||
},
|
||||
issues: [{ type: "标注不一致", count: 15, severity: "medium" }],
|
||||
},
|
||||
]
|
||||
|
||||
// 模拟QA对数据
|
||||
export const mockQAPairs: QAPair[] = [
|
||||
{
|
||||
id: "qa_1",
|
||||
question: "这个产品的退货政策是什么?",
|
||||
answer: "我们提供7天无理由退货服务,商品需要保持原包装完整。",
|
||||
sliceId: "slice_1",
|
||||
score: 4.5,
|
||||
feedback: "回答准确且完整",
|
||||
},
|
||||
{
|
||||
id: "qa_2",
|
||||
question: "如何联系客服?",
|
||||
answer: "您可以通过在线客服、电话400-123-4567或邮箱service@company.com联系我们。",
|
||||
sliceId: "slice_2",
|
||||
score: 5.0,
|
||||
feedback: "提供了多种联系方式,非常全面",
|
||||
},
|
||||
{
|
||||
id: "qa_3",
|
||||
question: "配送时间需要多久?",
|
||||
answer: "一般情况下,我们会在1-3个工作日内发货,配送时间根据地区不同为2-7天。",
|
||||
sliceId: "slice_3",
|
||||
score: 4.0,
|
||||
feedback: "时间范围说明清楚",
|
||||
},
|
||||
]
|
||||
// 评估维度模板配置
|
||||
export const evaluationTemplates = {
|
||||
dialogue_text: {
|
||||
name: "对话文本评估",
|
||||
dimensions: [
|
||||
{
|
||||
id: "answer_relevance",
|
||||
name: "回答是否有针对性",
|
||||
description: "评估回答内容是否针对问题,是否切中要点",
|
||||
category: "accuracy" as const,
|
||||
isEnabled: true,
|
||||
},
|
||||
{
|
||||
id: "question_correctness",
|
||||
name: "问题是否正确",
|
||||
description: "评估问题表述是否清晰、准确、合理",
|
||||
category: "quality" as const,
|
||||
isEnabled: true,
|
||||
},
|
||||
{
|
||||
id: "answer_independence",
|
||||
name: "回答是否独立",
|
||||
description: "评估回答是否独立完整,不依赖外部信息",
|
||||
category: "completeness" as const,
|
||||
isEnabled: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
data_quality: {
|
||||
name: "数据质量评估",
|
||||
dimensions: [
|
||||
{
|
||||
id: "data_quality",
|
||||
name: "数据质量",
|
||||
description: "评估数据的整体质量,包括格式规范性、完整性等",
|
||||
category: "quality" as const,
|
||||
isEnabled: true,
|
||||
},
|
||||
{
|
||||
id: "label_accuracy",
|
||||
name: "标签准确性",
|
||||
description: "评估数据标签的准确性和一致性",
|
||||
category: "accuracy" as const,
|
||||
isEnabled: true,
|
||||
},
|
||||
{
|
||||
id: "data_completeness",
|
||||
name: "数据完整性",
|
||||
description: "评估数据集的完整性,是否存在缺失数据",
|
||||
category: "completeness" as const,
|
||||
isEnabled: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
254
frontend/src/mock/knowledgeBase.tsx
Normal file
254
frontend/src/mock/knowledgeBase.tsx
Normal file
@@ -0,0 +1,254 @@
|
||||
export const mockChunks = Array.from({ length: 23 }, (_, i) => ({
|
||||
id: i + 1,
|
||||
content: `这是第 ${
|
||||
i + 1
|
||||
} 个文档分块的内容示例。在实际应用中,这里会显示从原始文档中提取和分割的具体文本内容。用户可以在这里查看和编辑分块的内容,确保知识库的质量和准确性。这个分块包含了重要的业务信息和技术细节,需要仔细维护以确保检索的准确性。`,
|
||||
position: i + 1,
|
||||
tokens: Math.floor(Math.random() * 200) + 100,
|
||||
embedding: Array.from({ length: 1536 }, () => Math.random() - 0.5),
|
||||
similarity: (Math.random() * 0.3 + 0.7).toFixed(3),
|
||||
createdAt: "2024-01-22 10:35",
|
||||
updatedAt: "2024-01-22 10:35",
|
||||
vectorId: `vec_${i + 1}_${Math.random().toString(36).substr(2, 9)}`,
|
||||
sliceOperator: ["semantic-split", "paragraph-split", "table-extract"][
|
||||
Math.floor(Math.random() * 3)
|
||||
],
|
||||
parentChunkId: i > 0 ? Math.floor(Math.random() * i) + 1 : undefined,
|
||||
metadata: {
|
||||
source: "API文档.pdf",
|
||||
page: Math.floor(i / 5) + 1,
|
||||
section: `第${Math.floor(i / 3) + 1}章`,
|
||||
},
|
||||
}));
|
||||
|
||||
export const mockQAPairs = [
|
||||
{
|
||||
id: 1,
|
||||
question: "什么是API文档的主要用途?",
|
||||
answer:
|
||||
"API文档的主要用途是为开发者提供详细的接口说明,包括请求参数、响应格式和使用示例.",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
question: "如何正确使用这个API?",
|
||||
answer:
|
||||
"使用API时需要先获取访问令牌,然后按照文档中的格式发送请求,注意处理错误响应.",
|
||||
},
|
||||
];
|
||||
|
||||
export const sliceOperators: SliceOperator[] = [
|
||||
{
|
||||
id: "paragraph-split",
|
||||
name: "段落分割",
|
||||
description: "按段落自然分割文档",
|
||||
type: "text",
|
||||
icon: "📄",
|
||||
params: { minLength: 50, maxLength: 1000 },
|
||||
},
|
||||
{
|
||||
id: "sentence-split",
|
||||
name: "句子分割",
|
||||
description: "按句子边界分割文档",
|
||||
type: "text",
|
||||
icon: "📝",
|
||||
params: { maxSentences: 5, overlap: 1 },
|
||||
},
|
||||
{
|
||||
id: "semantic-split",
|
||||
name: "语义分割",
|
||||
description: "基于语义相似度智能分割",
|
||||
type: "semantic",
|
||||
icon: "🧠",
|
||||
params: { threshold: 0.7, windowSize: 3 },
|
||||
},
|
||||
{
|
||||
id: "length-split",
|
||||
name: "长度分割",
|
||||
description: "按固定字符长度分割",
|
||||
type: "text",
|
||||
icon: "📏",
|
||||
params: { chunkSize: 512, overlap: 50 },
|
||||
},
|
||||
{
|
||||
id: "structure-split",
|
||||
name: "结构化分割",
|
||||
description: "按文档结构(标题、章节)分割",
|
||||
type: "structure",
|
||||
icon: "🏗️",
|
||||
params: { preserveHeaders: true, minSectionLength: 100 },
|
||||
},
|
||||
{
|
||||
id: "table-extract",
|
||||
name: "表格提取",
|
||||
description: "提取并单独处理表格内容",
|
||||
type: "structure",
|
||||
icon: "📊",
|
||||
params: { includeHeaders: true, mergeRows: false },
|
||||
},
|
||||
{
|
||||
id: "code-extract",
|
||||
name: "代码提取",
|
||||
description: "识别并提取代码块",
|
||||
type: "custom",
|
||||
icon: "💻",
|
||||
params: {
|
||||
languages: ["python", "javascript", "sql"],
|
||||
preserveIndentation: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "qa-extract",
|
||||
name: "问答提取",
|
||||
description: "自动识别问答格式内容",
|
||||
type: "semantic",
|
||||
icon: "❓",
|
||||
params: { confidenceThreshold: 0.8, generateAnswers: true },
|
||||
},
|
||||
];
|
||||
|
||||
export const vectorDatabases = [
|
||||
{
|
||||
id: "pinecone",
|
||||
name: "Pinecone",
|
||||
description: "云端向量数据库,高性能检索",
|
||||
},
|
||||
{
|
||||
id: "weaviate",
|
||||
name: "Weaviate",
|
||||
description: "开源向量数据库,支持多模态",
|
||||
},
|
||||
{ id: "qdrant", name: "Qdrant", description: "高性能向量搜索引擎" },
|
||||
{ id: "chroma", name: "ChromaDB", description: "轻量级向量数据库" },
|
||||
{ id: "milvus", name: "Milvus", description: "分布式向量数据库" },
|
||||
{ id: "faiss", name: "FAISS", description: "Facebook AI 相似性搜索库" },
|
||||
];
|
||||
|
||||
export const mockKnowledgeBases: KnowledgeBase[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: "产品技术文档库",
|
||||
description:
|
||||
"包含所有产品相关的技术文档和API说明,支持多种格式文档的智能解析和向量化处理",
|
||||
type: "unstructured",
|
||||
status: "ready",
|
||||
fileCount: 45,
|
||||
chunkCount: 1250,
|
||||
vectorCount: 1250,
|
||||
size: "2.3 GB",
|
||||
progress: 100,
|
||||
createdAt: "2024-01-15",
|
||||
lastUpdated: "2024-01-22",
|
||||
vectorDatabase: "pinecone",
|
||||
config: {
|
||||
embeddingModel: "text-embedding-3-large",
|
||||
llmModel: "gpt-4o",
|
||||
chunkSize: 512,
|
||||
overlap: 50,
|
||||
sliceMethod: "semantic",
|
||||
enableQA: true,
|
||||
vectorDimension: 1536,
|
||||
sliceOperators: ["semantic-split", "paragraph-split", "table-extract"],
|
||||
},
|
||||
files: [
|
||||
{
|
||||
id: 1,
|
||||
name: "API文档.pdf",
|
||||
type: "pdf",
|
||||
size: "2.5 MB",
|
||||
status: "completed",
|
||||
chunkCount: 156,
|
||||
progress: 100,
|
||||
uploadedAt: "2024-01-15",
|
||||
source: "upload",
|
||||
vectorizationStatus: "completed",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "用户手册.docx",
|
||||
type: "docx",
|
||||
size: "1.8 MB",
|
||||
status: "disabled",
|
||||
chunkCount: 89,
|
||||
progress: 65,
|
||||
uploadedAt: "2024-01-22",
|
||||
source: "dataset",
|
||||
datasetId: "dataset-1",
|
||||
vectorizationStatus: "failed",
|
||||
},
|
||||
],
|
||||
vectorizationHistory: [
|
||||
{
|
||||
id: 1,
|
||||
timestamp: "2024-01-22 14:30:00",
|
||||
operation: "create",
|
||||
fileId: 1,
|
||||
fileName: "API文档.pdf",
|
||||
chunksProcessed: 156,
|
||||
vectorsGenerated: 156,
|
||||
status: "success",
|
||||
duration: "2m 15s",
|
||||
config: {
|
||||
embeddingModel: "text-embedding-3-large",
|
||||
chunkSize: 512,
|
||||
sliceMethod: "semantic",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
timestamp: "2024-01-22 15:45:00",
|
||||
operation: "update",
|
||||
fileId: 2,
|
||||
fileName: "用户手册.docx",
|
||||
chunksProcessed: 89,
|
||||
vectorsGenerated: 0,
|
||||
status: "failed",
|
||||
duration: "0m 45s",
|
||||
config: {
|
||||
embeddingModel: "text-embedding-3-large",
|
||||
chunkSize: 512,
|
||||
sliceMethod: "semantic",
|
||||
},
|
||||
error: "向量化服务连接超时",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "FAQ结构化知识库",
|
||||
description: "客服常见问题的结构化问答对,支持快速检索和智能匹配",
|
||||
type: "structured",
|
||||
status: "vectorizing",
|
||||
fileCount: 12,
|
||||
chunkCount: 890,
|
||||
vectorCount: 750,
|
||||
size: "156 MB",
|
||||
progress: 75,
|
||||
createdAt: "2024-01-20",
|
||||
lastUpdated: "2024-01-23",
|
||||
vectorDatabase: "weaviate",
|
||||
config: {
|
||||
embeddingModel: "text-embedding-ada-002",
|
||||
chunkSize: 256,
|
||||
overlap: 0,
|
||||
sliceMethod: "paragraph",
|
||||
enableQA: false,
|
||||
vectorDimension: 1536,
|
||||
sliceOperators: ["qa-extract", "paragraph-split"],
|
||||
},
|
||||
files: [
|
||||
{
|
||||
id: 3,
|
||||
name: "FAQ模板.xlsx",
|
||||
type: "xlsx",
|
||||
size: "450 KB",
|
||||
status: "vectorizing",
|
||||
chunkCount: 234,
|
||||
progress: 75,
|
||||
uploadedAt: "2024-01-20",
|
||||
source: "upload",
|
||||
vectorizationStatus: "processing",
|
||||
},
|
||||
],
|
||||
vectorizationHistory: [],
|
||||
},
|
||||
];
|
||||
149
frontend/src/mock/mock-apis.cjs
Normal file
149
frontend/src/mock/mock-apis.cjs
Normal file
@@ -0,0 +1,149 @@
|
||||
const { addMockPrefix } = require("./mock-core/util.cjs");
|
||||
|
||||
const MockAPI = {
|
||||
// 数据归集接口
|
||||
queryTasksUsingPost: "/data-collection/tasks", // 获取数据源任务列表
|
||||
createTaskUsingPost: "/data-collection/tasks/create", // 创建数据源任务
|
||||
queryTaskByIdUsingGet: "/data-collection/tasks/:id", // 根据ID获取数据源任务详情
|
||||
updateTaskByIdUsingPut: "/data-collection/tasks/:id", // 更新数据源任务
|
||||
deleteTaskByIdUsingDelete: "/data-collection/tasks/:id", // 删除数据源任务
|
||||
executeTaskByIdUsingPost: "/data-collection/tasks/:id/execute", // 执行数据源任务
|
||||
stopTaskByIdUsingPost: "/data-collection/tasks/:id/stop", // 停止数据源任务
|
||||
queryExecutionLogUsingPost: "/data-collection/executions", // 获取任务执行日志
|
||||
queryExecutionLogByIdUsingGet: "/data-collection/executions/:id", // 获取任务执行日志详情
|
||||
queryCollectionStatisticsUsingGet: "/data-collection/monitor/statistics", // 获取数据归集统计信息
|
||||
|
||||
// 数据管理接口
|
||||
queryDatasetsUsingGet: "/data-management/datasets", // 获取数据集列表
|
||||
createDatasetUsingPost: "/data-management/datasets", // 创建数据集
|
||||
queryDatasetByIdUsingGet: "/data-management/datasets/:id", // 根据ID获取数据集详情
|
||||
updateDatasetByIdUsingPut: "/data-management/datasets/:id", // 更新数据集
|
||||
deleteDatasetByIdUsingDelete: "/data-management/datasets/:id", // 删除数据集
|
||||
queryFilesUsingGet: "/data-management/datasets/:id/files", // 获取数据集文件列表
|
||||
uploadFileUsingPost: "/data-management/datasets/:id/files", // 添加数据集文件
|
||||
queryFileByIdUsingGet: "/data-management/datasets/:id/files/:fileId", // 获取数据集文件详情
|
||||
deleteFileByIdUsingDelete: "/data-management/datasets/:id/files/:fileId", // 删除数据集文件
|
||||
downloadFileByIdUsingGet:
|
||||
"/data-management/datasets/:id/files/:fileId/download", // 下载文件
|
||||
queryDatasetTypesUsingGet: "/data-management/dataset-types", // 获取数据集类型列表
|
||||
queryTagsUsingGet: "/data-management/tags", // 获取数据集标签列表
|
||||
createTagUsingPost: "/data-management/tags", // 创建数据集标签
|
||||
updateTagUsingPost: "/data-management/tags", // 更新数据集标签
|
||||
deleteTagUsingPost: "/data-management/tags", // 删除数据集标签
|
||||
queryDatasetStatisticsUsingGet: "/data-management/datasets/statistics", // 获取数据集统计信息
|
||||
preUploadFileUsingPost: "/data-management/datasets/:id/upload/pre-upload", // 预上传文件
|
||||
cancelUploadUsingPut: "/data-management/datasets/upload/cancel-upload/:id", // 取消上传
|
||||
uploadFileChunkUsingPost: "/data-management/datasets/:id/upload/chunk", // 上传切片
|
||||
|
||||
// 数据清洗接口
|
||||
queryCleaningTasksUsingGet: "/cleaning/tasks", // 获取清洗任务列表
|
||||
createCleaningTaskUsingPost: "/cleaning/tasks", // 创建清洗任务
|
||||
queryCleaningTaskByIdUsingGet: "/cleaning/tasks/:taskId", // 根据ID获取清洗任务详情
|
||||
deleteCleaningTaskByIdUsingDelete: "/cleaning/tasks/:taskId", // 删除清洗任务
|
||||
executeCleaningTaskUsingPost: "/cleaning/tasks/:taskId/execute", // 执行清洗任务
|
||||
stopCleaningTaskUsingPost: "/cleaning/tasks/:taskId/stop", // 停止清洗任务
|
||||
queryCleaningTemplatesUsingGet: "/cleaning/templates", // 获取清洗模板列表
|
||||
createCleaningTemplateUsingPost: "/cleaning/templates", // 创建清洗模板
|
||||
queryCleaningTemplateByIdUsingGet: "/cleaning/templates/:templateId", // 根据ID获取清洗模板详情
|
||||
updateCleaningTemplateByIdUsingPut: "/cleaning/templates/:templateId", // 根据ID更新清洗模板详情
|
||||
deleteCleaningTemplateByIdUsingDelete: "/cleaning/templates/:templateId", // 删除清洗模板
|
||||
|
||||
// 数据标注接口
|
||||
queryAnnotationTasksUsingGet: "/project/mappings/list", // 获取标注任务列表
|
||||
createAnnotationTaskUsingPost: "/project/create", // 创建标注任务
|
||||
syncAnnotationTaskByIdUsingPost: "/project/sync", // 同步标注任务
|
||||
deleteAnnotationTaskByIdUsingDelete: "/project/mappings", // 删除标注任务
|
||||
queryAnnotationTaskByIdUsingGet: "/annotation/tasks/:taskId", // 根据ID获取标注任务详情
|
||||
executeAnnotationTaskByIdUsingPost: "/annotation/tasks/:taskId/execute", // 执行标注任务
|
||||
stopAnnotationTaskByIdUsingPost: "/annotation/tasks/:taskId/stop", // 停止标注任务
|
||||
queryAnnotationDataUsingGet: "/annotation/data", // 获取标注数据列表
|
||||
submitAnnotationUsingPost: "/annotation/submit/:id", // 提交标注
|
||||
updateAnnotationUsingPut: "/annotation/update/:id", // 根据ID更新标注
|
||||
deleteAnnotationUsingDelete: "/annotation/delete/:id", // 根据ID删除标注
|
||||
startAnnotationTaskUsingPost: "/annotation/start/:taskId", // 开始标注任务
|
||||
pauseAnnotationTaskUsingPost: "/annotation/pause/:taskId", // 暂停标注任务
|
||||
resumeAnnotationTaskUsingPost: "/annotation/resume/:taskId", // 恢复标注任务
|
||||
completeAnnotationTaskUsingPost: "/annotation/complete/:taskId", // 完成标注任务
|
||||
getAnnotationTaskStatisticsUsingGet: "/annotation/statistics/:taskId", // 获取标注任务统计信息
|
||||
getAnnotationStatisticsUsingGet: "/annotation/statistics", // 获取标注统计信息
|
||||
queryAnnotationTemplatesUsingGet: "/annotation/templates", // 获取标注模板列表
|
||||
createAnnotationTemplateUsingPost: "/annotation/templates", // 创建标注模板
|
||||
queryAnnotationTemplateByIdUsingGet: "/annotation/templates/:templateId", // 根据ID获取标注模板详情
|
||||
queryAnnotatorsUsingGet: "/annotation/annotators", // 获取标注者列表
|
||||
assignAnnotatorUsingPost: "/annotation/annotators/:annotatorId", // 分配标注者
|
||||
|
||||
// 数据合成接口
|
||||
querySynthesisJobsUsingGet: "/synthesis/jobs", // 获取合成任务列表
|
||||
createSynthesisJobUsingPost: "/synthesis/jobs/create", // 创建合成任务
|
||||
querySynthesisJobByIdUsingGet: "/synthesis/jobs/:jobId", // 根据ID获取合成任务详情
|
||||
updateSynthesisJobByIdUsingPut: "/synthesis/jobs/:jobId", // 更新合成任务
|
||||
deleteSynthesisJobByIdUsingDelete: "/synthesis/jobs/:jobId", // 删除合成任务
|
||||
executeSynthesisJobUsingPost: "/synthesis/jobs/execute/:jobId", // 执行合成任务
|
||||
stopSynthesisJobByIdUsingPost: "/synthesis/jobs/stop/:jobId", // 停止合成任务
|
||||
querySynthesisTemplatesUsingGet: "/synthesis/templates", // 获取合成模板列表
|
||||
createSynthesisTemplateUsingPost: "/synthesis/templates/create", // 创建合成模板
|
||||
querySynthesisTemplateByIdUsingGet: "/synthesis/templates/:templateId", // 根据ID获取合成模板详情
|
||||
updateSynthesisTemplateByIdUsingPut: "/synthesis/templates/:templateId", // 更新合成模板
|
||||
deleteSynthesisTemplateByIdUsingDelete: "/synthesis/templates/:templateId", // 删除合成模板
|
||||
queryInstructionTemplatesUsingPost: "/synthesis/templates", // 获取指令模板列表
|
||||
createInstructionTemplateUsingPost: "/synthesis/templates/create", // 创建指令模板
|
||||
queryInstructionTemplateByIdUsingGet: "/synthesis/templates/:templateId", // 根据ID获取指令模板详情
|
||||
deleteInstructionTemplateByIdUsingDelete: "/synthesis/templates/:templateId", // 删除指令模板
|
||||
instructionTuningUsingPost: "/synthesis/instruction-tuning", // 指令微调
|
||||
cotDistillationUsingPost: "/synthesis/cot-distillation", // Cot蒸馏
|
||||
queryOperatorsUsingPost: "/synthesis/operators", // 获取操作列表
|
||||
|
||||
// 数据评测接口
|
||||
queryEvaluationTasksUsingPost: "/evaluation/tasks", // 获取评测任务列表
|
||||
createEvaluationTaskUsingPost: "/evaluation/tasks/create", // 创建评测任务
|
||||
queryEvaluationTaskByIdUsingGet: "/evaluation/tasks/:taskId", // 根据ID获取评测任务详情
|
||||
updateEvaluationTaskByIdUsingPut: "/evaluation/tasks/:taskId", // 更新评测任务
|
||||
deleteEvaluationTaskByIdUsingDelete: "/evaluation/tasks/:taskId", // 删除评测任务
|
||||
executeEvaluationTaskByIdUsingPost: "/evaluation/tasks/:taskId/execute", // 执行评测任务
|
||||
stopEvaluationTaskByIdUsingPost: "/evaluation/tasks/:taskId/stop", // 停止评测任务
|
||||
queryEvaluationReportsUsingPost: "/evaluation/reports", // 获取评测报告列表
|
||||
queryEvaluationReportByIdUsingGet: "/evaluation/reports/:reportId", // 根据ID获取评测报告详情
|
||||
manualEvaluateUsingPost: "/evaluation/manual-evaluate", // 人工评测
|
||||
queryEvaluationStatisticsUsingGet: "/evaluation/statistics", // 获取评测统计信息
|
||||
evaluateDataQualityUsingPost: "/evaluation/data-quality", // 数据质量评测
|
||||
getQualityEvaluationByIdUsingGet: "/evaluation/data-quality/:id", // 根据ID获取数据质量评测详情
|
||||
evaluateCompatibilityUsingPost: "/evaluation/compatibility", // 兼容性评测
|
||||
evaluateValueUsingPost: "/evaluation/value", // 价值评测
|
||||
queryEvaluationReportsUsingGet: "/evaluation/reports", // 获取评测报告列表(简化版)
|
||||
getEvaluationReportByIdUsingGet: "/evaluation/reports/:reportId", // 根据ID获取评测报告详情(简化版)
|
||||
exportEvaluationReportUsingGet: "/evaluation/reports/:reportId/export", // 导出评测报告
|
||||
batchEvaluationUsingPost: "/evaluation/batch-evaluate", // 批量评测
|
||||
|
||||
// 知识生成接口
|
||||
queryKnowledgeBasesUsingPost: "/knowledge/bases", // 获取知识库列表
|
||||
createKnowledgeBaseUsingPost: "/knowledge/bases/create", // 创建知识库
|
||||
queryKnowledgeBaseByIdUsingGet: "/knowledge/bases/:baseId", // 根据ID获取知识库详情
|
||||
updateKnowledgeBaseByIdUsingPut: "/knowledge/bases/:baseId", // 更新知识库
|
||||
deleteKnowledgeBaseByIdUsingDelete: "/knowledge/bases/:baseId", // 删除知识库
|
||||
queryKnowledgeGenerationTasksUsingPost: "/knowledge/tasks", // 获取知识生成任务列表
|
||||
createKnowledgeGenerationTaskUsingPost: "/knowledge/tasks/create", // 创建知识生成任务
|
||||
queryKnowledgeGenerationTaskByIdUsingGet: "/knowledge/tasks/:taskId", // 根据ID获取知识生成任务详情
|
||||
updateKnowledgeGenerationTaskByIdUsingPut: "/knowledge/tasks/:taskId", // 更新知识生成任务
|
||||
deleteKnowledgeGenerationTaskByIdUsingDelete: "/knowledge/tasks/:taskId", // 删除知识生成任务
|
||||
executeKnowledgeGenerationTaskByIdUsingPost:
|
||||
"/knowledge/tasks/:taskId/execute", // 执行知识生成任务
|
||||
stopKnowledgeGenerationTaskByIdUsingPost: "/knowledge/tasks/:taskId/stop", // 停止知识生成任务
|
||||
queryKnowledgeStatisticsUsingGet: "/knowledge/statistics", // 获取知识生成
|
||||
|
||||
// 算子市场
|
||||
queryOperatorsUsingPost: "/operators/list", // 获取算子列表
|
||||
queryCategoryTreeUsingGet: "/categories/tree", // 获取算子分类树
|
||||
queryOperatorByIdUsingGet: "/operators/:operatorId", // 根据ID获取算子详情
|
||||
createOperatorUsingPost: "/operators/create", // 创建算子
|
||||
updateOperatorByIdUsingPut: "/operators/:operatorId", // 更新算子
|
||||
uploadOperatorUsingPost: "/operators/upload", // 上传算子
|
||||
createLabelUsingPost: "/operators/labels", // 创建算子标签
|
||||
queryLabelsUsingGet: "/labels", // 获取算子标签列表
|
||||
deleteLabelsUsingDelete: "/labels", // 删除算子标签
|
||||
updateLabelByIdUsingPut: "/labels/:labelId", // 更新算子标签
|
||||
deleteOperatorByIdUsingDelete: "/operators/:operatorId", // 删除算子
|
||||
publishOperatorUsingPost: "/operators/:operatorId/publish", // 发布算子
|
||||
unpublishOperatorUsingPost: "/operators/:operatorId/unpublish", // 下架算子
|
||||
};
|
||||
|
||||
module.exports = addMockPrefix("/api", MockAPI);
|
||||
25
frontend/src/mock/mock-core/module-loader.cjs
Normal file
25
frontend/src/mock/mock-core/module-loader.cjs
Normal file
@@ -0,0 +1,25 @@
|
||||
const fs = require('fs');
|
||||
|
||||
function loadAllMockModules(router, pathDir) {
|
||||
if (!fs.existsSync(pathDir)) {
|
||||
throw new Error(`Mock directory ${pathDir} does not exist.`);
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(pathDir);
|
||||
files.forEach(file => {
|
||||
const filePath = `${pathDir}/${file}`;
|
||||
if(fs.lstatSync(filePath).isDirectory()) {
|
||||
loadAllMockModules(router, filePath);
|
||||
} else {
|
||||
let fileNameModule = file.replace('/\.js\b$/', '');
|
||||
let module = require(`${pathDir}/${fileNameModule}`);
|
||||
if(typeof module === 'function' && module.length === 1) {
|
||||
module(router);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
loadAllMockModules,
|
||||
};
|
||||
63
frontend/src/mock/mock-core/session-helper.cjs
Normal file
63
frontend/src/mock/mock-core/session-helper.cjs
Normal file
@@ -0,0 +1,63 @@
|
||||
const path = require("path");
|
||||
const Mock = require("mockjs");
|
||||
const session = require("express-session");
|
||||
const FileStore = require("session-file-store")(session);
|
||||
|
||||
const { isFunction } = require("lodash");
|
||||
|
||||
const argv = require("minimist")(process.argv.slice(2));
|
||||
const isDev = (argv.env || "development") === "development";
|
||||
const TOKEN_KEY = isDev ? "X-Auth-Token" : "X-Csrf-Token";
|
||||
|
||||
const setSessionUser = (req, getLoginInfo) => {
|
||||
if (!isFunction(getLoginInfo)) {
|
||||
throw new Error("getLoginInfo must be a function");
|
||||
}
|
||||
|
||||
if (!req.session?.users) {
|
||||
req.session.users = {};
|
||||
}
|
||||
|
||||
let token = req.get(TOKEN_KEY);
|
||||
const { users } = req.session;
|
||||
if (!token || !users[token]) {
|
||||
token = Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, "");
|
||||
const userInfo = getLoginInfo(req) || {};
|
||||
users[token] = user;
|
||||
}
|
||||
return token;
|
||||
};
|
||||
|
||||
const getSessionUser = (req) => {
|
||||
const token = req.get(TOKEN_KEY);
|
||||
if (token && req.session?.users) {
|
||||
return req.session.users[token];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const genExpressSession = () => {
|
||||
return session({
|
||||
name: "demo.name",
|
||||
secret: "demo.secret",
|
||||
resave: true,
|
||||
saveUninitialized: true,
|
||||
cookie: {
|
||||
maxAge: 60 * 60 * 1e3,
|
||||
expires: new Date(Date.now() + 60 * 60 * 1e3),
|
||||
}, // 1 hour
|
||||
store: new FileStore({
|
||||
path: path.join(__dirname, "../sessions"),
|
||||
retries: 0,
|
||||
keyFunction: (secret, sessionId) => {
|
||||
return secret + sessionId;
|
||||
},
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
setSessionUser,
|
||||
getSessionUser,
|
||||
genExpressSession,
|
||||
};
|
||||
30
frontend/src/mock/mock-core/util.cjs
Normal file
30
frontend/src/mock/mock-core/util.cjs
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
function log(message, type = "log", provided = 'console') {
|
||||
const providedFn = globalThis[provided] || console;
|
||||
if (providedFn && typeof providedFn[type] === 'function') {
|
||||
const invokeMethod = providedFn[type ?? 'log'];
|
||||
invokeMethod.call(providedFn, message);
|
||||
}
|
||||
}
|
||||
|
||||
function addMockPrefix(urlPrefix, api) {
|
||||
const newMockApi = {};
|
||||
Object.keys(api).map(apiKey=>{
|
||||
newMockApi[apiKey] = urlPrefix + api[apiKey];
|
||||
});
|
||||
|
||||
return new Proxy(newMockApi, {
|
||||
get(target, prop) {
|
||||
if (prop in target) {
|
||||
return target[prop];
|
||||
} else {
|
||||
throw new Error(`API ${String(prop)} is not defined.`);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
log,
|
||||
addMockPrefix,
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
const errorHandle = (err, req, res, next) => {
|
||||
if(res.headersSent) {
|
||||
return next(err);
|
||||
}
|
||||
console.error('Server Error:', err.message);
|
||||
res.status(500).json({
|
||||
code: '500',
|
||||
msg: 'Internal Server Error',
|
||||
data: null,
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = errorHandle;
|
||||
11
frontend/src/mock/mock-middleware/index.cjs
Normal file
11
frontend/src/mock/mock-middleware/index.cjs
Normal file
@@ -0,0 +1,11 @@
|
||||
const setHeader = require('./set-header-middleware.cjs');
|
||||
const strongMatch = require('./strong-match-middleware.cjs');
|
||||
const sendJSON = require('./send-json-middleawre.cjs');
|
||||
const errorHandle = require('./error-handle-middleware.cjs');
|
||||
|
||||
module.exports = {
|
||||
setHeader,
|
||||
strongMatch,
|
||||
sendJSON,
|
||||
errorHandle,
|
||||
};
|
||||
18
frontend/src/mock/mock-middleware/send-json-middleawre.cjs
Normal file
18
frontend/src/mock/mock-middleware/send-json-middleawre.cjs
Normal file
@@ -0,0 +1,18 @@
|
||||
const sendJSON = (req, res, next) => {
|
||||
res.sendJSON = (
|
||||
data = null,
|
||||
{ code = '0', msg = 'success', statusCode = 200, timeout = 0 } = {}
|
||||
) => {
|
||||
const timer = setTimeout(() => {
|
||||
res.status(statusCode).json({
|
||||
code,
|
||||
msg,
|
||||
data,
|
||||
});
|
||||
clearTimeout(timer);
|
||||
}, timeout);
|
||||
};
|
||||
next();
|
||||
};
|
||||
|
||||
module.exports = sendJSON;
|
||||
14
frontend/src/mock/mock-middleware/set-header-middleware.cjs
Normal file
14
frontend/src/mock/mock-middleware/set-header-middleware.cjs
Normal file
@@ -0,0 +1,14 @@
|
||||
const setHeader = (req, res, next) => {
|
||||
res.set({
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE,OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
'Content-Security-Policy': "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src *; font-src 'self';",
|
||||
'X-Content-Type-Options': 'nosniff',
|
||||
'X-Frame-Options': 'SAMEORIGIN',
|
||||
'X-XSS-Protection': '1; mode=block',
|
||||
});
|
||||
next();
|
||||
};
|
||||
|
||||
module.exports = setHeader;
|
||||
@@ -0,0 +1,13 @@
|
||||
const API = require('../mock-apis.cjs');
|
||||
|
||||
const strongMatch = (req, res, next) => {
|
||||
res.strongMatch = () => {
|
||||
const { url } = req;
|
||||
const index = url.indexOf('?');
|
||||
const targetUrl = index !== -1 ? url.substring(0, index) : url;
|
||||
const isExistedUrl = Object.values(API).includes(targetUrl);
|
||||
return isExistedUrl;
|
||||
};
|
||||
next();
|
||||
};
|
||||
module.exports = strongMatch;
|
||||
618
frontend/src/mock/mock-seed/data-annotation.cjs
Normal file
618
frontend/src/mock/mock-seed/data-annotation.cjs
Normal file
@@ -0,0 +1,618 @@
|
||||
const Mock = require("mockjs");
|
||||
const API = require("../mock-apis.cjs");
|
||||
|
||||
// 标注任务数据
|
||||
function annotationTaskItem() {
|
||||
return {
|
||||
source_dataset_id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
mapping_id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
labelling_project_id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
labelling_project_name: Mock.Random.ctitle(5, 20),
|
||||
created_at: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
last_updated_at: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
deleted_at: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
// id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
// name: Mock.Random.ctitle(5, 20),
|
||||
// description: Mock.Random.csentence(5, 30),
|
||||
// type: Mock.Random.pick([
|
||||
// "TEXT_CLASSIFICATION",
|
||||
// "NAMED_ENTITY_RECOGNITION",
|
||||
// "OBJECT_DETECTION",
|
||||
// "SEMANTIC_SEGMENTATION",
|
||||
// ]),
|
||||
// status: Mock.Random.pick(["PENDING", "IN_PROGRESS", "COMPLETED", "PAUSED"]),
|
||||
// datasetId: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
// progress: Mock.Random.float(0, 100, 2, 2),
|
||||
// createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
// updatedAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
// createdBy: Mock.Random.cname(),
|
||||
// assignedTo: Mock.Random.cname(),
|
||||
// totalDataCount: Mock.Random.integer(100, 10000),
|
||||
// annotatedCount: Mock.Random.integer(10, 500),
|
||||
// configuration: {
|
||||
// labels: Mock.Random.shuffle([
|
||||
// "正面",
|
||||
// "负面",
|
||||
// "中性",
|
||||
// "人物",
|
||||
// "地点",
|
||||
// "组织",
|
||||
// "时间",
|
||||
// ]).slice(0, Mock.Random.integer(3, 5)),
|
||||
// guidelines: Mock.Random.csentence(10, 50),
|
||||
// qualityThreshold: Mock.Random.float(0.8, 1.0, 2, 2),
|
||||
// },
|
||||
// statistics: {
|
||||
// accuracy: Mock.Random.float(0.85, 0.99, 2, 2),
|
||||
// averageTime: Mock.Random.integer(30, 300), // seconds
|
||||
// reviewCount: Mock.Random.integer(0, 50),
|
||||
// },
|
||||
};
|
||||
}
|
||||
|
||||
const annotationTaskList = new Array(25).fill(null).map(annotationTaskItem);
|
||||
|
||||
// 标注数据项
|
||||
function annotationDataItem() {
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
taskId: Mock.Random.pick(annotationTaskList).id,
|
||||
content: Mock.Random.cparagraph(1, 3),
|
||||
originalData: {
|
||||
text: Mock.Random.cparagraph(1, 3),
|
||||
source: Mock.Random.url(),
|
||||
metadata: {
|
||||
author: Mock.Random.cname(),
|
||||
timestamp: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
},
|
||||
},
|
||||
annotations: [
|
||||
{
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
label: Mock.Random.pick(["正面", "负面", "中性"]),
|
||||
confidence: Mock.Random.float(0.7, 1.0, 2, 2),
|
||||
annotator: Mock.Random.cname(),
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
isPreAnnotation: Mock.Random.boolean(),
|
||||
},
|
||||
],
|
||||
status: Mock.Random.pick(["PENDING", "ANNOTATED", "REVIEWED", "REJECTED"]),
|
||||
priority: Mock.Random.integer(1, 5),
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
updatedAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
};
|
||||
}
|
||||
|
||||
const annotationDataList = new Array(200).fill(null).map(annotationDataItem);
|
||||
|
||||
// 标注模板数据
|
||||
function annotationTemplateItem() {
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
name: Mock.Random.ctitle(5, 15),
|
||||
description: Mock.Random.csentence(5, 25),
|
||||
type: Mock.Random.pick([
|
||||
"TEXT_CLASSIFICATION",
|
||||
"NAMED_ENTITY_RECOGNITION",
|
||||
"OBJECT_DETECTION",
|
||||
"SEMANTIC_SEGMENTATION",
|
||||
]),
|
||||
category: Mock.Random.ctitle(3, 8),
|
||||
labels: Mock.Random.shuffle([
|
||||
"正面",
|
||||
"负面",
|
||||
"中性",
|
||||
"人物",
|
||||
"地点",
|
||||
"组织",
|
||||
"时间",
|
||||
"产品",
|
||||
"服务",
|
||||
]).slice(0, Mock.Random.integer(3, 6)),
|
||||
guidelines: Mock.Random.csentence(10, 50),
|
||||
usageCount: Mock.Random.integer(0, 100),
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
createdBy: Mock.Random.cname(),
|
||||
};
|
||||
}
|
||||
|
||||
const annotationTemplateList = new Array(15)
|
||||
.fill(null)
|
||||
.map(annotationTemplateItem);
|
||||
|
||||
// 标注者数据
|
||||
function annotatorItem() {
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
name: Mock.Random.cname(),
|
||||
email: Mock.Random.email(),
|
||||
role: Mock.Random.pick(["ANNOTATOR", "REVIEWER", "ADMIN"]),
|
||||
skillLevel: Mock.Random.pick(["BEGINNER", "INTERMEDIATE", "EXPERT"]),
|
||||
specialties: Mock.Random.shuffle([
|
||||
"文本分类",
|
||||
"命名实体识别",
|
||||
"目标检测",
|
||||
"语义分割",
|
||||
]).slice(0, Mock.Random.integer(1, 3)),
|
||||
statistics: {
|
||||
totalAnnotations: Mock.Random.integer(100, 5000),
|
||||
accuracy: Mock.Random.float(0.85, 0.99, 2, 2),
|
||||
averageSpeed: Mock.Random.integer(50, 200), // annotations per hour
|
||||
totalWorkTime: Mock.Random.integer(10, 500), // hours
|
||||
},
|
||||
status: Mock.Random.pick(["ACTIVE", "INACTIVE", "SUSPENDED"]),
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
};
|
||||
}
|
||||
|
||||
const annotatorList = new Array(20).fill(null).map(annotatorItem);
|
||||
|
||||
module.exports = function (router) {
|
||||
// 获取标注任务列表
|
||||
router.get(API.queryAnnotationTasksUsingGet, (req, res) => {
|
||||
const { page = 0, size = 20, status, type } = req.query;
|
||||
let filteredTasks = annotationTaskList;
|
||||
|
||||
if (status) {
|
||||
filteredTasks = filteredTasks.filter((task) => task.status === status);
|
||||
}
|
||||
|
||||
if (type) {
|
||||
filteredTasks = filteredTasks.filter((task) => task.type === type);
|
||||
}
|
||||
|
||||
const startIndex = page * size;
|
||||
const endIndex = startIndex + parseInt(size);
|
||||
const pageData = filteredTasks.slice(startIndex, endIndex);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
content: pageData,
|
||||
totalElements: filteredTasks.length,
|
||||
totalPages: Math.ceil(filteredTasks.length / size),
|
||||
size: parseInt(size),
|
||||
number: parseInt(page),
|
||||
first: page == 0,
|
||||
last: page >= Math.ceil(filteredTasks.length / size) - 1,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 创建标注任务
|
||||
router.post(API.createAnnotationTaskUsingPost, (req, res) => {
|
||||
const newTask = {
|
||||
...annotationTaskItem(),
|
||||
...req.body,
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
status: "PENDING",
|
||||
progress: 0,
|
||||
annotatedCount: 0,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
annotationTaskList.push(newTask);
|
||||
|
||||
res.status(201).send({
|
||||
code: "0",
|
||||
msg: "Annotation task created successfully",
|
||||
data: newTask,
|
||||
});
|
||||
});
|
||||
|
||||
// 获取标注任务详情
|
||||
router.get(API.queryAnnotationTaskByIdUsingGet, (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const task = annotationTaskList.find((t) => t.id === taskId);
|
||||
|
||||
if (task) {
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: task,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Annotation task not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 更新标注任务
|
||||
router.put(API.syncAnnotationTaskByIdUsingPost, (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const index = annotationTaskList.findIndex((t) => t.id === taskId);
|
||||
|
||||
if (index !== -1) {
|
||||
annotationTaskList[index] = {
|
||||
...annotationTaskList[index],
|
||||
...req.body,
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Annotation task updated successfully",
|
||||
data: annotationTaskList[index],
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Annotation task not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 删除标注任务
|
||||
router.delete(API.deleteAnnotationTaskByIdUsingDelete, (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const index = annotationTaskList.findIndex((t) => t.id === taskId);
|
||||
|
||||
if (index !== -1) {
|
||||
annotationTaskList.splice(index, 1);
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Annotation task deleted successfully",
|
||||
data: null,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Annotation task not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取标注数据列表
|
||||
router.get(API.queryAnnotationDataUsingGet, (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const { page = 0, size = 20, status } = req.query;
|
||||
|
||||
let filteredData = annotationDataList.filter(
|
||||
(data) => data.taskId === taskId
|
||||
);
|
||||
|
||||
if (status) {
|
||||
filteredData = filteredData.filter((data) => data.status === status);
|
||||
}
|
||||
|
||||
const startIndex = page * size;
|
||||
const endIndex = startIndex + parseInt(size);
|
||||
const pageData = filteredData.slice(startIndex, endIndex);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
content: pageData,
|
||||
totalElements: filteredData.length,
|
||||
totalPages: Math.ceil(filteredData.length / size),
|
||||
size: parseInt(size),
|
||||
number: parseInt(page),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 提交标注
|
||||
router.post(API.submitAnnotationUsingPost, (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const newAnnotation = {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
taskId,
|
||||
...req.body,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
res.status(201).send({
|
||||
code: "0",
|
||||
msg: "Annotation submitted successfully",
|
||||
data: newAnnotation,
|
||||
});
|
||||
});
|
||||
|
||||
// 更新标注
|
||||
router.put(API.updateAnnotationUsingPut, (req, res) => {
|
||||
const { taskId, annotationId } = req.params;
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Annotation updated successfully",
|
||||
data: {
|
||||
id: annotationId,
|
||||
taskId,
|
||||
...req.body,
|
||||
updatedAt: new Date().toISOString(),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 删除标注
|
||||
router.delete(API.deleteAnnotationUsingDelete, (req, res) => {
|
||||
const { taskId, annotationId } = req.params;
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Annotation deleted successfully",
|
||||
data: null,
|
||||
});
|
||||
});
|
||||
|
||||
// 开始标注任务
|
||||
router.post(API.startAnnotationTaskUsingPost, (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const task = annotationTaskList.find((t) => t.id === taskId);
|
||||
|
||||
if (task) {
|
||||
task.status = "IN_PROGRESS";
|
||||
task.updatedAt = new Date().toISOString();
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Annotation task started successfully",
|
||||
data: task,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Annotation task not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 暂停标注任务
|
||||
router.post(API.pauseAnnotationTaskUsingPost, (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const task = annotationTaskList.find((t) => t.id === taskId);
|
||||
|
||||
if (task) {
|
||||
task.status = "PAUSED";
|
||||
task.updatedAt = new Date().toISOString();
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Annotation task paused successfully",
|
||||
data: task,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Annotation task not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 恢复标注任务
|
||||
router.post(API.resumeAnnotationTaskUsingPost, (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const task = annotationTaskList.find((t) => t.id === taskId);
|
||||
|
||||
if (task) {
|
||||
task.status = "IN_PROGRESS";
|
||||
task.updatedAt = new Date().toISOString();
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Annotation task resumed successfully",
|
||||
data: task,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Annotation task not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 完成标注任务
|
||||
router.post(API.completeAnnotationTaskUsingPost, (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const task = annotationTaskList.find((t) => t.id === taskId);
|
||||
|
||||
if (task) {
|
||||
task.status = "COMPLETED";
|
||||
task.progress = 100;
|
||||
task.updatedAt = new Date().toISOString();
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Annotation task completed successfully",
|
||||
data: task,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Annotation task not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取标注任务统计信息
|
||||
router.get(API.getAnnotationTaskStatisticsUsingGet, (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const task = annotationTaskList.find((t) => t.id === taskId);
|
||||
|
||||
if (task) {
|
||||
const statistics = {
|
||||
taskId,
|
||||
totalDataCount: task.totalDataCount,
|
||||
annotatedCount: task.annotatedCount,
|
||||
progress: task.progress,
|
||||
accuracy: task.statistics.accuracy,
|
||||
averageAnnotationTime: task.statistics.averageTime,
|
||||
reviewCount: task.statistics.reviewCount,
|
||||
qualityScore: Mock.Random.float(0.8, 0.99, 2, 2),
|
||||
annotatorDistribution: {
|
||||
[Mock.Random.cname()]: Mock.Random.integer(10, 100),
|
||||
[Mock.Random.cname()]: Mock.Random.integer(10, 100),
|
||||
[Mock.Random.cname()]: Mock.Random.integer(10, 100),
|
||||
},
|
||||
};
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: statistics,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Annotation task not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取整体标注统计信息
|
||||
router.get(API.getAnnotationStatisticsUsingGet, (req, res) => {
|
||||
const statistics = {
|
||||
totalTasks: annotationTaskList.length,
|
||||
completedTasks: annotationTaskList.filter((t) => t.status === "COMPLETED")
|
||||
.length,
|
||||
inProgressTasks: annotationTaskList.filter(
|
||||
(t) => t.status === "IN_PROGRESS"
|
||||
).length,
|
||||
pendingTasks: annotationTaskList.filter((t) => t.status === "PENDING")
|
||||
.length,
|
||||
totalAnnotations: annotationDataList.length,
|
||||
totalAnnotators: annotatorList.length,
|
||||
averageAccuracy: Mock.Random.float(0.85, 0.95, 2, 2),
|
||||
taskTypeDistribution: {
|
||||
TEXT_CLASSIFICATION: Mock.Random.integer(5, 15),
|
||||
NAMED_ENTITY_RECOGNITION: Mock.Random.integer(3, 10),
|
||||
OBJECT_DETECTION: Mock.Random.integer(2, 8),
|
||||
SEMANTIC_SEGMENTATION: Mock.Random.integer(1, 5),
|
||||
},
|
||||
};
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: statistics,
|
||||
});
|
||||
});
|
||||
|
||||
// 获取标注模板列表
|
||||
router.get(API.queryAnnotationTemplatesUsingGet, (req, res) => {
|
||||
const { page = 0, size = 20, type } = req.query;
|
||||
let filteredTemplates = annotationTemplateList;
|
||||
|
||||
if (type) {
|
||||
filteredTemplates = filteredTemplates.filter(
|
||||
(template) => template.type === type
|
||||
);
|
||||
}
|
||||
|
||||
const startIndex = page * size;
|
||||
const endIndex = startIndex + parseInt(size);
|
||||
const pageData = filteredTemplates.slice(startIndex, endIndex);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
content: pageData,
|
||||
totalElements: filteredTemplates.length,
|
||||
totalPages: Math.ceil(filteredTemplates.length / size),
|
||||
size: parseInt(size),
|
||||
number: parseInt(page),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 创建标注模板
|
||||
router.post(API.createAnnotationTemplateUsingPost, (req, res) => {
|
||||
const newTemplate = {
|
||||
...annotationTemplateItem(),
|
||||
...req.body,
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
usageCount: 0,
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
annotationTemplateList.push(newTemplate);
|
||||
|
||||
res.status(201).send({
|
||||
code: "0",
|
||||
msg: "Annotation template created successfully",
|
||||
data: newTemplate,
|
||||
});
|
||||
});
|
||||
|
||||
// 获取标注模板详情
|
||||
router.get(API.queryAnnotationTemplateByIdUsingGet, (req, res) => {
|
||||
const { templateId } = req.params;
|
||||
const template = annotationTemplateList.find((t) => t.id === templateId);
|
||||
|
||||
if (template) {
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: template,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Annotation template not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取标注者列表
|
||||
router.get(API.queryAnnotatorsUsingGet, (req, res) => {
|
||||
const { page = 0, size = 20, status, skillLevel } = req.query;
|
||||
let filteredAnnotators = annotatorList;
|
||||
|
||||
if (status) {
|
||||
filteredAnnotators = filteredAnnotators.filter(
|
||||
(annotator) => annotator.status === status
|
||||
);
|
||||
}
|
||||
|
||||
if (skillLevel) {
|
||||
filteredAnnotators = filteredAnnotators.filter(
|
||||
(annotator) => annotator.skillLevel === skillLevel
|
||||
);
|
||||
}
|
||||
|
||||
const startIndex = page * size;
|
||||
const endIndex = startIndex + parseInt(size);
|
||||
const pageData = filteredAnnotators.slice(startIndex, endIndex);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
content: pageData,
|
||||
totalElements: filteredAnnotators.length,
|
||||
totalPages: Math.ceil(filteredAnnotators.length / size),
|
||||
size: parseInt(size),
|
||||
number: parseInt(page),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 分配标注者
|
||||
router.post(API.assignAnnotatorUsingPost, (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const { annotatorIds } = req.body;
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Annotators assigned successfully",
|
||||
data: {
|
||||
taskId,
|
||||
assignedAnnotators: annotatorIds,
|
||||
assignedAt: new Date().toISOString(),
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
544
frontend/src/mock/mock-seed/data-cleansing.cjs
Normal file
544
frontend/src/mock/mock-seed/data-cleansing.cjs
Normal file
@@ -0,0 +1,544 @@
|
||||
const Mock = require("mockjs");
|
||||
const API = require("../mock-apis.cjs");
|
||||
|
||||
function operatorItem() {
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
name: Mock.Random.ctitle(3, 10),
|
||||
description: Mock.Random.csentence(5, 20),
|
||||
version: "1.0.0",
|
||||
inputs: Mock.Random.integer(1, 5),
|
||||
outputs: Mock.Random.integer(1, 5),
|
||||
settings: JSON.stringify({
|
||||
fileLength: {
|
||||
name: "文档字数",
|
||||
description:
|
||||
"过滤字数不在指定范围内的文档,如[10,10000000]。若输入为空,则不对字数上/下限做限制。",
|
||||
type: "range",
|
||||
defaultVal: [10, 10000000],
|
||||
min: 0,
|
||||
max: 10000000000000000,
|
||||
step: 1,
|
||||
},
|
||||
host: { type: "input", name: "主机地址", defaultVal: "localhost" },
|
||||
limit: {
|
||||
type: "range",
|
||||
name: "读取行数",
|
||||
defaultVal: [1000, 2000],
|
||||
min: 100,
|
||||
max: 10000,
|
||||
step: 100,
|
||||
},
|
||||
filepath: { type: "input", name: "文件路径", defaultVal: "/path" },
|
||||
encoding: {
|
||||
type: "select",
|
||||
name: "编码",
|
||||
defaultVal: "utf-8",
|
||||
options: ["utf-8", "gbk", "ascii"],
|
||||
},
|
||||
radio: {
|
||||
type: "radio",
|
||||
name: "radio",
|
||||
defaultVal: "utf-8",
|
||||
options: ["utf-8", "gbk", "ascii"],
|
||||
},
|
||||
features: {
|
||||
type: "checkbox",
|
||||
name: "特征列",
|
||||
defaultVal: ["feature1", "feature3"],
|
||||
options: ["feature1", "feature2", "feature3"],
|
||||
},
|
||||
repeatPhraseRatio: {
|
||||
name: "文档词重复率",
|
||||
description: "某个词的统计数/文档总词数 > 设定值,该文档被去除。",
|
||||
type: "slider",
|
||||
defaultVal: 0.5,
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.1,
|
||||
},
|
||||
hitStopwords: {
|
||||
name: "去除停用词",
|
||||
description: "统计重复词时,选择是否要去除停用词。",
|
||||
type: "switch",
|
||||
defaultVal: false,
|
||||
required: true,
|
||||
checkedLabel: "去除",
|
||||
unCheckedLabel: "不去除",
|
||||
},
|
||||
}),
|
||||
categories: [Mock.Random.pick([3, 4, 5, 6, 7, 8, 9])],
|
||||
isStar: Mock.Random.boolean(),
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
updatedAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
};
|
||||
}
|
||||
|
||||
const operatorList = new Array(50).fill(null).map(operatorItem);
|
||||
|
||||
// 清洗任务数据
|
||||
function cleaningTaskItem() {
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
name: Mock.Random.ctitle(5, 20),
|
||||
description: Mock.Random.csentence(5, 30),
|
||||
status: Mock.Random.pick([
|
||||
"PENDING",
|
||||
"RUNNING",
|
||||
"COMPLETED",
|
||||
"FAILED",
|
||||
"STOPPED",
|
||||
]),
|
||||
srcDatasetId: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
srcDatasetName: Mock.Random.ctitle(5, 15),
|
||||
destDatasetId: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
destDatasetName: Mock.Random.ctitle(5, 15),
|
||||
progress: Mock.Random.float(0, 100, 2, 2),
|
||||
startedAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
endedAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
updatedAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
instance: operatorList,
|
||||
};
|
||||
}
|
||||
|
||||
const cleaningTaskList = new Array(20).fill(null).map(cleaningTaskItem);
|
||||
|
||||
// 清洗模板数据
|
||||
function cleaningTemplateItem() {
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
name: Mock.Random.ctitle(5, 15),
|
||||
description: Mock.Random.csentence(5, 25),
|
||||
instance: operatorList.slice(
|
||||
Mock.Random.integer(0, 5),
|
||||
Mock.Random.integer(6, 50)
|
||||
),
|
||||
category: Mock.Random.ctitle(3, 8),
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
updatedAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
};
|
||||
}
|
||||
|
||||
const cleaningTemplateList = new Array(15).fill(null).map(cleaningTemplateItem);
|
||||
|
||||
const categoryTree = [
|
||||
{
|
||||
id: 1,
|
||||
name: "modal",
|
||||
count: 7,
|
||||
categories: [
|
||||
{ id: 3, name: "text", count: 3, type: null, parentId: null },
|
||||
{ id: 4, name: "image", count: 0, type: null, parentId: null },
|
||||
{ id: 5, name: "audio", count: 0, type: null, parentId: null },
|
||||
{ id: 6, name: "video", count: 0, type: null, parentId: null },
|
||||
{
|
||||
id: 7,
|
||||
name: "multimodal",
|
||||
count: 0,
|
||||
type: null,
|
||||
parentId: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "language",
|
||||
count: 3,
|
||||
categories: [
|
||||
{ id: 8, name: "python", count: 2, type: null, parentId: null },
|
||||
{ id: 9, name: "java", count: 1, type: null, parentId: null },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
module.exports = function (router) {
|
||||
// 获取清洗任务列表
|
||||
router.get(API.queryCleaningTasksUsingGet, (req, res) => {
|
||||
const { page = 0, size = 10, status } = req.query;
|
||||
let filteredTasks = cleaningTaskList;
|
||||
|
||||
if (status) {
|
||||
filteredTasks = cleaningTaskList.filter((task) => task.status === status);
|
||||
}
|
||||
|
||||
const startIndex = page * size;
|
||||
const endIndex = startIndex + parseInt(size);
|
||||
const pageData = filteredTasks.slice(startIndex, endIndex);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
content: pageData,
|
||||
totalElements: filteredTasks.length,
|
||||
totalPages: Math.ceil(filteredTasks.length / size),
|
||||
size: parseInt(size),
|
||||
number: parseInt(page),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 创建清洗任务
|
||||
router.post(API.createCleaningTaskUsingPost, (req, res) => {
|
||||
const newTask = {
|
||||
...cleaningTaskItem(),
|
||||
...req.body,
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
status: "PENDING",
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
cleaningTaskList.push(newTask);
|
||||
|
||||
res.status(201).send({
|
||||
code: "0",
|
||||
msg: "Cleaning task created successfully",
|
||||
data: newTask,
|
||||
});
|
||||
});
|
||||
|
||||
// 获取清洗任务详情
|
||||
router.get(API.queryCleaningTaskByIdUsingGet, (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const task = cleaningTaskList.find((j) => j.id === taskId);
|
||||
|
||||
if (task) {
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: task,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Cleaning task not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 删除清洗任务
|
||||
router.delete(API.deleteCleaningTaskByIdUsingDelete, (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const index = cleaningTaskList.findIndex((j) => j.id === taskId);
|
||||
|
||||
if (index !== -1) {
|
||||
cleaningTaskList.splice(index, 1);
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Cleaning task deleted successfully",
|
||||
data: null,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Cleaning task not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 执行清洗任务
|
||||
router.post(API.executeCleaningTaskUsingPost, (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const task = cleaningTaskList.find((j) => j.id === taskId);
|
||||
|
||||
if (task) {
|
||||
task.status = "running";
|
||||
task.startTime = new Date().toISOString();
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Cleaning task execution started",
|
||||
data: {
|
||||
executionId: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
status: "running",
|
||||
message: "Task execution started successfully",
|
||||
},
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Cleaning task not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 停止清洗任务
|
||||
router.post(API.stopCleaningTaskUsingPost, (req, res) => {
|
||||
const { taskId } = req.params;
|
||||
const task = cleaningTaskList.find((j) => j.id === taskId);
|
||||
|
||||
if (task) {
|
||||
task.status = "pending";
|
||||
task.endTime = new Date().toISOString();
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Cleaning task stopped successfully",
|
||||
data: null,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Cleaning task not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取清洗模板列表
|
||||
router.get(API.queryCleaningTemplatesUsingGet, (req, res) => {
|
||||
const { page = 0, size = 20 } = req.query;
|
||||
const startIndex = page * size;
|
||||
const endIndex = startIndex + parseInt(size);
|
||||
const pageData = cleaningTemplateList.slice(startIndex, endIndex);
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: { content: pageData, totalElements: cleaningTemplateList.length },
|
||||
});
|
||||
});
|
||||
|
||||
// 创建清洗模板
|
||||
router.post(API.createCleaningTemplateUsingPost, (req, res) => {
|
||||
const newTemplate = {
|
||||
...cleaningTemplateItem(),
|
||||
...req.body,
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
cleaningTemplateList.push(newTemplate);
|
||||
|
||||
res.status(201).send({
|
||||
code: "0",
|
||||
msg: "Cleaning template created successfully",
|
||||
data: newTemplate,
|
||||
});
|
||||
});
|
||||
|
||||
// 获取清洗模板详情
|
||||
router.get(API.queryCleaningTemplateByIdUsingGet, (req, res) => {
|
||||
const { templateId } = req.params;
|
||||
const template = cleaningTemplateList.find((t) => t.id === templateId);
|
||||
|
||||
if (template) {
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: template,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Cleaning template not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 删除清洗模板
|
||||
router.delete(API.deleteCleaningTemplateByIdUsingDelete, (req, res) => {
|
||||
const { templateId } = req.params;
|
||||
const index = cleaningTemplateList.findIndex((t) => t.id === templateId);
|
||||
|
||||
if (index !== -1) {
|
||||
cleaningTemplateList.splice(index, 1);
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Cleaning template deleted successfully",
|
||||
data: null,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Cleaning template not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取算子列表
|
||||
router.post(API.queryOperatorsUsingPost, (req, res) => {
|
||||
const {
|
||||
page = 0,
|
||||
size = 20,
|
||||
categories = [],
|
||||
operatorName = "",
|
||||
labelName = "",
|
||||
isStar,
|
||||
} = req.body;
|
||||
|
||||
let filteredOperators = operatorList;
|
||||
|
||||
// 按分类筛选
|
||||
if (categories && categories.length > 0) {
|
||||
filteredOperators = filteredOperators.filter((op) =>
|
||||
categories.includes(op.category.id)
|
||||
);
|
||||
}
|
||||
|
||||
// 按名称搜索
|
||||
if (operatorName) {
|
||||
filteredOperators = filteredOperators.filter((op) =>
|
||||
op.name.toLowerCase().includes(operatorName.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
// 按标签筛选
|
||||
if (labelName) {
|
||||
filteredOperators = filteredOperators.filter((op) =>
|
||||
op.labels.some((label) => label.name.includes(labelName))
|
||||
);
|
||||
}
|
||||
|
||||
// 按收藏状态筛选
|
||||
if (typeof isStar === "boolean") {
|
||||
filteredOperators = filteredOperators.filter(
|
||||
(op) => op.isStar === isStar
|
||||
);
|
||||
}
|
||||
|
||||
const startIndex = page * size;
|
||||
const endIndex = startIndex + parseInt(size);
|
||||
const pageData = filteredOperators.slice(startIndex, endIndex);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
content: pageData,
|
||||
totalElements: filteredOperators.length,
|
||||
totalPages: Math.ceil(filteredOperators.length / size),
|
||||
size: parseInt(size),
|
||||
number: parseInt(page),
|
||||
first: page === 0,
|
||||
last: page >= Math.ceil(filteredOperators.length / size) - 1,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 获取算子详情
|
||||
router.get(API.queryOperatorByIdUsingGet, (req, res) => {
|
||||
const { id } = req.params;
|
||||
const operator = operatorList.find((op) => op.id === id);
|
||||
|
||||
if (operator) {
|
||||
// 增加浏览次数模拟
|
||||
operator.viewCount = (operator.viewCount || 0) + 1;
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: operator,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
error: "OPERATOR_NOT_FOUND",
|
||||
message: "算子不存在",
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 更新算子信息
|
||||
router.put(API.updateOperatorByIdUsingPut, (req, res) => {
|
||||
const { id } = req.params;
|
||||
const index = operatorList.findIndex((op) => op.id === id);
|
||||
|
||||
if (index !== -1) {
|
||||
operatorList[index] = {
|
||||
...operatorList[index],
|
||||
...req.body,
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Operator updated successfully",
|
||||
data: operatorList[index],
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
error: "OPERATOR_NOT_FOUND",
|
||||
message: "算子不存在",
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 创建算子
|
||||
router.post(API.createOperatorUsingPost, (req, res) => {
|
||||
const { name, description, version, category, documentation } = req.body;
|
||||
|
||||
const newOperator = {
|
||||
...operatorItem(),
|
||||
...req.body,
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
name,
|
||||
description,
|
||||
version,
|
||||
category:
|
||||
typeof category === "string"
|
||||
? { id: category, name: category }
|
||||
: category,
|
||||
documentation,
|
||||
status: "REVIEWING",
|
||||
downloadCount: 0,
|
||||
rating: 0,
|
||||
ratingCount: 0,
|
||||
isStar: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
operatorList.push(newOperator);
|
||||
|
||||
res.status(201).send({
|
||||
code: "0",
|
||||
msg: "Operator created successfully",
|
||||
data: newOperator,
|
||||
});
|
||||
});
|
||||
|
||||
// 上传算子
|
||||
router.post(API.uploadOperatorUsingPost, (req, res) => {
|
||||
const { description } = req.body;
|
||||
|
||||
const newOperator = {
|
||||
...operatorItem(),
|
||||
description: description || "通过文件上传创建的算子",
|
||||
status: "REVIEWING",
|
||||
downloadCount: 0,
|
||||
rating: 0,
|
||||
ratingCount: 0,
|
||||
isStar: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
operatorList.push(newOperator);
|
||||
|
||||
res.status(201).send({
|
||||
code: "0",
|
||||
msg: "Operator uploaded successfully",
|
||||
data: newOperator,
|
||||
});
|
||||
});
|
||||
|
||||
// 获取算子分类树
|
||||
router.get(API.queryCategoryTreeUsingGet, (req, res) => {
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
page: 0,
|
||||
size: categoryTree.length,
|
||||
totalElements: categoryTree.length,
|
||||
totalPages: 1,
|
||||
content: categoryTree,
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
231
frontend/src/mock/mock-seed/data-collection.cjs
Normal file
231
frontend/src/mock/mock-seed/data-collection.cjs
Normal file
@@ -0,0 +1,231 @@
|
||||
const Mock = require("mockjs");
|
||||
const API = require("../mock-apis.cjs");
|
||||
const { Random } = Mock;
|
||||
|
||||
// 生成模拟数据归集统计信息
|
||||
const collectionStatistics = {
|
||||
period: Random.pick(["HOUR", "DAY", "WEEK", "MONTH"]),
|
||||
totalTasks: Random.integer(50, 200),
|
||||
activeTasks: Random.integer(10, 50),
|
||||
successfulExecutions: Random.integer(30, 150),
|
||||
failedExecutions: Random.integer(0, 50),
|
||||
totalExecutions: Random.integer(20, 100),
|
||||
avgExecutionTime: Random.integer(1000, 10000), // in milliseconds
|
||||
avgThroughput: Random.integer(100, 1000), // records per second
|
||||
topDataSources: new Array(5).fill(null).map(() => ({
|
||||
dataSourceId: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
dataSourceName: Mock.Random.word(5, 15),
|
||||
type: Mock.Random.pick([
|
||||
"MySQL",
|
||||
"PostgreSQL",
|
||||
"ORACLE",
|
||||
"SQLSERVER",
|
||||
"MONGODB",
|
||||
"REDIS",
|
||||
"ELASTICSEARCH",
|
||||
"HIVE",
|
||||
"HDFS",
|
||||
"KAFKA",
|
||||
"HTTP",
|
||||
"FILE",
|
||||
]),
|
||||
taskCount: Mock.Random.integer(1, 20),
|
||||
executionCount: Mock.Random.integer(1, 50),
|
||||
recordsProcessed: Mock.Random.integer(70, 100), // percentage
|
||||
})),
|
||||
};
|
||||
|
||||
// 生成模拟任务数据
|
||||
function taskItem() {
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
name: Mock.Random.ctitle(5, 20),
|
||||
description: Mock.Random.csentence(5, 20),
|
||||
syncMode: Mock.Random.pick(["ONCE", "SCHEDULED"]),
|
||||
config: {
|
||||
query: "SELECT * FROM table WHERE condition",
|
||||
batchSize: Mock.Random.integer(100, 1000),
|
||||
frequency: Mock.Random.integer(1, 60), // in minutes
|
||||
},
|
||||
scheduleExpression: "0 0 * * *", // cron expression
|
||||
lastExecutionId: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
status: Mock.Random.pick([
|
||||
"DRAFT",
|
||||
"READY",
|
||||
"RUNNING",
|
||||
"FAILED",
|
||||
"STOPPED",
|
||||
"SUCCESS",
|
||||
]),
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
updatedAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
sourceDataSourceId: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
sourceDataSourceName: Mock.Random.ctitle(5, 20),
|
||||
targetDataSourceId: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
targetDataSourceName: Mock.Random.ctitle(5, 20),
|
||||
};
|
||||
}
|
||||
|
||||
const taskList = new Array(50).fill(null).map(taskItem);
|
||||
|
||||
// 生成模拟任务执行日志数据
|
||||
function executionLogItem() {
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
taskName: Mock.Random.ctitle(5, 20),
|
||||
dataSource: Mock.Random.ctitle(5, 15),
|
||||
startTime: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
endTime: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
status: Mock.Random.pick(["SUCCESS", "FAILED", "RUNNING"]),
|
||||
triggerType: Mock.Random.pick(["MANUAL", "SCHEDULED", "API"]),
|
||||
duration: Mock.Random.integer(1, 120),
|
||||
retryCount: Mock.Random.integer(0, 5),
|
||||
recordsProcessed: Mock.Random.integer(100, 10000),
|
||||
processId: Mock.Random.integer(1000, 9999),
|
||||
errorMessage: Mock.Random.boolean() ? "" : Mock.Random.csentence(5, 20),
|
||||
};
|
||||
}
|
||||
|
||||
const executionLogList = new Array(100).fill(null).map(executionLogItem);
|
||||
|
||||
module.exports = function (router) {
|
||||
// 获取数据统计信息
|
||||
router.get(API.queryCollectionStatisticsUsingGet, (req, res) => {
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: collectionStatistics,
|
||||
});
|
||||
});
|
||||
|
||||
// 获取任务列表
|
||||
router.post(API.queryTasksUsingPost, (req, res) => {
|
||||
const { searchTerm, filters, page = 1, size = 10 } = req.body;
|
||||
let filteredTasks = taskList;
|
||||
if (searchTerm) {
|
||||
filteredTasks = filteredTasks.filter((task) =>
|
||||
task.name.includes(searchTerm)
|
||||
);
|
||||
}
|
||||
if (filters && filters.status && filters.status.length > 0) {
|
||||
filteredTasks = filteredTasks.filter((task) =>
|
||||
filters.status.includes(task.status)
|
||||
);
|
||||
}
|
||||
const startIndex = (page - 1) * size;
|
||||
const endIndex = startIndex + size;
|
||||
const paginatedTasks = filteredTasks.slice(startIndex, endIndex);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
totalElements: filteredTasks.length,
|
||||
page,
|
||||
size,
|
||||
results: paginatedTasks,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 创建任务
|
||||
router.post(API.createTaskUsingPost, (req, res) => {
|
||||
taskList.unshift(taskItem()); // 添加一个新的任务到列表开头
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "任务创建成功",
|
||||
data: {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 更新任务
|
||||
router.post(API.updateTaskByIdUsingPut, (req, res) => {
|
||||
const { id } = req.body;
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Data source task updated successfully",
|
||||
data: taskList.find((task) => task.id === id),
|
||||
});
|
||||
});
|
||||
|
||||
// 删除任务
|
||||
router.post(API.deleteTaskByIdUsingDelete, (req, res) => {
|
||||
const { id } = req.body;
|
||||
const index = taskList.findIndex((task) => task.id === id);
|
||||
if (index !== -1) {
|
||||
taskList.splice(index, 1);
|
||||
}
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Data source task deleted successfully",
|
||||
data: null,
|
||||
});
|
||||
});
|
||||
|
||||
// 执行任务
|
||||
router.post(API.executeTaskByIdUsingPost, (req, res) => {
|
||||
console.log("Received request to execute task", req.body);
|
||||
const { id } = req.body;
|
||||
console.log("Executing task with ID:", id);
|
||||
taskList.find((task) => task.id === id).status = "RUNNING";
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Data source task execution started",
|
||||
data: null,
|
||||
});
|
||||
});
|
||||
|
||||
// 停止任务
|
||||
router.post(API.stopTaskByIdUsingPost, (req, res) => {
|
||||
const { id } = req.body;
|
||||
const task = taskList.find((task) => task.id === id);
|
||||
if (task) {
|
||||
task.status = "STOPPED";
|
||||
}
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Data source task stopped successfully",
|
||||
data: null,
|
||||
});
|
||||
});
|
||||
|
||||
// 获取任务执行日志
|
||||
router.post(API.queryExecutionLogUsingPost, (req, res) => {
|
||||
const { keyword, page = 1, size = 10, status } = req.body;
|
||||
let filteredLogs = executionLogList;
|
||||
if (keyword) {
|
||||
filteredLogs = filteredLogs.filter((log) =>
|
||||
log.taskName.includes(keyword)
|
||||
);
|
||||
}
|
||||
if (status && status.length > 0) {
|
||||
filteredLogs = filteredLogs.filter((log) => status.includes(log.status));
|
||||
}
|
||||
const startIndex = (page - 1) * size;
|
||||
const endIndex = startIndex + size;
|
||||
const paginatedLogs = filteredLogs.slice(startIndex, endIndex);
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
totalElements: filteredLogs.length,
|
||||
page,
|
||||
size,
|
||||
results: paginatedLogs,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 获取任务执行日志详情
|
||||
router.post(API.queryExecutionLogByIdUsingGet, (req, res) => {
|
||||
const { id } = req.body;
|
||||
const log = executionLogList.find((log) => log.id === id);
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: log,
|
||||
});
|
||||
});
|
||||
};
|
||||
501
frontend/src/mock/mock-seed/data-evaluation.cjs
Normal file
501
frontend/src/mock/mock-seed/data-evaluation.cjs
Normal file
@@ -0,0 +1,501 @@
|
||||
const Mock = require("mockjs");
|
||||
const API = require("../mock-apis.cjs");
|
||||
|
||||
// 质量指标枚举
|
||||
const QualityMetrics = [
|
||||
"COMPLETENESS",
|
||||
"ACCURACY",
|
||||
"CONSISTENCY",
|
||||
"VALIDITY",
|
||||
"UNIQUENESS",
|
||||
"TIMELINESS"
|
||||
];
|
||||
|
||||
// 适配性标准枚举
|
||||
const CompatibilityCriteria = [
|
||||
"FORMAT_COMPATIBILITY",
|
||||
"SCHEMA_COMPATIBILITY",
|
||||
"SIZE_ADEQUACY",
|
||||
"DISTRIBUTION_MATCH",
|
||||
"FEATURE_COVERAGE"
|
||||
];
|
||||
|
||||
// 价值标准枚举
|
||||
const ValueCriteria = [
|
||||
"RARITY",
|
||||
"DEMAND",
|
||||
"QUALITY",
|
||||
"COMPLETENESS",
|
||||
"TIMELINESS",
|
||||
"STRATEGIC_IMPORTANCE"
|
||||
];
|
||||
|
||||
// 评估类型枚举
|
||||
const EvaluationTypes = ["QUALITY", "COMPATIBILITY", "VALUE", "COMPREHENSIVE"];
|
||||
|
||||
// 评估状态枚举
|
||||
const EvaluationStatuses = ["PENDING", "RUNNING", "COMPLETED", "FAILED"];
|
||||
|
||||
// 生成质量评估结果
|
||||
function qualityEvaluationItem() {
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
datasetId: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
status: Mock.Random.pick(EvaluationStatuses),
|
||||
overallScore: Mock.Random.float(0.6, 1.0, 2, 2),
|
||||
metrics: Mock.Random.shuffle(QualityMetrics).slice(0, Mock.Random.integer(3, 5)).map(metric => ({
|
||||
metric,
|
||||
score: Mock.Random.float(0.5, 1.0, 2, 2),
|
||||
details: {
|
||||
totalRecords: Mock.Random.integer(1000, 100000),
|
||||
validRecords: Mock.Random.integer(800, 95000),
|
||||
issues: Mock.Random.integer(0, 50)
|
||||
},
|
||||
issues: new Array(Mock.Random.integer(0, 3)).fill(null).map(() => ({
|
||||
type: Mock.Random.pick(["MISSING_VALUE", "INVALID_FORMAT", "DUPLICATE", "OUTLIER"]),
|
||||
severity: Mock.Random.pick(["LOW", "MEDIUM", "HIGH", "CRITICAL"]),
|
||||
description: Mock.Random.csentence(5, 15),
|
||||
affectedRecords: Mock.Random.integer(1, 1000),
|
||||
suggestions: [Mock.Random.csentence(5, 20)]
|
||||
}))
|
||||
})),
|
||||
recommendations: new Array(Mock.Random.integer(2, 5)).fill(null).map(() =>
|
||||
Mock.Random.csentence(10, 30)
|
||||
),
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
detailedResults: {
|
||||
fieldAnalysis: new Array(Mock.Random.integer(3, 8)).fill(null).map(() => ({
|
||||
fieldName: Mock.Random.word(5, 10),
|
||||
dataType: Mock.Random.pick(["STRING", "INTEGER", "FLOAT", "BOOLEAN", "DATE"]),
|
||||
nullCount: Mock.Random.integer(0, 100),
|
||||
uniqueCount: Mock.Random.integer(100, 1000),
|
||||
statistics: {
|
||||
mean: Mock.Random.float(0, 100, 2, 2),
|
||||
median: Mock.Random.float(0, 100, 2, 2),
|
||||
stdDev: Mock.Random.float(0, 50, 2, 2)
|
||||
}
|
||||
})),
|
||||
distributionAnalysis: {
|
||||
distributions: new Array(3).fill(null).map(() => ({
|
||||
field: Mock.Random.word(5, 10),
|
||||
type: Mock.Random.pick(["NORMAL", "UNIFORM", "SKEWED"]),
|
||||
parameters: {}
|
||||
})),
|
||||
outliers: new Array(Mock.Random.integer(0, 5)).fill(null).map(() => ({
|
||||
field: Mock.Random.word(5, 10),
|
||||
value: Mock.Random.float(-100, 100, 2, 2),
|
||||
zScore: Mock.Random.float(-3, 3, 2, 2)
|
||||
})),
|
||||
patterns: [
|
||||
"数据分布较为均匀",
|
||||
"存在少量异常值",
|
||||
"部分字段相关性较强"
|
||||
]
|
||||
},
|
||||
correlationAnalysis: {
|
||||
correlationMatrix: new Array(5).fill(null).map(() =>
|
||||
new Array(5).fill(null).map(() => Mock.Random.float(-1, 1, 2, 2))
|
||||
),
|
||||
significantCorrelations: new Array(Mock.Random.integer(1, 3)).fill(null).map(() => ({
|
||||
field1: Mock.Random.word(5, 10),
|
||||
field2: Mock.Random.word(5, 10),
|
||||
correlation: Mock.Random.float(0.5, 1, 2, 2),
|
||||
pValue: Mock.Random.float(0, 0.05, 3, 3)
|
||||
}))
|
||||
}
|
||||
},
|
||||
visualizations: new Array(Mock.Random.integer(2, 4)).fill(null).map(() => ({
|
||||
type: Mock.Random.pick(["CHART", "GRAPH", "HISTOGRAM", "HEATMAP"]),
|
||||
title: Mock.Random.ctitle(5, 15),
|
||||
data: {
|
||||
labels: new Array(5).fill(null).map(() => Mock.Random.word(3, 8)),
|
||||
values: new Array(5).fill(null).map(() => Mock.Random.integer(0, 100))
|
||||
},
|
||||
config: {
|
||||
width: 400,
|
||||
height: 300,
|
||||
color: Mock.Random.color()
|
||||
}
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
// 生成适配性评估结果
|
||||
function compatibilityEvaluationItem() {
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
datasetId: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
targetType: Mock.Random.pick(["LANGUAGE_MODEL", "CLASSIFICATION_MODEL", "RECOMMENDATION_SYSTEM", "CUSTOM_TASK"]),
|
||||
compatibilityScore: Mock.Random.float(0.6, 1.0, 2, 2),
|
||||
results: Mock.Random.shuffle(CompatibilityCriteria).slice(0, Mock.Random.integer(3, 5)).map(criterion => ({
|
||||
criterion,
|
||||
score: Mock.Random.float(0.5, 1.0, 2, 2),
|
||||
status: Mock.Random.pick(["PASS", "WARN", "FAIL"]),
|
||||
details: Mock.Random.csentence(10, 30)
|
||||
})),
|
||||
suggestions: new Array(Mock.Random.integer(2, 4)).fill(null).map(() =>
|
||||
Mock.Random.csentence(10, 25)
|
||||
),
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss")
|
||||
};
|
||||
}
|
||||
|
||||
// 生成价值评估结果
|
||||
function valueEvaluationItem() {
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
datasetId: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
valueScore: Mock.Random.float(0.6, 1.0, 2, 2),
|
||||
monetaryValue: Mock.Random.float(10000, 1000000, 2, 2),
|
||||
strategicValue: Mock.Random.float(0.6, 1.0, 2, 2),
|
||||
results: Mock.Random.shuffle(ValueCriteria).slice(0, Mock.Random.integer(3, 5)).map(criterion => ({
|
||||
criterion,
|
||||
score: Mock.Random.float(0.5, 1.0, 2, 2),
|
||||
impact: Mock.Random.pick(["LOW", "MEDIUM", "HIGH"]),
|
||||
explanation: Mock.Random.csentence(10, 30)
|
||||
})),
|
||||
insights: new Array(Mock.Random.integer(3, 6)).fill(null).map(() =>
|
||||
Mock.Random.csentence(15, 40)
|
||||
),
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss")
|
||||
};
|
||||
}
|
||||
|
||||
// 生成评估报告
|
||||
function evaluationReportItem() {
|
||||
const type = Mock.Random.pick(EvaluationTypes);
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
datasetId: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
datasetName: Mock.Random.ctitle(5, 15),
|
||||
type,
|
||||
status: Mock.Random.pick(EvaluationStatuses),
|
||||
overallScore: Mock.Random.float(0.6, 1.0, 2, 2),
|
||||
summary: Mock.Random.csentence(20, 50),
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
completedAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
qualityResults: type === "QUALITY" || type === "COMPREHENSIVE" ? qualityEvaluationItem() : null,
|
||||
compatibilityResults: type === "COMPATIBILITY" || type === "COMPREHENSIVE" ? compatibilityEvaluationItem() : null,
|
||||
valueResults: type === "VALUE" || type === "COMPREHENSIVE" ? valueEvaluationItem() : null,
|
||||
attachments: new Array(Mock.Random.integer(1, 3)).fill(null).map(() => ({
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
name: Mock.Random.word(5, 10) + "." + Mock.Random.pick(["pdf", "xlsx", "json"]),
|
||||
type: Mock.Random.pick(["PDF", "EXCEL", "JSON"]),
|
||||
size: Mock.Random.integer(1024, 1024 * 1024),
|
||||
downloadUrl: "/api/v1/evaluation/attachments/" + Mock.Random.guid()
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
const qualityEvaluationList = new Array(30).fill(null).map(qualityEvaluationItem);
|
||||
const compatibilityEvaluationList = new Array(20).fill(null).map(compatibilityEvaluationItem);
|
||||
const valueEvaluationList = new Array(25).fill(null).map(valueEvaluationItem);
|
||||
const evaluationReportList = new Array(50).fill(null).map(evaluationReportItem);
|
||||
|
||||
module.exports = function (router) {
|
||||
// 数据质量评估
|
||||
router.post(API.evaluateDataQualityUsingPost, (req, res) => {
|
||||
const { datasetId, metrics, sampleSize, parameters } = req.body;
|
||||
|
||||
const newEvaluation = {
|
||||
...qualityEvaluationItem(),
|
||||
datasetId,
|
||||
status: "RUNNING",
|
||||
metrics: metrics.map(metric => ({
|
||||
metric,
|
||||
score: Mock.Random.float(0.5, 1.0, 2, 2),
|
||||
details: {
|
||||
totalRecords: sampleSize || Mock.Random.integer(1000, 100000),
|
||||
validRecords: Mock.Random.integer(800, 95000),
|
||||
issues: Mock.Random.integer(0, 50)
|
||||
},
|
||||
issues: []
|
||||
})),
|
||||
createdAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
qualityEvaluationList.push(newEvaluation);
|
||||
|
||||
// 模拟异步处理,2秒后完成
|
||||
setTimeout(() => {
|
||||
newEvaluation.status = "COMPLETED";
|
||||
}, 2000);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Quality evaluation started successfully",
|
||||
data: newEvaluation
|
||||
});
|
||||
});
|
||||
|
||||
// 获取质量评估结果
|
||||
router.get(API.getQualityEvaluationByIdUsingGet, (req, res) => {
|
||||
const { evaluationId } = req.params;
|
||||
const evaluation = qualityEvaluationList.find(e => e.id === evaluationId);
|
||||
|
||||
if (evaluation) {
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: evaluation
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Quality evaluation not found",
|
||||
data: null
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 适配性评估
|
||||
router.post(API.evaluateCompatibilityUsingPost, (req, res) => {
|
||||
const { datasetId, targetType, targetConfig, evaluationCriteria } = req.body;
|
||||
|
||||
const newEvaluation = {
|
||||
...compatibilityEvaluationItem(),
|
||||
datasetId,
|
||||
targetType,
|
||||
results: evaluationCriteria.map(criterion => ({
|
||||
criterion,
|
||||
score: Mock.Random.float(0.5, 1.0, 2, 2),
|
||||
status: Mock.Random.pick(["PASS", "WARN", "FAIL"]),
|
||||
details: Mock.Random.csentence(10, 30)
|
||||
})),
|
||||
createdAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
compatibilityEvaluationList.push(newEvaluation);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Compatibility evaluation completed successfully",
|
||||
data: newEvaluation
|
||||
});
|
||||
});
|
||||
|
||||
// 价值评估
|
||||
router.post(API.evaluateValueUsingPost, (req, res) => {
|
||||
const { datasetId, valueCriteria, marketContext, businessContext } = req.body;
|
||||
|
||||
const newEvaluation = {
|
||||
...valueEvaluationItem(),
|
||||
datasetId,
|
||||
results: valueCriteria.map(criterion => ({
|
||||
criterion,
|
||||
score: Mock.Random.float(0.5, 1.0, 2, 2),
|
||||
impact: Mock.Random.pick(["LOW", "MEDIUM", "HIGH"]),
|
||||
explanation: Mock.Random.csentence(10, 30)
|
||||
})),
|
||||
createdAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
valueEvaluationList.push(newEvaluation);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Value evaluation completed successfully",
|
||||
data: newEvaluation
|
||||
});
|
||||
});
|
||||
|
||||
// 获取评估报告列表
|
||||
router.get(API.queryEvaluationReportsUsingGet, (req, res) => {
|
||||
const { page = 0, size = 20, type, datasetId } = req.query;
|
||||
let filteredReports = evaluationReportList;
|
||||
|
||||
if (type) {
|
||||
filteredReports = filteredReports.filter(report => report.type === type);
|
||||
}
|
||||
|
||||
if (datasetId) {
|
||||
filteredReports = filteredReports.filter(report => report.datasetId === datasetId);
|
||||
}
|
||||
|
||||
const startIndex = page * size;
|
||||
const endIndex = startIndex + parseInt(size);
|
||||
const pageData = filteredReports.slice(startIndex, endIndex);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
content: pageData,
|
||||
totalElements: filteredReports.length,
|
||||
totalPages: Math.ceil(filteredReports.length / size),
|
||||
size: parseInt(size),
|
||||
number: parseInt(page)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 获取评估报告详情
|
||||
router.get(API.getEvaluationReportByIdUsingGet, (req, res) => {
|
||||
const { reportId } = req.params;
|
||||
const report = evaluationReportList.find(r => r.id === reportId);
|
||||
|
||||
if (report) {
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: report
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Evaluation report not found",
|
||||
data: null
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 导出评估报告
|
||||
router.get(API.exportEvaluationReportUsingGet, (req, res) => {
|
||||
const { reportId } = req.params;
|
||||
const { format = "PDF" } = req.query;
|
||||
const report = evaluationReportList.find(r => r.id === reportId);
|
||||
|
||||
if (report) {
|
||||
const fileName = `evaluation_report_${reportId}.${format.toLowerCase()}`;
|
||||
|
||||
res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`);
|
||||
res.setHeader('Content-Type', 'application/octet-stream');
|
||||
res.send(`Mock ${format} content for evaluation report ${reportId}`);
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Evaluation report not found",
|
||||
data: null
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 批量评估
|
||||
router.post(API.batchEvaluationUsingPost, (req, res) => {
|
||||
const { datasetIds, evaluationTypes, parameters } = req.body;
|
||||
|
||||
const batchId = Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, "");
|
||||
const totalTasks = datasetIds.length * evaluationTypes.length;
|
||||
|
||||
// 为每个数据集和评估类型组合创建任务
|
||||
datasetIds.forEach(datasetId => {
|
||||
evaluationTypes.forEach(type => {
|
||||
const report = {
|
||||
...evaluationReportItem(),
|
||||
datasetId,
|
||||
type,
|
||||
status: "PENDING",
|
||||
batchId
|
||||
};
|
||||
evaluationReportList.push(report);
|
||||
|
||||
// 模拟异步处理
|
||||
setTimeout(() => {
|
||||
report.status = "COMPLETED";
|
||||
}, Mock.Random.integer(3000, 10000));
|
||||
});
|
||||
});
|
||||
|
||||
res.status(202).send({
|
||||
code: "0",
|
||||
msg: "Batch evaluation submitted successfully",
|
||||
data: {
|
||||
batchId,
|
||||
status: "SUBMITTED",
|
||||
totalTasks,
|
||||
submittedAt: new Date().toISOString()
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 获取批量评估状态
|
||||
router.get("/api/v1/evaluation/batch/:batchId", (req, res) => {
|
||||
const { batchId } = req.params;
|
||||
const batchReports = evaluationReportList.filter(r => r.batchId === batchId);
|
||||
|
||||
const completedTasks = batchReports.filter(r => r.status === "COMPLETED").length;
|
||||
const runningTasks = batchReports.filter(r => r.status === "RUNNING").length;
|
||||
const pendingTasks = batchReports.filter(r => r.status === "PENDING").length;
|
||||
const failedTasks = batchReports.filter(r => r.status === "FAILED").length;
|
||||
|
||||
let overallStatus = "COMPLETED";
|
||||
if (runningTasks > 0 || pendingTasks > 0) {
|
||||
overallStatus = "RUNNING";
|
||||
} else if (failedTasks > 0) {
|
||||
overallStatus = "PARTIAL_FAILED";
|
||||
}
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
batchId,
|
||||
status: overallStatus,
|
||||
totalTasks: batchReports.length,
|
||||
completedTasks,
|
||||
runningTasks,
|
||||
pendingTasks,
|
||||
failedTasks,
|
||||
progress: batchReports.length > 0 ? Math.round((completedTasks / batchReports.length) * 100) : 0,
|
||||
reports: batchReports
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 获取评估统计信息
|
||||
router.get("/api/v1/evaluation/statistics", (req, res) => {
|
||||
const { timeRange = "LAST_30_DAYS" } = req.query;
|
||||
|
||||
const statistics = {
|
||||
totalEvaluations: evaluationReportList.length,
|
||||
completedEvaluations: evaluationReportList.filter(r => r.status === "COMPLETED").length,
|
||||
runningEvaluations: evaluationReportList.filter(r => r.status === "RUNNING").length,
|
||||
failedEvaluations: evaluationReportList.filter(r => r.status === "FAILED").length,
|
||||
averageScore: Mock.Random.float(0.75, 0.95, 2, 2),
|
||||
evaluationTypeDistribution: {
|
||||
QUALITY: evaluationReportList.filter(r => r.type === "QUALITY").length,
|
||||
COMPATIBILITY: evaluationReportList.filter(r => r.type === "COMPATIBILITY").length,
|
||||
VALUE: evaluationReportList.filter(r => r.type === "VALUE").length,
|
||||
COMPREHENSIVE: evaluationReportList.filter(r => r.type === "COMPREHENSIVE").length
|
||||
},
|
||||
scoreDistribution: {
|
||||
excellent: evaluationReportList.filter(r => r.overallScore >= 0.9).length,
|
||||
good: evaluationReportList.filter(r => r.overallScore >= 0.8 && r.overallScore < 0.9).length,
|
||||
fair: evaluationReportList.filter(r => r.overallScore >= 0.6 && r.overallScore < 0.8).length,
|
||||
poor: evaluationReportList.filter(r => r.overallScore < 0.6).length
|
||||
},
|
||||
trends: new Array(30).fill(null).map((_, index) => ({
|
||||
date: Mock.Random.date("yyyy-MM-dd"),
|
||||
evaluations: Mock.Random.integer(5, 50),
|
||||
averageScore: Mock.Random.float(0.7, 0.95, 2, 2)
|
||||
}))
|
||||
};
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: statistics
|
||||
});
|
||||
});
|
||||
|
||||
// 删除评估报告
|
||||
router.delete("/api/v1/evaluation/reports/:reportId", (req, res) => {
|
||||
const { reportId } = req.params;
|
||||
const index = evaluationReportList.findIndex(r => r.id === reportId);
|
||||
|
||||
if (index !== -1) {
|
||||
evaluationReportList.splice(index, 1);
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Evaluation report deleted successfully",
|
||||
data: null
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Evaluation report not found",
|
||||
data: null
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
437
frontend/src/mock/mock-seed/data-management.cjs
Normal file
437
frontend/src/mock/mock-seed/data-management.cjs
Normal file
@@ -0,0 +1,437 @@
|
||||
const Mock = require("mockjs");
|
||||
const API = require("../mock-apis.cjs");
|
||||
|
||||
function tagItem() {
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
name: Mock.Random.word(3, 10),
|
||||
description: Mock.Random.csentence(5, 20),
|
||||
color: Mock.Random.color(),
|
||||
usageCount: Mock.Random.integer(0, 100),
|
||||
};
|
||||
}
|
||||
const tagList = new Array(20).fill(null).map((_, index) => tagItem(index));
|
||||
|
||||
function datasetItem() {
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
name: Mock.Random.ctitle(5, 20),
|
||||
type: Mock.Random.pick(["TEXT", "IMAGE", "AUDIO", "VIDEO"]),
|
||||
status: Mock.Random.pick(["ACTIVE", "INACTIVE", "PROCESSING"]),
|
||||
tags: Mock.Random.shuffle(tagList).slice(0, Mock.Random.integer(1, 3)),
|
||||
totalSize: Mock.Random.integer(1024, 1024 * 1024 * 1024), // in bytes
|
||||
description: Mock.Random.cparagraph(1, 3),
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
updatedAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
createdBy: Mock.Random.cname(),
|
||||
updatedBy: Mock.Random.cname(),
|
||||
};
|
||||
}
|
||||
|
||||
const datasetList = new Array(50)
|
||||
.fill(null)
|
||||
.map((_, index) => datasetItem(index));
|
||||
|
||||
function datasetFileItem() {
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
fileName:
|
||||
Mock.Random.word(5, 15) +
|
||||
"." +
|
||||
Mock.Random.pick(["csv", "json", "xml", "parquet", "avro"]),
|
||||
originName:
|
||||
Mock.Random.word(5, 15) +
|
||||
"." +
|
||||
Mock.Random.pick(["csv", "json", "xml", "parquet", "avro"]),
|
||||
fileType: Mock.Random.pick(["CSV", "JSON", "XML", "Parquet", "Avro"]),
|
||||
size: Mock.Random.integer(1024, 1024 * 1024 * 1024), // in bytes
|
||||
type: Mock.Random.pick(["CSV", "JSON", "XML", "Parquet", "Avro"]),
|
||||
status: Mock.Random.pick(["UPLOADED", "PROCESSING", "COMPLETED", "ERROR"]),
|
||||
description: Mock.Random.csentence(5, 20),
|
||||
filePath: "/path/to/file/" + Mock.Random.word(5, 10),
|
||||
uploadedAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
uploadedBy: Mock.Random.cname(),
|
||||
};
|
||||
}
|
||||
|
||||
const datasetFileList = new Array(200)
|
||||
.fill(null)
|
||||
.map((_, index) => datasetFileItem(index));
|
||||
|
||||
const datasetStatistics = {
|
||||
count: {
|
||||
text: 10,
|
||||
image: 34,
|
||||
audio: 23,
|
||||
video: 5,
|
||||
},
|
||||
size: {
|
||||
text: "120 MB",
|
||||
image: "3.4 GB",
|
||||
audio: "2.3 GB",
|
||||
video: "15 GB",
|
||||
},
|
||||
totalDatasets: datasetList.length,
|
||||
totalFiles: datasetFileList.length,
|
||||
completedFiles: datasetFileList.filter((file) => file.status === "COMPLETED")
|
||||
.length,
|
||||
totalSize: datasetFileList.reduce((acc, file) => acc + file.size, 0), // in bytes
|
||||
completionRate:
|
||||
datasetFileList.length === 0
|
||||
? 0
|
||||
: Math.round(
|
||||
(datasetFileList.filter((file) => file.status === "COMPLETED")
|
||||
.length /
|
||||
datasetFileList.length) *
|
||||
100
|
||||
), // percentage
|
||||
};
|
||||
|
||||
const datasetTypes = [
|
||||
{
|
||||
code: "PRETRAIN",
|
||||
name: "预训练数据集",
|
||||
description: "用于模型预训练的大规模数据集",
|
||||
supportedFormats: ["txt", "json", "csv", "parquet"],
|
||||
icon: "brain",
|
||||
},
|
||||
{
|
||||
code: "FINE_TUNE",
|
||||
name: "微调数据集",
|
||||
description: "用于模型微调的专业数据集",
|
||||
supportedFormats: ["json", "csv", "xlsx"],
|
||||
icon: "tune",
|
||||
},
|
||||
{
|
||||
code: "EVAL",
|
||||
name: "评估数据集",
|
||||
description: "用于模型评估的标准数据集",
|
||||
supportedFormats: ["json", "csv", "xml"],
|
||||
icon: "assessment",
|
||||
},
|
||||
];
|
||||
|
||||
module.exports = { datasetList };
|
||||
module.exports = function (router) {
|
||||
// 获取数据统计信息
|
||||
router.get(API.queryDatasetStatisticsUsingGet, (req, res) => {
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: datasetStatistics,
|
||||
});
|
||||
});
|
||||
|
||||
// 创建数据
|
||||
router.post(API.createDatasetUsingPost, (req, res) => {
|
||||
const newDataset = {
|
||||
...req.body,
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
status: "ACTIVE",
|
||||
fileCount: 0,
|
||||
totalSize: 0,
|
||||
completionRate: 0,
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
updatedAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
createdBy: "Admin",
|
||||
updatedBy: "Admin",
|
||||
tags: tagList.filter((tag) => req.body?.tagIds?.includes?.(tag.id)),
|
||||
};
|
||||
datasetList.unshift(newDataset); // Add to the beginning of the list
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Dataset created successfully",
|
||||
data: newDataset,
|
||||
});
|
||||
});
|
||||
|
||||
// 获取数据集列表
|
||||
router.get(API.queryDatasetsUsingGet, (req, res) => {
|
||||
const { page = 0, size = 10, keyword, type, status, tags } = req.query;
|
||||
console.log("Received query params:", req.query);
|
||||
|
||||
let filteredDatasets = datasetList;
|
||||
if (keyword) {
|
||||
console.log("filter keyword:", keyword);
|
||||
|
||||
filteredDatasets = filteredDatasets.filter(
|
||||
(dataset) =>
|
||||
dataset.name.includes(keyword) ||
|
||||
dataset.description.includes(keyword)
|
||||
);
|
||||
}
|
||||
if (type) {
|
||||
console.log("filter type:", type);
|
||||
|
||||
filteredDatasets = filteredDatasets.filter(
|
||||
(dataset) => dataset.type === type
|
||||
);
|
||||
}
|
||||
if (status) {
|
||||
console.log("filter status:", status);
|
||||
filteredDatasets = filteredDatasets.filter(
|
||||
(dataset) => dataset.status === status
|
||||
);
|
||||
}
|
||||
if (tags && tags.length > 0) {
|
||||
console.log("filter tags:", tags);
|
||||
filteredDatasets = filteredDatasets.filter((dataset) =>
|
||||
tags.every((tag) => dataset.tags.some((t) => t.name === tag))
|
||||
);
|
||||
}
|
||||
|
||||
const totalElements = filteredDatasets.length;
|
||||
const paginatedDatasets = filteredDatasets.slice(
|
||||
page * size,
|
||||
(page + 1) * size
|
||||
);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
totalElements,
|
||||
page,
|
||||
size,
|
||||
content: paginatedDatasets,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 根据ID获取数据集详情
|
||||
router.get(API.queryDatasetByIdUsingGet, (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
const dataset = datasetList.find((d) => d.id === id);
|
||||
if (dataset) {
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: dataset,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Dataset not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 更新数据集
|
||||
router.put(API.updateDatasetByIdUsingPut, (req, res) => {
|
||||
const { id } = req.params;
|
||||
let { tags } = req.body;
|
||||
|
||||
const index = datasetList.findIndex((d) => d.id === id);
|
||||
tags = [...datasetList[index].tags.map((tag) => tag.name), ...tags];
|
||||
if (index !== -1) {
|
||||
datasetList[index] = {
|
||||
...datasetList[index],
|
||||
...req.body,
|
||||
tags: tagList.filter((tag) => tags?.includes?.(tag.name)),
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: "Admin",
|
||||
};
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Dataset updated successfully",
|
||||
data: datasetList[index],
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Dataset not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 删除数据集
|
||||
router.delete(API.deleteDatasetByIdUsingDelete, (req, res) => {
|
||||
const { datasetId } = req.params;
|
||||
const index = datasetList.findIndex((d) => d.id === datasetId);
|
||||
|
||||
if (index !== -1) {
|
||||
datasetList.splice(index, 1);
|
||||
res.status(204).send();
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Dataset not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取数据集文件列表
|
||||
router.get(API.queryFilesUsingGet, (req, res) => {
|
||||
const { datasetId } = req.params;
|
||||
const { page = 0, size = 20, fileType, status } = req.query;
|
||||
|
||||
let filteredFiles = datasetFileList;
|
||||
|
||||
if (fileType) {
|
||||
filteredFiles = filteredFiles.filter(
|
||||
(file) => file.fileType === fileType
|
||||
);
|
||||
}
|
||||
|
||||
if (status) {
|
||||
filteredFiles = filteredFiles.filter((file) => file.status === status);
|
||||
}
|
||||
|
||||
const startIndex = page * size;
|
||||
const endIndex = startIndex + parseInt(size);
|
||||
const pageData = filteredFiles.slice(startIndex, endIndex);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
content: pageData,
|
||||
page: parseInt(page),
|
||||
size: parseInt(size),
|
||||
totalElements: filteredFiles.length,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 上传文件到数据集
|
||||
router.post(API.uploadFileUsingPost, (req, res) => {
|
||||
const { datasetId } = req.params;
|
||||
const newFile = {
|
||||
...datasetFileItem(),
|
||||
...req.body,
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
uploadedAt: new Date().toISOString(),
|
||||
uploadedBy: "Admin",
|
||||
};
|
||||
|
||||
datasetFileList.push(newFile);
|
||||
|
||||
res.status(201).send({
|
||||
code: "0",
|
||||
msg: "File uploaded successfully",
|
||||
data: newFile,
|
||||
});
|
||||
});
|
||||
|
||||
// 获取文件详情
|
||||
router.get(API.queryFileByIdUsingGet, (req, res) => {
|
||||
const { datasetId, fileId } = req.params;
|
||||
const file = datasetFileList.find((f) => f.id === fileId);
|
||||
|
||||
if (file) {
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: file,
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "File not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 删除文件
|
||||
router.delete(API.deleteFileByIdUsingDelete, (req, res) => {
|
||||
const { datasetId, fileId } = req.params;
|
||||
const index = datasetFileList.findIndex((f) => f.id === fileId);
|
||||
|
||||
if (index !== -1) {
|
||||
datasetFileList.splice(index, 1);
|
||||
res.status(204).send();
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "File not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 下载文件
|
||||
router.get(API.downloadFileByIdUsingGet, (req, res) => {
|
||||
const { datasetId, fileId } = req.params;
|
||||
const file = datasetFileList.find((f) => f.id === fileId);
|
||||
|
||||
if (file) {
|
||||
res.setHeader(
|
||||
"Content-Disposition",
|
||||
`attachment; filename="${file.fileName}"`
|
||||
);
|
||||
res.setHeader("Content-Type", "application/octet-stream");
|
||||
res.send(`Mock file content for ${file.fileName}`);
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "File not found",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取数据集类型列表
|
||||
router.get(API.queryDatasetTypesUsingGet, (req, res) => {
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: datasetTypes,
|
||||
});
|
||||
});
|
||||
|
||||
// 获取标签列表
|
||||
router.get(API.queryTagsUsingGet, (req, res) => {
|
||||
const { keyword } = req.query;
|
||||
let filteredTags = tagList;
|
||||
|
||||
if (keyword) {
|
||||
filteredTags = tagList.filter((tag) =>
|
||||
tag.name.toLowerCase().includes(keyword.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: filteredTags,
|
||||
});
|
||||
});
|
||||
|
||||
// 创建标签
|
||||
router.post(API.createTagUsingPost, (req, res) => {
|
||||
const newTag = {
|
||||
...tagItem(),
|
||||
...req.body,
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
usageCount: 0,
|
||||
};
|
||||
|
||||
tagList.push(newTag);
|
||||
|
||||
res.status(201).send({
|
||||
code: "0",
|
||||
msg: "Tag created successfully",
|
||||
data: newTag,
|
||||
});
|
||||
});
|
||||
|
||||
router.post(API.preUploadFileUsingPost, (req, res) => {
|
||||
res.status(201).send(Mock.Random.guid());
|
||||
});
|
||||
|
||||
// 上传
|
||||
router.post(API.uploadFileChunkUsingPost, (req, res) => {
|
||||
res.status(500).send({ message: "Simulated upload failure" });
|
||||
// res.status(201).send({ data: "success" });
|
||||
});
|
||||
|
||||
// 取消上传
|
||||
router.put(API.cancelUploadUsingPut, (req, res) => {
|
||||
res.status(201).send({ data: "success" });
|
||||
});
|
||||
};
|
||||
522
frontend/src/mock/mock-seed/data-synthesis.cjs
Normal file
522
frontend/src/mock/mock-seed/data-synthesis.cjs
Normal file
@@ -0,0 +1,522 @@
|
||||
const Mock = require("mockjs");
|
||||
const API = require("../mock-apis.cjs");
|
||||
|
||||
// 合成类型枚举
|
||||
const SynthesisTypes = [
|
||||
"INSTRUCTION_TUNING",
|
||||
"COT_DISTILLATION",
|
||||
"DIALOGUE_GENERATION",
|
||||
"TEXT_AUGMENTATION",
|
||||
"MULTIMODAL_SYNTHESIS",
|
||||
"CUSTOM"
|
||||
];
|
||||
|
||||
// 任务状态枚举
|
||||
const JobStatuses = ["PENDING", "RUNNING", "COMPLETED", "FAILED", "CANCELLED"];
|
||||
|
||||
// 模型配置
|
||||
function modelConfigItem() {
|
||||
return {
|
||||
modelName: Mock.Random.pick([
|
||||
"gpt-3.5-turbo",
|
||||
"gpt-4",
|
||||
"claude-3",
|
||||
"llama-2-70b",
|
||||
"qwen-max"
|
||||
]),
|
||||
temperature: Mock.Random.float(0.1, 1.0, 2, 2),
|
||||
maxTokens: Mock.Random.pick([512, 1024, 2048, 4096]),
|
||||
topP: Mock.Random.float(0.1, 1.0, 2, 2),
|
||||
frequencyPenalty: Mock.Random.float(0, 2.0, 2, 2)
|
||||
};
|
||||
}
|
||||
|
||||
// 合成模板数据
|
||||
function synthesisTemplateItem() {
|
||||
const type = Mock.Random.pick(SynthesisTypes);
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
name: Mock.Random.ctitle(5, 20),
|
||||
description: Mock.Random.csentence(5, 30),
|
||||
type,
|
||||
category: Mock.Random.pick([
|
||||
"教育培训", "对话系统", "内容生成", "代码生成", "多模态", "自定义"
|
||||
]),
|
||||
modelConfig: modelConfigItem(),
|
||||
enabled: Mock.Random.boolean(),
|
||||
promptTemplate: type === "INSTRUCTION_TUNING"
|
||||
? "请根据以下主题生成一个指令:{topic}\n指令应该包含:\n1. 明确的任务描述\n2. 具体的输入要求\n3. 期望的输出格式"
|
||||
: type === "COT_DISTILLATION"
|
||||
? "问题:{question}\n请提供详细的推理步骤,然后给出最终答案。\n推理过程:\n1. 分析问题的关键信息\n2. 应用相关知识和规则\n3. 逐步推导出结论"
|
||||
: "请根据以下模板生成内容:{template}",
|
||||
parameters: {
|
||||
maxLength: Mock.Random.integer(100, 2000),
|
||||
diversity: Mock.Random.float(0.1, 1.0, 2, 2),
|
||||
quality: Mock.Random.float(0.7, 1.0, 2, 2)
|
||||
},
|
||||
examples: new Array(Mock.Random.integer(2, 5)).fill(null).map(() => ({
|
||||
input: Mock.Random.csentence(10, 30),
|
||||
output: Mock.Random.csentence(20, 50),
|
||||
explanation: Mock.Random.csentence(5, 20)
|
||||
})),
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
updatedAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss")
|
||||
};
|
||||
}
|
||||
|
||||
const synthesisTemplateList = new Array(25).fill(null).map(synthesisTemplateItem);
|
||||
|
||||
// 合成任务数据
|
||||
function synthesisJobItem() {
|
||||
const template = Mock.Random.pick(synthesisTemplateList);
|
||||
const targetCount = Mock.Random.integer(100, 10000);
|
||||
const generatedCount = Mock.Random.integer(0, targetCount);
|
||||
const progress = targetCount > 0 ? (generatedCount / targetCount) * 100 : 0;
|
||||
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
name: Mock.Random.ctitle(5, 20),
|
||||
description: Mock.Random.csentence(5, 30),
|
||||
templateId: template.id,
|
||||
template: {
|
||||
id: template.id,
|
||||
name: template.name,
|
||||
type: template.type
|
||||
},
|
||||
status: Mock.Random.pick(JobStatuses),
|
||||
progress: Math.round(progress * 100) / 100,
|
||||
targetCount,
|
||||
generatedCount,
|
||||
startTime: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
endTime: progress >= 100 ? Mock.Random.datetime("yyyy-MM-dd HH:mm:ss") : null,
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
updatedAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
statistics: {
|
||||
totalGenerated: generatedCount,
|
||||
successfulGenerated: Math.floor(generatedCount * Mock.Random.float(0.85, 0.98, 2, 2)),
|
||||
failedGenerated: Math.floor(generatedCount * Mock.Random.float(0.02, 0.15, 2, 2)),
|
||||
averageLength: Mock.Random.integer(50, 500),
|
||||
uniqueCount: Math.floor(generatedCount * Mock.Random.float(0.8, 0.95, 2, 2))
|
||||
},
|
||||
samples: new Array(Math.min(10, generatedCount)).fill(null).map(() => ({
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
content: Mock.Random.cparagraph(1, 3),
|
||||
score: Mock.Random.float(0.6, 1.0, 2, 2),
|
||||
metadata: {
|
||||
length: Mock.Random.integer(50, 500),
|
||||
model: template.modelConfig.modelName,
|
||||
timestamp: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss")
|
||||
},
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss")
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
const synthesisJobList = new Array(30).fill(null).map(synthesisJobItem);
|
||||
|
||||
// 生成指令数据
|
||||
function generatedInstructionItem() {
|
||||
return {
|
||||
instruction: Mock.Random.csentence(10, 30),
|
||||
input: Mock.Random.csentence(5, 20),
|
||||
output: Mock.Random.csentence(10, 40),
|
||||
quality: Mock.Random.float(0.7, 1.0, 2, 2)
|
||||
};
|
||||
}
|
||||
|
||||
// COT 示例数据
|
||||
function cotExampleItem() {
|
||||
return {
|
||||
question: Mock.Random.csentence(10, 25) + "?",
|
||||
reasoning: Mock.Random.cparagraph(2, 4),
|
||||
answer: Mock.Random.csentence(5, 15)
|
||||
};
|
||||
}
|
||||
|
||||
// 蒸馏COT数据
|
||||
function distilledCOTDataItem() {
|
||||
return {
|
||||
question: Mock.Random.csentence(10, 25) + "?",
|
||||
reasoning: Mock.Random.cparagraph(2, 4),
|
||||
answer: Mock.Random.csentence(5, 15),
|
||||
confidence: Mock.Random.float(0.7, 1.0, 2, 2)
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = function (router) {
|
||||
// 获取合成模板列表
|
||||
router.get(API.querySynthesisTemplatesUsingGet, (req, res) => {
|
||||
const { page = 0, size = 20, type } = req.query;
|
||||
let filteredTemplates = synthesisTemplateList;
|
||||
|
||||
if (type) {
|
||||
filteredTemplates = synthesisTemplateList.filter(
|
||||
(template) => template.type === type
|
||||
);
|
||||
}
|
||||
|
||||
const startIndex = page * size;
|
||||
const endIndex = startIndex + parseInt(size);
|
||||
const pageData = filteredTemplates.slice(startIndex, endIndex);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
content: pageData,
|
||||
totalElements: filteredTemplates.length,
|
||||
totalPages: Math.ceil(filteredTemplates.length / size),
|
||||
size: parseInt(size),
|
||||
number: parseInt(page)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 创建合成模板
|
||||
router.post(API.createSynthesisTemplateUsingPost, (req, res) => {
|
||||
const newTemplate = {
|
||||
...synthesisTemplateItem(),
|
||||
...req.body,
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
enabled: true,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString()
|
||||
};
|
||||
synthesisTemplateList.push(newTemplate);
|
||||
|
||||
res.status(201).send({
|
||||
code: "0",
|
||||
msg: "Synthesis template created successfully",
|
||||
data: newTemplate
|
||||
});
|
||||
});
|
||||
|
||||
// 获取合成模板详情
|
||||
router.get(API.querySynthesisTemplateByIdUsingGet, (req, res) => {
|
||||
const { templateId } = req.params;
|
||||
const template = synthesisTemplateList.find((t) => t.id === templateId);
|
||||
|
||||
if (template) {
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: template
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Synthesis template not found",
|
||||
data: null
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 更新合成模板
|
||||
router.put(API.updateSynthesisTemplateByIdUsingPut, (req, res) => {
|
||||
const { templateId } = req.params;
|
||||
const index = synthesisTemplateList.findIndex((t) => t.id === templateId);
|
||||
|
||||
if (index !== -1) {
|
||||
synthesisTemplateList[index] = {
|
||||
...synthesisTemplateList[index],
|
||||
...req.body,
|
||||
updatedAt: new Date().toISOString()
|
||||
};
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Synthesis template updated successfully",
|
||||
data: synthesisTemplateList[index]
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Synthesis template not found",
|
||||
data: null
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 删除合成模板
|
||||
router.delete(API.deleteSynthesisTemplateByIdUsingDelete, (req, res) => {
|
||||
const { templateId } = req.params;
|
||||
const index = synthesisTemplateList.findIndex((t) => t.id === templateId);
|
||||
|
||||
if (index !== -1) {
|
||||
synthesisTemplateList.splice(index, 1);
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Synthesis template deleted successfully",
|
||||
data: null
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Synthesis template not found",
|
||||
data: null
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取合成任务列表
|
||||
router.get(API.querySynthesisJobsUsingGet, (req, res) => {
|
||||
const { page = 0, size = 20, status } = req.query;
|
||||
let filteredJobs = synthesisJobList;
|
||||
|
||||
if (status) {
|
||||
filteredJobs = synthesisJobList.filter((job) => job.status === status);
|
||||
}
|
||||
|
||||
const startIndex = page * size;
|
||||
const endIndex = startIndex + parseInt(size);
|
||||
const pageData = filteredJobs.slice(startIndex, endIndex);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
content: pageData,
|
||||
totalElements: filteredJobs.length,
|
||||
totalPages: Math.ceil(filteredJobs.length / size),
|
||||
size: parseInt(size),
|
||||
number: parseInt(page)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 创建合成任务
|
||||
router.post(API.createSynthesisJobUsingPost, (req, res) => {
|
||||
const { templateId } = req.body;
|
||||
const template = synthesisTemplateList.find(t => t.id === templateId);
|
||||
|
||||
const newJob = {
|
||||
...synthesisJobItem(),
|
||||
...req.body,
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
templateId,
|
||||
template: template ? {
|
||||
id: template.id,
|
||||
name: template.name,
|
||||
type: template.type
|
||||
} : null,
|
||||
status: "PENDING",
|
||||
progress: 0,
|
||||
generatedCount: 0,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString()
|
||||
};
|
||||
synthesisJobList.push(newJob);
|
||||
|
||||
res.status(201).send({
|
||||
code: "0",
|
||||
msg: "Synthesis job created successfully",
|
||||
data: newJob
|
||||
});
|
||||
});
|
||||
|
||||
// 获取合成任务详情
|
||||
router.get(API.querySynthesisJobByIdUsingGet, (req, res) => {
|
||||
const { jobId } = req.params;
|
||||
const job = synthesisJobList.find((j) => j.id === jobId);
|
||||
|
||||
if (job) {
|
||||
const template = synthesisTemplateList.find(t => t.id === job.templateId);
|
||||
const jobDetail = {
|
||||
...job,
|
||||
template: template || null
|
||||
};
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: jobDetail
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Synthesis job not found",
|
||||
data: null
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 删除合成任务
|
||||
router.delete(API.deleteSynthesisJobByIdUsingDelete, (req, res) => {
|
||||
const { jobId } = req.params;
|
||||
const index = synthesisJobList.findIndex((j) => j.id === jobId);
|
||||
|
||||
if (index !== -1) {
|
||||
synthesisJobList.splice(index, 1);
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Synthesis job deleted successfully",
|
||||
data: null
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Synthesis job not found",
|
||||
data: null
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 执行合成任务
|
||||
router.post(API.executeSynthesisJobUsingPost, (req, res) => {
|
||||
const { jobId } = req.params;
|
||||
const job = synthesisJobList.find((j) => j.id === jobId);
|
||||
|
||||
if (job) {
|
||||
job.status = "RUNNING";
|
||||
job.startTime = new Date().toISOString();
|
||||
job.updatedAt = new Date().toISOString();
|
||||
|
||||
// 模拟异步执行
|
||||
setTimeout(() => {
|
||||
job.status = Mock.Random.pick(["COMPLETED", "FAILED"]);
|
||||
job.progress = job.status === "COMPLETED" ? 100 : Mock.Random.float(10, 90, 2, 2);
|
||||
job.generatedCount = Math.floor((job.progress / 100) * job.targetCount);
|
||||
job.endTime = new Date().toISOString();
|
||||
}, Mock.Random.integer(2000, 5000));
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Synthesis job execution started",
|
||||
data: {
|
||||
executionId: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
status: "RUNNING",
|
||||
message: "Job execution started successfully"
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({
|
||||
code: "1",
|
||||
msg: "Synthesis job not found",
|
||||
data: null
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 指令调优数据合成
|
||||
router.post(API.instructionTuningUsingPost, (req, res) => {
|
||||
const { baseInstructions, targetDomain, count, modelConfig, parameters } = req.body;
|
||||
|
||||
const jobId = Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, "");
|
||||
const generatedInstructions = new Array(count).fill(null).map(() => generatedInstructionItem());
|
||||
|
||||
const statistics = {
|
||||
totalGenerated: count,
|
||||
averageQuality: Mock.Random.float(0.8, 0.95, 2, 2),
|
||||
diversityScore: Mock.Random.float(0.7, 0.9, 2, 2)
|
||||
};
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Instruction tuning completed successfully",
|
||||
data: {
|
||||
jobId,
|
||||
generatedInstructions,
|
||||
statistics
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// COT蒸馏数据合成
|
||||
router.post(API.cotDistillationUsingPost, (req, res) => {
|
||||
const { sourceModel, targetFormat, examples, parameters } = req.body;
|
||||
|
||||
const jobId = Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, "");
|
||||
const processedCount = examples.length;
|
||||
const successfulCount = Math.floor(processedCount * Mock.Random.float(0.85, 0.98, 2, 2));
|
||||
|
||||
const distilledData = new Array(successfulCount).fill(null).map(() => distilledCOTDataItem());
|
||||
|
||||
const statistics = {
|
||||
totalProcessed: processedCount,
|
||||
successfulDistilled: successfulCount,
|
||||
averageConfidence: Mock.Random.float(0.8, 0.95, 2, 2)
|
||||
};
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "COT distillation completed successfully",
|
||||
data: {
|
||||
jobId,
|
||||
distilledData,
|
||||
statistics
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 获取合成任务统计信息
|
||||
router.get("/api/v1/synthesis/statistics", (req, res) => {
|
||||
const statistics = {
|
||||
totalJobs: synthesisJobList.length,
|
||||
completedJobs: synthesisJobList.filter(j => j.status === "COMPLETED").length,
|
||||
runningJobs: synthesisJobList.filter(j => j.status === "RUNNING").length,
|
||||
failedJobs: synthesisJobList.filter(j => j.status === "FAILED").length,
|
||||
totalGenerated: synthesisJobList.reduce((sum, job) => sum + job.generatedCount, 0),
|
||||
averageQuality: Mock.Random.float(0.8, 0.95, 2, 2),
|
||||
templateTypeDistribution: {
|
||||
"INSTRUCTION_TUNING": synthesisTemplateList.filter(t => t.type === "INSTRUCTION_TUNING").length,
|
||||
"COT_DISTILLATION": synthesisTemplateList.filter(t => t.type === "COT_DISTILLATION").length,
|
||||
"DIALOGUE_GENERATION": synthesisTemplateList.filter(t => t.type === "DIALOGUE_GENERATION").length,
|
||||
"TEXT_AUGMENTATION": synthesisTemplateList.filter(t => t.type === "TEXT_AUGMENTATION").length,
|
||||
"MULTIMODAL_SYNTHESIS": synthesisTemplateList.filter(t => t.type === "MULTIMODAL_SYNTHESIS").length,
|
||||
"CUSTOM": synthesisTemplateList.filter(t => t.type === "CUSTOM").length
|
||||
},
|
||||
dailyGeneration: new Array(7).fill(null).map((_, index) => ({
|
||||
date: Mock.Random.date("yyyy-MM-dd"),
|
||||
count: Mock.Random.integer(100, 5000)
|
||||
}))
|
||||
};
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: statistics
|
||||
});
|
||||
});
|
||||
|
||||
// 批量操作
|
||||
router.post("/api/v1/synthesis/jobs/batch", (req, res) => {
|
||||
const { action, jobIds } = req.body;
|
||||
|
||||
let successCount = 0;
|
||||
let failedCount = 0;
|
||||
|
||||
jobIds.forEach(jobId => {
|
||||
const job = synthesisJobList.find(j => j.id === jobId);
|
||||
if (job) {
|
||||
switch(action) {
|
||||
case "DELETE":
|
||||
const index = synthesisJobList.findIndex(j => j.id === jobId);
|
||||
synthesisJobList.splice(index, 1);
|
||||
successCount++;
|
||||
break;
|
||||
case "START":
|
||||
job.status = "RUNNING";
|
||||
job.startTime = new Date().toISOString();
|
||||
successCount++;
|
||||
break;
|
||||
case "STOP":
|
||||
job.status = "CANCELLED";
|
||||
job.endTime = new Date().toISOString();
|
||||
successCount++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
failedCount++;
|
||||
}
|
||||
});
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: `Batch ${action.toLowerCase()} completed`,
|
||||
data: {
|
||||
total: jobIds.length,
|
||||
success: successCount,
|
||||
failed: failedCount
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
124
frontend/src/mock/mock-seed/operator-market.cjs
Normal file
124
frontend/src/mock/mock-seed/operator-market.cjs
Normal file
@@ -0,0 +1,124 @@
|
||||
const Mock = require("mockjs");
|
||||
const API = require("../mock-apis.cjs");
|
||||
|
||||
// 算子标签数据
|
||||
function labelItem() {
|
||||
return {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
name: Mock.Random.pick([
|
||||
"数据清洗",
|
||||
"特征选择",
|
||||
"分类算法",
|
||||
"聚类算法",
|
||||
"回归分析",
|
||||
"深度神经网络",
|
||||
"卷积神经网络",
|
||||
"循环神经网络",
|
||||
"注意力机制",
|
||||
"文本分析",
|
||||
"图像处理",
|
||||
"语音识别",
|
||||
"推荐算法",
|
||||
"异常检测",
|
||||
"优化算法",
|
||||
"集成学习",
|
||||
"迁移学习",
|
||||
"强化学习",
|
||||
"联邦学习",
|
||||
]),
|
||||
usageCount: Mock.Random.integer(1, 500),
|
||||
createdAt: Mock.Random.datetime("yyyy-MM-dd HH:mm:ss"),
|
||||
};
|
||||
}
|
||||
|
||||
const labelList = new Array(50).fill(null).map(labelItem);
|
||||
|
||||
module.exports = function (router) {
|
||||
// 获取算子标签列表
|
||||
router.get(API.queryLabelsUsingGet, (req, res) => {
|
||||
const { page = 0, size = 20, keyword = "" } = req.query;
|
||||
|
||||
let filteredLabels = labelList;
|
||||
|
||||
if (keyword) {
|
||||
filteredLabels = labelList.filter((label) =>
|
||||
label.name.toLowerCase().includes(keyword.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
const startIndex = page * size;
|
||||
const endIndex = startIndex + parseInt(size);
|
||||
const pageData = filteredLabels.slice(startIndex, endIndex);
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Success",
|
||||
data: {
|
||||
content: pageData,
|
||||
totalElements: filteredLabels.length,
|
||||
totalPages: Math.ceil(filteredLabels.length / size),
|
||||
size: parseInt(size),
|
||||
number: parseInt(page),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// 创建标签
|
||||
router.post(API.createLabelUsingPost, (req, res) => {
|
||||
const { name } = req.body;
|
||||
|
||||
const newLabel = {
|
||||
id: Mock.Random.guid().replace(/[^a-zA-Z0-9]/g, ""),
|
||||
name,
|
||||
usageCount: 0,
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
labelList.push(newLabel);
|
||||
|
||||
res.status(201).send({
|
||||
code: "0",
|
||||
msg: "Label created successfully",
|
||||
data: newLabel,
|
||||
});
|
||||
});
|
||||
|
||||
// 批量删除标签
|
||||
router.delete(API.deleteLabelsUsingDelete, (req, res) => {
|
||||
const labelIds = req.body; // 数组形式的标签ID列表
|
||||
|
||||
let deletedCount = 0;
|
||||
labelIds.forEach((labelId) => {
|
||||
const index = labelList.findIndex((label) => label.id === labelId);
|
||||
if (index !== -1) {
|
||||
labelList.splice(index, 1);
|
||||
deletedCount++;
|
||||
}
|
||||
});
|
||||
|
||||
res.status(204).send();
|
||||
});
|
||||
|
||||
// 更新标签
|
||||
router.put(API.updateLabelByIdUsingPut, (req, res) => {
|
||||
const { id } = req.params;
|
||||
const updates = req.body; // 数组形式的更新数据
|
||||
|
||||
updates.forEach((update) => {
|
||||
const index = labelList.findIndex((label) => label.id === update.id);
|
||||
if (index !== -1) {
|
||||
labelList[index] = {
|
||||
...labelList[index],
|
||||
...update,
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
res.send({
|
||||
code: "0",
|
||||
msg: "Labels updated successfully",
|
||||
data: null,
|
||||
});
|
||||
});
|
||||
};
|
||||
58
frontend/src/mock/mock.cjs
Normal file
58
frontend/src/mock/mock.cjs
Normal file
@@ -0,0 +1,58 @@
|
||||
const express = require('express');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const bodyParser = require('body-parser');
|
||||
const { genExpressSession } = require('./mock-core/session-helper.cjs');
|
||||
const {
|
||||
setHeader,
|
||||
sendJSON,
|
||||
strongMatch,
|
||||
errorHandle,
|
||||
} = require('./mock-middleware/index.cjs');
|
||||
|
||||
|
||||
const { loadAllMockModules } = require('./mock-core/module-loader.cjs');
|
||||
const { log } = require('./mock-core/util.cjs');
|
||||
|
||||
const app = express();
|
||||
const router = express.Router();
|
||||
|
||||
const argv = require('minimist')(process.argv.slice(2));
|
||||
const deployUrl = argv['deploy-url'] || '/';
|
||||
const deployPath = argv['deploy-path'] || '/';
|
||||
const port = argv.port || 8002;
|
||||
const env = argv.env || 'development';
|
||||
|
||||
// app静态文件实际目录
|
||||
const deployAppPath = path.join(__dirname, deployPath);
|
||||
preStartCheck(deployAppPath);
|
||||
|
||||
app.use(setHeader);
|
||||
|
||||
// 提供静态文件服务
|
||||
app.use(deployUrl, express.static(deployAppPath));
|
||||
app.use(bodyParser.json({limit: '1mb'}));
|
||||
app.use(bodyParser.urlencoded({ extended: false, limit: '1mb' }));
|
||||
app.use(sendJSON);
|
||||
app.use(strongMatch);
|
||||
app.use(genExpressSession());
|
||||
|
||||
const mockDir = path.join(__dirname, '/mock-seed');
|
||||
loadAllMockModules(router, mockDir);
|
||||
app.use(deployUrl, router);
|
||||
app.use(errorHandle);
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
res.sendFile('default response', { root: deployAppPath });
|
||||
});
|
||||
|
||||
app.listen(port, function() {
|
||||
log(`Mock server is running at http://localhost:${port}${deployUrl} in ${env} mode`);
|
||||
})
|
||||
|
||||
function preStartCheck(deployAppPath) {
|
||||
if(!fs.existsSync(deployAppPath)) {
|
||||
log(`Error: The path ${deployAppPath} does not exist. Please build the frontend application first.`, 'error');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
22
frontend/src/mock/nodemon.json
Normal file
22
frontend/src/mock/nodemon.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"restartable": "rs",
|
||||
"ignore": [
|
||||
".git",
|
||||
"node_modules/**/node_modules",
|
||||
"dist",
|
||||
"build",
|
||||
"*.test.js",
|
||||
"*.spec.js"
|
||||
],
|
||||
"verbose": true,
|
||||
"watch": ["*.cjs"],
|
||||
"exec": "node --inspect=0.0.0.0:9229 mock.cjs",
|
||||
"ext": "js,cjs,json",
|
||||
"execMap": {
|
||||
"js": "node --harmony"
|
||||
},
|
||||
"env": {
|
||||
"NODE_ENV": "development"
|
||||
},
|
||||
"signal": "SIGTERM"
|
||||
}
|
||||
196
frontend/src/mock/operator.tsx
Normal file
196
frontend/src/mock/operator.tsx
Normal file
@@ -0,0 +1,196 @@
|
||||
export const mockOperators: Operator[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: "图像预处理算子",
|
||||
version: "1.2.0",
|
||||
description:
|
||||
"支持图像缩放、裁剪、旋转、颜色空间转换等常用预处理操作,优化了内存使用和处理速度",
|
||||
author: "张三",
|
||||
category: "图像处理",
|
||||
modality: ["image"],
|
||||
type: "preprocessing",
|
||||
tags: ["图像处理", "预处理", "缩放", "裁剪", "旋转"],
|
||||
createdAt: "2024-01-15",
|
||||
lastModified: "2024-01-23",
|
||||
status: "active",
|
||||
isFavorited: true,
|
||||
downloads: 1247,
|
||||
usage: 856,
|
||||
framework: "PyTorch",
|
||||
language: "Python",
|
||||
size: "2.3MB",
|
||||
dependencies: ["opencv-python", "pillow", "numpy"],
|
||||
inputFormat: ["jpg", "png", "bmp", "tiff"],
|
||||
outputFormat: ["jpg", "png", "tensor"],
|
||||
performance: {
|
||||
accuracy: 99.5,
|
||||
speed: "50ms/image",
|
||||
memory: "128MB",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "文本分词算子",
|
||||
version: "2.1.3",
|
||||
description:
|
||||
"基于深度学习的中文分词算子,支持自定义词典,在医学文本上表现优异",
|
||||
author: "李四",
|
||||
category: "自然语言处理",
|
||||
modality: ["text"],
|
||||
type: "preprocessing",
|
||||
tags: ["文本处理", "分词", "中文", "NLP", "医学"],
|
||||
createdAt: "2024-01-10",
|
||||
lastModified: "2024-01-20",
|
||||
status: "active",
|
||||
isFavorited: false,
|
||||
downloads: 892,
|
||||
usage: 634,
|
||||
framework: "TensorFlow",
|
||||
language: "Python",
|
||||
size: "15.6MB",
|
||||
dependencies: ["tensorflow", "jieba", "transformers"],
|
||||
inputFormat: ["txt", "json", "csv"],
|
||||
outputFormat: ["json", "txt"],
|
||||
performance: {
|
||||
accuracy: 96.8,
|
||||
speed: "10ms/sentence",
|
||||
memory: "256MB",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "音频特征提取",
|
||||
version: "1.0.5",
|
||||
description: "提取音频的MFCC、梅尔频谱、色度等特征,支持多种音频格式",
|
||||
author: "王五",
|
||||
category: "音频处理",
|
||||
modality: ["audio"],
|
||||
type: "preprocessing",
|
||||
tags: ["音频处理", "特征提取", "MFCC", "频谱分析"],
|
||||
createdAt: "2024-01-08",
|
||||
lastModified: "2024-01-18",
|
||||
status: "active",
|
||||
isFavorited: true,
|
||||
downloads: 456,
|
||||
usage: 312,
|
||||
framework: "PyTorch",
|
||||
language: "Python",
|
||||
size: "8.9MB",
|
||||
dependencies: ["librosa", "scipy", "numpy"],
|
||||
inputFormat: ["wav", "mp3", "flac", "m4a"],
|
||||
outputFormat: ["npy", "json", "csv"],
|
||||
performance: {
|
||||
speed: "2x实时",
|
||||
memory: "64MB",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "视频帧提取算子",
|
||||
version: "1.3.2",
|
||||
description: "高效的视频帧提取算子,支持关键帧检测和均匀采样",
|
||||
author: "赵六",
|
||||
category: "视频处理",
|
||||
modality: ["video"],
|
||||
type: "preprocessing",
|
||||
tags: ["视频处理", "帧提取", "关键帧", "采样"],
|
||||
createdAt: "2024-01-05",
|
||||
lastModified: "2024-01-22",
|
||||
status: "active",
|
||||
isFavorited: false,
|
||||
downloads: 723,
|
||||
usage: 445,
|
||||
framework: "OpenCV",
|
||||
language: "Python",
|
||||
size: "12.4MB",
|
||||
dependencies: ["opencv-python", "ffmpeg-python"],
|
||||
inputFormat: ["mp4", "avi", "mov", "mkv"],
|
||||
outputFormat: ["jpg", "png", "npy"],
|
||||
performance: {
|
||||
speed: "30fps处理",
|
||||
memory: "512MB",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "多模态融合算子",
|
||||
version: "2.0.1",
|
||||
description: "支持文本、图像、音频多模态数据融合的深度学习算子",
|
||||
author: "孙七",
|
||||
category: "多模态处理",
|
||||
modality: ["text", "image", "audio"],
|
||||
type: "training",
|
||||
tags: ["多模态", "融合", "深度学习", "注意力机制"],
|
||||
createdAt: "2024-01-12",
|
||||
lastModified: "2024-01-21",
|
||||
status: "beta",
|
||||
isFavorited: false,
|
||||
downloads: 234,
|
||||
usage: 156,
|
||||
framework: "PyTorch",
|
||||
language: "Python",
|
||||
size: "45.2MB",
|
||||
dependencies: ["torch", "transformers", "torchvision", "torchaudio"],
|
||||
inputFormat: ["json", "jpg", "wav"],
|
||||
outputFormat: ["tensor", "json"],
|
||||
performance: {
|
||||
accuracy: 94.2,
|
||||
speed: "100ms/sample",
|
||||
memory: "2GB",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "模型推理加速",
|
||||
version: "1.1.0",
|
||||
description: "基于TensorRT的模型推理加速算子,支持多种深度学习框架",
|
||||
author: "周八",
|
||||
category: "模型优化",
|
||||
modality: ["image", "text"],
|
||||
type: "inference",
|
||||
tags: ["推理加速", "TensorRT", "优化", "GPU"],
|
||||
createdAt: "2024-01-03",
|
||||
lastModified: "2024-01-19",
|
||||
status: "active",
|
||||
isFavorited: true,
|
||||
downloads: 567,
|
||||
usage: 389,
|
||||
framework: "TensorRT",
|
||||
language: "Python",
|
||||
size: "23.7MB",
|
||||
dependencies: ["tensorrt", "pycuda", "numpy"],
|
||||
inputFormat: ["onnx", "pb", "pth"],
|
||||
outputFormat: ["tensor", "json"],
|
||||
performance: {
|
||||
speed: "5x加速",
|
||||
memory: "减少40%",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "数据增强算子",
|
||||
version: "1.4.1",
|
||||
description: "丰富的数据增强策略,包括几何变换、颜色变换、噪声添加等",
|
||||
author: "吴九",
|
||||
category: "数据增强",
|
||||
modality: ["image"],
|
||||
type: "preprocessing",
|
||||
tags: ["数据增强", "几何变换", "颜色变换", "噪声"],
|
||||
createdAt: "2024-01-01",
|
||||
lastModified: "2024-01-17",
|
||||
status: "active",
|
||||
isFavorited: false,
|
||||
downloads: 934,
|
||||
usage: 678,
|
||||
framework: "Albumentations",
|
||||
language: "Python",
|
||||
size: "6.8MB",
|
||||
dependencies: ["albumentations", "opencv-python", "numpy"],
|
||||
inputFormat: ["jpg", "png", "bmp"],
|
||||
outputFormat: ["jpg", "png", "npy"],
|
||||
performance: {
|
||||
speed: "20ms/image",
|
||||
memory: "32MB",
|
||||
},
|
||||
},
|
||||
];
|
||||
193
frontend/src/mock/ratio.tsx
Normal file
193
frontend/src/mock/ratio.tsx
Normal file
@@ -0,0 +1,193 @@
|
||||
import type { RatioTask } from "@/pages/RatioTask/ratio";
|
||||
|
||||
export const mockRatioTasks: RatioTask[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: "多领域数据配比任务",
|
||||
status: "completed",
|
||||
progress: 100,
|
||||
sourceDatasets: [
|
||||
"orig_20250724_64082",
|
||||
"financial_qa_dataset",
|
||||
"medical_corpus",
|
||||
],
|
||||
targetCount: 10000,
|
||||
generatedCount: 10000,
|
||||
createdAt: "2025-01-24",
|
||||
ratioType: "dataset",
|
||||
estimatedTime: "已完成",
|
||||
quality: 94,
|
||||
ratioConfigs: [
|
||||
{
|
||||
id: "1",
|
||||
name: "通用文本",
|
||||
type: "dataset",
|
||||
quantity: 4000,
|
||||
percentage: 40,
|
||||
source: "orig_20250724_64082",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "金融问答",
|
||||
type: "dataset",
|
||||
quantity: 3000,
|
||||
percentage: 30,
|
||||
source: "financial_qa_dataset",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "医疗语料",
|
||||
type: "dataset",
|
||||
quantity: 3000,
|
||||
percentage: 30,
|
||||
source: "medical_corpus",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "标签配比训练集",
|
||||
status: "running",
|
||||
progress: 68,
|
||||
sourceDatasets: ["teacher_model_outputs", "image_text_pairs"],
|
||||
targetCount: 8000,
|
||||
generatedCount: 5440,
|
||||
createdAt: "2025-01-25",
|
||||
ratioType: "label",
|
||||
estimatedTime: "剩余 12 分钟",
|
||||
quality: 89,
|
||||
ratioConfigs: [
|
||||
{
|
||||
id: "1",
|
||||
name: "问答",
|
||||
type: "label",
|
||||
quantity: 2500,
|
||||
percentage: 31.25,
|
||||
source: "teacher_model_outputs_问答",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "推理",
|
||||
type: "label",
|
||||
quantity: 2000,
|
||||
percentage: 25,
|
||||
source: "teacher_model_outputs_推理",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "图像",
|
||||
type: "label",
|
||||
quantity: 1800,
|
||||
percentage: 22.5,
|
||||
source: "image_text_pairs_图像",
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
name: "描述",
|
||||
type: "label",
|
||||
quantity: 1700,
|
||||
percentage: 21.25,
|
||||
source: "image_text_pairs_描述",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "平衡数据集配比",
|
||||
status: "failed",
|
||||
progress: 25,
|
||||
sourceDatasets: ["orig_20250724_64082", "financial_qa_dataset"],
|
||||
targetCount: 5000,
|
||||
generatedCount: 1250,
|
||||
createdAt: "2025-01-25",
|
||||
ratioType: "dataset",
|
||||
errorMessage: "数据源连接失败,请检查数据集状态",
|
||||
ratioConfigs: [
|
||||
{
|
||||
id: "1",
|
||||
name: "通用文本",
|
||||
type: "dataset",
|
||||
quantity: 2500,
|
||||
percentage: 50,
|
||||
source: "orig_20250724_64082",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "金融问答",
|
||||
type: "dataset",
|
||||
quantity: 2500,
|
||||
percentage: 50,
|
||||
source: "financial_qa_dataset",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "文本分类配比任务",
|
||||
status: "pending",
|
||||
progress: 0,
|
||||
sourceDatasets: ["text_classification_data", "sentiment_analysis_data"],
|
||||
targetCount: 6000,
|
||||
generatedCount: 0,
|
||||
createdAt: "2025-01-26",
|
||||
ratioType: "label",
|
||||
estimatedTime: "预计 15 分钟",
|
||||
ratioConfigs: [
|
||||
{
|
||||
id: "1",
|
||||
name: "正面",
|
||||
type: "label",
|
||||
quantity: 2000,
|
||||
percentage: 33.33,
|
||||
source: "sentiment_analysis_data_正面",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "负面",
|
||||
type: "label",
|
||||
quantity: 2000,
|
||||
percentage: 33.33,
|
||||
source: "sentiment_analysis_data_负面",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "中性",
|
||||
type: "label",
|
||||
quantity: 2000,
|
||||
percentage: 33.33,
|
||||
source: "sentiment_analysis_data_中性",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "多模态数据配比",
|
||||
status: "paused",
|
||||
progress: 45,
|
||||
sourceDatasets: ["image_caption_data", "video_description_data"],
|
||||
targetCount: 12000,
|
||||
generatedCount: 5400,
|
||||
createdAt: "2025-01-23",
|
||||
ratioType: "dataset",
|
||||
estimatedTime: "已暂停",
|
||||
quality: 91,
|
||||
ratioConfigs: [
|
||||
{
|
||||
id: "1",
|
||||
name: "图像描述",
|
||||
type: "dataset",
|
||||
quantity: 7000,
|
||||
percentage: 58.33,
|
||||
source: "image_caption_data",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "视频描述",
|
||||
type: "dataset",
|
||||
quantity: 5000,
|
||||
percentage: 41.67,
|
||||
source: "video_description_data",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
209
frontend/src/mock/synthesis.tsx
Normal file
209
frontend/src/mock/synthesis.tsx
Normal file
@@ -0,0 +1,209 @@
|
||||
// Add mock files data
|
||||
export const mockFiles = [
|
||||
{ id: "file1", name: "dataset_part_001.jsonl", size: "2.5MB", type: "JSONL" },
|
||||
{ id: "file2", name: "dataset_part_002.jsonl", size: "2.3MB", type: "JSONL" },
|
||||
{ id: "file3", name: "dataset_part_003.jsonl", size: "2.7MB", type: "JSONL" },
|
||||
{ id: "file4", name: "training_data.txt", size: "1.8MB", type: "TXT" },
|
||||
{ id: "file5", name: "validation_set.csv", size: "856KB", type: "CSV" },
|
||||
{ id: "file6", name: "test_samples.json", size: "1.2MB", type: "JSON" },
|
||||
{ id: "file7", name: "raw_text_001.txt", size: "3.1MB", type: "TXT" },
|
||||
{ id: "file8", name: "raw_text_002.txt", size: "2.9MB", type: "TXT" },
|
||||
];
|
||||
|
||||
export const mockSynthesisTasks: SynthesisTask[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: "文字生成问答对_判断题",
|
||||
type: "qa",
|
||||
status: "completed",
|
||||
progress: 100,
|
||||
sourceDataset: "orig_20250724_64082",
|
||||
targetCount: 1000,
|
||||
generatedCount: 1000,
|
||||
createdAt: "2025-01-20",
|
||||
template: "判断题生成模板",
|
||||
estimatedTime: "已完成",
|
||||
quality: 95,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "知识蒸馏数据集",
|
||||
type: "distillation",
|
||||
status: "running",
|
||||
progress: 65,
|
||||
sourceDataset: "teacher_model_outputs",
|
||||
targetCount: 5000,
|
||||
generatedCount: 3250,
|
||||
createdAt: "2025-01-22",
|
||||
template: "蒸馏模板v2",
|
||||
estimatedTime: "剩余 15 分钟",
|
||||
quality: 88,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "多模态对话生成",
|
||||
type: "multimodal",
|
||||
status: "failed",
|
||||
progress: 25,
|
||||
sourceDataset: "image_text_pairs",
|
||||
targetCount: 2000,
|
||||
generatedCount: 500,
|
||||
createdAt: "2025-01-23",
|
||||
template: "多模态对话模板",
|
||||
errorMessage: "模型API调用失败,请检查配置",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "金融问答数据生成",
|
||||
type: "qa",
|
||||
status: "pending",
|
||||
progress: 0,
|
||||
sourceDataset: "financial_qa_dataset",
|
||||
targetCount: 800,
|
||||
generatedCount: 0,
|
||||
createdAt: "2025-01-24",
|
||||
template: "金融问答模板",
|
||||
estimatedTime: "等待开始",
|
||||
quality: 0,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "医疗文本蒸馏",
|
||||
type: "distillation",
|
||||
status: "paused",
|
||||
progress: 45,
|
||||
sourceDataset: "medical_corpus",
|
||||
targetCount: 3000,
|
||||
generatedCount: 1350,
|
||||
createdAt: "2025-01-21",
|
||||
template: "医疗蒸馏模板",
|
||||
estimatedTime: "已暂停",
|
||||
quality: 92,
|
||||
},
|
||||
];
|
||||
|
||||
export const mockTemplates: Template[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: "判断题生成模板",
|
||||
type: "preset",
|
||||
category: "问答对生成",
|
||||
prompt: `根据给定的文本内容,生成一个判断题。
|
||||
|
||||
文本内容:{text}
|
||||
|
||||
请按照以下格式生成:
|
||||
1. 判断题:[基于文本内容的判断题]
|
||||
2. 答案:[对/错]
|
||||
3. 解释:[简要解释为什么这个答案是正确的]
|
||||
|
||||
要求:
|
||||
- 判断题应该基于文本的核心内容
|
||||
- 答案必须明确且有依据
|
||||
- 解释要简洁清晰`,
|
||||
variables: ["text"],
|
||||
description: "根据文本内容生成判断题,适用于教育和培训场景",
|
||||
usageCount: 156,
|
||||
lastUsed: "2025-01-20",
|
||||
quality: 95,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "选择题生成模板",
|
||||
type: "preset",
|
||||
category: "问答对生成",
|
||||
prompt: `基于以下文本,创建一个多选题:
|
||||
|
||||
{text}
|
||||
|
||||
请按照以下格式生成:
|
||||
问题:[基于文本的问题]
|
||||
A. [选项A]
|
||||
B. [选项B]
|
||||
C. [选项C]
|
||||
D. [选项D]
|
||||
正确答案:[A/B/C/D]
|
||||
解析:[详细解释]
|
||||
|
||||
要求:
|
||||
- 问题要有一定难度
|
||||
- 选项要有迷惑性
|
||||
- 正确答案要有充分依据`,
|
||||
variables: ["text"],
|
||||
description: "生成多选题的标准模板,适用于考试和评估",
|
||||
usageCount: 89,
|
||||
lastUsed: "2025-01-19",
|
||||
quality: 92,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "知识蒸馏模板",
|
||||
type: "preset",
|
||||
category: "蒸馏数据集",
|
||||
prompt: `作为学生模型,学习教师模型的输出:
|
||||
|
||||
输入:{input}
|
||||
教师输出:{teacher_output}
|
||||
|
||||
请模仿教师模型的推理过程和输出格式,生成相似质量的回答。
|
||||
|
||||
要求:
|
||||
- 保持教师模型的推理逻辑
|
||||
- 输出格式要一致
|
||||
- 质量要接近教师模型水平`,
|
||||
variables: ["input", "teacher_output"],
|
||||
description: "用于知识蒸馏的模板,帮助小模型学习大模型的能力",
|
||||
usageCount: 234,
|
||||
lastUsed: "2025-01-22",
|
||||
quality: 88,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "金融问答模板",
|
||||
type: "custom",
|
||||
category: "问答对生成",
|
||||
prompt: `基于金融领域知识,生成专业问答对:
|
||||
|
||||
参考内容:{content}
|
||||
|
||||
生成格式:
|
||||
问题:[专业的金融问题]
|
||||
答案:[准确的专业回答]
|
||||
关键词:[相关金融术语]
|
||||
|
||||
要求:
|
||||
- 问题具有实用性
|
||||
- 答案准确专业
|
||||
- 符合金融行业标准`,
|
||||
variables: ["content"],
|
||||
description: "专门用于金融领域的问答对生成",
|
||||
usageCount: 45,
|
||||
lastUsed: "2025-01-18",
|
||||
quality: 89,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "医疗蒸馏模板",
|
||||
type: "custom",
|
||||
category: "蒸馏数据集",
|
||||
prompt: `医疗知识蒸馏模板:
|
||||
|
||||
原始医疗文本:{medical_text}
|
||||
专家标注:{expert_annotation}
|
||||
|
||||
生成医疗知识点:
|
||||
1. 核心概念:[提取关键医疗概念]
|
||||
2. 临床意义:[说明临床应用价值]
|
||||
3. 注意事项:[重要提醒和禁忌]
|
||||
|
||||
要求:
|
||||
- 确保医疗信息准确性
|
||||
- 遵循医疗伦理规范
|
||||
- 适合医学教育使用`,
|
||||
variables: ["medical_text", "expert_annotation"],
|
||||
description: "医疗领域专用的知识蒸馏模板",
|
||||
usageCount: 67,
|
||||
lastUsed: "2025-01-21",
|
||||
quality: 94,
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user