| @@ -0,0 +1,338 @@ | |||
| import { defineMock } from 'umi'; | |||
| export default defineMock({ | |||
| 'POST /api/mmp/modelDependency/queryModelAtlas': { | |||
| code: 200, | |||
| msg: '操作成功', | |||
| data: { | |||
| current_model_id: 29, | |||
| exp_ins_id: 229, | |||
| version: 'v0.2.0', | |||
| ref_item: null, | |||
| train_task: { | |||
| name: '模型训练测试导出0529', | |||
| ins_id: 229, | |||
| task_id: 'model-train-5d76f002', | |||
| }, | |||
| train_dataset: [ | |||
| { | |||
| dataset_id: 20, | |||
| dataset_version: 'v0.1.0', | |||
| dataset_name: '手写体识别模型依赖测试训练数据集', | |||
| }, | |||
| ], | |||
| train_params: ['256', '2'], | |||
| train_image: '172.20.32.187/machine-learning/pytorch:pytorch_1.9.1_cuda11.1_detection_aim', | |||
| test_dataset: [ | |||
| { | |||
| dataset_id: 20, | |||
| dataset_version: 'v0.1.0', | |||
| dataset_name: '手写体识别模型依赖测试训练数据集', | |||
| }, | |||
| ], | |||
| project_dependency: { | |||
| url: 'https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git', | |||
| name: 'somun202304241505581', | |||
| branch: 'train_ci_test', | |||
| }, | |||
| parent_models_map: [ | |||
| { | |||
| model_id: 29, | |||
| model_version: 'v0.1.0', | |||
| model_name: 'mnist模型演化', | |||
| }, | |||
| ], | |||
| parent_models: [ | |||
| { | |||
| current_model_id: 29, | |||
| exp_ins_id: null, | |||
| version: 'v0.1.0', | |||
| ref_item: null, | |||
| train_task: {}, | |||
| train_dataset: [], | |||
| train_params: [], | |||
| train_image: null, | |||
| test_dataset: [], | |||
| project_dependency: {}, | |||
| parent_models_map: [], | |||
| parent_models: [], | |||
| children_models: null, | |||
| workflow_id: null, | |||
| model_version_dependcy_vo: { | |||
| name: 'mnist模型演化', | |||
| description: '手写体识别模型演化', | |||
| available_range: 0, | |||
| model_type: '37', | |||
| model_tag: '46', | |||
| model_type_name: 'PyTorch', | |||
| model_tag_name: '图像转文本', | |||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||
| file_name: 'mnist_epoch1_0.00.pkl', | |||
| file_size: '176.63 KB', | |||
| create_by: 'admin', | |||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||
| }, | |||
| }, | |||
| ], | |||
| children_models: [ | |||
| { | |||
| current_model_id: 29, | |||
| exp_ins_id: null, | |||
| version: 'v0.3.0', | |||
| ref_item: null, | |||
| train_task: {}, | |||
| train_dataset: [], | |||
| train_params: [], | |||
| train_image: null, | |||
| test_dataset: [], | |||
| project_dependency: {}, | |||
| parent_models_map: [], | |||
| parent_models: [], | |||
| children_models: [], | |||
| workflow_id: null, | |||
| model_version_dependcy_vo: { | |||
| name: 'mnist模型演化', | |||
| description: '手写体识别模型演化', | |||
| available_range: 0, | |||
| model_type: '37', | |||
| model_tag: '46', | |||
| model_type_name: 'PyTorch', | |||
| model_tag_name: '图像转文本', | |||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||
| file_name: 'mnist_epoch1_0.00.pkl', | |||
| file_size: '176.63 KB', | |||
| create_by: 'admin', | |||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||
| }, | |||
| }, | |||
| { | |||
| current_model_id: 29, | |||
| exp_ins_id: null, | |||
| version: 'v0.31.0', | |||
| ref_item: null, | |||
| train_task: {}, | |||
| train_dataset: [], | |||
| train_params: [], | |||
| train_image: null, | |||
| test_dataset: [], | |||
| project_dependency: {}, | |||
| parent_models_map: [], | |||
| parent_models: [], | |||
| children_models: [], | |||
| workflow_id: null, | |||
| model_version_dependcy_vo: { | |||
| name: 'mnist模型演化', | |||
| description: '手写体识别模型演化', | |||
| available_range: 0, | |||
| model_type: '37', | |||
| model_tag: '46', | |||
| model_type_name: 'PyTorch', | |||
| model_tag_name: '图像转文本', | |||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||
| file_name: 'mnist_epoch1_0.00.pkl', | |||
| file_size: '176.63 KB', | |||
| create_by: 'admin', | |||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||
| }, | |||
| }, | |||
| { | |||
| current_model_id: 29, | |||
| exp_ins_id: null, | |||
| version: 'v0.4.0', | |||
| ref_item: null, | |||
| train_task: {}, | |||
| train_dataset: [], | |||
| train_params: [], | |||
| train_image: null, | |||
| test_dataset: [], | |||
| project_dependency: {}, | |||
| parent_models_map: [], | |||
| parent_models: [], | |||
| children_models: [ | |||
| { | |||
| current_model_id: 29, | |||
| exp_ins_id: null, | |||
| version: 'v0.6.0', | |||
| ref_item: null, | |||
| train_task: {}, | |||
| train_dataset: [], | |||
| train_params: [], | |||
| train_image: null, | |||
| test_dataset: [], | |||
| project_dependency: {}, | |||
| parent_models_map: [], | |||
| parent_models: [], | |||
| children_models: [], | |||
| workflow_id: null, | |||
| model_version_dependcy_vo: { | |||
| name: 'mnist模型演化', | |||
| description: '手写体识别模型演化', | |||
| available_range: 0, | |||
| model_type: '37', | |||
| model_tag: '46', | |||
| model_type_name: 'PyTorch', | |||
| model_tag_name: '图像转文本', | |||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||
| file_name: 'mnist_epoch1_0.00.pkl', | |||
| file_size: '176.63 KB', | |||
| create_by: 'admin', | |||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||
| }, | |||
| }, | |||
| { | |||
| current_model_id: 29, | |||
| exp_ins_id: null, | |||
| version: 'v0.7.0', | |||
| ref_item: null, | |||
| train_task: {}, | |||
| train_dataset: [], | |||
| train_params: [], | |||
| train_image: null, | |||
| test_dataset: [], | |||
| project_dependency: {}, | |||
| parent_models_map: [], | |||
| parent_models: [], | |||
| children_models: [], | |||
| workflow_id: null, | |||
| model_version_dependcy_vo: { | |||
| name: 'mnist模型演化', | |||
| description: '手写体识别模型演化', | |||
| available_range: 0, | |||
| model_type: '37', | |||
| model_tag: '46', | |||
| model_type_name: 'PyTorch', | |||
| model_tag_name: '图像转文本', | |||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||
| file_name: 'mnist_epoch1_0.00.pkl', | |||
| file_size: '176.63 KB', | |||
| create_by: 'admin', | |||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||
| }, | |||
| }, | |||
| ], | |||
| workflow_id: null, | |||
| model_version_dependcy_vo: { | |||
| name: 'mnist模型演化', | |||
| description: '手写体识别模型演化', | |||
| available_range: 0, | |||
| model_type: '37', | |||
| model_tag: '46', | |||
| model_type_name: 'PyTorch', | |||
| model_tag_name: '图像转文本', | |||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||
| file_name: 'mnist_epoch1_0.00.pkl', | |||
| file_size: '176.63 KB', | |||
| create_by: 'admin', | |||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||
| }, | |||
| }, | |||
| { | |||
| current_model_id: 29, | |||
| exp_ins_id: null, | |||
| version: 'v0.5.0', | |||
| ref_item: null, | |||
| train_task: {}, | |||
| train_dataset: [], | |||
| train_params: [], | |||
| train_image: null, | |||
| test_dataset: [], | |||
| project_dependency: {}, | |||
| parent_models_map: [], | |||
| parent_models: [], | |||
| children_models: [ | |||
| { | |||
| current_model_id: 29, | |||
| exp_ins_id: null, | |||
| version: 'v0.10.0', | |||
| ref_item: null, | |||
| train_task: {}, | |||
| train_dataset: [], | |||
| train_params: [], | |||
| train_image: null, | |||
| test_dataset: [], | |||
| project_dependency: {}, | |||
| parent_models_map: [], | |||
| parent_models: [], | |||
| children_models: [], | |||
| workflow_id: null, | |||
| model_version_dependcy_vo: { | |||
| name: 'mnist模型演化', | |||
| description: '手写体识别模型演化', | |||
| available_range: 0, | |||
| model_type: '37', | |||
| model_tag: '46', | |||
| model_type_name: 'PyTorch', | |||
| model_tag_name: '图像转文本', | |||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||
| file_name: 'mnist_epoch1_0.00.pkl', | |||
| file_size: '176.63 KB', | |||
| create_by: 'admin', | |||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||
| }, | |||
| }, | |||
| { | |||
| current_model_id: 29, | |||
| exp_ins_id: null, | |||
| version: 'v0.11.0', | |||
| ref_item: null, | |||
| train_task: {}, | |||
| train_dataset: [], | |||
| train_params: [], | |||
| train_image: null, | |||
| test_dataset: [], | |||
| project_dependency: {}, | |||
| parent_models_map: [], | |||
| parent_models: [], | |||
| children_models: [], | |||
| workflow_id: null, | |||
| model_version_dependcy_vo: { | |||
| name: 'mnist模型演化', | |||
| description: '手写体识别模型演化', | |||
| available_range: 0, | |||
| model_type: '37', | |||
| model_tag: '46', | |||
| model_type_name: 'PyTorch', | |||
| model_tag_name: '图像转文本', | |||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||
| file_name: 'mnist_epoch1_0.00.pkl', | |||
| file_size: '176.63 KB', | |||
| create_by: 'admin', | |||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||
| }, | |||
| }, | |||
| ], | |||
| workflow_id: null, | |||
| model_version_dependcy_vo: { | |||
| name: 'mnist模型演化', | |||
| description: '手写体识别模型演化', | |||
| available_range: 0, | |||
| model_type: '37', | |||
| model_tag: '46', | |||
| model_type_name: 'PyTorch', | |||
| model_tag_name: '图像转文本', | |||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||
| file_name: 'mnist_epoch1_0.00.pkl', | |||
| file_size: '176.63 KB', | |||
| create_by: 'admin', | |||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||
| }, | |||
| }, | |||
| ], | |||
| workflow_id: 144, | |||
| model_version_dependcy_vo: { | |||
| name: 'mnist模型演化', | |||
| description: '手写体识别模型演化', | |||
| available_range: 0, | |||
| model_type: '37', | |||
| model_tag: '46', | |||
| model_type_name: 'PyTorch', | |||
| model_tag_name: '图像转文本', | |||
| url: 'models/admin/1718172760650/mnist_cnn.pt', | |||
| file_name: 'mnist_cnn.pt', | |||
| file_size: '176.76 KB', | |||
| create_by: 'admin', | |||
| create_time: '2024-06-12T06:12:42.000+00:00', | |||
| }, | |||
| }, | |||
| }, | |||
| }); | |||
| @@ -33,7 +33,7 @@ | |||
| "serve": "umi-serve", | |||
| "start": "cross-env UMI_ENV=dev max dev", | |||
| "start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev max dev", | |||
| "start:no-mock": "cross-env MOCK=none UMI_ENV=dev max dev", | |||
| "start:mock": "cross-env REACT_APP_ENV=dev UMI_ENV=dev max dev", | |||
| "start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev max dev", | |||
| "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev max dev", | |||
| "test": "jest", | |||
| @@ -9,8 +9,8 @@ export const vGap = nodeHeight + 20; | |||
| export const hGap = nodeHeight + 20; | |||
| export const ellipseWidth = nodeWidth; | |||
| // 数据集节点矩形数组 | |||
| const datasetRects: Rect[] = []; | |||
| // 数据集节点 | |||
| const datasetNodes: NodeConfig[] = []; | |||
| export enum NodeType { | |||
| current = 'current', | |||
| @@ -22,8 +22,8 @@ export enum NodeType { | |||
| } | |||
| export type Rect = { | |||
| x: number; | |||
| y: number; | |||
| x: number; // 矩形中心的 x 坐标 | |||
| y: number; // 矩形中心的 y 坐标 | |||
| width: number; | |||
| height: number; | |||
| }; | |||
| @@ -142,14 +142,6 @@ export function normalizeTreeData(apiData: ModelDepsAPIData): ModelDepsData { | |||
| normalizedData.id = `$M_${normalizedData.current_model_id}_${normalizedData.version}`; | |||
| normalizedData.label = getLabel(normalizedData); | |||
| normalizedData.style = getStyle(NodeType.current); | |||
| // let first1 = { ...normalizedData.children[0] }; | |||
| // let first2 = { ...normalizedData.children[0] }; | |||
| // let first3 = { ...normalizedData.children[0] }; | |||
| // first1.current_model_id = 202020; | |||
| // first2.current_model_id = 202021; | |||
| // first3.current_model_id = 202022; | |||
| // normalizedData.children.push(first1, first2, first3); | |||
| normalizeChildren(normalizedData.children as ModelDepsData[]); | |||
| // 将 parent_models 转换成树形结构 | |||
| @@ -191,14 +183,12 @@ export function getGraphData(data: ModelDepsData): GraphData { | |||
| const edges: EdgeConfig[] = []; | |||
| Util.traverseTree(treeLayoutData, (node: NodeConfig, parent: NodeConfig) => { | |||
| const data = node.data as ModelDepsData; | |||
| console.log('data', data); | |||
| // 当前模型显示数据集和项目 | |||
| if (data.model_type === NodeType.current) { | |||
| addDatasetDependency(data, node, nodes, edges); | |||
| addProjectDependency(data, node, nodes, edges); | |||
| } else if (data.model_type === NodeType.children) { | |||
| adjustChildrenPosition(node); | |||
| adjustDatasetPosition(node); | |||
| } | |||
| nodes.push({ | |||
| ...data, | |||
| @@ -224,17 +214,17 @@ const addDatasetDependency = ( | |||
| ) => { | |||
| const { train_dataset, test_dataset } = data; | |||
| train_dataset.forEach((item) => { | |||
| item.id = `$DTrain_${item.dataset_id}`; | |||
| item.id = `$DTrain_${item.dataset_id}_${item.dataset_version}`; | |||
| item.model_type = NodeType.trainDataset; | |||
| item.style = getStyle(NodeType.trainDataset); | |||
| }); | |||
| test_dataset.forEach((item) => { | |||
| item.id = `$DTest_${item.dataset_id}`; | |||
| item.id = `$DTest_${item.dataset_id}_${item.dataset_version}`; | |||
| item.model_type = NodeType.testDataset; | |||
| item.style = getStyle(NodeType.testDataset); | |||
| }); | |||
| datasetRects.length = 0; | |||
| datasetNodes.length = 0; | |||
| const len = train_dataset.length + test_dataset.length; | |||
| [...train_dataset, ...test_dataset].forEach((item, index) => { | |||
| const node = { ...item }; | |||
| @@ -246,9 +236,10 @@ const addDatasetDependency = ( | |||
| fittingString(node.dataset_version, ellipseWidth - 12, 8); | |||
| const half = len / 2 - 0.5; | |||
| node.x = currentNode.x! - (half - index) * (ellipseWidth + hGap); | |||
| node.x = currentNode.x! - (half - index) * (ellipseWidth + hGap / 2); | |||
| node.y = currentNode.y! - nodeHeight - vGap; | |||
| nodes.push(node); | |||
| datasetNodes.push(node); | |||
| edges.push({ | |||
| source: currentNode.id, | |||
| target: node.id, | |||
| @@ -256,12 +247,6 @@ const addDatasetDependency = ( | |||
| targetAnchor: 3, | |||
| type: 'cubic-vertical', | |||
| }); | |||
| datasetRects.push({ | |||
| x: node.x - ellipseWidth / 2, | |||
| y: node.y - nodeHeight / 2, | |||
| width: ellipseWidth, | |||
| height: nodeHeight, | |||
| }); | |||
| }); | |||
| }; | |||
| @@ -275,7 +260,7 @@ const addProjectDependency = ( | |||
| const { project_dependency } = data; | |||
| if (project_dependency?.url) { | |||
| const node = { ...project_dependency }; | |||
| node.id = `$P_${node.url}`; | |||
| node.id = `$P_${node.url}_${node.branch}`; | |||
| node.model_type = NodeType.project; | |||
| node.type = 'rect'; | |||
| node.label = fittingString(node.name, nodeWidth - 12, 8); | |||
| @@ -296,42 +281,48 @@ const addProjectDependency = ( | |||
| }; | |||
| // 判断两个矩形是否相交 | |||
| function isRectanglesIntersect(rect1: Rect, rect2: Rect) { | |||
| return !( | |||
| rect1.x + rect1.width < rect2.x || | |||
| rect1.x > rect2.x + rect2.width || | |||
| rect1.y + rect1.height < rect2.y || | |||
| rect1.y > rect2.y + rect2.height | |||
| ); | |||
| function isRectanglesOverlap(rect1: Rect, rect2: Rect) { | |||
| const a2x = rect1.x + rect1.width / 2; | |||
| const a2y = rect1.y + rect1.height / 2; | |||
| const b1x = rect2.x - rect2.width / 2; | |||
| const b1y = rect2.y - rect2.height / 2; | |||
| return b1y <= a2y && b1x <= a2x; | |||
| } | |||
| // 判断子节点是否与数据集节点重叠 | |||
| function isChildrenIntersectDataset(rects: Rect[], childrenRect: Rect) { | |||
| for (const r of rects) { | |||
| if (isRectanglesIntersect(r, childrenRect)) { | |||
| return r; | |||
| function isChildrenOverlapDataset(nodes: NodeConfig[], childrenRect: Rect) { | |||
| for (const node of nodes) { | |||
| const rect = { x: node.x!, y: node.y!, width: nodeWidth, height: nodeHeight }; | |||
| if (isRectanglesOverlap(rect, childrenRect)) { | |||
| return childrenRect; | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| // 计算子节点位置 | |||
| function adjustChildrenPosition(node: NodeConfig) { | |||
| // 调整数据集位置 | |||
| function adjustDatasetPosition(node: NodeConfig) { | |||
| const nodeRect = { | |||
| x: node.x! - nodeWidth / 2, | |||
| y: node.y! - nodeHeight / 2, | |||
| x: node.x!, | |||
| y: node.y!, | |||
| width: nodeWidth, | |||
| height: nodeHeight, | |||
| }; | |||
| const overlapRect = isChildrenIntersectDataset(datasetRects, nodeRect); | |||
| const overlapRect = isChildrenOverlapDataset(datasetNodes, nodeRect); | |||
| if (overlapRect) { | |||
| const offsetY = nodeRect.y - overlapRect.y; | |||
| const space = 10; //(vGap + Math.abs(offsetY) - nodeHeight) / 2; | |||
| if (offsetY >= 0) { | |||
| node.y = node.y! + (nodeHeight - offsetY + space); | |||
| } else { | |||
| node.y = node.y! - (nodeHeight - Math.abs(offsetY) + space); | |||
| } | |||
| console.log(node); | |||
| const adjustRect = { | |||
| x: overlapRect.x - nodeWidth - hGap / 2, | |||
| y: overlapRect.y, | |||
| width: overlapRect.width, | |||
| height: overlapRect.height, | |||
| }; | |||
| const lastNode = datasetNodes[datasetNodes.length - 1] as NodeConfig; | |||
| const distance = lastNode.x! - adjustRect.x; | |||
| datasetNodes.forEach((item) => { | |||
| item.x = item.x! - distance; | |||
| }); | |||
| } | |||
| } | |||