Browse Source

feat: 模型演练添加数据集节点

pull/54/head
cp3hnu 1 year ago
parent
commit
06dd4e5a30
50 changed files with 2969 additions and 369 deletions
  1. +3
    -2
      react-ui/src/app.tsx
  2. +26
    -1
      react-ui/src/hooks/index.ts
  3. +15
    -6
      react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx
  4. +22
    -10
      react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx
  5. +6
    -0
      react-ui/src/pages/Dataset/config.tsx
  6. +1
    -1
      react-ui/src/pages/DatasetPreparation/DatasetAnnotation/index.tsx
  7. +43
    -81
      react-ui/src/pages/Experiment/training/index.jsx
  8. +73
    -36
      react-ui/src/pages/Model/components/ModelEvolution/index.tsx
  9. +16
    -11
      react-ui/src/pages/Model/components/NodeTooltips/index.tsx
  10. +67
    -142
      react-ui/src/pages/Pipeline/editPipeline/index.jsx
  11. +9
    -7
      react-ui/src/utils/ui.tsx
  12. +90
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/devEnvironment/DevEnvironmentController.java
  13. +1
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/experiment/ExperimentController.java
  14. +32
    -3
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/jupyter/JupyterController.java
  15. +115
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/model/ModelDependencyController.java
  16. +2
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/model/ModelsVersionController.java
  17. +1
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/workflow/WorkflowController.java
  18. +22
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/Component.java
  19. +213
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/DevEnvironment.java
  20. +247
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/ModelDependency.java
  21. +14
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/dependencydomain/ProjectDepency.java
  22. +17
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/dependencydomain/TrainTaskDepency.java
  23. +84
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/mapper/DevEnvironmentDao.java
  24. +88
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/mapper/ModelDependencyDao.java
  25. +50
    -9
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ExperimentInstanceStatusTask.java
  26. +57
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/DevEnvironmentService.java
  27. +1
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ExperimentInsService.java
  28. +1
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ExperimentService.java
  29. +6
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/JupyterService.java
  30. +65
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ModelDependencyService.java
  31. +2
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ModelsVersionService.java
  32. +1
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/WorkflowService.java
  33. +2
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ComponentServiceImpl.java
  34. +2
    -9
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/DatasetServiceImpl.java
  35. +125
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/DevEnvironmentServiceImpl.java
  36. +3
    -3
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentInsServiceImpl.java
  37. +233
    -22
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentServiceImpl.java
  38. +65
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/JupyterServiceImpl.java
  39. +252
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ModelDependencyServiceImpl.java
  40. +1
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ModelsServiceImpl.java
  41. +39
    -2
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ModelsVersionServiceImpl.java
  42. +3
    -3
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/WorkflowServiceImpl.java
  43. +1
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/WorkspaceServiceImpl.java
  44. +20
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/JacksonUtil.java
  45. +116
    -5
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/K8sClientUtil.java
  46. +72
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/ModelDependcyTreeVo.java
  47. +48
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/ModelVersionDependcyVo.java
  48. +18
    -8
      ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ComponentDaoMapper.xml
  49. +246
    -0
      ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/DevEnvironmentDaoMapper.xml
  50. +333
    -0
      ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ModelDependencyDaoMapper.xml

+ 3
- 2
react-ui/src/app.tsx View File

@@ -21,6 +21,7 @@ import './styles/menu.less';
export { requestConfig as request } from './requestConfig';
// const isDev = process.env.NODE_ENV === 'development';
import { menuItemRender } from '@/utils/menuRender';
import { gotoLoginPage } from './utils/ui';
/**
* @see https://umijs.org/zh-CN/plugins/plugin-initial-state
* */
@@ -45,7 +46,7 @@ export async function getInitialState(): Promise<{
} as API.CurrentUser;
} catch (error) {
console.log(error);
history.push(PageEnum.LOGIN);
gotoLoginPage();
}
return undefined;
};
@@ -97,7 +98,7 @@ export const layout: RuntimeConfig['layout'] = ({ initialState }) => {
const { location } = history;
// 如果没有登录,重定向到 login
if (!initialState?.currentUser && location.pathname !== PageEnum.LOGIN) {
history.push(PageEnum.LOGIN);
gotoLoginPage();
}
},
layoutBgImgList: [


+ 26
- 1
react-ui/src/hooks/index.ts View File

@@ -1,7 +1,7 @@
/*
* @Author: 赵伟
* @Date: 2024-04-15 10:01:29
* @Description:
* @Description: 自定义 hooks
*/
import { FormInstance } from 'antd';
import { debounce } from 'lodash';
@@ -126,3 +126,28 @@ export const useResetFormOnCloseModal = (form: FormInstance, open: boolean) => {
}
}, [form, prevOpen, open]);
};

/**
* Executes the effect function when the specified condition is true.
*
* @param effect - The effect function to execute.
* @param deps - The dependencies for the effect.
* @param when - The condition to trigger the effect.
*/
export const useEffectWhen = (effect: () => void, deps: React.DependencyList, when: boolean) => {
const requestFns = useRef<(() => void)[]>([]);
useEffect(() => {
if (when) {
effect();
} else {
requestFns.current.splice(0, 1, effect);
}
}, deps);

useEffect(() => {
if (when) {
const fn = requestFns.current.pop();
fn?.();
}
}, [when]);
};

+ 15
- 6
react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx View File

@@ -11,14 +11,21 @@ type ResourceIntroProps = {
resourceType: ResourceType;
};

enum TabKeys {
Introduction = '1',
Version = '2',
Evolution = '3',
}

const ResourceIntro = ({ resourceType }: ResourceIntroProps) => {
const [info, setInfo] = useState<ResourceData>({} as ResourceData);
const locationParams = useParams();
const [searchParams] = useSearchParams();
const [versionList, setVersionList] = useState([]);
const [version, setVersion] = useState<string | undefined>(undefined);
const defaultTab = searchParams.get('tab') || '1';
let versionParam = searchParams.get('version');
const [versionList, setVersionList] = useState([]);
const [version, setVersion] = useState<string | undefined>(undefined);
const [activeTab, setActiveTab] = useState<string>(defaultTab);
const resourceId = Number(locationParams.id);
const typeName = resourceConfig[resourceType].name; // 数据集/模型

@@ -67,7 +74,7 @@ const ResourceIntro = ({ resourceType }: ResourceIntroProps) => {

const items = [
{
key: '1',
key: TabKeys.Introduction,
label: `${typeName}简介`,
children: (
<>
@@ -77,7 +84,7 @@ const ResourceIntro = ({ resourceType }: ResourceIntroProps) => {
),
},
{
key: '2',
key: TabKeys.Version,
label: `${typeName}文件/版本`,
children: (
<ResourceVersion
@@ -87,6 +94,7 @@ const ResourceIntro = ({ resourceType }: ResourceIntroProps) => {
isPublic={info.available_range === 1}
versionList={versionList}
version={version}
isActive={activeTab === TabKeys.Version}
getVersionList={getVersionList}
onVersionChange={handleVersionChange}
></ResourceVersion>
@@ -96,7 +104,7 @@ const ResourceIntro = ({ resourceType }: ResourceIntroProps) => {

if (resourceType === ResourceType.Model) {
items.push({
key: '3',
key: TabKeys.Evolution,
label: `模型演化`,
children: (
<ModelEvolution
@@ -104,6 +112,7 @@ const ResourceIntro = ({ resourceType }: ResourceIntroProps) => {
resourceName={info.name}
versionList={versionList}
version={version}
isActive={activeTab === TabKeys.Evolution}
onVersionChange={handleVersionChange}
></ModelEvolution>
),
@@ -136,7 +145,7 @@ const ResourceIntro = ({ resourceType }: ResourceIntroProps) => {
</Flex>
</div>
<div className={styles['resource-intro__bottom']}>
<Tabs defaultActiveKey={defaultTab} items={items}></Tabs>
<Tabs activeKey={activeTab} items={items} onChange={(key) => setActiveTab(key)}></Tabs>
</div>
</div>
);


+ 22
- 10
react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx View File

@@ -1,14 +1,20 @@
import CommonTableCell from '@/components/CommonTableCell';
import DateTableCell from '@/components/DateTableCell';
import KFIcon from '@/components/KFIcon';
import { useEffectWhen } from '@/hooks';
import AddVersionModal from '@/pages/Dataset/components/AddVersionModal';
import { ResourceFileData, ResourceType, resourceConfig } from '@/pages/Dataset/config';
import {
ResourceFileData,
ResourceType,
ResourceVersionData,
resourceConfig,
} from '@/pages/Dataset/config';
import { downLoadZip } from '@/utils/downloadfile';
import { openAntdModal } from '@/utils/modal';
import { to } from '@/utils/promise';
import { modalConfirm } from '@/utils/ui';
import { App, Button, Flex, Select, Table } from 'antd';
import { useEffect, useState } from 'react';
import { useState } from 'react';
import styles from './index.less';

type ResourceVersionProps = {
@@ -16,8 +22,9 @@ type ResourceVersionProps = {
resourceId: number;
resourceName: string;
isPublic: boolean;
versionList: { label: string; value: string }[];
versionList: ResourceVersionData[];
version?: string;
isActive: boolean;
getVersionList: () => void;
onVersionChange: (version: string) => void;
};
@@ -28,6 +35,7 @@ function ResourceVersion({
isPublic,
versionList,
version,
isActive,
getVersionList,
onVersionChange,
}: ResourceVersionProps) {
@@ -35,13 +43,17 @@ function ResourceVersion({
const { message } = App.useApp();

// 获取版本文件列表
useEffect(() => {
if (version) {
getFileList(version);
} else {
setFileList([]);
}
}, [resourceId, version]);
useEffectWhen(
() => {
if (version) {
getFileList(version);
} else {
setFileList([]);
}
},
[resourceId, version],
isActive,
);

// 获取版本下的文件列表
const getFileList = async (version: string) => {


+ 6
- 0
react-ui/src/pages/Dataset/config.tsx View File

@@ -155,6 +155,12 @@ export type ResourceData = {
dataset_tag_name?: string;
};

// 版本数据
export type ResourceVersionData = {
label: string;
value: string;
};

// 版本文件数据
export type ResourceFileData = {
id: number;


+ 1
- 1
react-ui/src/pages/DatasetPreparation/DatasetAnnotation/index.tsx View File

@@ -16,7 +16,7 @@ function DatasetAnnotation() {
};
return (
<div className={styles.container}>
<iframe src={iframeUrl} className={styles.frame}></iframe>
{iframeUrl && <iframe src={iframeUrl} className={styles.frame}></iframe>}
</div>
);
}


+ 43
- 81
react-ui/src/pages/Experiment/training/index.jsx View File

@@ -1,12 +1,13 @@
import { useStateRef, useVisible } from '@/hooks';
import { getExperimentIns } from '@/services/experiment/index.js';
import { getWorkflowById } from '@/services/pipeline/index.js';
import themes from '@/styles/theme.less';
import { fittingString } from '@/utils';
import { elapsedTime, formatDate } from '@/utils/date';
import G6 from '@antv/g6';
import { Button } from 'antd';
import { useEffect, useRef } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { s8 } from '../../../utils';
import ParamsModal from '../components/ViewParamsModal';
import { experimentStatusInfo } from '../status';
import styles from './index.less';
@@ -22,27 +23,22 @@ function ExperimentText() {
const [paramsModalOpen, openParamsModal, closeParamsModal] = useVisible(false);

const graphRef = useRef();
const onDragEnd = (val) => {
console.log(val, 'eee');
const _x = val.x;
const _y = val.y;
const point = graph.getPointByClient(_x, _y);
let model = {};
// 元模型
model = {
...val,
x: point.x,
y: point.y,
id: val.component_name + '-' + s8(),
isCluster: false,
};
graph.addItem('node', model, true);
};
const handlerClick = (e) => {
if (e.target.get('name') !== 'anchor-point' && e.item) {
propsRef.current.showDrawer(e, locationParams.id, messageRef.current);
}
};
// const onDragEnd = (val) => {
// console.log(val, 'eee');
// const _x = val.x;
// const _y = val.y;
// const point = graph.getPointByClient(_x, _y);
// let model = {};
// // 元模型
// model = {
// ...val,
// x: point.x,
// y: point.y,
// id: val.component_name + '-' + s8(),
// isCluster: false,
// };
// graph.addItem('node', model, true);
// };
const getGraphData = (data) => {
if (graph) {
graph.data(data);
@@ -89,32 +85,6 @@ function ExperimentText() {
}, []);

const initGraph = () => {
const fittingString = (str, maxWidth, fontSize) => {
const ellipsis = '...';
const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0];
let currentWidth = 0;
let res = str;
const pattern = new RegExp('[\u4E00-\u9FA5]+'); // distinguish the Chinese charactors and letters
str.split('').forEach((letter, i) => {
if (currentWidth > maxWidth - ellipsisLength) return;
if (pattern.test(letter)) {
// Chinese charactors
currentWidth += fontSize;
} else {
// get the width of single letter according to the fontSize
currentWidth += G6.Util.getLetterWidth(letter, fontSize);
}
if (currentWidth > maxWidth - ellipsisLength) {
res = `${str.substr(0, i)}${ellipsis}`;
}
});
return res;
};
// 获取文本的长度
const getTextSize = (str, maxWidth, fontSize) => {
let width = G6.Util.getTextSize(str, fontSize)[0];
return width > maxWidth ? maxWidth : width;
};
G6.registerNode(
'rect-node',
{
@@ -129,7 +99,6 @@ function ExperimentText() {
);
},
afterDraw(cfg, group) {
// console.log(group, cfg, 12312);
const image = group.addShape('image', {
attrs: {
x: -45,
@@ -158,7 +127,6 @@ function ExperimentText() {
}
const bbox = group.getBBox();
const anchorPoints = this.getAnchorPoints(cfg);
// console.log(anchorPoints);
anchorPoints.forEach((anchorPos, i) => {
group.addShape('circle', {
attrs: {
@@ -179,19 +147,19 @@ function ExperimentText() {

// response the state changes and show/hide the link-point circles
setState(name, value, item) {
const anchorPoints = item
.getContainer()
.findAll((ele) => ele.get('name') === 'anchor-point');
anchorPoints.forEach((point) => {
if (value || point.get('links') > 0) point.show();
else point.hide();
});
// }
const group = item.getContainer();
const shape = group.get('children')[0];
if (name === 'hover') {
if (value) {
shape.attr('stroke', themes['primaryColor']);
} else {
shape.attr('stroke', '#fff');
}
}
},
},
'rect',
);
console.log(graphRef, 'graphRef');
graph = new G6.Graph({
container: graphRef.current,
grid: true,
@@ -209,10 +177,6 @@ function ExperimentText() {
if (e.target.get('name') === 'anchor-point') return false;
return true;
},
// shouldEnd: e => {
// console.log(e);
// return false;
// },
},
// config the shouldBegin and shouldEnd to make sure the create-edge is began and ended at anchor-point circles
'drag-canvas',
@@ -237,7 +201,6 @@ function ExperimentText() {
style: {
fill: '#000',
fontSize: 10,

cursor: 'pointer',
x: -20,
y: 0,
@@ -252,17 +215,6 @@ function ExperimentText() {
lineWidth: 0.5,
},
},
nodeStateStyles: {
nodeSelected: {
fill: 'red',
shadowColor: 'red',
stroke: 'red',
'text-shape': {
fill: 'red',
stroke: 'red',
},
},
},
defaultEdge: {
// type: 'quadratic',
type: 'cubic-vertical',
@@ -308,15 +260,25 @@ function ExperimentText() {
// linkCenter: true,
fitView: true,
minZoom: 0.5,
maxZoom: 3,
fitViewPadding: [320, 320, 220, 320],
maxZoom: 5,
fitViewPadding: 300,
});
graph.on('node:click', (e) => {
if (e.target.get('name') !== 'anchor-point' && e.item) {
propsRef.current.showDrawer(e, locationParams.id, messageRef.current);
}
});
graph.on('node:mouseenter', (e) => {
graph.setItemState(e.item, 'hover', true);
});
graph.on('node:mouseleave', (e) => {
graph.setItemState(e.item, 'hover', false);
});
graph.on('node:click', handlerClick);
window.onresize = () => {
if (!graph || graph.get('destroyed')) return;
if (!graphRef.current || !graphRef.current.scrollWidth || !graphRef.current.scrollHeight)
return;
graph.changeSize(graphRef.current.scrollWidth, graphRef.current.scrollHeight - 20);
if (!graphRef.current) return;
graph.changeSize(graphRef.current.clientWidth, graphRef.current.clientHeight);
graph.fitView();
};
};
return (


+ 73
- 36
react-ui/src/pages/Model/components/ModelEvolution/index.tsx View File

@@ -1,3 +1,5 @@
import { useEffectWhen } from '@/hooks';
import { ResourceVersionData } from '@/pages/Dataset/config';
import { getModelAtlasReq } from '@/services/dataset/index.js';
import themes from '@/styles/theme.less';
import { changePropertyName, fittingString } from '@/utils';
@@ -19,10 +21,11 @@ import { useEffect, useRef, useState } from 'react';
import GraphLegand from '../GraphLegand';
import NodeTooltips from '../NodeTooltips';
import styles from './index.less';

const nodeWidth = 98;
const nodeHeight = 58;
const vGap = 30;
const hGap = 30;
const vGap = 58;
const hGap = 58;

enum NodeType {
current = 'current',
@@ -53,7 +56,18 @@ interface ProjectDependency extends NodeConfig {
model_type: NodeType;
}

export interface ModelDepsAPIData {
type ModalDetail = {
name: string;
available_range: number;
file_name: string;
file_size: string;
description: string;
model_type_name: string;
model_tag_name: string;
create_time: string;
};

interface ModelDepsAPIData {
current_model_id: number;
version: string;
exp_ins_id: number;
@@ -63,11 +77,12 @@ export interface ModelDepsAPIData {
test_dataset: TrainDataset[];
train_dataset: TrainDataset[];
train_task: TrainTask;
model_version_dependcy_vo: ModalDetail;
children_models: ModelDepsAPIData[];
parent_models: ModelDepsAPIData[];
}

interface ModelDepsData extends Omit<ModelDepsAPIData, 'children_models'>, TreeGraphData {
export interface ModelDepsData extends Omit<ModelDepsAPIData, 'children_models'>, TreeGraphData {
children: ModelDepsData[];
}

@@ -75,10 +90,10 @@ interface ModelDepsData extends Omit<ModelDepsAPIData, 'children_models'>, TreeG
function normalizeChildren(data: ModelDepsData[]) {
if (Array.isArray(data)) {
data.forEach((item) => {
item.model_type = NodeType.children;
item.id = `$M_${item.current_model_id}_${item.version}`;
item.label = getLabel(item);
item.style = getStyle(NodeType.children);
item.model_type = NodeType.children;
normalizeChildren(item.children);
});
}
@@ -107,7 +122,7 @@ function getStyle(model_type: NodeType) {
fill = '#b7cfff';
break;
case NodeType.project:
fill = '#0000ff';
fill = '#FA8C16';
break;
case NodeType.trainDataset:
fill = '#ff0000';
@@ -131,11 +146,12 @@ function normalizeTreeData(apiData: ModelDepsAPIData, currentNodeName: string):
}) as ModelDepsData;

// 设置当前模型的数据
normalizedData.label = getLabel(normalizedData);
normalizedData.id = `$M_${normalizedData.current_model_id}_${normalizedData.version}`;
normalizedData.style = getStyle(NodeType.current);
normalizedData.model_type = NodeType.current;
normalizedData.current_model_name = currentNodeName;
normalizedData.id = `$M_${normalizedData.current_model_id}_${normalizedData.version}`;
normalizedData.label = getLabel(normalizedData);
normalizedData.style = getStyle(NodeType.current);

normalizeChildren(normalizedData.children as ModelDepsData[]);

// 将 parent_models 转换成树形结构
@@ -144,8 +160,8 @@ function normalizeTreeData(apiData: ModelDepsAPIData, currentNodeName: string):
const parent = parent_models[0];
normalizedData = {
...parent,
id: `$M_${parent.current_model_id}_${parent.version}`,
model_type: NodeType.parent,
id: `$M_${parent.current_model_id}_${parent.version}`,
label: getLabel(parent),
style: getStyle(NodeType.parent),
children: [
@@ -166,8 +182,8 @@ function getGraphData(data: ModelDepsData): GraphData {
direction: 'LR',
getHeight: () => nodeHeight,
getWidth: () => nodeWidth,
getVGap: () => vGap,
getHGap: () => hGap,
getVGap: () => vGap / 2,
getHGap: () => hGap / 2,
};

// 树形布局计算出坐标
@@ -210,8 +226,8 @@ function getGraphData(data: ModelDepsData): GraphData {
const len = train_dataset.length + test_dataset.length;
[...train_dataset, ...test_dataset].forEach((item, index) => {
const half = len / 2 - 0.5;
item.x = node.x! - (half - index) * (nodeWidth + 30);
item.y = node.y! - nodeHeight - 30;
item.x = node.x! - (half - index) * (nodeWidth + hGap);
item.y = node.y! - nodeHeight - vGap;
nodes.push(item);
edges.push({
source: node.id,
@@ -222,7 +238,7 @@ function getGraphData(data: ModelDepsData): GraphData {
});
});

if (project_dependency.url) {
if (project_dependency?.url) {
project_dependency.id = `$P_${project_dependency.url}`;
project_dependency.model_type = NodeType.project;
project_dependency.type = 'rect';
@@ -230,7 +246,7 @@ function getGraphData(data: ModelDepsData): GraphData {
project_dependency.label = fittingString(project_dependency.name, 48, 8);
project_dependency.style = getStyle(NodeType.project);
project_dependency.x = node.x;
project_dependency.y = node.y! + nodeHeight + 30;
project_dependency.y = node.y! + nodeHeight + vGap;
nodes.push(project_dependency);
edges.push({
source: node.id,
@@ -248,8 +264,9 @@ function getGraphData(data: ModelDepsData): GraphData {
type modeModelEvolutionProps = {
resourceId: number;
resourceName: string;
versionList: { label: string; value: string }[];
versionList: ResourceVersionData[];
version?: string;
isActive: boolean;
onVersionChange: (version: string) => void;
};

@@ -259,6 +276,7 @@ function ModelEvolution({
resourceName,
versionList,
version,
isActive,
onVersionChange,
}: modeModelEvolutionProps) {
const graphRef = useRef<HTMLDivElement>(null);
@@ -283,18 +301,17 @@ function ModelEvolution({
};
}, []);

useEffect(() => {
if (version) {
getModelAtlas();
} else {
graph.data({
nodes: [],
edges: [],
});
graph.render();
graph.fitView();
}
}, [resourceId, version]);
useEffectWhen(
() => {
if (version) {
getModelAtlas();
} else {
clearGraphData();
}
},
[resourceId, version],
isActive,
);

// 初始化图
const initGraph = () => {
@@ -302,7 +319,6 @@ function ModelEvolution({
container: graphRef.current!,
width: graphRef.current!.clientWidth,
height: graphRef.current!.clientHeight,
// animate: false,
fitView: true,
fitViewPadding: [50, 100, 50, 100],
minZoom: 0.5,
@@ -380,10 +396,14 @@ function ModelEvolution({
if (point.x + 300 > canvasWidth) {
point.x = canvasWidth - 300;
}
const zoom = graph.getZoom();
// 更加缩放,调整 tooltip 位置
const offsetY = (nodeHeight * zoom) / 4;

setHoverNodeData(model as ModelDepsData);
setHoverNodeData(model);
setNodeToolTipX(point.x);
setNodeToolTipY(point.y - 240);
// 92: 版本选择器的高度,296: tooltip的高度
setNodeToolTipY(point.y + 92 - 296 - offsetY);
setShowNodeTooltip(true);
});

@@ -395,16 +415,15 @@ function ModelEvolution({

graph.on('node:click', (e: G6GraphEvent) => {
const nodeItem = e.item;
const model = nodeItem.getModel() as ModelDepsChildren;
const model = nodeItem.getModel();
const { model_type } = model;
const { origin } = location;
let url: string = '';
switch (model_type) {
case NodeType.children:
case NodeType.current:
case NodeType.parent: {
const { current_model_id, version } = model as ModelDepsData;
url = `${origin}/dataset/model/${current_model_id}?isPublic=true&tab=3&version=${version}`;
url = `${origin}/dataset/model/${current_model_id}?tab=3&version=${version}`;
break;
}
case NodeType.project: {
@@ -415,7 +434,7 @@ function ModelEvolution({
case NodeType.trainDataset:
case NodeType.testDataset: {
const { dataset_id, dataset_version } = model as TrainDataset;
url = `${origin}/dataset/dataset/${dataset_id}?isPublic=true&tab=2&version=${dataset_version}`;
url = `${origin}/dataset/dataset/${dataset_id}?tab=2&version=${dataset_version}`;
break;
}
default:
@@ -426,6 +445,12 @@ function ModelEvolution({
window.open(url, '_blank');
}
});

// 鼠标滚轮缩放时,隐藏 tooltip
graph.on('wheelzoom', () => {
setShowNodeTooltip(false);
setEnterTooltip(false);
});
};

const handleTooltipsMouseEnter = () => {
@@ -450,9 +475,21 @@ function ModelEvolution({
graph.data(graphData);
graph.render();
graph.fitView();
} else {
clearGraphData();
}
};

// 请求失败或者版本不存在时,清除图形
function clearGraphData() {
graph.data({
nodes: [],
edges: [],
});
graph.render();
graph.fitView();
}

return (
<div className={styles['model-evolution']}>
<Flex align="center" className={styles['model-evolution__top']}>


+ 16
- 11
react-ui/src/pages/Model/components/NodeTooltips/index.tsx View File

@@ -1,5 +1,4 @@
import { useNavigate } from '@umijs/max';
import { useEffect } from 'react';
import { formatDate } from '@/utils/date';
import { ModelDepsData } from '../ModelEvolution';
import styles from './index.less';

@@ -12,12 +11,10 @@ type NodeTooltipsProps = {
};

function NodeTooltips({ data, x, y, onMouseEnter, onMouseLeave }: NodeTooltipsProps) {
const navigate = useNavigate();
useEffect(() => {}, []);

const gotoExperimentPage = () => {
if (data.train_task?.ins_id) {
navigate(`/pipeline/experiment/144/${data.train_task.ins_id}`);
const { origin } = location;
window.open(`${origin}/pipeline/experiment/144/${data.train_task.ins_id}`, '_blank');
}
};

@@ -35,24 +32,32 @@ function NodeTooltips({ data, x, y, onMouseEnter, onMouseLeave }: NodeTooltipsPr
<span className={styles['node-tooltips__row__value']}>{data.current_model_name}</span>
</div>
<div className={styles['node-tooltips__row']}>
<span className={styles['node-tooltips__row__title']}>版本:</span>
<span className={styles['node-tooltips__row__title']}>模型版本:</span>
<span className={styles['node-tooltips__row__value']}>{data.version}</span>
</div>
<div className={styles['node-tooltips__row']}>
<span className={styles['node-tooltips__row__title']}>模型框架:</span>
<span className={styles['node-tooltips__row__value']}>{data.version}</span>
<span className={styles['node-tooltips__row__value']}>
{data.model_version_dependcy_vo?.model_type_name || '--'}
</span>
</div>
<div className={styles['node-tooltips__row']}>
<span className={styles['node-tooltips__row__title']}>模型大小:</span>
<span className={styles['node-tooltips__row__value']}>{data.version}</span>
<span className={styles['node-tooltips__row__value']}>
{data.model_version_dependcy_vo?.file_size || '--'}
</span>
</div>
<div className={styles['node-tooltips__row']}>
<span className={styles['node-tooltips__row__title']}>创建时间:</span>
<span className={styles['node-tooltips__row__value']}>{data.version}</span>
<span className={styles['node-tooltips__row__value']}>
{formatDate(data.model_version_dependcy_vo?.create_time)}
</span>
</div>
<div className={styles['node-tooltips__row']}>
<span className={styles['node-tooltips__row__title']}>模型权限:</span>
<span className={styles['node-tooltips__row__value']}>{data.version}</span>
<span className={styles['node-tooltips__row__value']}>
{data.model_version_dependcy_vo?.available_range === 1 ? '公开' : '私有'}
</span>
</div>
</div>
<div className={styles['node-tooltips__title']}>训练相关信息</div>


+ 67
- 142
react-ui/src/pages/Pipeline/editPipeline/index.jsx View File

@@ -1,6 +1,8 @@
import KFIcon from '@/components/KFIcon';
import { useStateRef, useVisible } from '@/hooks';
import { getWorkflowById, saveWorkflow } from '@/services/pipeline/index.js';
import themes from '@/styles/theme.less';
import { fittingString } from '@/utils';
import { to } from '@/utils/promise';
import G6 from '@antv/g6';
import { App, Button } from 'antd';
@@ -27,6 +29,11 @@ const EditPipeline = () => {
const { message } = App.useApp();
let sourceAnchorIdx, targetAnchorIdx;

useEffect(() => {
initMenu();
getFirstWorkflow(locationParams.id);
}, []);

const onDragEnd = (val) => {
console.log(val);
const _x = val.x;
@@ -103,20 +110,8 @@ const EditPipeline = () => {
});
}, 500);
};
const handlerClick = (e) => {
e.stopPropagation();
if (e.target.get('name') !== 'anchor-point' && e.item) {
graph.setItemState(e.item, 'nodeClicked', true);
const parentNodes = findAllParentNodes(graph, e.item);
// 如果没有打开过全局参数抽屉,获取不到全局参数
const globalParams =
paramsDrawerRef.current.getFieldsValue().global_param || globalParamRef.current;
propsRef.current.showDrawer(e, globalParams, parentNodes);
}
};
const getGraphData = (data) => {
if (graph) {
console.log(data);
graph.data(data);
graph.render();
} else {
@@ -312,49 +307,8 @@ const EditPipeline = () => {

initGraph();
};
useEffect(() => {
initMenu();
getFirstWorkflow(locationParams.id);

return () => {
graph.off('node:mouseenter', (e) => {
graph.setItemState(e.item, 'showAnchors', true);
graph.setItemState(e.item, 'nodeSelected', true);
});
graph.off('node:mouseleave', (e) => {
// this.graph.setItemState(e.item, 'showAnchors', false);
graph.setItemState(e.item, 'nodeSelected', false);
});
// graph.off('dblclick', handlerClick);
};
}, []);
const initGraph = () => {
const fittingString = (str, maxWidth, fontSize) => {
const ellipsis = '...';
const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0];
let currentWidth = 0;
let res = str;
const pattern = new RegExp('[\u4E00-\u9FA5]+'); // distinguish the Chinese charactors and letters
str.split('').forEach((letter, i) => {
if (currentWidth > maxWidth - ellipsisLength) return;
if (pattern.test(letter)) {
// Chinese charactors
currentWidth += fontSize;
} else {
// get the width of single letter according to the fontSize
currentWidth += G6.Util.getLetterWidth(letter, fontSize);
}
if (currentWidth > maxWidth - ellipsisLength) {
res = `${str.substr(0, i)}${ellipsis}`;
}
});
return res;
};
// 获取文本的长度
const getTextSize = (str, maxWidth, fontSize) => {
let width = G6.Util.getTextSize(str, fontSize)[0];
return width > maxWidth ? maxWidth : width;
};
G6.registerNode(
'rect-node',
{
@@ -407,6 +361,7 @@ const EditPipeline = () => {
y: bbox.y + bbox.height * anchorPos[1],
fill: '#fff',
stroke: '#a4a4a5',
cursor: 'crosshair',
},
name: `anchor-point`, // the name, for searching by group.find(ele => ele.get('name') === 'anchor-point')
anchorPointIdx: i, // flag the idx of the anchor-point circle
@@ -420,14 +375,30 @@ const EditPipeline = () => {

// response the state changes and show/hide the link-point circles
setState(name, value, item) {
const anchorPoints = item
.getContainer()
.findAll((ele) => ele.get('name') === 'anchor-point');
anchorPoints.forEach((point) => {
if (value || point.get('links') > 0) point.show();
else point.hide();
});
// }
// const anchorPoints = item
// .getContainer()
// .findAll((ele) => ele.get('name') === 'anchor-point');
// anchorPoints.forEach((point) => {
// if (value || point.get('links') > 0) point.show();
// else point.hide();
// });

const group = item.getContainer();
const shape = group.get('children')[0];
const anchorPoints = group.findAll((ele) => ele.get('name') === 'anchor-point');
if (name === 'hover') {
if (value) {
shape.attr('stroke', themes['primaryColor']);
anchorPoints.forEach((point) => {
point.show();
});
} else {
shape.attr('stroke', '#fff');
anchorPoints.forEach((point) => {
point.hide();
});
}
}
},
},
'rect',
@@ -435,7 +406,6 @@ const EditPipeline = () => {

graph = new G6.Graph({
container: graphRef.current,
grid: true,
width: graphRef.current.clientWidth || 500,
height: graphRef.current.clientHeight || '100%',
animate: false,
@@ -519,20 +489,8 @@ const EditPipeline = () => {
lineWidth: 0.5,
},
},
nodeStateStyles: {
nodeSelected: {
fill: 'red',
shadowColor: 'red',
stroke: 'red',
'text-shape': {
fill: 'red',
stroke: 'red',
},
},
},
defaultEdge: {
// type: 'quadratic',
// type: 'cubic-vertical',
//type: 'cubic-vertical',

style: {
endArrow: {
@@ -575,17 +533,20 @@ const EditPipeline = () => {
// linkCenter: true,
fitView: true,
minZoom: 0.5,
maxZoom: 3,
fitViewPadding: [320, 320, 220, 320],
maxZoom: 5,
fitViewPadding: 300,
});
graph.on('node:click', (e) => {
e.stopPropagation();
if (e.target.get('name') !== 'anchor-point' && e.item) {
// graph.setItemState(e.item, 'nodeClicked', true);
const parentNodes = findAllParentNodes(graph, e.item);
// 如果没有打开过全局参数抽屉,获取不到全局参数
const globalParams =
paramsDrawerRef.current.getFieldsValue().global_param || globalParamRef.current;
propsRef.current.showDrawer(e, globalParams, parentNodes);
}
});
// graph.on('dblclick', (e) => {
// console.log(e.item);
// if (e.item) {
// graph.setItemState(e.item, 'nodeClicked', true);
// handlerClick(e);
// }
// });
graph.on('node:click', handlerClick);
graph.on('aftercreateedge', (e) => {
// update the sourceAnchor and targetAnchor for the newly added edge
graph.updateItem(e.edge, {
@@ -603,59 +564,6 @@ const EditPipeline = () => {
});
});
});
graph.on('node:mouseenter', (e) => {
// this.graph.setItemState(e.item, 'showAnchors', true);
graph.setItemState(e.item, 'nodeSelected', true);
graph.updateItem(e.item, {
// 节点的样式
style: {
stroke: '#1664ff',
},
});
});
graph.on('node:mouseleave', (e) => {
// this.graph.setItemState(e.item, 'showAnchors', false);
graph.setItemState(e.item, 'nodeSelected', false);
graph.updateItem(e.item, {
// 节点的样式
style: {
stroke: 'transparent',
},
});
});
graph.on('node:dragenter', (e) => {
console.log(e.target.get('name'));
console.log('node:dragenter');
graph.setItemState(e.item, 'nodeSelected', true);
graph.updateItem(e.item, {
// 节点的样式
style: {
stroke: '#1664ff',
},
});
});
graph.on('node:dragleave', (e) => {
console.log(e.target.get('name'));
console.log('node:dragleave');
graph.setItemState(e.item, 'nodeSelected', false);
graph.updateItem(e.item, {
// 节点的样式
style: {
stroke: 'transparent',
},
});
});
graph.on('node:dragstart', (e) => {
console.log('node:dragstart');
graph.setItemState(e.item, 'nodeSelected', true);
graph.updateItem(e.item, {
// 节点的样式
style: {
stroke: '#1664ff',
},
});
});

graph.on('afterremoveitem', (e) => {
if (e.item && e.item.source && e.item.target) {
const sourceNode = graph.findById(e.item.source);
@@ -681,7 +589,6 @@ const EditPipeline = () => {
}
}
});

// after clicking on the first node, the edge is created, update the sourceAnchor
graph.on('afteradditem', (e) => {
if (e.item && e.item.getType() === 'edge') {
@@ -690,11 +597,29 @@ const EditPipeline = () => {
});
}
});
graph.on('node:mouseenter', (e) => {
graph.setItemState(e.item, 'hover', true);
});
graph.on('node:mouseleave', (e) => {
graph.setItemState(e.item, 'hover', false);
});
graph.on('node:dragenter', (e) => {
graph.setItemState(e.item, 'hover', true);
});
graph.on('node:dragleave', (e) => {
graph.setItemState(e.item, 'hover', false);
});
graph.on('node:dragstart', (e) => {
graph.setItemState(e.item, 'hover', true);
});
graph.on('node:drag', (e) => {
graph.setItemState(e.item, 'hover', true);
});
window.onresize = () => {
if (!graph || graph.get('destroyed')) return;
if (!graphRef.current || !graphRef.current.scrollWidth || !graphRef.current.scrollHeight)
return;
graph.changeSize(graphRef.current.scrollWidth, graphRef.current.scrollHeight - 20);
if (!graphRef.current) return;
graph.changeSize(graphRef.current.clientWidth, graphRef.current.clientHeight);
graph.fitView();
};
};
return (


+ 9
- 7
react-ui/src/utils/ui.tsx View File

@@ -50,16 +50,18 @@ export const getFileListFromEvent = (e: any) => {
});
};

// 去登录页面
/**
* 跳转到登录页
* @param toHome 是否跳转到首页
*/
export const gotoLoginPage = (toHome: boolean = true) => {
const { pathname, search } = window.location;
const { pathname, search } = location;
const urlParams = new URLSearchParams();
urlParams.append('redirect', pathname + search);
const newSearch =
toHome && pathname !== PageEnum.LOGIN && pathname !== '/' ? '' : urlParams.toString();
console.log('pathname', pathname);
console.log('search', search);
if (window.location.pathname !== PageEnum.LOGIN) {
const newSearch = toHome && pathname !== '/' ? '' : urlParams.toString();
// console.log('pathname', pathname);
// console.log('search', search);
if (pathname !== PageEnum.LOGIN) {
closeAllModals();
removeAllPageCacheState();
history.replace({


+ 90
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/devEnvironment/DevEnvironmentController.java View File

@@ -0,0 +1,90 @@
package com.ruoyi.platform.controller.devEnvironment;

import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.GenericsAjaxResult;
import com.ruoyi.platform.domain.DevEnvironment;
import com.ruoyi.platform.service.DevEnvironmentService;
import io.swagger.annotations.Api;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
* (DevEnvironment)表控制层
*
* @author Xidaray
* @since 2024-06-03 15:17:37
*/
@RestController
@RequestMapping("devEnvironment")
@Api("开发环境管理")
public class DevEnvironmentController extends BaseController {
/**
* 服务对象
*/
@Resource
private DevEnvironmentService devEnvironmentService;

/**
* 分页查询
*
* @param devEnvironment 筛选条件
* @param page 页数
* @param size 每页大小
* @return 查询结果
*/
@GetMapping
public GenericsAjaxResult<Page<DevEnvironment>> queryByPage(DevEnvironment devEnvironment, int page, int size) {
PageRequest pageRequest = PageRequest.of(page,size);
return genericsSuccess(this.devEnvironmentService.queryByPage(devEnvironment, pageRequest));
}

/**
* 通过主键查询单条数据
*
* @param id 主键
* @return 单条数据
*/
@GetMapping("{id}")
public ResponseEntity<DevEnvironment> queryById(@PathVariable("id") Integer id) {
return ResponseEntity.ok(this.devEnvironmentService.queryById(id));
}

/**
* 新增数据
*
* @param devEnvironment 实体
* @return 新增结果
*/
@PostMapping
public ResponseEntity<DevEnvironment> add(@RequestBody DevEnvironment devEnvironment) {
return ResponseEntity.ok(this.devEnvironmentService.insert(devEnvironment));
}

/**
* 编辑数据
*
* @param devEnvironment 实体
* @return 编辑结果
*/
@PutMapping
public ResponseEntity<DevEnvironment> edit(@RequestBody DevEnvironment devEnvironment) {
return ResponseEntity.ok(this.devEnvironmentService.update(devEnvironment));
}

/**
* 删除数据
*
* @param id 主键
* @return 删除是否成功
*/
@DeleteMapping("{id}")
public ResponseEntity<String> deleteById(@PathVariable("id") Integer id) {
return ResponseEntity.ok(this.devEnvironmentService.removeById(id));
}

}


+ 1
- 1
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/experiment/ExperimentController.java View File

@@ -91,7 +91,7 @@ public class ExperimentController extends BaseController {
*/
@PutMapping
@ApiOperation("编辑实验")
public GenericsAjaxResult<Experiment> edit(@RequestBody Experiment experiment) throws IOException {
public GenericsAjaxResult<Experiment> edit(@RequestBody Experiment experiment) throws Exception {
return genericsSuccess(this.experimentService.update(experiment));
}



+ 32
- 3
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/jupyter/JupyterController.java View File

@@ -4,11 +4,11 @@ import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.domain.GenericsAjaxResult;
import com.ruoyi.platform.service.JupyterService;
import com.ruoyi.platform.vo.FrameLogPathVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.File;
@@ -28,6 +28,35 @@ public class JupyterController extends BaseController {
return genericsSuccess(jupyterService.getJupyterServiceUrl());
}


/**
* 启动jupyter容器接口
*
* @param id 开发环境配置id
* @return url
*/
@PostMapping("/run/{id}")
@ApiOperation("根据开发环境id启动jupyter pod")
@ApiResponse
public GenericsAjaxResult<String> runJupyter(@PathVariable("id") Integer id) throws Exception {
return genericsSuccess(this.jupyterService.runJupyterService(id));
}


/**
* 停止jupyter容器接口
*
* @param id 开发环境配置id
* @return 操作结果
*/
@DeleteMapping("/stop/{id}")
@ApiOperation("根据开发环境id停止jupyter pod")
@ApiResponse
public GenericsAjaxResult<String> stopJupyter(@PathVariable("id") Integer id) throws Exception {
return genericsSuccess(this.jupyterService.stopJupyterService(id));
}


@GetMapping(value = "/upload")
public AjaxResult upload() throws Exception {
File file = new File("D://nexus-deploy.yaml");


+ 115
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/model/ModelDependencyController.java View File

@@ -0,0 +1,115 @@
package com.ruoyi.platform.controller.model;

import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.GenericsAjaxResult;
import com.ruoyi.platform.domain.ModelDependency;
import com.ruoyi.platform.domain.ModelsVersion;
import com.ruoyi.platform.service.ModelDependencyService;
import com.ruoyi.platform.vo.ModelDependcyTreeVo;
import io.swagger.annotations.ApiOperation;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;

/**
* (ModelDependency)表控制层
*
* @author Xidaray
* @since 2024-05-29 13:51:23
*/
@RestController
@RequestMapping("modelDependency")
public class ModelDependencyController extends BaseController {
/**
* 服务对象
*/
@Resource
private ModelDependencyService modelDependencyService;

/**
* 分页查询
*
* @param modelDependency 筛选条件
* @param page 分页对象
* @param size 分页对象
* @return 查询结果
*/
@GetMapping
@ApiOperation("分页查询")
public GenericsAjaxResult<Page<ModelDependency>> queryByPage(ModelDependency modelDependency, int page ,int size) {
PageRequest pageRequest = PageRequest.of(page,size);
return genericsSuccess(this.modelDependencyService.queryByPage(modelDependency, pageRequest));
}

/**
* 根据对象查询
*
* @param modelDependency 筛选条件
* @return 查询结果
*/
@GetMapping("/queryModelDependency")
@ApiOperation("根据对象查询")
public GenericsAjaxResult<List<ModelDependency>> queryByModelDependency(@RequestBody ModelDependency modelDependency) throws IOException {
modelDependency.setState(1);
return genericsSuccess(this.modelDependencyService.queryByModelDependency(modelDependency));
}

/**
* 通过主键查询单条数据
*
* @param id 主键
* @return 单条数据
*/
@GetMapping("{id}")
@ApiOperation("根据id查询")
public GenericsAjaxResult<ModelDependency> queryById(@PathVariable("id") Integer id) {
return genericsSuccess(this.modelDependencyService.queryById(id));
}

/**
* 新增数据
*
* @param modelDependency 实体
* @return 新增结果
*/
@PostMapping
public GenericsAjaxResult<ModelDependency> add(@RequestBody ModelDependency modelDependency) {
return genericsSuccess(this.modelDependencyService.insert(modelDependency));
}

/**
* 编辑数据
*
* @param modelDependency 实体
* @return 编辑结果
*/
@PutMapping
public GenericsAjaxResult<ModelDependency> edit(@RequestBody ModelDependency modelDependency) {
return genericsSuccess(this.modelDependencyService.update(modelDependency));
}

/**
* 删除数据
*
* @param id 主键
* @return 删除是否成功
*/
@DeleteMapping("{id}")
@ApiOperation("删除模型依赖")
public GenericsAjaxResult<String> deleteById(@PathVariable("id") Integer id) {
return genericsSuccess(this.modelDependencyService.removeById(id));
}


@PostMapping("/queryModelAtlas")
@ApiOperation("根据模型id与版本两个属性得到模型的演化图谱")
public GenericsAjaxResult<ModelDependcyTreeVo> queryModelAtlas(@RequestBody ModelDependency modelDependency) throws Exception {
return genericsSuccess(this.modelDependencyService.getModelDependencyTree(modelDependency));
}
}


+ 2
- 1
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/model/ModelsVersionController.java View File

@@ -11,6 +11,7 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
import java.util.Map;

@@ -129,7 +130,7 @@ public class ModelsVersionController extends BaseController {
@DeleteMapping("/deleteVersion")
@ApiOperation(value = "逻辑删除模型版本", notes = "根据模型ID和版本逻辑删除模型版本记录。")
public GenericsAjaxResult<Map<Integer, String>> deleteModelsVersion(@RequestParam("models_id") Integer modelsId,
@RequestParam("version") String version) {
@RequestParam("version") String version) throws IOException {
return genericsSuccess(this.modelsVersionService.deleteModelsVersion(modelsId, version));
}



+ 1
- 1
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/workflow/WorkflowController.java View File

@@ -116,7 +116,7 @@ public class WorkflowController extends BaseController {
*/
@PutMapping
@ApiOperation("编辑流水线")
public GenericsAjaxResult<Workflow> edit(@RequestBody Workflow workflow) {
public GenericsAjaxResult<Workflow> edit(@RequestBody Workflow workflow) throws Exception {
return genericsSuccess(this.workflowService.update(workflow));
}



+ 22
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/Component.java View File

@@ -1,6 +1,7 @@
package com.ruoyi.platform.domain;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRawValue;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import io.swagger.annotations.ApiModelProperty;
@@ -58,6 +59,7 @@ public class Component implements Serializable {
*/
@JsonProperty("env_variables")
@ApiModelProperty(name = "env_variables", value = "环境变量")
//@JsonRawValue
private String envVirables;
/**
* 资源规格
@@ -78,12 +80,20 @@ public class Component implements Serializable {
* 输入参数
*/
@ApiModelProperty(name = "in_parameters" ,value = "输入参数")
//@JsonRawValue
private String inParameters;
/**
* 输出参数
*/
@ApiModelProperty(name = "out_parameters" ,value = "输出参数")
//@JsonRawValue
private String outParameters;

/**
* 可见范围
*/
@ApiModelProperty(name = "available_range" ,value = "1公开0私有")
private int availableRange;
/**
* 描述
*/
@@ -94,6 +104,8 @@ public class Component implements Serializable {
* 图标路径
*/
@ApiModelProperty(name = "icon_path" ,value = "图标路径")


private String iconPath;
/**
* 创建者
@@ -124,6 +136,8 @@ public class Component implements Serializable {
@ApiModelProperty(name = "state" , value = "状态")
private Integer state;



public Integer getId() {
return id;
}
@@ -228,6 +242,14 @@ public class Component implements Serializable {
this.outParameters = outParameters;
}

public int getAvailableRange() {
return availableRange;
}

public void setAvailableRange(int availableRange) {
this.availableRange = availableRange;
}

public String getDescription() {
return description;
}


+ 213
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/DevEnvironment.java View File

@@ -0,0 +1,213 @@
package com.ruoyi.platform.domain;

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

import java.util.Date;
import java.io.Serializable;

/**
* (DevEnvironment)实体类
*
* @author Xidaray
* @since 2024-06-03 15:17:37
*/
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class DevEnvironment implements Serializable {
private static final long serialVersionUID = 936999018935545992L;
/**
* 主键
*/
private Integer id;
/**
* 编辑器名称
*/
private String name;
/**
* 状态
*/
private String status;
/**
* 计算资源
*/
private String computingResource;
/**
* 资源规格
*/
private String standard;
/**
* 环境变量
*/
private String envVariable;
/**
* 所用镜像
*/
private String image;
/**
* 对应数据集
*/
private String dataset;
/**
* 对应模型
*/
private String model;
/**
* 备用字段1
*/
private String altField1;
/**
* 备用字段2
*/
private String altField2;
/**
* 创建者
*/
private String createBy;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新者
*/
private String updateBy;
/**
* 更新时间
*/
private Date updateTime;
/**
* 状态,0失效1生效
*/
private Integer state;


public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public String getComputingResource() {
return computingResource;
}

public void setComputingResource(String computingResource) {
this.computingResource = computingResource;
}

public String getStandard() {
return standard;
}

public void setStandard(String standard) {
this.standard = standard;
}

public String getEnvVariable() {
return envVariable;
}

public void setEnvVariable(String envVariable) {
this.envVariable = envVariable;
}

public String getImage() {
return image;
}

public void setImage(String image) {
this.image = image;
}

public String getDataset() {
return dataset;
}

public void setDataset(String dataset) {
this.dataset = dataset;
}

public String getModel() {
return model;
}

public void setModel(String model) {
this.model = model;
}

public String getAltField1() {
return altField1;
}

public void setAltField1(String altField1) {
this.altField1 = altField1;
}

public String getAltField2() {
return altField2;
}

public void setAltField2(String altField2) {
this.altField2 = altField2;
}

public String getCreateBy() {
return createBy;
}

public void setCreateBy(String createBy) {
this.createBy = createBy;
}

public Date getCreateTime() {
return createTime;
}

public void setCreateTime(Date createTime) {
this.createTime = createTime;
}

public String getUpdateBy() {
return updateBy;
}

public void setUpdateBy(String updateBy) {
this.updateBy = updateBy;
}

public Date getUpdateTime() {
return updateTime;
}

public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}

public Integer getState() {
return state;
}

public void setState(Integer state) {
this.state = state;
}

}


+ 247
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/ModelDependency.java View File

@@ -0,0 +1,247 @@
package com.ruoyi.platform.domain;

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import io.swagger.annotations.ApiModelProperty;

import java.util.Date;
import java.io.Serializable;

/**
* (ModelDependency)实体类
*
* @author Xidaray
* @since 2024-05-29 13:51:23
*/
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class ModelDependency implements Serializable {
private static final long serialVersionUID = -86753423714028539L;
/**
* 主键
*/
private Integer id;
/**
* 当前模型id
*/
private Integer currentModelId;
/**
* 实验实例id
*/
private Integer expInsId;

/**
* 父模型
*/
private String parentModels;
/**
* 引用项目
*/
private String refItem;
/**
* 训练任务
*/
private String trainTask;
/**
* 训练数据集
*/
private String trainDataset;
/**
* 训练参数
*/
private String trainParams;
/**
* 训练镜像
*/
private String trainImage;
/**
* 测试数据集
*/
private String testDataset;
/**
* 依赖项目
*/
private String projectDependency;

/**
* 版本
*/
private String version;


/**
* 创建者
*/
private String createBy;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新者
*/
private String updateBy;
/**
* 更新时间
*/
private Date updateTime;
/**
* 状态,0失效1生效
*/
private Integer state;

private Long workflowId;
private Models models;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public Integer getCurrentModelId() {
return currentModelId;
}

public void setCurrentModelId(Integer currentModelId) {
this.currentModelId = currentModelId;
}

public Integer getExpInsId() {
return expInsId;
}

public void setExpInsId(Integer expInsId) {
this.expInsId = expInsId;
}

public String getParentModels() {
return parentModels;
}

public void setParentModels(String parentModels) {
this.parentModels = parentModels;
}

public String getRefItem() {
return refItem;
}

public void setRefItem(String refItem) {
this.refItem = refItem;
}

public String getTrainTask() {
return trainTask;
}

public void setTrainTask(String trainTask) {
this.trainTask = trainTask;
}

public String getTrainDataset() {
return trainDataset;
}

public void setTrainDataset(String trainDataset) {
this.trainDataset = trainDataset;
}

public String getTrainParams() {
return trainParams;
}

public void setTrainParams(String trainParams) {
this.trainParams = trainParams;
}

public String getTrainImage() {
return trainImage;
}

public void setTrainImage(String trainImage) {
this.trainImage = trainImage;
}

public String getTestDataset() {
return testDataset;
}

public void setTestDataset(String testDataset) {
this.testDataset = testDataset;
}

public String getProjectDependency() {
return projectDependency;
}

public void setProjectDependency(String projectDependency) {
this.projectDependency = projectDependency;
}

public String getVersion() {
return version;
}

public void setVersion(String version) {
this.version = version;
}

public String getCreateBy() {
return createBy;
}

public void setCreateBy(String createBy) {
this.createBy = createBy;
}

public Date getCreateTime() {
return createTime;
}

public void setCreateTime(Date createTime) {
this.createTime = createTime;
}

public String getUpdateBy() {
return updateBy;
}

public void setUpdateBy(String updateBy) {
this.updateBy = updateBy;
}

public Date getUpdateTime() {
return updateTime;
}

public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}

public Integer getState() {
return state;
}

public void setState(Integer state) {
this.state = state;
}

public Long getWorkflowId() {
return workflowId;
}

public void setWorkflowId(Long workflowId) {
this.workflowId = workflowId;
}

public Models getModels() {
return models;
}

public void setModels(Models models) {
this.models = models;
}
}


+ 14
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/dependencydomain/ProjectDepency.java View File

@@ -0,0 +1,14 @@
package com.ruoyi.platform.domain.dependencydomain;

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import lombok.Data;

import java.io.Serializable;
@Data
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class ProjectDepency implements Serializable {
private String url;
private String name;
private String branch;
}

+ 17
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/dependencydomain/TrainTaskDepency.java View File

@@ -0,0 +1,17 @@
package com.ruoyi.platform.domain.dependencydomain;

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import lombok.Data;

import java.io.Serializable;
@Data
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class TrainTaskDepency implements Serializable {
//训练任务名
private String name;
//实例id
private Integer insId;
//节点Id
private String taskId;
}

+ 84
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/mapper/DevEnvironmentDao.java View File

@@ -0,0 +1,84 @@
package com.ruoyi.platform.mapper;

import com.ruoyi.platform.domain.DevEnvironment;
import org.apache.ibatis.annotations.Param;
import org.springframework.data.domain.Pageable;
import java.util.List;

/**
* (DevEnvironment)表数据库访问层
*
* @author Xidaray
* @since 2024-06-03 15:17:37
*/
public interface DevEnvironmentDao {

/**
* 通过ID查询单条数据
*
* @param id 主键
* @return 实例对象
*/
DevEnvironment queryById(Integer id);

/**
* 查询指定行数据
*
* @param devEnvironment 查询条件
* @param pageable 分页对象
* @return 对象列表
*/
List<DevEnvironment> queryAllByLimit(@Param("devEnvironment") DevEnvironment devEnvironment, @Param("pageable") Pageable pageable);

/**
* 统计总行数
*
* @param devEnvironment 查询条件
* @return 总行数
*/
long count(@Param("devEnvironment") DevEnvironment devEnvironment);

/**
* 新增数据
*
* @param devEnvironment 实例对象
* @return 影响行数
*/
int insert(@Param("devEnvironment") DevEnvironment devEnvironment);

/**
* 批量新增数据(MyBatis原生foreach方法)
*
* @param entities List<DevEnvironment> 实例对象列表
* @return 影响行数
*/
int insertBatch(@Param("entities") List<DevEnvironment> entities);

/**
* 批量新增或按主键更新数据(MyBatis原生foreach方法)
*
* @param entities List<DevEnvironment> 实例对象列表
*
* @return 影响行数
* @throws org.springframework.jdbc.BadSqlGrammarException 入参是空List的时候会抛SQL语句错误的异常,请自行校验入参
*/
int insertOrUpdateBatch(@Param("entities") List<DevEnvironment> entities);

/**
* 修改数据
*
* @param devEnvironment 实例对象
* @return 影响行数
*/
int update(@Param("devEnvironment") DevEnvironment devEnvironment);

/**
* 通过主键删除数据
*
* @param id 主键
* @return 影响行数
*/
int deleteById(Integer id);

}


+ 88
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/mapper/ModelDependencyDao.java View File

@@ -0,0 +1,88 @@
package com.ruoyi.platform.mapper;

import com.ruoyi.platform.domain.ModelDependency;
import org.apache.ibatis.annotations.Param;
import org.springframework.data.domain.Pageable;
import java.util.List;

/**
* (ModelDependency)表数据库访问层
*
* @author Xidaray
* @since 2024-05-29 13:51:23
*/
public interface ModelDependencyDao {

/**
* 通过ID查询单条数据
*
* @param id 主键
* @return 实例对象
*/
ModelDependency queryById(Integer id);

/**
* 查询指定行数据
*
* @param modelDependency 查询条件
* @param pageable 分页对象
* @return 对象列表
*/
List<ModelDependency> queryAllByLimit(ModelDependency modelDependency, @Param("pageable") Pageable pageable);



/**
* 统计总行数
*
* @param modelDependency 查询条件
* @return 总行数
*/
long count(ModelDependency modelDependency);

/**
* 新增数据
*
* @param modelDependency 实例对象
* @return 影响行数
*/
int insert(ModelDependency modelDependency);

/**
* 批量新增数据(MyBatis原生foreach方法)
*
* @param entities List<ModelDependency> 实例对象列表
* @return 影响行数
*/
int insertBatch(@Param("entities") List<ModelDependency> entities);

/**
* 批量新增或按主键更新数据(MyBatis原生foreach方法)
*
* @param entities List<ModelDependency> 实例对象列表
* @return 影响行数
* @throws org.springframework.jdbc.BadSqlGrammarException 入参是空List的时候会抛SQL语句错误的异常,请自行校验入参
*/
int insertOrUpdateBatch(@Param("entities") List<ModelDependency> entities);

/**
* 修改数据
*
* @param modelDependency 实例对象
* @return 影响行数
*/
int update(ModelDependency modelDependency);

/**
* 通过主键删除数据
*
* @param id 主键
* @return 影响行数
*/
int deleteById(Integer id);

List<ModelDependency> queryByModelDependency(@Param("modelDependency") ModelDependency modelDependency);

List<ModelDependency> queryChildrenByVersionId(@Param("model_id")String modelId, @Param("version")String version);
}


+ 50
- 9
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ExperimentInstanceStatusTask.java View File

@@ -1,24 +1,26 @@
package com.ruoyi.platform.scheduling;

import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.platform.domain.Experiment;
import com.ruoyi.platform.domain.ExperimentIns;
import com.ruoyi.platform.domain.ModelDependency;
import com.ruoyi.platform.mapper.ExperimentDao;
import com.ruoyi.platform.mapper.ExperimentInsDao;
import com.ruoyi.platform.mapper.ModelDependencyDao;
import com.ruoyi.platform.service.ExperimentInsService;
import com.ruoyi.platform.service.ExperimentService;
import com.ruoyi.platform.utils.JsonUtils;
import com.ruoyi.system.api.model.LoginUser;
import io.swagger.models.auth.In;
import com.ruoyi.platform.service.ModelDependencyService;
import com.ruoyi.platform.utils.JacksonUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Component()
public class ExperimentInstanceStatusTask {
@@ -28,7 +30,8 @@ public class ExperimentInstanceStatusTask {
private ExperimentDao experimentDao;
@Resource
private ExperimentInsDao experimentInsDao;

@Resource
private ModelDependencyDao modelDependencyDao;
private List<Integer> experimentIds = new ArrayList<>();

@Scheduled(cron = "0/30 * * * * ?") // 每30S执行一次
@@ -55,12 +58,50 @@ public class ExperimentInstanceStatusTask {
updateList.add(experimentIns);

}
experimentInsDao.update(experimentIns);
// experimentInsDao.update(experimentIns);
}

}
if (updateList.size() > 0){
experimentInsDao.insertOrUpdateBatch(updateList);

//遍历模型关系表,找到
List<ModelDependency> modelDependencyList = new ArrayList<ModelDependency>();
for (ExperimentIns experimentIns : updateList){
ModelDependency modelDependencyquery = new ModelDependency();
modelDependencyquery.setExpInsId(experimentIns.getId());
modelDependencyquery.setState(2);

List<ModelDependency> modelDependencyListquery = modelDependencyDao.queryByModelDependency(modelDependencyquery);
if (modelDependencyListquery==null||modelDependencyListquery.size()==0){
continue;
}
ModelDependency modelDependency = modelDependencyListquery.get(0);
//查看状态,
if (StringUtils.equals("Failed",experimentIns.getStatus())){
//取出节点状态
String trainTask = modelDependency.getTrainTask();
Map<String, Object> trainMap = JacksonUtil.parseJSONStr2Map(trainTask);
String task_id = (String) trainMap.get("task_id");
if (StringUtils.isEmpty(task_id)){
continue;
}
String nodesStatus = experimentIns.getNodesStatus();
Map<String, Object> nodeMaps = JacksonUtil.parseJSONStr2Map(nodesStatus);
Map<String, Object> nodeMap = JacksonUtil.parseJSONStr2Map(JacksonUtil.toJSONString(nodeMaps.get(task_id)));

if (nodeMap==null){
continue;
}
if (!StringUtils.equals("Succeeded",(String)nodeMap.get("phase"))){
modelDependency.setState(0);
modelDependencyList.add(modelDependency);
}
}
}
if (modelDependencyList.size()>0) {
modelDependencyDao.insertOrUpdateBatch(modelDependencyList);
}
}

}


+ 57
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/DevEnvironmentService.java View File

@@ -0,0 +1,57 @@
package com.ruoyi.platform.service;

import com.ruoyi.platform.domain.DevEnvironment;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;

/**
* (DevEnvironment)表服务接口
*
* @author Xidaray
* @since 2024-06-03 15:17:37
*/
public interface DevEnvironmentService {

/**
* 通过ID查询单条数据
*
* @param id 主键
* @return 实例对象
*/
DevEnvironment queryById(Integer id);

/**
* 分页查询
*
* @param devEnvironment 筛选条件
* @param pageRequest 分页对象
* @return 查询结果
*/
Page<DevEnvironment> queryByPage(DevEnvironment devEnvironment, PageRequest pageRequest);

/**
* 新增数据
*
* @param devEnvironment 实例对象
* @return 实例对象
*/
DevEnvironment insert(DevEnvironment devEnvironment);

/**
* 修改数据
*
* @param devEnvironment 实例对象
* @return 实例对象
*/
DevEnvironment update(DevEnvironment devEnvironment);

/**
* 通过主键删除数据
*
* @param id 主键
* @return 是否成功
*/
boolean deleteById(Integer id);

String removeById(Integer id);
}

+ 1
- 1
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ExperimentInsService.java View File

@@ -100,7 +100,7 @@ public interface ExperimentInsService {

/**
* 查询非终止态的实例
* @return
*
*/
List<ExperimentIns> queryByExperimentIsNotTerminated();



+ 1
- 1
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ExperimentService.java View File

@@ -48,7 +48,7 @@ public interface ExperimentService {
* @param experiment 实例对象
* @return 实例对象
*/
Experiment update(Experiment experiment) throws IOException;
Experiment update(Experiment experiment) throws Exception;

/**
* 通过主键删除数据


+ 6
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/JupyterService.java View File

@@ -1,5 +1,7 @@
package com.ruoyi.platform.service;

import com.ruoyi.platform.vo.FrameLogPathVo;

import java.io.InputStream;

public interface JupyterService {
@@ -8,4 +10,8 @@ public interface JupyterService {
void upload(InputStream inputStream);

void mlflow();

String runJupyterService(Integer id);

String stopJupyterService(Integer id) throws Exception;
}

+ 65
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ModelDependencyService.java View File

@@ -0,0 +1,65 @@
package com.ruoyi.platform.service;

import com.ruoyi.platform.domain.ModelDependency;
import com.ruoyi.platform.vo.ModelDependcyTreeVo;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;

import java.io.IOException;
import java.util.List;

/**
* (ModelDependency)表服务接口
*
* @author Xidaray
* @since 2024-05-29 13:51:23
*/
public interface ModelDependencyService {

/**
* 通过ID查询单条数据
*
* @param id 主键
* @return 实例对象
*/
ModelDependency queryById(Integer id);

/**
* 分页查询
*
* @param modelDependency 筛选条件
* @param pageRequest 分页对象
* @return 查询结果
*/
Page<ModelDependency> queryByPage(ModelDependency modelDependency, PageRequest pageRequest);

/**
* 修改数据
*
* @param modelDependency 实例对象
* @return 实例对象
*/
ModelDependency update(ModelDependency modelDependency);

/**
* 新增数据
*
* @param modelDependency 实例对象
* @return 实例对象
*/
ModelDependency insert(ModelDependency modelDependency);

/**
* 通过主键删除数据
*
* @param id 主键
* @return 是否成功
*/
boolean deleteById(Integer id);

String removeById(Integer id);

List<ModelDependency> queryByModelDependency(ModelDependency modelDependency) throws IOException;

ModelDependcyTreeVo getModelDependencyTree(ModelDependency modelDependency) throws Exception;
}

+ 2
- 1
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ModelsVersionService.java View File

@@ -6,6 +6,7 @@ import com.ruoyi.platform.domain.ModelsVersion;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;

import java.io.IOException;
import java.util.List;
import java.util.Map;

@@ -68,7 +69,7 @@ public interface ModelsVersionService {

Map<String,Object> queryByModelsIdAndVersion(Integer modelsId, String version);

Map<Integer, String> deleteModelsVersion(Integer modelsId, String version);
Map<Integer, String> deleteModelsVersion(Integer modelsId, String version) throws IOException;

String addModelVersions(List<ModelsVersion> modelsVersions) throws Exception;



+ 1
- 1
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/WorkflowService.java View File

@@ -45,7 +45,7 @@ public interface WorkflowService {
* @param workflow 实例对象
* @return 实例对象
*/
Workflow update(Workflow workflow);
Workflow update(Workflow workflow) throws Exception;

/**
* 通过主键删除数据


+ 2
- 1
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ComponentServiceImpl.java View File

@@ -51,7 +51,7 @@ public class ComponentServiceImpl implements ComponentService {
throw new RuntimeException("组件不存在");
}

return this.componentDao.queryById(id);
return component;
}

@Override
@@ -149,6 +149,7 @@ public class ComponentServiceImpl implements ComponentService {

String inParameters= gson.toJson(componentVo.getInParameters(), LinkedHashMap.class);
String outParameters = gson.toJson(componentVo.getOutParameters(), LinkedHashMap.class);

String envVariable = gson.toJson(componentVo.getEnvVirables(), LinkedHashMap.class);
component.setEnvVirables(envVariable);
component.setInParameters(inParameters);


+ 2
- 9
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/DatasetServiceImpl.java View File

@@ -353,22 +353,15 @@ public class DatasetServiceImpl implements DatasetService {
public void checkDeclaredName(Dataset insert) throws Exception {
Dataset existingDataset = datasetDao.findByName(insert.getName());
if (existingDataset != null) {
// Check if the found dataset is not the same as the one being inserted
// This is important if you are using this method for both insert and update operations
// You may need an identifier check here, e.g., if 'insert' has an ID and it's the same as 'existingDataset'
if (insert.getId() != null && insert.getId().equals(existingDataset.getId())) {
// This is the same dataset, no duplicate name issue for update operation
// 相同数据集,无需判断
return;
}

// Now we know there's another dataset with the same name
Field[] fields = Dataset.class.getDeclaredFields();

for (Field field : fields) {
field.setAccessible(true); // Make private fields accessible

field.setAccessible(true);
if ("name".equals(field.getName()) && field.isAnnotationPresent(CheckDuplicate.class)) {
// If the field is 'name' and is marked with CheckDuplicate annotation
CheckDuplicate annotation = field.getAnnotation(CheckDuplicate.class);
throw new Exception("重复的数据集名称: " + insert.getName() + ". " + annotation.message());
}


+ 125
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/DevEnvironmentServiceImpl.java View File

@@ -0,0 +1,125 @@
package com.ruoyi.platform.service.impl;

import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.platform.domain.DevEnvironment;
import com.ruoyi.platform.mapper.DevEnvironmentDao;
import com.ruoyi.platform.service.DevEnvironmentService;
import com.ruoyi.platform.service.JupyterService;
import com.ruoyi.platform.utils.JacksonUtil;
import com.ruoyi.system.api.model.LoginUser;
import io.kubernetes.client.openapi.models.V1PersistentVolumeClaim;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Map;

/**
* (DevEnvironment)表服务实现类
*
* @author Xidaray
* @since 2024-06-03 15:17:37
*/
@Service("devEnvironmentService")
public class DevEnvironmentServiceImpl implements DevEnvironmentService {
@Resource
private DevEnvironmentDao devEnvironmentDao;


@Resource
private JupyterService jupyterService;


/**
* 通过ID查询单条数据
*
* @param id 主键
* @return 实例对象
*/
@Override
public DevEnvironment queryById(Integer id) {
return this.devEnvironmentDao.queryById(id);
}

/**
* 分页查询
*
* @param devEnvironment 筛选条件
* @param pageRequest 分页对象
* @return 查询结果
*/
@Override
public Page<DevEnvironment> queryByPage(DevEnvironment devEnvironment, PageRequest pageRequest) {
long total = this.devEnvironmentDao.count(devEnvironment);
return new PageImpl<>(this.devEnvironmentDao.queryAllByLimit(devEnvironment, pageRequest), pageRequest, total);
}

/**
* 新增数据
*
* @param devEnvironment 实例对象
* @return 实例对象
*/
@Override
public DevEnvironment insert(DevEnvironment devEnvironment) {
//插入预备,此时不需要判断版本重复
LoginUser loginUser = SecurityUtils.getLoginUser();
devEnvironment.setCreateBy(loginUser.getUsername());
devEnvironment.setUpdateBy(loginUser.getUsername());
devEnvironment.setUpdateTime(new Date());
devEnvironment.setCreateTime(new Date());
this.devEnvironmentDao.insert(devEnvironment);
return devEnvironment;
}

/**
* 修改数据
*
* @param devEnvironment 实例对象
* @return 实例对象
*/
@Override
public DevEnvironment update(DevEnvironment devEnvironment) {
LoginUser loginUser = SecurityUtils.getLoginUser();
devEnvironment.setUpdateBy(loginUser.getUsername());
devEnvironment.setUpdateTime(new Date());
this.devEnvironmentDao.update(devEnvironment);
return this.queryById(devEnvironment.getId());
}

/**
* 通过主键删除数据
*
* @param id 主键
* @return 是否成功
*/
@Override
public boolean deleteById(Integer id) {
return this.devEnvironmentDao.deleteById(id) > 0;
}

@Override
public String removeById(Integer id) {
DevEnvironment devEnvironment = this.devEnvironmentDao.queryById(id);
if (devEnvironment == null){
return "开发环境信息不存在";
}

//判断权限,只有admin和创建者本身可以删除该数据集
LoginUser loginUser = SecurityUtils.getLoginUser();
String username = loginUser.getUsername();
String createdBy = devEnvironment.getCreateBy();
if (!(StringUtils.equals(username,"admin") || StringUtils.equals(username,createdBy))){
return "无权限删除该开发环境";
}

devEnvironment.setState(0);
return this.devEnvironmentDao.update(devEnvironment)>0?"删除成功":"删除失败";
}


}

+ 3
- 3
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentInsServiceImpl.java View File

@@ -427,7 +427,6 @@ public class ExperimentInsServiceImpl implements ExperimentInsService {
throw new RuntimeException("日志为空。");
}
//返回日志内容

return experimentInsLog;
} catch (Exception e) {
throw new RuntimeException("查询实验日志失败: " + e.getMessage(), e);
@@ -554,7 +553,7 @@ public class ExperimentInsServiceImpl implements ExperimentInsService {
// 查询具有相同状态的实例数量
Long count = experimentInsDao.count(experimentIns);

// 将状态及其对应的实例数量放入映射
// 将状态及其对应的实例数量放入map
statusCountMap.put(status.toString(), count);
}

@@ -580,8 +579,9 @@ public class ExperimentInsServiceImpl implements ExperimentInsService {
flag = StringUtils.equals("Terminated", (String) workflowMap.get("phase"));
}
}

return flag;
}

}



+ 233
- 22
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ExperimentServiceImpl.java View File

@@ -2,14 +2,12 @@ package com.ruoyi.platform.service.impl;

import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.platform.annotations.CheckDuplicate;
import com.ruoyi.platform.domain.Experiment;
import com.ruoyi.platform.domain.ExperimentIns;
import com.ruoyi.platform.domain.Workflow;
import com.ruoyi.platform.domain.*;
import com.ruoyi.platform.domain.dependencydomain.ProjectDepency;
import com.ruoyi.platform.domain.dependencydomain.TrainTaskDepency;
import com.ruoyi.platform.mapper.ExperimentDao;
import com.ruoyi.platform.mapper.ExperimentInsDao;
import com.ruoyi.platform.service.ExperimentInsService;
import com.ruoyi.platform.service.ExperimentService;
import com.ruoyi.platform.service.WorkflowService;
import com.ruoyi.platform.service.*;
import com.ruoyi.platform.utils.HttpUtils;
import com.ruoyi.platform.utils.JacksonUtil;
import com.ruoyi.platform.utils.JsonUtils;
@@ -42,8 +40,12 @@ public class ExperimentServiceImpl implements ExperimentService {

@Resource
private ExperimentInsDao experimentInsDao;


@Resource
private ModelsService modelsService;
@Resource
private DatasetService datasetService;
@Resource
private ModelDependencyService modelDependencyService;

@Resource
@Lazy
@@ -151,8 +153,9 @@ public class ExperimentServiceImpl implements ExperimentService {
* @return 实例对象
*/
@Override
public Experiment update(Experiment experiment) throws IOException {
public Experiment update(Experiment experiment) throws Exception {
LoginUser loginUser = SecurityUtils.getLoginUser();
checkDeclaredName(experiment);
experiment.setUpdateBy(loginUser.getUsername());
experiment.setUpdateTime(new Date());
this.experimentDao.update(experiment);
@@ -207,12 +210,9 @@ public class ExperimentServiceImpl implements ExperimentService {
public Experiment runExperiment(Integer id) throws Exception {
//先查出实验记录
Experiment experiment = this.queryById(id);

if (experiment == null) {
System.out.println("No experiment");
}


Workflow workflow = workflowService.queryById(experiment.getWorkflowId());
if(workflow == null) {
throw new RuntimeException("流水线不存在,请先创建流水线");
@@ -226,13 +226,14 @@ public class ExperimentServiceImpl implements ExperimentService {
throw new RuntimeException("转换流水线失败");
}
Map<String, Object> converMap = JsonUtils.jsonToMap(convertRes);

// 组装运行接口json
Map<String, Object> runReqMap = new HashMap<>();
runReqMap.put("data", converMap.get("data"));
//这里全局参数是一个json数组,需要转换成一个list<Map>
List<Map<String, Object>> params = JacksonUtil.parseJSONStr2MapList(StringUtils.isEmpty(experiment.getGlobalParam()) ? "[]" : experiment.getGlobalParam());
runReqMap.put("params", params);
//// 实验字段的Map,不要写成一行!否则会返回null
// 实验字段的Map,不要写成一行!否则会返回null
Map<String, Object> experimentMap = new HashMap<>();
experimentMap.put("name", "experiment-"+experiment.getId());
runReqMap.put("experiment", experimentMap);
@@ -246,14 +247,11 @@ public class ExperimentServiceImpl implements ExperimentService {
}
Map<String, Object> runResMap = JsonUtils.jsonToMap(runRes);
Map<String, Object> data = (Map<String, Object>) runResMap.get("data");

//判断data为空
if (data == null || MapUtils.isEmpty(data)) {
throw new RuntimeException("Failed to run workflow.");
}

Map<String, Object> metadata = (Map<String, Object>) data.get("metadata");

// 插入记录到实验实例表
ExperimentIns experimentIns = new ExperimentIns();
experimentIns.setExperimentId(experiment.getId());
@@ -262,24 +260,237 @@ public class ExperimentServiceImpl implements ExperimentService {
experimentIns.setStatus("Pending");

//传入实验全局参数

experimentIns.setGlobalParam(experiment.getGlobalParam());

//替换argoInsName
String outputString = JsonUtils.mapToJson(output);
experimentIns.setNodesResult(outputString.replace("{{workflow.name}}", (String) metadata.get("name")));
//插入ExperimentIns表中
experimentInsService.insert(experimentIns);
ExperimentIns insert = experimentInsService.insert(experimentIns);

//插入到模型依赖关系表
//得到dependendcy
Map<String, Object> converMap2 = JsonUtils.jsonToMap(JacksonUtil.replaceInAarry(convertRes, params));
Map<String ,Object> dependendcy = (Map<String, Object>)converMap2.get("model_dependency");
Map<String ,Object> trainInfo = (Map<String, Object>)converMap2.get("component_info");
insertModelDependency(dependendcy,trainInfo,insert.getId(),experiment.getName());

}catch (Exception e){
throw new RuntimeException(e);
}
List<ExperimentIns> updatedExperimentInsList = experimentInsService.getByExperimentId(id);

experiment.setExperimentInsList(updatedExperimentInsList);

return experiment;
}
private void insertModelDependency(Map<String ,Object> dependendcy,Map<String ,Object> trainInfo, Integer experimentInsId, String experimentName) throws Exception {
Iterator<Map.Entry<String, Object>> dependendcyIterator = dependendcy.entrySet().iterator();
Map<String, Object> modelTrain = (Map<String, Object>) trainInfo.get("model_train");
Map<String, Object> modelEvaluate = (Map<String, Object>) trainInfo.get("model_evaluate");
Map<String, Object> modelExport = (Map<String, Object>) trainInfo.get("model_export");
while (dependendcyIterator.hasNext()) {
ModelDependency modelDependency = new ModelDependency();
Map.Entry<String, Object> entry = dependendcyIterator.next();
Map<String, Object> modelDel = (Map<String, Object>) entry.getValue();
Map<String, Object> source = (Map<String, Object>) modelDel.get("source");
List<Map<String, Object>> test = (List<Map<String, Object>>) modelDel.get("test");
List<Map<String, Object>> target = (List<Map<String, Object>>) modelDel.get("target");
String sourceTaskId = (String) source.get("task_id");

Map<String, Object> modelTrainMap = (Map<String, Object>)modelTrain.get(sourceTaskId);
//处理project数据
Map<String, String> projectMap = (Map<String, String>) modelTrainMap.get("project");
ProjectDepency projectDepency = new ProjectDepency();
projectDepency.setBranch(projectMap.get("branch"));
String projectUrl = projectMap.get("url");
projectDepency.setUrl(projectUrl);
projectDepency.setName(projectUrl.substring(projectUrl.lastIndexOf('/') + 1, projectUrl.length() - 4));
//依赖项目
modelDependency.setProjectDependency(JsonUtils.objectToJson(projectDepency));
//处理镜像
Map<String, String> imagesMap = (Map<String, String>) modelTrainMap.get("image");
modelDependency.setTrainImage(imagesMap.get("name"));
List<Map<String, Object>> trainParamList = (List<Map<String, Object>>) modelTrainMap.get("params");
modelDependency.setTrainParams(JsonUtils.objectToJson(trainParamList));
//处理source数据
List<Map<String, Object>> modelsList = (List<Map<String, Object>>) modelTrainMap.get("models");
if (modelsList != null) {
for (int i = 0; i < modelsList.size(); i++) {
Map<String, Object> model = modelsList.get(i);
Models models = modelsService.queryById((Integer) model.get("model_id"));
if (models == null) {
throw new Exception("源模型不存在");
}
model.put("model_name", models.getName());
}
//父模型
modelDependency.setParentModels(JsonUtils.objectToJson(modelsList));
}
List<Map<String, Object>> datasetsList = (List<Map<String, Object>>) modelTrainMap.get("datasets");
if (datasetsList != null) {
for (int i = 0; i < datasetsList.size(); i++) {
Map<String, Object> datasets = datasetsList.get(i);
Dataset dataset = datasetService.queryById((Integer) datasets.get("dataset_id"));
if (dataset == null) {
throw new Exception("源数据集不存在");
}
datasets.put("dataset_name", dataset.getName());
}
}
//训练数据集
modelDependency.setTrainDataset(JsonUtils.objectToJson(datasetsList));
TrainTaskDepency trainTaskDepency = new TrainTaskDepency();
trainTaskDepency.setTaskId(sourceTaskId);
trainTaskDepency.setInsId(experimentInsId);
trainTaskDepency.setName(experimentName);
//训练任务
modelDependency.setTrainTask(JsonUtils.objectToJson(trainTaskDepency));
modelDependency.setExpInsId(experimentInsId);
List<Map<String, Object>> resultTestDatasets = new ArrayList<Map<String, Object>>();
//处理test数据
if (test != null) {
for(int i=0;i<test.size();i++){
Map<String, Object> testMap = test.get(i);
String testTaskId = (String) testMap.get("task_id");
Map<String, Object> evaluateMap = (Map<String, Object>) modelEvaluate.get(testTaskId);
List<Map<String, Object>> realDataSetList = (List<Map<String, Object>>) evaluateMap.get("datasets");
for(int j=0;j<realDataSetList.size();j++){
Map<String, Object> realDataSet = realDataSetList.get(j);
Dataset dataset = datasetService.queryById((Integer) realDataSet.get("dataset_id"));
if (dataset == null){
throw new Exception("源数据集不存在");
}
realDataSet.put("dataset_name", dataset.getName());
resultTestDatasets.add(realDataSet);
}
}

//测试数据集
modelDependency.setTestDataset(JsonUtils.objectToJson(resultTestDatasets));
}
//处理target数据
if (target != null) {
for (int i = 0; i < target.size(); i++) {
Map<String, Object> targetMap = target.get(i);
String targetaskId = (String) targetMap.get("task_id");
Map<String, Object> exportMap = (Map<String, Object>) modelExport.get(targetaskId);
List<Map<String, Object>> modelTargetList = (List<Map<String, Object>>) exportMap.get("models");
modelDependency.setState(2);
for (int j = 0; j < modelTargetList.size(); j++) {
Map<String, Object> model = modelTargetList.get(i);
modelDependency.setVersion((String) model.get("model_version"));
modelDependency.setCurrentModelId((Integer) model.get("model_id"));
//因为可能有多成果模型,多次插入
modelDependencyService.insert(modelDependency);
}
}
}else {
modelDependency.setState(2);
modelDependencyService.insert(modelDependency);
}

}
}

/**
* 被废弃的旧JSON
* @param experiment
* @return
* @throws Exception
*/
// private void insertModelDependency(Map<String ,Object> dependendcy,Map<String ,Object> trainInfo, Integer experimentInsId, String experimentName, List<Map<String, Object>> params) throws Exception {
// Iterator<Map.Entry<String, Object>> dependendcyIterator = dependendcy.entrySet().iterator();
// while (dependendcyIterator.hasNext()) {
// ModelDependency modelDependency = new ModelDependency();
// Map.Entry<String, Object> entry = dependendcyIterator.next();
// String key = entry.getKey();
// Map<String, Object> modelDel = (Map<String, Object>) entry.getValue();
// //处理project数据
// Map<String, String> projectMap = (Map<String, String>) modelDel.get("project");
// ProjectDepency projectDepency = new ProjectDepency();
// projectDepency.setBranch(projectMap.get("branch"));
// String projectUrl = projectMap.get("url");
// projectDepency.setUrl(projectUrl);
// projectDepency.setName(projectUrl.substring(projectUrl.lastIndexOf('/') + 1, projectUrl.length() - 4));
// //依赖项目
// modelDependency.setProjectDependency(JsonUtils.objectToJson(projectDepency));
// //处理source数据
// Map<String, Object> sourceMap = (Map<String, Object>) modelDel.get("source");
// List<Map<String, Object>> modelsList = (List<Map<String, Object>>) sourceMap.get("models");
// for(int i=0;i<modelsList.size();i++){
// Map<String, Object> model = modelsList.get(i);
// Models models = modelsService.queryById((Integer) model.get("model_id"));
// if (models == null){
// throw new Exception("源模型不存在");
// }
// model.put("model_name", models.getName());
// }
// //父模型
// modelDependency.setParentModels(JsonUtils.objectToJson(modelsList));
//
// List<Map<String, Object>> datasetsList = (List<Map<String, Object>>) sourceMap.get("datasets");
// for(int i=0;i<datasetsList.size();i++){
// Map<String, Object> datasets = datasetsList.get(i);
// Dataset dataset = datasetService.queryById((Integer) datasets.get("dataset_id"));
// if (dataset == null){
// throw new Exception("源数据集不存在");
// }
// datasets.put("dataset_name", dataset.getName());
// }
// //训练数据集
// modelDependency.setTrainDataset(JsonUtils.objectToJson(datasetsList));
//
// TrainTaskDepency trainTaskDepency = new TrainTaskDepency();
// trainTaskDepency.setTaskId(key);
// trainTaskDepency.setInsId(experimentInsId);
// trainTaskDepency.setName(experimentName);
// //训练任务
// modelDependency.setTrainTask(JsonUtils.objectToJson(trainTaskDepency));
// modelDependency.setExpInsId(experimentInsId);
// //处理test数据
// List<Map<String, Object>> testDatasetsList = (List<Map<String, Object>>) modelDel.get("test");
// List<Map<String, Object>> resultTestDatasets = new ArrayList<Map<String, Object>>();
// for(int i=0;i<testDatasetsList.size();i++){
// Map<String, Object> datasets = testDatasetsList.get(i);
// List<Map<String, Object>> realDataSetList = (List<Map<String, Object>>) datasets.get("datasets");
// for(int j=0;j<realDataSetList.size();j++){
// Map<String, Object> realDataSet = realDataSetList.get(j);
// Dataset dataset = datasetService.queryById((Integer) realDataSet.get("dataset_id"));
// if (dataset == null){
// throw new Exception("源数据集不存在");
// }
// realDataSet.put("dataset_name", dataset.getName());
// resultTestDatasets.add(realDataSet);
// }
//
// }
// //测试数据集
// modelDependency.setTestDataset(JsonUtils.objectToJson(resultTestDatasets));
//
// //检查是否存在target,如果存在说明在流水线用了节点导入,如果没有说明没有导入,等待手动push
// List<Map<String, Object>> modelTargetList = (List<Map<String, Object>>) modelDel.get("target");
// if (modelTargetList==null||modelTargetList.size()==0){
// modelDependency.setState(1);
// modelDependencyService.insert(modelDependency);
// }else {
// modelDependency.setState(2);
// for(int i=0;i<modelTargetList.size();i++){
// Map<String, Object> model = modelTargetList.get(i);
// String version = null;
// //可能是参数,必须从实验参数读取
// if (params != null) {
// for (Map<String, Object> param : params) {
// if (param.containsKey("param_name") && StringUtils.equals("model_version",(String) param.get("param_name"))) {
// version = param.get("param_value").toString();
// }
// }
// }
// modelDependency.setVersion(StringUtils.isEmpty(version)?(String)model.get("model_version"):version);
// modelDependency.setCurrentModelId((Integer) model.get("model_id"));
// //因为可能有多成果模型,多次插入
// modelDependencyService.insert(modelDependency);
// }
// }
// }
// }

@Override
public Experiment addAndRunExperiment(Experiment experiment) throws Exception {
@@ -332,7 +543,7 @@ public class ExperimentServiceImpl implements ExperimentService {
// 现在我们知道还有另一个具有相同名称的流水线
Field[] fields = Experiment.class.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true); // 使私有字段可访问
field.setAccessible(true);
if ("name".equals(field.getName()) && field.isAnnotationPresent(CheckDuplicate.class)) {
// 如果字段是“name”并且标记了CheckDuplicate注解
CheckDuplicate annotation = field.getAnnotation(CheckDuplicate.class);


+ 65
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/JupyterServiceImpl.java View File

@@ -1,7 +1,12 @@
package com.ruoyi.platform.service.impl;

import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.platform.domain.DevEnvironment;
import com.ruoyi.platform.mapper.DevEnvironmentDao;
import com.ruoyi.platform.service.DevEnvironmentService;
import com.ruoyi.platform.service.JupyterService;
import com.ruoyi.platform.utils.JacksonUtil;
import com.ruoyi.platform.utils.K8sClientUtil;
import com.ruoyi.platform.utils.MinioUtil;
import com.ruoyi.platform.utils.MlflowUtil;
@@ -13,6 +18,7 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

@Service
public class JupyterServiceImpl implements JupyterService {
@@ -39,6 +45,15 @@ public class JupyterServiceImpl implements JupyterService {
@Resource
private MlflowUtil mlflowUtil;

@Resource
private DevEnvironmentDao devEnvironmentDao;

@Resource
private DevEnvironmentService devEnvironmentService;

@Resource
private RedisService redisService;

public JupyterServiceImpl(MinioUtil minioUtil) {
this.minioUtil = minioUtil;
}
@@ -53,6 +68,54 @@ public class JupyterServiceImpl implements JupyterService {
return masterIp + ":" + podPort;
}

@Override
public String runJupyterService(Integer id) {
DevEnvironment devEnvironment = this.devEnvironmentDao.queryById(id);
String envName = devEnvironment.getName();
//TODO 设置环境变量

// 提取数据集,模型信息,得到数据集模型的path
Map<String, Object> dataset = JacksonUtil.parseJSONStr2Map(devEnvironment.getDataset());
String datasetPath = (String) dataset.get("path");
Map<String, Object> model = JacksonUtil.parseJSONStr2Map(devEnvironment.getModel());
String modelPath = (String) model.get("path");

LoginUser loginUser = SecurityUtils.getLoginUser();
String podName = loginUser.getUsername().toLowerCase() + "-editor-pod";
String pvcName = loginUser.getUsername().toLowerCase() + "-editor-pvc";
V1PersistentVolumeClaim pvc = k8sClientUtil.createPvc(namespace, pvcName, storage, storageClassName);

//TODO 设置镜像可配置,这里先用默认镜像启动pod

// 调用修改后的 createPod 方法,传入额外的参数
Integer podPort = k8sClientUtil.createConfiguredPod(podName, namespace, port, mountPath, pvc, image, datasetPath, modelPath);
return masterIp + ":" + podPort;


}

@Override
public String stopJupyterService(Integer id) throws Exception {
DevEnvironment devEnvironment = this.devEnvironmentDao.queryById(id);
if (devEnvironment==null){
throw new Exception("开发环境配置不存在");
}

LoginUser loginUser = SecurityUtils.getLoginUser();
String podName = loginUser.getUsername().toLowerCase() + "-editor-pod";

// 使用 Kubernetes API 删除 Pod
String deleteResult = k8sClientUtil.deletePod(podName, namespace);

// 检查 Pod 是否存在
boolean exists = k8sClientUtil.checkPodExists(podName, namespace);
if (exists) {
throw new Exception("Pod " + podName + " 删除失败");
}
return deleteResult + ",编辑器已停止";
}


@Override
public void upload(InputStream inputStream) {
try {
@@ -71,4 +134,6 @@ public class JupyterServiceImpl implements JupyterService {
}




}

+ 252
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ModelDependencyServiceImpl.java View File

@@ -0,0 +1,252 @@
package com.ruoyi.platform.service.impl;

import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.platform.domain.*;
import com.ruoyi.platform.mapper.ModelDependencyDao;
import com.ruoyi.platform.service.*;
import com.ruoyi.platform.utils.JacksonUtil;
import com.ruoyi.platform.vo.ModelDependcyTreeVo;
import com.ruoyi.platform.vo.ModelVersionDependcyVo;
import com.ruoyi.system.api.model.LoginUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* (ModelDependency)表服务实现类
*
* @author Xidaray
* @since 2024-05-29 13:51:23
*/
@Service("modelDependencyService")
public class ModelDependencyServiceImpl implements ModelDependencyService {
@Resource
private ModelDependencyDao modelDependencyDao;

@Resource
private ModelsService modelsService;
@Resource
private ModelsVersionService modelsVersionService;
@Lazy
@Resource
private ExperimentService experimentService;
@Lazy
@Resource
private ExperimentInsService experimentInsService;
/**
* 通过ID查询单条数据
*
* @param id 主键
* @return 实例对象
*/
@Override
public ModelDependency queryById(Integer id) {
return this.modelDependencyDao.queryById(id);
}

/**
* 分页查询
*
* @param modelDependency 筛选条件
* @param pageRequest 分页对象
* @return 查询结果
*/
@Override
public Page<ModelDependency> queryByPage(ModelDependency modelDependency, PageRequest pageRequest) {
long total = this.modelDependencyDao.count(modelDependency);
return new PageImpl<>(this.modelDependencyDao.queryAllByLimit(modelDependency, pageRequest), pageRequest, total);
}

/**
* 根据对象查询
*
* @param modelDependency 筛选条件
* @return 查询结果
*/
@Override
public List<ModelDependency> queryByModelDependency(ModelDependency modelDependency) throws IOException {
List<ModelDependency> modelDependencyList = this.modelDependencyDao.queryByModelDependency(modelDependency);
return modelDependencyList;
}

@Override
public ModelDependcyTreeVo getModelDependencyTree(ModelDependency modelDependencyQuery) throws Exception {
//查询当前模型
modelDependencyQuery.setState(1);
List<ModelDependency> modelDependencyList = this.queryByModelDependency(modelDependencyQuery);
if (modelDependencyList==null || modelDependencyList.size()==0){
throw new Exception("当前模型依赖关系不存在");
}
ModelDependency modelDependency = modelDependencyList.get(0);
ModelDependcyTreeVo modelDependcyTreeVo = ModelDependencyConvertToTree(modelDependency);
//递归父模型
processParentModel(modelDependcyTreeVo);
//递归子模型
processChildrenModel(modelDependcyTreeVo);
return modelDependcyTreeVo;
}

/**
* 递归父模型
* @param modelDependcyTreeVo
*/
private void processParentModel(ModelDependcyTreeVo modelDependcyTreeVo) throws IOException {
if (modelDependcyTreeVo.getParentModelsMap() != null) {
List<Map<String, Object>> parentMaps = modelDependcyTreeVo.getParentModelsMap();
List<ModelDependcyTreeVo> ps = new ArrayList<ModelDependcyTreeVo>();
for (Map<String, Object> parent:parentMaps) {
Integer model_id = (Integer) parent.get("model_id");
String version = (String) parent.get("model_version");
ModelDependency modelDependencyQuery = new ModelDependency();
modelDependencyQuery.setVersion(version);
modelDependencyQuery.setCurrentModelId(model_id);
List<ModelDependency> modelDependencyList = this.queryByModelDependency(modelDependencyQuery);
if (modelDependencyList!=null&&modelDependencyList.size()>=0){
for (ModelDependency modelDependency:modelDependencyList){
ModelDependcyTreeVo modelDependencyTreeVoIn = ModelDependencyConvertToTree(modelDependency);
processParentModel(modelDependencyTreeVoIn);
ps.add(modelDependencyTreeVoIn);
}
}

}
modelDependcyTreeVo.setParentModels(ps);
}
}


private void processChildrenModel(ModelDependcyTreeVo modelDependcyTreeVo) throws IOException {
String version = modelDependcyTreeVo.getVersion();
Integer modelId = modelDependcyTreeVo.getCurrentModelId();
List<ModelDependcyTreeVo> cs = new ArrayList<ModelDependcyTreeVo>();
//查儿子们

List<ModelDependency> modelDependencyList = modelDependencyDao.queryChildrenByVersionId("\"model_id\":"+modelId, "\"model_version\":\""+version+"\"");
if (modelDependencyList!=null&&modelDependencyList.size()>=0){
for (ModelDependency modelDependency:modelDependencyList){
ModelDependcyTreeVo modelDependencyTreeVoIn = ModelDependencyConvertToTree(modelDependency);
processChildrenModel(modelDependencyTreeVoIn);
cs.add(modelDependencyTreeVoIn);
}
}
modelDependcyTreeVo.setChildrenModels(cs);
}

private ModelDependcyTreeVo ModelDependencyConvertToTree(ModelDependency modelDependency) throws IOException {
ModelDependcyTreeVo modelDependcyTreeVo = new ModelDependcyTreeVo();
modelDependcyTreeVo.setCurrentModelId(modelDependency.getCurrentModelId());
modelDependcyTreeVo.setExpInsId(modelDependency.getExpInsId());
modelDependcyTreeVo.setVersion(modelDependency.getVersion());
modelDependcyTreeVo.setRefItem(modelDependency.getRefItem());
modelDependcyTreeVo.setTrainTask(JacksonUtil.parseJSONStr2Map(modelDependency.getTrainTask()));
modelDependcyTreeVo.setTrainDataset(JacksonUtil.parseJSONStr2MapList(modelDependency.getTrainDataset()));
modelDependcyTreeVo.setTrainImage(modelDependency.getTrainImage());
modelDependcyTreeVo.setTrainParams(JacksonUtil.parseJSONStr2TList(modelDependency.getTrainParams(),Object.class,null));
modelDependcyTreeVo.setTestDataset(JacksonUtil.parseJSONStr2MapList(modelDependency.getTestDataset()));
modelDependcyTreeVo.setProjectDependency(JacksonUtil.parseJSONStr2Map(modelDependency.getProjectDependency()));
modelDependcyTreeVo.setParentModelsMap(JacksonUtil.parseJSONStr2MapList(modelDependency.getParentModels()));

/**
* 补充workFlow_id + 是否共有
*/
Integer currentModelId = modelDependency.getCurrentModelId();
Integer expInsId = modelDependency.getExpInsId();
Models models = modelsService.queryById(currentModelId);
ModelsVersion modelsVersionquery = new ModelsVersion();
modelsVersionquery.setModelsId(currentModelId);
modelsVersionquery.setVersion(modelDependency.getVersion());
ModelsVersion modelsVersion = modelsVersionService.queryByModelsVersion(modelsVersionquery);
ExperimentIns experimentIns = experimentInsService.queryById(expInsId);
Experiment experiment = experimentService.queryById(experimentIns.getExperimentId());
ModelVersionDependcyVo modelVersionDependcyVo = new ModelVersionDependcyVo();
modelVersionDependcyVo.setName(models.getName());
modelVersionDependcyVo.setAvailableRange(models.getAvailableRange());
modelVersionDependcyVo.setDescription(models.getDescription());
modelVersionDependcyVo.setModelTag(models.getModelTag());
modelVersionDependcyVo.setModelType(models.getModelType());
modelVersionDependcyVo.setModelTagName(models.getModelTagName());
modelVersionDependcyVo.setModelTypeName(models.getModelTypeName());
modelVersionDependcyVo.setFileName(modelsVersion.getFileName());
modelVersionDependcyVo.setFileSize(modelsVersion.getFileSize());
modelVersionDependcyVo.setUrl(modelsVersion.getUrl());
modelDependcyTreeVo.setWorkflowId(experiment.getWorkflowId());
modelDependcyTreeVo.setModelVersionDependcyVo(modelVersionDependcyVo);
return modelDependcyTreeVo;
}

/**
* 新增数据
*
* @param modelDependency 实例对象
* @return 实例对象
*/
@Override
public ModelDependency insert(ModelDependency modelDependency) {
//插入预备,此时不需要判断版本重复
LoginUser loginUser = SecurityUtils.getLoginUser();
modelDependency.setCreateBy(loginUser.getUsername());
modelDependency.setUpdateBy(loginUser.getUsername());
modelDependency.setUpdateTime(new Date());
modelDependency.setCreateTime(new Date());
this.modelDependencyDao.insert(modelDependency);
return modelDependency;
}

/**
* 修改数据
*
* @param modelDependency 实例对象
* @return 实例对象
*/
@Override
public ModelDependency update(ModelDependency modelDependency) {
LoginUser loginUser = SecurityUtils.getLoginUser();
modelDependency.setUpdateBy(loginUser.getUsername());
modelDependency.setUpdateTime(new Date());
this.modelDependencyDao.update(modelDependency);
return this.queryById(modelDependency.getId());
}

/**
* 通过主键删除数据
*
* @param id 主键
* @return 是否成功
*/
@Override
public boolean deleteById(Integer id) {
return this.modelDependencyDao.deleteById(id) > 0;
}

@Override
public String removeById(Integer id) {
ModelDependency modelDependency = this.modelDependencyDao.queryById(id);
if (modelDependency == null){
return "模型依赖信息不存在";
}

//判断权限,只有admin和创建者本身可以删除该数据集
LoginUser loginUser = SecurityUtils.getLoginUser();
String username = loginUser.getUsername();
String createdBy = modelDependency.getCreateBy();
if (!(StringUtils.equals(username,"admin") || StringUtils.equals(username,createdBy))){
return "无权限删除";
}

modelDependency.setState(0);
return this.modelDependencyDao.update(modelDependency)>0?"删除成功":"删除失败";
}

}

+ 1
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ModelsServiceImpl.java View File

@@ -192,6 +192,7 @@ public class ModelsServiceImpl implements ModelsService {
*
* @param id models_version表的主键
* @return 文件内容
*
*/

@Override


+ 39
- 2
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ModelsVersionServiceImpl.java View File

@@ -3,20 +3,24 @@ package com.ruoyi.platform.service.impl;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.platform.annotations.CheckDuplicate;
import com.ruoyi.platform.domain.Dataset;
import com.ruoyi.platform.domain.ModelDependency;
import com.ruoyi.platform.domain.Models;
import com.ruoyi.platform.domain.ModelsVersion;
import com.ruoyi.platform.mapper.ModelsDao;
import com.ruoyi.platform.mapper.ModelsVersionDao;
import com.ruoyi.platform.service.ModelDependencyService;
import com.ruoyi.platform.service.ModelsVersionService;
import com.ruoyi.system.api.model.LoginUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.HashMap;
@@ -36,7 +40,9 @@ public class ModelsVersionServiceImpl implements ModelsVersionService {

@Resource
private ModelsDao modelsDao;

@Resource
@Lazy
private ModelDependencyService modelDependencyService;
// 固定存储桶名
@Value("${minio.dataReleaseBucketName}")
private String bucketName;
@@ -81,6 +87,7 @@ public class ModelsVersionServiceImpl implements ModelsVersionService {
modelsVersion.setCreateTime(new Date());
modelsVersion.setState(1);
this.modelsVersionDao.insert(modelsVersion);
insertModelsDependency(modelsVersion);
return modelsVersion;
}

@@ -191,7 +198,7 @@ public class ModelsVersionServiceImpl implements ModelsVersionService {
}

@Override
public Map<Integer, String> deleteModelsVersion(Integer modelsId, String version) {
public Map<Integer, String> deleteModelsVersion(Integer modelsId, String version) throws IOException {
Map<Integer, String> results = new HashMap<Integer,String>();
// 根据模型ID和版本查询所有模型版本
List<ModelsVersion> versions = this.modelsVersionDao.queryAllByModelsVersion(modelsId, version);
@@ -200,6 +207,16 @@ public class ModelsVersionServiceImpl implements ModelsVersionService {
String result = this.removeById(modelsVersion.getId());
results.put(modelsVersion.getId(), result);
}
// 删除依赖关系
ModelDependency modelDependency = new ModelDependency();
modelDependency.setCurrentModelId(modelsId);
modelDependency.setVersion(version);
modelDependency.setState(1);
List<ModelDependency> modelDependencyList = modelDependencyService.queryByModelDependency(modelDependency);
if (modelDependencyList.size()>0){
ModelDependency modelDependency1 = modelDependencyList.get(0);
modelDependencyService.removeById(modelDependency1.getId());
}
return results;
}

@@ -210,6 +227,7 @@ public class ModelsVersionServiceImpl implements ModelsVersionService {
for(ModelsVersion modelsVersion : modelsVersions) {
insertPrepare(modelsVersion);
}
insertModelsDependency(modelsVersions.get(0));
this.modelsVersionDao.insertBatch(modelsVersions);
return "新增模型版本成功";
} catch (Exception e) {
@@ -248,4 +266,23 @@ public class ModelsVersionServiceImpl implements ModelsVersionService {

}

//新增模型依赖关系
private void insertModelsDependency(ModelsVersion modelsVersion) throws Exception {
ModelDependency modelDependency = new ModelDependency();
modelDependency.setCurrentModelId(modelsVersion.getModelsId());
modelDependency.setVersion(modelsVersion.getVersion());
modelDependency.setState(2);
List<ModelDependency> modelDependencyList = modelDependencyService.queryByModelDependency(modelDependency);
if (modelDependencyList != null && modelDependencyList.size()>0){
//查到2,说明是之前流水线推送的,你就直接该状态生效就完了
ModelDependency modelDependency1 = modelDependencyList.get(0);
modelDependency1.setState(1);
modelDependencyService.update(modelDependency1);

}else {
modelDependency.setState(1);
modelDependencyService.insert(modelDependency);
}
}

}

+ 3
- 3
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/WorkflowServiceImpl.java View File

@@ -110,8 +110,9 @@ public class WorkflowServiceImpl implements WorkflowService {
* @return 实例对象
*/
@Override
public Workflow update(Workflow workflow) {
public Workflow update(Workflow workflow) throws Exception {
LoginUser loginUser = SecurityUtils.getLoginUser();
checkDeclaredName(workflow);
workflow.setUpdateBy(loginUser.getUsername());
workflow.setUpdateTime(new Date());
this.workflowDao.update(workflow);
@@ -207,10 +208,9 @@ public class WorkflowServiceImpl implements WorkflowService {
// 这是相同的流水线,更新操作中没有重复名称问题
return;
}
// 现在我们知道还有另一个具有相同名称的流水线
Field[] fields = Workflow.class.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true); // 使私有字段可访问
field.setAccessible(true);
if ("name".equals(field.getName()) && field.isAnnotationPresent(CheckDuplicate.class)) {
// 如果字段是“name”并且标记了CheckDuplicate注解
CheckDuplicate annotation = field.getAnnotation(CheckDuplicate.class);


+ 1
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/WorkspaceServiceImpl.java View File

@@ -103,6 +103,7 @@ public class WorkspaceServiceImpl implements WorkspaceService {
assetCountMap.put("image", imageCount);
//统计组件数量
Component component = new Component();
component.setAvailableRange(availableRange);
Integer componentCount = (int) this.componentDao.count(component);
assetCountMap.put("component", componentCount);
//统计流水线数量


+ 20
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/JacksonUtil.java View File

@@ -5,9 +5,12 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.ruoyi.common.core.utils.StringUtils;
import org.apache.xmlbeans.impl.xb.xsdschema.Public;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@@ -56,6 +59,21 @@ public class JacksonUtil {
}
}



public static String replaceInAarry(String res, List<Map<String, Object>> params) {
// 解析 JSON 数组
if (params == null) {
return res;
}
for (int i = 0; i < params.size(); i++) {
Map<String, Object> stringObjectMap = params.get(i);
if (res.contains("${" + stringObjectMap.get("param_name") + "}")) {
res = res.replace("${" + stringObjectMap.get("param_name") + "}", String.valueOf( stringObjectMap.get("param_value")));
}
}
return res;
}
/**
* 获取ObjectMapper。其本身是线程安全的,可以作为成员变量,但传入的参数不可能每次都一样,所以不使用成员变量。
*
@@ -140,6 +158,7 @@ public class JacksonUtil {
*/
public static Map<String, Object> parseJSONStr2Map(String jsonStr) {
try {
if (StringUtils.isEmpty(jsonStr)) {return new HashMap<String, Object>();}
// 对于json字符串新增的字段,由于返回的是map,不管 compatNewProps 设置成什么值都不会抛出异常
ObjectMapper objectMapper = getObjectMapper(null, false, false, true);
return objectMapper.readValue(jsonStr, Map.class);
@@ -158,6 +177,7 @@ public class JacksonUtil {
*/
public static List<Map<String, Object>> parseJSONStr2MapList(String jsonStr) {
try {
if (StringUtils.isEmpty(jsonStr)) {return new ArrayList<>();}
// 对于json字符串新增的字段,由于返回的是map,不管 compatNewProps 设置成什么值都不会抛出异常
ObjectMapper objectMapper = getObjectMapper(null, false, false, true);
CollectionType listType = objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, Map.class);


+ 116
- 5
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/K8sClientUtil.java View File

@@ -22,9 +22,7 @@ import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.*;

/**
* k8s客户端
@@ -282,13 +280,13 @@ public class K8sClientUtil {
.endSpec()
.build();


try {
pod = api.createNamespacedPod(namespace, pod, null, null, null);
} catch (ApiException e) {
log.error("创建pod异常:" + e.getResponseBody(), e);
} catch (Exception e) {
log.error("创建pod系统异常:", e);

}

V1Service service = createService(namespace, podName + "-svc", port, selector);
@@ -324,7 +322,6 @@ public class K8sClientUtil {
for (V1Pod pod1 : v1PodList.getItems()) {
if (StringUtils.equals(pod1.getMetadata().getName(), podName)) {
// PVC 已存在

V1Service service = createService(namespace, podName + "-svc", port, selector);
if (service != null) {
return service.getSpec().getPorts().get(0).getNodePort();
@@ -378,6 +375,73 @@ public class K8sClientUtil {
return service.getSpec().getPorts().get(0).getNodePort();
}


public Integer createConfiguredPod(String podName, String namespace, Integer port, String mountPath, V1PersistentVolumeClaim pvc, String image, String datasetPath, String modelPath) {
Map<String, String> selector = new LinkedHashMap<>();
selector.put("k8s-jupyter", podName);

CoreV1Api api = new CoreV1Api(apiClient);
V1PodList v1PodList = null;
try {
v1PodList = api.listNamespacedPod(namespace, null, null, null, null, null, null, null, null, null, null);
} catch (ApiException e) {
log.error("获取 POD 异常:", e);
}
if (v1PodList != null) {
for (V1Pod pod1 : v1PodList.getItems()) {
// PVC 已存在
if (StringUtils.equals(pod1.getMetadata().getName(), podName)) {
V1Service service = createService(namespace, podName + "-svc", port, selector);
if (service != null) {
return service.getSpec().getPorts().get(0).getNodePort();
}
}
}
}

// 配置卷和卷挂载
List<V1VolumeMount> volumeMounts = new ArrayList<>();
volumeMounts.add(new V1VolumeMount().name("workspace").mountPath(mountPath));
volumeMounts.add(new V1VolumeMount().name("dataset").mountPath("/datasets").subPath(datasetPath).readOnly(true));
volumeMounts.add(new V1VolumeMount().name("model").mountPath("/model").subPath(modelPath).readOnly(true));

List<V1Volume> volumes = new ArrayList<>();
volumes.add(new V1Volume().name("workspace").persistentVolumeClaim(new V1PersistentVolumeClaimVolumeSource().claimName(pvc.getMetadata().getName())));
volumes.add(new V1Volume().name("dataset").persistentVolumeClaim(new V1PersistentVolumeClaimVolumeSource().claimName(pvc.getMetadata().getName())));
volumes.add(new V1Volume().name("model").persistentVolumeClaim(new V1PersistentVolumeClaimVolumeSource().claimName(pvc.getMetadata().getName())));

V1Pod pod = new V1PodBuilder()
.withNewMetadata()
.withName(podName)
.withLabels(selector)
.endMetadata()
.withNewSpec()
.addNewContainer()
.withName(podName)
.withImage(image)
.withPorts(new V1ContainerPort().containerPort(port).protocol("TCP"))
.withVolumeMounts(volumeMounts)
.endContainer()
.withVolumes(volumes)
.withTerminationGracePeriodSeconds(14400L)
.endSpec()
.build();

try {
pod = api.createNamespacedPod(namespace, pod, null, null, null);
} catch (ApiException e) {
log.error("创建pod异常:" + e.getResponseBody(), e);
} catch (Exception e) {
log.error("创建pod系统异常:", e);
}

V1Service service = createService(namespace, podName + "-svc", port, selector);
return service.getSpec().getPorts().get(0).getNodePort();
}




/**
* 根据获取namespace,deploymentName的Pod Name
*
@@ -495,4 +559,51 @@ public class K8sClientUtil {
}
return pod;
}

/**
* 删除 Pod
*
* @param podName Pod 名称
* @param namespace 命名空间
* @throws ApiException 异常
*/
public String deletePod(String podName, String namespace) throws ApiException {
CoreV1Api api = new CoreV1Api(apiClient);
try {
V1Pod pod = api.deleteNamespacedPod(podName, namespace, null, null, null, null, null, null);
return "Pod " + podName + " 删除请求已发送";
} catch (ApiException e) {
if (e.getCode() == 404) {
return "Pod " + podName + " 不存在";
} else {
log.error("删除pod异常:" + e.getResponseBody(), e);
throw e;
}
}
}

/**
* 检查 Pod 是否存在
*
* @param podName Pod 名称
* @param namespace 命名空间
* @return 是否存在
* @throws ApiException 异常
*/
public boolean checkPodExists(String podName, String namespace) throws ApiException {
CoreV1Api api = new CoreV1Api(apiClient);
try {
api.readNamespacedPod(podName, namespace, null,false,false);
return true;
} catch (ApiException e) {
if (e.getCode() == 404) {
return false;
} else {
log.error("检查pod存在性异常:" + e.getResponseBody(), e);
throw e;
}
}
}


}

+ 72
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/ModelDependcyTreeVo.java View File

@@ -0,0 +1,72 @@
package com.ruoyi.platform.vo;

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.ruoyi.platform.domain.Models;
import lombok.Data;

import java.util.List;
import java.util.Map;

@Data
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class ModelDependcyTreeVo {
/**
* 当前模型id
*/
private Integer currentModelId;
/**
* 实验实例id
*/
private Integer expInsId;

/**
* 版本
*/
private String version;


/**
* 引用项目
*/
private String refItem;
/**
* 训练任务
*/
private Map trainTask;
/**
* 训练数据集
*/
private List<Map<String, Object>> trainDataset;

/**
* 训练参数
*/
private List trainParams;
/**
* 训练镜像
*/
private String trainImage;
/**
* 测试数据集
*/
private List<Map<String, Object>> testDataset;
/**
* 依赖项目
*/
private Map projectDependency;

private List<Map<String, Object>> parentModelsMap;
/**
* 父模型
*/
private List<ModelDependcyTreeVo> parentModels;

/**
* 子模型
*/
private List<ModelDependcyTreeVo> childrenModels;

private Long workflowId;
private ModelVersionDependcyVo modelVersionDependcyVo;
}

+ 48
- 0
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/ModelVersionDependcyVo.java View File

@@ -0,0 +1,48 @@
package com.ruoyi.platform.vo;

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.ruoyi.platform.annotations.CheckDuplicate;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;

@Data
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class ModelVersionDependcyVo implements Serializable {


@ApiModelProperty(name = "name")
private String name;

// private String version;
@ApiModelProperty(name = "description")
private String description;

@ApiModelProperty(value = "模型可见范围,1表示公开,0表示私有")
private int availableRange;

@ApiModelProperty(value = "模型类型(模型框架)")
private String modelType;

@ApiModelProperty(value = "模型标签")
private String modelTag;


@ApiModelProperty(value = "模型类型名")
private String modelTypeName;

@ApiModelProperty(value = "模型tag名")
private String modelTagName;

@ApiModelProperty(value = "模型存储地址")
private String url;

@ApiModelProperty(value = "文件名")
private String fileName;

@ApiModelProperty(value = "文件大小")
private String fileSize;

}

+ 18
- 8
ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ComponentDaoMapper.xml View File

@@ -16,6 +16,7 @@
<result property="mountPath" column="mount_path" jdbcType="VARCHAR"/>
<result property="inParameters" column="in_parameters" jdbcType="VARCHAR"/>
<result property="outParameters" column="out_parameters" jdbcType="VARCHAR"/>
<result property="availableRange" column="available_range" jdbcType="INTEGER"/>
<result property="description" column="description" jdbcType="VARCHAR"/>
<result property="iconPath" column="icon_path" jdbcType="VARCHAR"/>
<result property="createBy" column="create_by" jdbcType="VARCHAR"/>
@@ -28,7 +29,7 @@
<!--查询单个-->
<select id="queryById" resultMap="ComponentMap">
select
id,category_id,component_name,component_Label,images,working_directory,command,env_virables,resources_standard,control_strategy,mount_path,in_parameters,out_parameters,description,icon_path,create_by,create_time,update_by,update_time,state
id,category_id,component_name,component_Label,images,working_directory,command,env_virables,resources_standard,control_strategy,mount_path,in_parameters,out_parameters,available_range,description,icon_path,create_by,create_time,update_by,update_time,state
from component
where id = #{id} and state = 1
</select>
@@ -42,7 +43,7 @@
<!--查询指定行数据-->
<select id="queryAllByLimit" resultMap="ComponentMap">
select
id,category_id,component_name,component_Label,images,working_directory,command,env_virables,resources_standard,control_strategy,mount_path,in_parameters,out_parameters,description,icon_path,create_by,create_time,update_by,update_time,state
id,category_id,component_name,component_Label,images,working_directory,command,env_virables,resources_standard,control_strategy,mount_path,in_parameters,out_parameters,available_range,description,icon_path,create_by,create_time,update_by,update_time,state
from component
<where>
state = 1
@@ -85,6 +86,9 @@
<if test="component.outParameters != null and component.outParameters != ''">
and out_parameters = #{component.outParameters}
</if>
<if test="component.availableRange != null">
and available_range = #{component.availableRange}
</if>
<if test="component.description != null and component.description != ''">
and description = #{component.description}
</if>
@@ -155,6 +159,9 @@
<if test="component.outParameters != null and component.outParameters != ''">
and out_parameters = #{component.outParameters}
</if>
<if test="component.availableRange != null">
and available_range = #{component.availableRange}
</if>
<if test="component.description != null and component.description != ''">
and description = #{component.description}
</if>
@@ -190,23 +197,23 @@

<!--新增所有列-->
<insert id="insert" keyProperty="id" useGeneratedKeys="true">
insert into component(category_id,component_name,component_Label,images,working_directory,command,env_virables,resources_standard,control_strategy,mount_path,in_parameters,out_parameters,description,icon_path,create_by,create_time,update_by,update_time,state)
values (#{component.categoryId},#{component.componentName},#{component.componentLabel},#{component.images},#{component.workingDirectory},#{component.command},#{component.envVirables},#{component.resourcesStandard},#{component.controlStrategy},#{component.mountPath},#{component.inParameters},#{component.outParameters},#{component.description},#{component.iconPath},#{component.createBy},#{component.createTime},#{component.updateBy},#{component.updateTime},#{component.state})
insert into component(category_id,component_name,component_Label,images,working_directory,command,env_virables,resources_standard,control_strategy,mount_path,in_parameters,out_parameters,available_range,description,icon_path,create_by,create_time,update_by,update_time,state)
values (#{component.categoryId},#{component.componentName},#{component.componentLabel},#{component.images},#{component.workingDirectory},#{component.command},#{component.envVirables},#{component.resourcesStandard},#{component.controlStrategy},#{component.mountPath},#{component.inParameters},#{component.outParameters},#{component.availableRange},#{component.description},#{component.iconPath},#{component.createBy},#{component.createTime},#{component.updateBy},#{component.updateTime},#{component.state})
</insert>

<insert id="insertBatch" keyProperty="id" useGeneratedKeys="true">
insert into component(category_idcomponent_namecomponent_labelimagesworking_directorycommandenv_virablesresources_standardcontrol_strategymount_pathin_parametersout_parameterscreate_bycreate_timeupdate_byupdate_timestate)
insert into component(category_id,component_name,component_Label,images,working_directory,command,env_virables,resources_standard,control_strategy,mount_path,in_parameters,out_parameters,available_range,description,icon_path,create_by,create_time,update_by,update_time,state)
values
<foreach collection="entities" item="entity" separator=",">
(#{entity.categoryId}#{entity.componentName}#{entity.componentLabel}#{entity.images}#{entity.workingDirectory}#{entity.command}#{entity.envVirables}#{entity.resourcesStandard}#{entity.controlStrategy}#{entity.mountPath}#{entity.inParameters}#{entity.outParameters}#{entity.createBy}#{entity.createTime}#{entity.updateBy}#{entity.updateTime}#{entity.state})
(#{entity.categoryId},#{entity.componentName},#{entity.componentLabel},#{entity.images},#{entity.workingDirectory},#{entity.command},#{entity.envVirables},#{entity.resourcesStandard},#{entity.controlStrategy},#{entity.mountPath},#{entity.inParameters},#{entity.outParameters},#{entity.availableRange},#{entity.createBy},#{entity.createTime},#{entity.updateBy},#{entity.updateTime},#{entity.state})
</foreach>
</insert>

<insert id="insertOrUpdateBatch" keyProperty="id" useGeneratedKeys="true">
insert into component(category_idcomponent_namecomponent_labelimagesworking_directorycommandenv_virablesresources_standardcontrol_strategymount_pathin_parametersout_parameterscreate_bycreate_timeupdate_byupdate_timestate)
insert into component(category_id,component_name,component_Label,images,working_directory,command,env_virables,resources_standard,control_strategy,mount_path,in_parameters,out_parameters,available_range,description,icon_path,create_by,create_time,update_by,update_time,state)
values
<foreach collection="entities" item="entity" separator=",">
(#{entity.categoryId}#{entity.componentName}#{entity.componentId}#{entity.images}#{entity.workingDirectory}#{entity.command}#{entity.envVirables}#{entity.resourcesStandard}#{entity.controlStrategy}#{entity.mountPath}#{entity.inParameters}#{entity.outParameters}#{entity.createBy}#{entity.createTime}#{entity.updateBy}#{entity.updateTime}#{entity.state})
(#{entity.categoryId},#{entity.componentName},#{entity.componentLabel},#{entity.images},#{entity.workingDirectory},#{entity.command},#{entity.envVirables},#{entity.resourcesStandard},#{entity.controlStrategy},#{entity.mountPath},#{entity.inParameters},#{entity.outParameters},#{entity.availableRange},#{entity.createBy},#{entity.createTime},#{entity.updateBy},#{entity.updateTime},#{entity.state})
</foreach>
on duplicate key update
category_id = values(category_id)component_name = values(component_name)component_id = values(component_id)images = values(images)working_directory = values(working_directory)command = values(command)env_virables = values(env_virables)resources_standard = values(resources_standard)control_strategy = values(control_strategy)mount_path = values(mount_path)in_parameters = values(in_parameters)out_parameters = values(out_parameters)create_by = values(create_by)create_time = values(create_time)update_by = values(update_by)update_time = values(update_time)state = values(state)
@@ -255,6 +262,9 @@ category_id = values(category_id)component_name = values(component_name)componen
<if test="component.outParameters != null and component.outParameters != ''">
out_parameters = #{component.outParameters},
</if>
<if test="component.availableRange != null">
available_range = #{component.availableRange},
</if>
<if test="component.description != null and component.description != ''">
description = #{component.description},
</if>


+ 246
- 0
ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/DevEnvironmentDaoMapper.xml View File

@@ -0,0 +1,246 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.platform.mapper.DevEnvironmentDao">

<resultMap type="com.ruoyi.platform.domain.DevEnvironment" id="DevEnvironmentMap">
<result property="id" column="id" jdbcType="INTEGER"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="status" column="status" jdbcType="VARCHAR"/>
<result property="computingResource" column="computing_resource" jdbcType="VARCHAR"/>
<result property="standard" column="standard" jdbcType="VARCHAR"/>
<result property="envVariable" column="env_variable" jdbcType="VARCHAR"/>
<result property="image" column="image" jdbcType="VARCHAR"/>
<result property="dataset" column="dataset" jdbcType="VARCHAR"/>
<result property="model" column="model" jdbcType="VARCHAR"/>
<result property="altField1" column="alt_field1" jdbcType="VARCHAR"/>
<result property="altField2" column="alt_field2" jdbcType="VARCHAR"/>
<result property="createBy" column="create_by" jdbcType="VARCHAR"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
<result property="updateBy" column="update_by" jdbcType="VARCHAR"/>
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
<result property="state" column="state" jdbcType="INTEGER"/>
</resultMap>

<!--查询单个-->
<select id="queryById" resultMap="DevEnvironmentMap">
select
id,name,status,computing_resource,standard,env_variable,image,dataset,model,alt_field1,alt_field2,create_by,create_time,update_by,update_time,state
from dev_environment
where id = #{id}
</select>

<!--查询指定行数据-->
<select id="queryAllByLimit" resultMap="DevEnvironmentMap">
select
id,name,status,computing_resource,standard,env_variable,image,dataset,model,alt_field1,alt_field2,create_by,create_time,update_by,update_time,state
from dev_environment
<where>
<if test="devEnvironment.id != null">
and id = #{devEnvironment.id}
</if>
<if test="devEnvironment.name != null and devEnvironment.name != ''">
and name = #{devEnvironment.name}
</if>
<if test="devEnvironment.status != null and devEnvironment.status != ''">
and status = #{devEnvironment.status}
</if>
<if test="devEnvironment.computingResource != null and devEnvironment.computingResource != ''">
and computing_resource = #{devEnvironment.computingResource}
</if>
<if test="devEnvironment.standard != null and devEnvironment.standard != ''">
and standard = #{devEnvironment.standard}
</if>
<if test="devEnvironment.envVariable != null and devEnvironment.envVariable != ''">
and env_variable = #{devEnvironment.envVariable}
</if>
<if test="devEnvironment.image != null and devEnvironment.image != ''">
and image = #{devEnvironment.image}
</if>
<if test="devEnvironment.dataset != null and devEnvironment.dataset != ''">
and dataset = #{devEnvironment.dataset}
</if>
<if test="devEnvironment.model != null and devEnvironment.model != ''">
and model = #{devEnvironment.model}
</if>
<if test="devEnvironment.altField1 != null and devEnvironment.altField1 != ''">
and alt_field1 = #{devEnvironment.altField1}
</if>
<if test="devEnvironment.altField2 != null and devEnvironment.altField2 != ''">
and alt_field2 = #{devEnvironment.altField2}
</if>
<if test="devEnvironment.createBy != null and devEnvironment.createBy != ''">
and create_by = #{devEnvironment.createBy}
</if>
<if test="devEnvironment.createTime != null">
and create_time = #{devEnvironment.createTime}
</if>
<if test="devEnvironment.updateBy != null and devEnvironment.updateBy != ''">
and update_by = #{devEnvironment.updateBy}
</if>
<if test="devEnvironment.updateTime != null">
and update_time = #{devEnvironment.updateTime}
</if>
<if test="devEnvironment.state != null">
and state = #{devEnvironment.state}
</if>
</where>
limit #{pageable.offset}, #{pageable.pageSize}
</select>


<!--统计总行数-->
<select id="count" resultType="java.lang.Long">
select count(1)
from dev_environment
<where>
<if test="devEnvironment.id != null">
and id = #{devEnvironment.id}
</if>
<if test="devEnvironment.name != null and devEnvironment.name != ''">
and name = #{devEnvironment.name}
</if>
<if test="devEnvironment.status != null and devEnvironment.status != ''">
and status = #{devEnvironment.status}
</if>
<if test="devEnvironment.computingResource != null and devEnvironment.computingResource != ''">
and computing_resource = #{devEnvironment.computingResource}
</if>
<if test="devEnvironment.standard != null and devEnvironment.standard != ''">
and standard = #{devEnvironment.standard}
</if>
<if test="devEnvironment.envVariable != null and devEnvironment.envVariable != ''">
and env_variable = #{devEnvironment.envVariable}
</if>
<if test="devEnvironment.image != null and devEnvironment.image != ''">
and image = #{devEnvironment.image}
</if>
<if test="devEnvironment.dataset != null and devEnvironment.dataset != ''">
and dataset = #{devEnvironment.dataset}
</if>
<if test="devEnvironment.model != null and devEnvironment.model != ''">
and model = #{devEnvironment.model}
</if>
<if test="devEnvironment.altField1 != null and devEnvironment.altField1 != ''">
and alt_field1 = #{devEnvironment.altField1}
</if>
<if test="devEnvironment.altField2 != null and devEnvironment.altField2 != ''">
and alt_field2 = #{devEnvironment.altField2}
</if>
<if test="devEnvironment.createBy != null and devEnvironment.createBy != ''">
and create_by = #{devEnvironment.createBy}
</if>
<if test="devEnvironment.createTime != null">
and create_time = #{devEnvironment.createTime}
</if>
<if test="devEnvironment.updateBy != null and devEnvironment.updateBy != ''">
and update_by = #{devEnvironment.updateBy}
</if>
<if test="devEnvironment.updateTime != null">
and update_time = #{devEnvironment.updateTime}
</if>
<if test="devEnvironment.state != null">
and state = #{devEnvironment.state}
</if>
</where>
</select>

<!--新增所有列-->
<insert id="insert" keyProperty="id" useGeneratedKeys="true">
insert into dev_environment(name,status,computing_resource,standard,env_variable,image,dataset,model,alt_field1,alt_field2,create_by,create_time,update_by,update_time,state)
values (#{devEnvironment.name},
#{devEnvironment.status},
#{devEnvironment.computingResource},
#{devEnvironment.standard},
#{devEnvironment.envVariable},
#{devEnvironment.image},
#{devEnvironment.dataset},
#{devEnvironment.model},
#{devEnvironment.altField1},
#{devEnvironment.altField2},
#{devEnvironment.createBy},
#{devEnvironment.createTime},
#{devEnvironment.updateBy},
#{devEnvironment.updateTime},
#{devEnvironment.state}
)
</insert>

<insert id="insertBatch" keyProperty="id" useGeneratedKeys="true">
insert into dev_environment(name,status,computing_resource,standard,env_variable,image,dataset,model,alt_field1,alt_field2,create_by,create_time,update_by,update_time,state )
values
<foreach collection="entities" item="entity" separator=",">
(#{entity.name},#{entity.status},#{entity.computingResource},#{entity.standard},#{entity.envVariable},#{entity.image},#{entity.dataset},#{entity.model},#{entity.altField1},#{entity.altField2},#{entity.createBy},#{entity.createTime},#{entity.updateBy},#{entity.updateTime},#{entity.state})
</foreach>
</insert>

<insert id="insertOrUpdateBatch" keyProperty="id" useGeneratedKeys="true">
insert into dev_environment(name,status,computing_resource,standard,env_variable,image,dataset,model,alt_field1,alt_field2,create_by,create_time,update_by,update_time,state)
values
<foreach collection="entities" item="entity" separator=",">
(#{entity.name}#{entity.status}#{entity.computingResource}#{entity.standard}#{entity.envVariable}#{entity.image}#{entity.dataset}#{entity.model}#{entity.altField1}#{entity.altField2}#{entity.createBy}#{entity.createTime}#{entity.updateBy}#{entity.updateTime}#{entity.state})
</foreach>
on duplicate key update
name = values(name)status = values(status)computing_resource = values(computing_resource)standard = values(standard)env_variable = values(env_variable)image = values(image)dataset = values(dataset)model = values(model)alt_field1 = values(alt_field1)alt_field2 = values(alt_field2)create_by = values(create_by)create_time = values(create_time)update_by = values(update_by)update_time = values(update_time)state = values(state)
</insert>

<!--通过主键修改数据-->
<update id="update">
update dev_environment
<set>
<if test="devEnvironment.name != null and devEnvironment.name != ''">
name = #{devEnvironment.name},
</if>
<if test="devEnvironment.status != null and devEnvironment.status != ''">
status = #{devEnvironment.status},
</if>
<if test="devEnvironment.computingResource != null and devEnvironment.computingResource != ''">
computing_resource = #{devEnvironment.computingResource},
</if>
<if test="devEnvironment.standard != null and devEnvironment.standard != ''">
standard = #{devEnvironment.standard},
</if>
<if test="devEnvironment.envVariable != null and devEnvironment.envVariable != ''">
env_variable = #{devEnvironment.envVariable},
</if>
<if test="devEnvironment.image != null and devEnvironment.image != ''">
image = #{devEnvironment.image},
</if>
<if test="devEnvironment.dataset != null and devEnvironment.dataset != ''">
dataset = #{devEnvironment.dataset},
</if>
<if test="devEnvironment.model != null and devEnvironment.model != ''">
model = #{devEnvironment.model},
</if>
<if test="devEnvironment.altField1 != null and devEnvironment.altField1 != ''">
alt_field1 = #{devEnvironment.altField1},
</if>
<if test="devEnvironment.altField2 != null and devEnvironment.altField2 != ''">
alt_field2 = #{devEnvironment.altField2},
</if>
<if test="devEnvironment.createBy != null and devEnvironment.createBy != ''">
create_by = #{devEnvironment.createBy},
</if>
<if test="devEnvironment.createTime != null">
create_time = #{devEnvironment.createTime},
</if>
<if test="devEnvironment.updateBy != null and devEnvironment.updateBy != ''">
update_by = #{devEnvironment.updateBy},
</if>
<if test="devEnvironment.updateTime != null">
update_time = #{devEnvironment.updateTime},
</if>
<if test="devEnvironment.state != null">
state = #{devEnvironment.state},
</if>
</set>
where id = #{devEnvironment.id}
</update>


<!--通过主键删除-->
<delete id="deleteById">
delete from dev_environment where id = #{id}
</delete>

</mapper>


+ 333
- 0
ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ModelDependencyDaoMapper.xml View File

@@ -0,0 +1,333 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.platform.mapper.ModelDependencyDao">

<resultMap type="com.ruoyi.platform.domain.ModelDependency" id="ModelDependencyMap">
<result property="id" column="id" jdbcType="INTEGER"/>
<result property="currentModelId" column="current_model_id" jdbcType="INTEGER"/>
<result property="expInsId" column="exp_ins_id" jdbcType="INTEGER"/>
<result property="parentModels" column="parent_models" jdbcType="VARCHAR"/>
<result property="refItem" column="ref_item" jdbcType="VARCHAR"/>
<result property="trainTask" column="train_task" jdbcType="VARCHAR"/>
<result property="trainDataset" column="train_dataset" jdbcType="VARCHAR"/>
<result property="trainParams" column="train_params" jdbcType="VARCHAR"/>
<result property="trainImage" column="train_image" jdbcType="VARCHAR"/>
<result property="testDataset" column="test_dataset" jdbcType="VARCHAR"/>
<result property="projectDependency" column="project_dependency" jdbcType="VARCHAR"/>
<result property="version" column="version" jdbcType="VARCHAR"/>
<result property="createBy" column="create_by" jdbcType="VARCHAR"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
<result property="updateBy" column="update_by" jdbcType="VARCHAR"/>
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
<result property="state" column="state" jdbcType="INTEGER"/>
</resultMap>

<select id="queryChildrenByVersionId" resultMap="ModelDependencyMap">
select
id,current_model_id,exp_ins_id,parent_models,ref_item,train_task,train_dataset,train_params,train_image,test_dataset,project_dependency,version,create_by,create_time,update_by,update_time,state
from model_dependency
<where>
parent_models like concat('%', #{model_id}, '%') AND parent_models like concat('%', #{version}, '%')
</where>
</select>

<select id="queryByModelDependency" resultMap="ModelDependencyMap">
select
id,current_model_id,exp_ins_id,parent_models,ref_item,train_task,train_dataset,train_params,train_image,test_dataset,project_dependency,version,create_by,create_time,update_by,update_time,state
from model_dependency
<where>
<if test="modelDependency.id != null">
and id = #{modelDependency.id}
</if>
<if test="modelDependency.currentModelId != null">
and current_model_id = #{modelDependency.currentModelId}
</if>
<if test="modelDependency.expInsId != null">
and exp_ins_id = #{modelDependency.expInsId}
</if>
<if test="modelDependency.parentModels != null">
and parent_models = #{modelDependency.parentModels}
</if>
<if test="modelDependency.refItem != null and modelDependency.refItem != ''">
and ref_item = #{modelDependency.refItem}
</if>
<if test="modelDependency.trainTask != null and modelDependency.trainTask != ''">
and train_task = #{modelDependency.trainTask}
</if>
<if test="modelDependency.trainDataset != null and modelDependency.trainDataset != ''">
and train_dataset = #{modelDependency.trainDataset}
</if>
<if test="modelDependency.trainParams != null and modelDependency.trainParams != ''">
and train_params = #{modelDependency.trainParams}
</if>
<if test="modelDependency.trainImage != null and modelDependency.trainImage != ''">
and train_image = #{modelDependency.trainImage}
</if>
<if test="modelDependency.testDataset != null and modelDependency.testDataset != ''">
and test_dataset = #{modelDependency.testDataset}
</if>
<if test="modelDependency.projectDependency != null and modelDependency.projectDependency != ''">
and project_dependency = #{modelDependency.projectDependency}
</if>
<if test="modelDependency.version != null and modelDependency.version != ''">
and version = #{modelDependency.version}
</if>
<if test="modelDependency.createBy != null and modelDependency.createBy != ''">
and create_by = #{modelDependency.createBy}
</if>
<if test="modelDependency.createTime != null">
and create_time = #{modelDependency.createTime}
</if>
<if test="modelDependency.updateBy != null and modelDependency.updateBy != ''">
and update_by = #{modelDependency.updateBy}
</if>
<if test="modelDependency.updateTime != null">
and update_time = #{modelDependency.updateTime}
</if>
<if test="modelDependency.state != null">
and state = #{modelDependency.state}
</if>
</where>
</select>

<!--查询单个-->
<select id="queryById" resultMap="ModelDependencyMap">
select
id, current_model_id, exp_ins_id, parent_models, ref_item, train_task, train_dataset, train_params, train_image, test_dataset, project_dependency, version, create_by, create_time, update_by, update_time, state
from model_dependency
where id = #{id}
</select>

<!--查询指定行数据-->
<select id="queryAllByLimit" resultMap="ModelDependencyMap">
select
id, current_model_id, exp_ins_id, parent_models, ref_item, train_task, train_dataset, train_params, train_image,
test_dataset, project_dependency, version, create_by, create_time, update_by, update_time, state
from model_dependency
<where>
<if test="id != null">
and id = #{id}
</if>
<if test="currentModelId != null">
and current_model_id = #{currentModelId}
</if>
<if test="expInsId != null">
and exp_ins_id = #{expInsId}
</if>
<if test="parentModels != null and parentModels != ''">
and parent_models = #{parentModels}
</if>
<if test="refItem != null and refItem != ''">
and ref_item = #{refItem}
</if>
<if test="trainTask != null and trainTask != ''">
and train_task = #{trainTask}
</if>
<if test="trainDataset != null and trainDataset != ''">
and train_dataset = #{trainDataset}
</if>
<if test="trainParams != null and trainParams != ''">
and train_params = #{trainParams}
</if>
<if test="trainImage != null and trainImage != ''">
and train_image = #{trainImage}
</if>
<if test="testDataset != null and testDataset != ''">
and test_dataset = #{testDataset}
</if>
<if test="projectDependency != null and projectDependency != ''">
and project_dependency = #{projectDependency}
</if>
<if test="version != null and version != ''">
and version = #{version}
</if>
<if test="createBy != null and createBy != ''">
and create_by = #{createBy}
</if>
<if test="createTime != null">
and create_time = #{createTime}
</if>
<if test="updateBy != null and updateBy != ''">
and update_by = #{updateBy}
</if>
<if test="updateTime != null">
and update_time = #{updateTime}
</if>
<if test="state != null">
and state = #{state}
</if>
</where>
limit #{pageable.offset}, #{pageable.pageSize}
</select>

<!--统计总行数-->
<select id="count" resultType="java.lang.Long">
select count(1)
from model_dependency
<where>
<if test="id != null">
and id = #{id}
</if>
<if test="currentModelId != null">
and current_model_id = #{currentModelId}
</if>
<if test="expInsId != null">
and exp_ins_id = #{expInsId}
</if>
<if test="parentModels != null and parentModels != ''">
and parent_models = #{parentModels}
</if>
<if test="refItem != null and refItem != ''">
and ref_item = #{refItem}
</if>
<if test="trainTask != null and trainTask != ''">
and train_task = #{trainTask}
</if>
<if test="trainDataset != null and trainDataset != ''">
and train_dataset = #{trainDataset}
</if>
<if test="trainParams != null and trainParams != ''">
and train_params = #{trainParams}
</if>
<if test="trainImage != null and trainImage != ''">
and train_image = #{trainImage}
</if>
<if test="testDataset != null and testDataset != ''">
and test_dataset = #{testDataset}
</if>
<if test="projectDependency != null and projectDependency != ''">
and project_dependency = #{projectDependency}
</if>
<if test="version != null and version != ''">
and version = #{version}
</if>
<if test="createBy != null and createBy != ''">
and create_by = #{createBy}
</if>
<if test="createTime != null">
and create_time = #{createTime}
</if>
<if test="updateBy != null and updateBy != ''">
and update_by = #{updateBy}
</if>
<if test="updateTime != null">
and update_time = #{updateTime}
</if>
<if test="state != null">
and state = #{state}
</if>
</where>
</select>

<!--新增所有列-->
<insert id="insert" keyProperty="id" useGeneratedKeys="true">
insert into model_dependency(current_model_id, exp_ins_id, parent_models, ref_item, train_task, train_dataset, train_params, train_image, test_dataset, project_dependency, version, create_by, create_time, update_by, update_time, state)
values (#{currentModelId}, #{expInsId}, #{parentModels}, #{refItem}, #{trainTask}, #{trainDataset}, #{trainParams}, #{trainImage}, #{testDataset}, #{projectDependency}, #{version}, #{createBy}, #{createTime}, #{updateBy}, #{updateTime}, #{state})
</insert>

<insert id="insertBatch" keyProperty="id" useGeneratedKeys="true">
insert into model_dependency(current_model_id, exp_ins_id, parent_models, ref_item, train_task, train_dataset,
train_params, train_image, test_dataset, project_dependency, version, create_by, create_time, update_by,
update_time, state)
values
<foreach collection="entities" item="entity" separator=",">
(#{entity.currentModelId}, #{entity.expInsId}, #{entity.parentModels}, #{entity.refItem},
#{entity.trainTask}, #{entity.trainDataset}, #{entity.trainParams}, #{entity.trainImage},
#{entity.testDataset}, #{entity.projectDependency}, #{entity.version}, #{entity.createBy},
#{entity.createTime}, #{entity.updateBy}, #{entity.updateTime}, #{entity.state})
</foreach>
</insert>

<insert id="insertOrUpdateBatch" keyProperty="id" useGeneratedKeys="true">
insert into model_dependency(current_model_id, exp_ins_id, parent_models, ref_item, train_task, train_dataset,
train_params, train_image, test_dataset, project_dependency, version, create_by, create_time, update_by,
update_time, state)
values
<foreach collection="entities" item="entity" separator=",">
(#{entity.currentModelId}, #{entity.expInsId}, #{entity.parentModels}, #{entity.refItem},
#{entity.trainTask}, #{entity.trainDataset}, #{entity.trainParams}, #{entity.trainImage},
#{entity.testDataset}, #{entity.projectDependency}, #{entity.version}, #{entity.createBy},
#{entity.createTime}, #{entity.updateBy}, #{entity.updateTime}, #{entity.state})
</foreach>
on duplicate key update
current_model_id = values(current_model_id),
exp_ins_id = values(exp_ins_id),
parent_models = values(parent_models),
ref_item = values(ref_item),
train_task = values(train_task),
train_dataset = values(train_dataset),
train_params = values(train_params),
train_image = values(train_image),
test_dataset = values(test_dataset),
project_dependency = values(project_dependency),
version = values(version),
create_by = values(create_by),
create_time = values(create_time),
update_by = values(update_by),
update_time = values(update_time),
state = values(state)
</insert>

<!--通过主键修改数据-->
<update id="update">
update model_dependency
<set>
<if test="currentModelId != null">
current_model_id = #{currentModelId},
</if>
<if test="expInsId != null">
exp_ins_id = #{expInsId},
</if>
<if test="parentModels != null and parentModels != ''">
parent_models = #{parentModels},
</if>
<if test="refItem != null and refItem != ''">
ref_item = #{refItem},
</if>
<if test="trainTask != null and trainTask != ''">
train_task = #{trainTask},
</if>
<if test="trainDataset != null and trainDataset != ''">
train_dataset = #{trainDataset},
</if>
<if test="trainParams != null and trainParams != ''">
train_params = #{trainParams},
</if>
<if test="trainImage != null and trainImage != ''">
train_image = #{trainImage},
</if>
<if test="testDataset != null and testDataset != ''">
test_dataset = #{testDataset},
</if>
<if test="projectDependency != null and projectDependency != ''">
project_dependency = #{projectDependency},
</if>
<if test="version != null and version != ''">
version = #{version},
</if>
<if test="createBy != null and createBy != ''">
create_by = #{createBy},
</if>
<if test="createTime != null">
create_time = #{createTime},
</if>
<if test="updateBy != null and updateBy != ''">
update_by = #{updateBy},
</if>
<if test="updateTime != null">
update_time = #{updateTime},
</if>
<if test="state != null">
state = #{state},
</if>
</set>
where id = #{id} and state = 1
</update>

<!--通过主键删除-->
<delete id="deleteById">
delete from model_dependency where id = #{id}
</delete>

</mapper>


Loading…
Cancel
Save