Browse Source

feature and bugfix

feature:
1. 新增tensorboard查看训练过程数据
2.解决模型版本错误问题
master-fzznrj423
somunslotus 1 year ago
parent
commit
4fd32f88bb
42 changed files with 487 additions and 152 deletions
  1. +3
    -1
      react-ui/config/config.ts
  2. BIN
      react-ui/src/assets/img/modal-select-model.png
  3. BIN
      react-ui/src/assets/img/tensor-board-export.png
  4. BIN
      react-ui/src/assets/img/tensor-board-failed.png
  5. BIN
      react-ui/src/assets/img/tensor-board-pending.png
  6. BIN
      react-ui/src/assets/img/tensor-board-running.png
  7. BIN
      react-ui/src/assets/img/tensor-board-stop.png
  8. BIN
      react-ui/src/assets/img/tensor-board-terminated.png
  9. BIN
      react-ui/src/assets/img/tensor-board-unknown.png
  10. +1
    -1
      react-ui/src/components/KFModal/index.less
  11. +1
    -0
      react-ui/src/components/ModalTitle/index.less
  12. +24
    -0
      react-ui/src/hooks/index.ts
  13. +3
    -3
      react-ui/src/pages/Dataset/datasetIntro.jsx
  14. +4
    -4
      react-ui/src/pages/Dataset/index.jsx
  15. +13
    -2
      react-ui/src/pages/Dataset/personalData.jsx
  16. +26
    -0
      react-ui/src/pages/Experiment/components/TensorBoardStatus/index.less
  17. +82
    -0
      react-ui/src/pages/Experiment/components/TensorBoardStatus/index.tsx
  18. +1
    -1
      react-ui/src/pages/Experiment/experimentText/paramsModal.less
  19. +122
    -14
      react-ui/src/pages/Experiment/index.jsx
  20. +9
    -7
      react-ui/src/pages/Model/modelIntro.jsx
  21. +41
    -5
      react-ui/src/pages/Model/personalData.jsx
  22. +1
    -1
      react-ui/src/pages/Model/publicData.jsx
  23. +1
    -0
      react-ui/src/pages/Pipeline/editPipeline/modelMenus.jsx
  24. +11
    -1
      react-ui/src/pages/Pipeline/editPipeline/modelMenus.less
  25. +1
    -1
      react-ui/src/pages/Pipeline/index.jsx
  26. +1
    -1
      react-ui/src/services/dataset/index.js
  27. +16
    -0
      react-ui/src/services/experiment/index.js
  28. +5
    -6
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/dataset/DatasetController.java
  29. +2
    -2
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/model/ModelsController.java
  30. +2
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/tensorBoard/TensorBoardController.java
  31. +1
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/DatasetService.java
  32. +1
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ModelsService.java
  33. +2
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/TensorBoardService.java
  34. +12
    -20
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/DatasetServiceImpl.java
  35. +4
    -3
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/DatasetVersionServiceImpl.java
  36. +31
    -27
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ModelsServiceImpl.java
  37. +4
    -3
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ModelsVersionServiceImpl.java
  38. +14
    -4
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/TensorBoardServiceImpl.java
  39. +5
    -3
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/DatasetVo.java
  40. +14
    -37
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/ModelsVo.java
  41. +28
    -0
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/TensorboardStatusVo.java
  42. +1
    -1
      ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/VersionVo.java

+ 3
- 1
react-ui/config/config.ts View File

@@ -108,7 +108,9 @@ export default defineConfig({
* @description 内置了 babel import 插件
* @doc https://umijs.org/docs/max/antd#antd
*/
antd: {},
antd: {
configProvider: {},
},
/**
* @name 网络请求配置
* @description 它基于 axios 和 ahooks 的 useRequest 提供了一套统一的网络请求和错误处理方案。


BIN
react-ui/src/assets/img/modal-select-model.png View File

Before After
Width: 43  |  Height: 44  |  Size: 2.3 kB

BIN
react-ui/src/assets/img/tensor-board-export.png View File

Before After
Width: 42  |  Height: 42  |  Size: 1.0 kB

BIN
react-ui/src/assets/img/tensor-board-failed.png View File

Before After
Width: 42  |  Height: 42  |  Size: 1.2 kB

BIN
react-ui/src/assets/img/tensor-board-pending.png View File

Before After
Width: 42  |  Height: 42  |  Size: 1.6 kB

BIN
react-ui/src/assets/img/tensor-board-running.png View File

Before After
Width: 42  |  Height: 42  |  Size: 1.1 kB

BIN
react-ui/src/assets/img/tensor-board-stop.png View File

Before After
Width: 42  |  Height: 42  |  Size: 815 B

BIN
react-ui/src/assets/img/tensor-board-terminated.png View File

Before After
Width: 42  |  Height: 42  |  Size: 923 B

BIN
react-ui/src/assets/img/tensor-board-unknown.png View File

Before After
Width: 42  |  Height: 42  |  Size: 1.6 kB

+ 1
- 1
react-ui/src/components/KFModal/index.less View File

@@ -5,7 +5,7 @@
border-radius: 21px;
}
.ant-modal-header {
margin: 20px 0;
margin: 20px 0 30px;
background-color: transparent;
}
.ant-modal-footer {


+ 1
- 0
react-ui/src/components/ModalTitle/index.less View File

@@ -3,6 +3,7 @@
display: flex;
align-items: center;
color: @kf-primary-color;
font-weight: 400;
font-size: 20px;

&_image {


+ 24
- 0
react-ui/src/hooks/index.ts View File

@@ -37,3 +37,27 @@ export function useAntdModal(initialValue: boolean) {

return [visible, open, close];
}

type Callback<T> = (state: T) => void;

/**
* Generates a stateful value and a function to update it that triggers callbacks.
*
* @param initialValue - The initial value of the state.
* @return A tuple containing the current state value and a function to update the state.
*/
export function useCallbackState<T>(initialValue: T) {
const [state, _setState] = useState(initialValue);
const callbackQueue = useRef<Callback<T>[]>([]);
useEffect(() => {
callbackQueue.current.forEach((cb) => cb(state));
callbackQueue.current = [];
}, [state]);
const setState = (newValue: T, callback: Callback<T>) => {
_setState(newValue);
if (callback && typeof callback === 'function') {
callbackQueue.current.push(callback);
}
};
return [state, setState];
}

+ 3
- 3
react-ui/src/pages/Dataset/datasetIntro.jsx View File

@@ -39,9 +39,9 @@ const Dataset = () => {
return {
...form.getFieldsValue(),
dataset_id: locationParams.id,
file_name: item.response.data[0].fileName,
file_size: item.response.data[0].fileSize,
url: item.response.data[0].url,
file_name: item.response.code === 200 ? item.response.data[0].fileName : null,
file_size: item.response.code === 200 ? item.response.data[0].fileSize : null,
url: item.response.code === 200 ? item.response.data[0].url : null,
};
}),
);


+ 4
- 4
react-ui/src/pages/Dataset/index.jsx View File

@@ -1,6 +1,6 @@
import { getDatasetList } from '@/services/dataset/index.js';
import { Form, Input, Tabs } from 'antd';
import React, { useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import Styles from './index.less';
import PersonalData from './personalData';
@@ -9,7 +9,7 @@ const { Search } = Input;
const { TabPane } = Tabs;
const leftdataList = [1, 2, 3];

const Dataset = (React.FC = () => {
const Dataset = () => {
const [queryFlow, setQueryFlow] = useState({
page: 0,
size: 10,
@@ -52,7 +52,7 @@ const Dataset = (React.FC = () => {
console.log('Failed:', errorInfo);
};
useEffect(() => {
getDatasetlist();
//getDatasetlist();
return () => {};
}, []);
return (
@@ -70,5 +70,5 @@ const Dataset = (React.FC = () => {
</div>
</div>
);
});
};
export default Dataset;

+ 13
- 2
react-ui/src/pages/Dataset/personalData.jsx View File

@@ -24,7 +24,16 @@ const PublicData = (React.FC = () => {
onChange({ file, fileList }) {
if (file.status !== 'uploading') {
console.log(file, fileList);
form.setFieldsValue({ dataset_version_vos: fileList.map((item) => item.response.data[0]) });
form.setFieldsValue({
dataset_version_vos: fileList.map((item) => {
const data = item.response.data[0];
return {
file_name: data.fileName,
file_size: data.fileSize,
url: data.url,
};
}),
});
}
},
defaultFileList: [],
@@ -51,6 +60,7 @@ const PublicData = (React.FC = () => {
const [total, setTotal] = useState(0);
const [form] = Form.useForm();
const [dialogTitle, setDialogTitle] = useState('新建数据');
const [uuid, setUuid] = useState(Date.now());
const getDatasetlist = (queryFlow) => {
getDatasetList(queryFlow).then((ret) => {
console.log(ret);
@@ -64,6 +74,7 @@ const PublicData = (React.FC = () => {
const showModal = () => {
form.resetFields();
setDialogTitle('新建数据集');
setUuid(Date.now());
setIsModalOpen(true);
};
const getAssetIconList = (params) => {
@@ -397,7 +408,7 @@ const PublicData = (React.FC = () => {
</Radio.Group>
</Form.Item>
<Form.Item label="数据文件" name="dataset_version_vos">
<Upload {...props}>
<Upload {...props} data={{ uuid: uuid }}>
<Button
style={{
fontSize: '14px',


+ 26
- 0
react-ui/src/pages/Experiment/components/TensorBoardStatus/index.less View File

@@ -0,0 +1,26 @@
.tensorBoard-status {
display: flex;
align-items: center;
color: rgba(29, 29, 32, 0.75);

&__label {
color: rgba(29, 29, 32, 0.75);
font-size: 15px;

&--running {
color: #6ac21d;
}
&--failed {
color: #df6d6d;
}
}
&__icon {
width: 14px;
color: #6ac21d;
cursor: pointer;

& + & {
margin-left: 6px;
}
}
}

+ 82
- 0
react-ui/src/pages/Experiment/components/TensorBoardStatus/index.tsx View File

@@ -0,0 +1,82 @@
import exportImg from '@/assets/img/tensor-board-export.png';
import pendingImg from '@/assets/img/tensor-board-pending.png';
import { LoadingOutlined } from '@ant-design/icons';
import classNames from 'classnames';
import styles from './index.less';
// import stopImg from '@/assets/img/tensor-board-stop.png';
import terminatedImg from '@/assets/img/tensor-board-terminated.png';

export enum TensorBoardStatusEnum {
Unknown = 'Unknown', // 未知
Pending = 'Pending', // 启动中
Running = 'Running', // 运行中
Terminated = 'Terminated', // 未启动或者已终止
Failed = 'Failed', // 失败
}

const statusConfig = {
Unknown: {
label: '未知',
icon: terminatedImg,
classname: '',
},
Terminated: {
label: '未启动',
icon: terminatedImg,
classname: '',
},
Failed: {
label: '失败',
icon: terminatedImg,
classname: 'tensorBoard-status__label--failed',
},
Pending: {
label: '启动中',
icon: pendingImg,
classname: '',
},
Running: {
label: '运行中',
icon: exportImg,
classname: 'tensorBoard-status__label--running',
},
};

type TensorBoardStatusProps = {
status: TensorBoardStatusEnum;
onClick: () => void;
};

function TensorBoardStatus({
status = TensorBoardStatusEnum.Unknown,
onClick,
}: TensorBoardStatusProps) {
return (
<div className={styles['tensorBoard-status']}>
<div
className={classNames(
styles['tensorBoard-status__label'],
styles[statusConfig[status].classname],
)}
>
{statusConfig[status].label}
</div>
{statusConfig[status].icon ? (
<>
<div style={{ margin: '0 6px' }}>|</div>
{status === TensorBoardStatusEnum.Pending ? (
<LoadingOutlined className={styles['tensorBoard-status__icon']} />
) : (
<img
className={styles['tensorBoard-status__icon']}
src={statusConfig[status].icon}
onClick={onClick}
/>
)}
</>
) : null}
</div>
);
}

export default TensorBoardStatus;

+ 1
- 1
react-ui/src/pages/Experiment/experimentText/paramsModal.less View File

@@ -1,6 +1,6 @@
.params_container {
max-height: 230px;
padding: 15px;
padding: 15px 15px 0;
border: 1px solid #e6e6e6;
border-radius: 8px;



+ 122
- 14
react-ui/src/pages/Experiment/index.jsx View File

@@ -4,10 +4,12 @@ import {
getExperiment,
getExperimentById,
getQueryByExperimentId,
getTensorBoardStatusReq,
postExperiment,
putExperiment,
putQueryByExperimentInsId,
runExperiments,
runTensorBoardReq,
} from '@/services/experiment/index.js';
import { getWorkflow } from '@/services/pipeline/index.js';
import { elapsedTime } from '@/utils/date';
@@ -23,10 +25,14 @@ import { Button, Modal, Space, Table, message } from 'antd';
import momnet from 'moment';
import { useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import TensorBoardStatus, { TensorBoardStatusEnum } from './components/TensorBoardStatus';
import AddExperimentModal from './experimentText/addExperimentModal';
import Styles from './index.less';
import { experimentStatusInfo } from './status';

// 定时器
const timerIds = new Map();

function Experiment() {
const navgite = useNavigate();
const [experimentList, setExperimentList] = useState([]);
@@ -44,9 +50,13 @@ function Experiment() {
const [isAdd, setIsAdd] = useState(true);
const [isModalOpen, setIsModalOpen] = useState(false);
const [addFormData, setAddFormData] = useState({});

useEffect(() => {
getList();
getWorkflowList();
return () => {
clearExperimentInTimers();
};
}, []);
// 获取实验列表
const getList = async () => {
@@ -72,11 +82,32 @@ function Experiment() {
setWorkflowList(res.data.content);
}
};
// 获取实验实例
const getQueryByExperiment = (val) => {
getQueryByExperimentId(val).then((ret) => {
setExpandedRowKeys(val);
if (ret.code === 200 && ret.data && ret.data.length > 0) {
setExperimentInList(ret.data);
if (ret && ret.data && ret.data.length > 0) {
try {
const list = ret.data.map((v) => {
const nodes_result = v.nodes_result ? JSON.parse(v.nodes_result) : {};
return {
...v,
nodes_result,
};
});
setExperimentInList(list);
// 获取 TensorBoard 状态
list.forEach((item) => {
if (item.nodes_result.tensorboard_log) {
const timerId = setTimeout(() => {
getTensorBoardStatus(item);
}, 0);
timerIds.set(item.id, timerId);
}
});
} catch (error) {
setExperimentInList([]);
}
getList();
} else {
setExperimentInList([]);
@@ -84,13 +115,66 @@ function Experiment() {
}
});
};
// 运行 TensorBoard
const runTensorBoard = async (experimentIn) => {
const params = {
namespace: experimentIn.nodes_result.tensorboard_log.namespace,
path: experimentIn.nodes_result.tensorboard_log.path,
pvc_name: experimentIn.nodes_result.tensorboard_log.pvc_name,
};
const [res] = await to(runTensorBoardReq(params));
if (res) {
experimentIn.tensorboardUrl = res.data;
const timerId = timerIds.get(experimentIn.id);
if (timerId) {
clearTimeout(timerId);
timerIds.delete(experimentIn.id);
getTensorBoardStatus(experimentIn);
}
}
};
// 获取 TensorBoard 状态
const getTensorBoardStatus = async (experimentIn) => {
const params = {
namespace: experimentIn.nodes_result.tensorboard_log.namespace,
path: experimentIn.nodes_result.tensorboard_log.path,
pvc_name: experimentIn.nodes_result.tensorboard_log.pvc_name,
};
const [res] = await to(getTensorBoardStatusReq(params));
if (res && res.data) {
setExperimentInList((prevList) => {
const newList = [...prevList];
const index = prevList.findIndex((item) => item.id === experimentIn.id);
const preObj = prevList[index];
const newObj = {
...preObj,
tensorBoardStatus: res.data.status,
tensorboardUrl: res.data.url,
};
newList.splice(index, 1, newObj);
return newList;
});
const timerId = setTimeout(() => {
getTensorBoardStatus(experimentIn);
}, 10000);
timerIds.set(experimentIn.id, timerId);
}
};
const expandChange = (e, record) => {
if (record.id === expandedRowKeys) {
clearExperimentInTimers();
setExpandedRowKeys(null);
} else {
getQueryByExperiment(record.id);
}
};
// 终止实验实例获取 TensorBoard 状态的定时器
const clearExperimentInTimers = () => {
timerIds.values().forEach((timerId) => {
clearTimeout(timerId);
});
timerIds.clear();
};
// 创建实验
const createExperiment = () => {
setIsAdd(true);
@@ -174,6 +258,19 @@ function Experiment() {
navgite({ pathname: `/experiment/pytorchtext/${record.workflow_id}/${item.id}` });
};

const handleTensorboard = async (experimentIn) => {
if (
experimentIn.tensorBoardStatus === TensorBoardStatusEnum.Terminated ||
experimentIn.tensorBoardStatus === TensorBoardStatusEnum.Failed
) {
await runTensorBoard(experimentIn);
} else if (
experimentIn.tensorBoardStatus === TensorBoardStatusEnum.Running &&
experimentIn.tensorboardUrl
) {
window.open(experimentIn.tensorboardUrl, '_blank');
}
};
const columns = [
{
title: '实验名称',
@@ -198,7 +295,6 @@ function Experiment() {
key: 'status_list',
render: (text) => {
let newText = text && text.replace(/\s+/g, '').split(',');
console.log(newText);
return (
<>
{newText && newText.length > 0
@@ -306,15 +402,17 @@ function Experiment() {
columns={columns}
dataSource={experimentList}
pagination={paginationProps}
rowKey="id"
expandable={{
expandedRowRender: (record) => (
<div>
{experimentInList && experimentInList.length > 0 ? (
<div className={Styles.tableExpandBox} style={{ paddingBottom: '16px' }}>
<div style={{ width: '50px' }}>序号</div>
<div style={{ width: '200px' }}>状态</div>
<div style={{ width: '150px' }}>序号</div>
<div style={{ width: '300px' }}>TensorBoard</div>
<div style={{ width: '300px' }}>运行时长</div>
<div style={{ width: '300px' }}>开始时间</div>
<div style={{ width: '200px' }}>状态</div>
<div style={{ width: '200px' }}>操作</div>
</div>
) : (
@@ -332,9 +430,27 @@ function Experiment() {
height: '45px',
}}
>
<a style={{ width: '50px' }} onClick={(e) => routerToText(e, item, record)}>
<a style={{ width: '150px' }} onClick={(e) => routerToText(e, item, record)}>
{index + 1}
</a>
<div style={{ width: '300px' }}>
{item.nodes_result.tensorboard_log ? (
<TensorBoardStatus
status={item.tensorBoardStatus}
onClick={() => handleTensorboard(item)}
></TensorBoardStatus>
) : (
'-'
)}
</div>
<div style={{ width: '300px' }}>
{item.finish_time
? elapsedTime(new Date(item.create_time), new Date(item.finish_time))
: elapsedTime(new Date(item.create_time), new Date())}
</div>
<div style={{ width: '300px' }}>
{momnet(item.create_time).format('YYYY-MM-DD HH:mm:ss')}
</div>
<div className={Styles.statusBox} style={{ width: '200px' }}>
<img
style={{ width: '17px', marginRight: '7px' }}
@@ -347,14 +463,6 @@ function Experiment() {
{experimentStatusInfo[item.status]?.label}
</span>
</div>
<div style={{ width: '300px' }}>
{item.finish_time
? elapsedTime(new Date(item.create_time), new Date(item.finish_time))
: elapsedTime(new Date(item.create_time), new Date())}
</div>
<div style={{ width: '300px' }}>
{momnet(item.create_time).format('YYYY-MM-DD HH:mm:ss')}
</div>
<div style={{ width: '200px' }}>
<Button
type="link"


+ 9
- 7
react-ui/src/pages/Model/modelIntro.jsx View File

@@ -39,9 +39,9 @@ const Dataset = () => {
return {
...form.getFieldsValue(),
models_id: locationParams.id,
file_name: item.response.data[0].fileName,
file_size: item.response.data[0].fileSize,
url: item.response.data[0].url,
file_name: item.response.code === 200 ? item.response.data[0].fileName : null,
file_size: item.response.code === 200 ? item.response.data[0].fileSize : null,
url: item.response.code === 200 ? item.response.data[0].url : null,
};
}),
);
@@ -59,6 +59,7 @@ const Dataset = () => {
const locationParams = useParams(); //新版本获取路由参数接口
console.log(locationParams);
const [wordList, setWordList] = useState([]);
const [uuid, setUuid] = useState(Date.now());
const getModelByDetail = () => {
getModelById(locationParams.id).then((ret) => {
console.log(ret);
@@ -68,7 +69,7 @@ const Dataset = () => {
const getModelVersionsList = () => {
getModelVersionsById(locationParams.id).then((ret) => {
console.log(ret);
if (ret.data && ret.data.length > 0) {
if (ret && ret.data && ret.data.length > 0) {
setVersionList(
ret.data.map((item) => {
return {
@@ -77,6 +78,8 @@ const Dataset = () => {
};
}),
);
setVersion(ret.data[0]);
getModelVersions({ version: ret.data[0], models_id: locationParams.id });
}
});
};
@@ -90,6 +93,7 @@ const Dataset = () => {
form.setFieldsValue({ name: datasetDetailObj.name });

setDialogTitle('创建新版本');
setUuid(Date.now());
setIsModalOpen(true);
};
const handleCancel = () => {
@@ -104,9 +108,7 @@ const Dataset = () => {

onOk: () => {
deleteModelVersion({ models_id: locationParams.id, version }).then((ret) => {
setVersion(null);
getModelVersionsList();
getModelVersions({ version, models_id: locationParams.id });
message.success('删除成功');
});
},
@@ -368,7 +370,7 @@ const Dataset = () => {
},
]}
>
<Upload {...props}>
<Upload {...props} data={{ uuid: uuid }}>
<Button
style={{
fontSize: '14px',


+ 41
- 5
react-ui/src/pages/Model/personalData.jsx View File

@@ -23,14 +23,23 @@ const PublicData = () => {
onChange({ file, fileList }) {
if (file.status !== 'uploading') {
console.log(file, fileList);
form.setFieldsValue({ dataset_version_vos: fileList.map((item) => item.response.data[0]) });
form.setFieldsValue({
models_version_vos: fileList.map((item) => {
const data = item.response.data[0];
return {
file_name: data.fileName,
file_size: data.fileSize,
url: data.url,
};
}),
});
}
},
defaultFileList: [],
};
const [queryFlow, setQueryFlow] = useState({
page: 0,
size: 10,
size: 20,
name: null,
available_range: 0,
});
@@ -49,6 +58,7 @@ const PublicData = () => {
const [total, setTotal] = useState(0);
const [form] = Form.useForm();
const [dialogTitle, setDialogTitle] = useState('新建模型');
const [uuid, setUuid] = useState(Date.now());
const getModelLists = (queryFlow) => {
getModelList(queryFlow).then((ret) => {
console.log(ret);
@@ -62,6 +72,7 @@ const PublicData = () => {
const showModal = () => {
form.resetFields();
setDialogTitle('新建模型');
setUuid(Date.now());
setIsModalOpen(true);
};
const getAssetIconList = (params) => {
@@ -324,6 +335,21 @@ const PublicData = () => {
<Input placeholder="请输入模型名称" showCount maxLength={64} />
</Form.Item>

<Form.Item
label="模型版本"
name="version"
rules={
[
// {
// required: true,
// message: 'Please input your username!',
// },
]
}
>
<Input placeholder="请输入模型版本" />
</Form.Item>

<Form.Item
label="模型描述"
name="description"
@@ -370,9 +396,19 @@ const PublicData = () => {
>
<Select allowClear placeholder="请选择模型标签" options={[]} />
</Form.Item>
<Form.Item label="模型文件" name="dataset_version_vos">
<Upload {...props}>
<Button icon={<UploadOutlined style={{ color: '#1664ff' }} />}>上传文件</Button>
<Form.Item label="模型文件" name="models_version_vos">
<Upload {...props} data={{ uuid: uuid }}>
<Button
style={{
fontSize: '14px',
border: '1px solid',
borderColor: '#1664ff',
background: '#fff',
}}
icon={<UploadOutlined style={{ color: '#1664ff', fontSize: '14px' }} />}
>
上传文件
</Button>
</Upload>
</Form.Item>
</Form>


+ 1
- 1
react-ui/src/pages/Model/publicData.jsx View File

@@ -10,7 +10,7 @@ const leftdataList = [1, 2, 3];
const PublicData = () => {
const [queryFlow, setQueryFlow] = useState({
page: 0,
size: 10,
size: 20,
name: null,
available_range: 1,
});


+ 1
- 0
react-ui/src/pages/Pipeline/editPipeline/modelMenus.jsx View File

@@ -42,6 +42,7 @@ const modelMenus = ({ onParDragEnd }) => {
const { Panel } = Collapse;
return (
<div style={{ width: '250px', height: '99%' }} className={Styles.collapse}>
<div className={Styles.modelMenusTitle}>组件库</div>
<Collapse collapsible="header" defaultActiveKey={['1']} expandIconPosition="end">
{modelMenusList && modelMenusList.length > 0
? modelMenusList.map((item) => (


+ 11
- 1
react-ui/src/pages/Pipeline/editPipeline/modelMenus.less View File

@@ -12,6 +12,7 @@
}
.collapseItem:hover {
background: rgba(22, 100, 255, 0.08);
color:#1664ff;
}
.collapse {
:global {
@@ -23,10 +24,12 @@
margin-bottom: 5px;
background-color: #fff;
border-color: transparent;
padding: 20px 16px 15px 16px;
}

.ant-collapse > .ant-collapse-item {
margin: 0 10px;
border-color: rgba(20, 49, 179, 0.12);
border-bottom:0.5px dashed rgba(20, 49, 179, 0.12);
border-radius: 0px;
}
.ant-collapse .ant-collapse-content {
@@ -38,3 +41,10 @@
}
}
}
.modelMenusTitle{
padding: 12px 25px;
margin-bottom: 10px;
color:#111111;
font-size:16px;
font-family: 'Alibaba';
}

+ 1
- 1
react-ui/src/pages/Pipeline/index.jsx View File

@@ -243,7 +243,7 @@ const Pipeline = () => {
新建流水线
</Button>
</div>
<Table columns={columns} dataSource={pipeList} pagination={paginationProps} />
<Table columns={columns} dataSource={pipeList} pagination={paginationProps} rowKey="id" />
<Modal
title={
<div style={{ display: 'flex', alignItems: 'center', fontWeight: 500 }}>


+ 1
- 1
react-ui/src/services/dataset/index.js View File

@@ -25,7 +25,7 @@ export function addDatesetAndVesion(data) {
}
// 新增模型
export function addModel(data) {
return request(`/api/mmp//models`, {
return request(`/api/mmp/models/addModelAndVersion`, {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=UTF-8',


+ 16
- 0
react-ui/src/services/experiment/index.js View File

@@ -100,3 +100,19 @@ export function putExperiment(data) {
data,
});
}

// 启动tensorBoard
export function runTensorBoardReq(data) {
return request(`/api/mmp/tensorBoard/run`, {
method: 'POST',
data,
});
}

// 启动tensorBoard
export function getTensorBoardStatusReq(data) {
return request(`/api/mmp/tensorBoard/getStatus`, {
method: 'POST',
data,
});
}

+ 5
- 6
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/dataset/DatasetController.java View File

@@ -52,13 +52,13 @@ public class DatasetController {
@ApiOperation("数据集广场公开数据集分页查询,根据data_type筛选,1公开0私有")
public AjaxResult queryByPage(Dataset dataset, @RequestParam("page") int page,
@RequestParam("size") int size,
//@RequestParam("available_range") int availableRange ,
@RequestParam(value = "available_range") int availableRange ,
@RequestParam(value = "data_type", required = false) String dataType) {

if (dataType != null) { // 仅当dataType有值时设置
dataset.setDataType(dataType);
}
dataset.setAvailableRange(1);
dataset.setAvailableRange(availableRange);
PageRequest pageRequest = PageRequest.of(page, size);
return AjaxResult.success(this.datasetService.queryByPage(dataset, pageRequest));
}
@@ -182,16 +182,15 @@ public class DatasetController {
/**
* 上传数据集
*
// * @param datasetId 数据集ID
* @param files 上传的数据集文件
*
* @param uuid 上传唯一标识,构建url
* @return 上传结果
*/
@CrossOrigin(origins = "*", allowedHeaders = "*")
@PostMapping("/upload")
@ApiOperation(value = "上传数据集", notes = "根据数据集版本表id上传数据集文件,并将信息存入数据库。")
public AjaxResult uploadDataset(@RequestParam("file") MultipartFile[] files) throws Exception {
return AjaxResult.success(this.datasetService.uploadDataset(files));
public AjaxResult uploadDataset(@RequestParam("file") MultipartFile[] files, @RequestParam("uuid") String uuid) throws Exception {
return AjaxResult.success(this.datasetService.uploadDataset(files,uuid));
}




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

@@ -176,8 +176,8 @@ public class ModelsController extends BaseController {
@CrossOrigin(origins = "*", allowedHeaders = "*")
@PostMapping("/upload")
@ApiOperation(value = "上传模型", notes = "根据模型id上传模型文件,并将信息存入数据库。")
public GenericsAjaxResult<List<Map<String, String>>> uploadModels(@RequestParam("file") MultipartFile[] files) throws Exception {
return genericsSuccess(this.modelsService.uploadModels(files));
public GenericsAjaxResult<List<Map<String, String>>> uploadModels(@RequestParam("file") MultipartFile[] files , @RequestParam("uuid") String uuid) throws Exception {
return genericsSuccess(this.modelsService.uploadModels(files,uuid));

}



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

@@ -4,6 +4,7 @@ import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.GenericsAjaxResult;
import com.ruoyi.platform.service.TensorBoardService;
import com.ruoyi.platform.vo.FrameLogPathVo;
import com.ruoyi.platform.vo.TensorboardStatusVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
@@ -36,7 +37,7 @@ public class TensorBoardController extends BaseController {
}
@PostMapping("/getStatus")
@ApiResponse
public GenericsAjaxResult<String> getStatus(@RequestBody FrameLogPathVo frameLogPathVo) throws Exception {
public GenericsAjaxResult<TensorboardStatusVo> getStatus(@RequestBody FrameLogPathVo frameLogPathVo) throws Exception {
return genericsSuccess(tensorBoardService.getTensorBoardStatus(frameLogPathVo));
}
}

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

@@ -72,7 +72,7 @@ DatasetService {

ResponseEntity<InputStreamResource> downloadDataset(Integer id) throws Exception;

List<Map<String, String>> uploadDataset(MultipartFile[] files) throws Exception;
List<Map<String, String>> uploadDataset(MultipartFile[] files, String uuid) throws Exception;

Map uploadDatasetPipeline(DatasetVersion datasetVersion) throws Exception;



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

@@ -70,7 +70,7 @@ public interface ModelsService {



List<Map<String, String>> uploadModels(MultipartFile[] files) throws Exception;
List<Map<String, String>> uploadModels(MultipartFile[] files, String uuid) throws Exception;

Map uploadModelsPipeline(ModelsVersion modelsVersion) throws Exception;



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

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

import com.ruoyi.platform.vo.FrameLogPathVo;
import com.ruoyi.platform.vo.TensorboardStatusVo;

public interface TensorBoardService {


String getTensorBoardStatus(FrameLogPathVo frameLogPathVo);
TensorboardStatusVo getTensorBoardStatus(FrameLogPathVo frameLogPathVo);
/**
* 在集群中启动TensorBoard容器,并且返回地址,4小时后销毁
* @param frameLogPathVo


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

@@ -12,7 +12,7 @@ import com.ruoyi.platform.service.DatasetVersionService;
import com.ruoyi.platform.utils.BeansUtils;
import com.ruoyi.platform.utils.FileUtil;
import com.ruoyi.platform.utils.MinioUtil;
import com.ruoyi.platform.vo.DatasetVersionVo;
import com.ruoyi.platform.vo.VersionVo;
import com.ruoyi.platform.vo.DatasetVo;
import com.ruoyi.system.api.model.LoginUser;
import org.apache.commons.lang3.StringUtils;
@@ -203,16 +203,16 @@ public class DatasetServiceImpl implements DatasetService {
/**
* 上传数据集
*
* @param files 文件
* @param files 文件
* @param uuid
* @return 是否成功
*/
@Override
public List<Map<String, String>> uploadDataset(MultipartFile[] files) throws Exception {
public List<Map<String, String>> uploadDataset(MultipartFile[] files, String uuid) throws Exception {
List<Map<String, String>> results = new ArrayList<>();
//时间戳统一定在外面,一次上传就定好
Date createTime = new Date();
String timestamp = new SimpleDateFormat("yyyyMMdd-HHmmss").format(createTime);
// //时间戳统一定在外面,一次上传就定好
// Date createTime = new Date();
// String timestamp = new SimpleDateFormat("yyyyMMdd-HHmmss").format(createTime);

for (MultipartFile file:files){
if (file.isEmpty()) {
@@ -225,20 +225,12 @@ public class DatasetServiceImpl implements DatasetService {
// 其余操作基于 modelsVersionToUse
String username = SecurityUtils.getLoginUser().getUsername();
String fileName = file.getOriginalFilename();
String objectName = "datasets/" + username + "/" + timestamp + "/" + fileName;
String objectName = "datasets/" + username + "/" + uuid + "/" + fileName;

// 上传文件到MinIO并将记录新增到数据库中
try (InputStream inputStream = file.getInputStream()) {
minioUtil.uploadObject(bucketName, objectName, inputStream);
// DatasetVersion datasetVersion = new DatasetVersion();
// datasetVersion.setDatasetId(id);
// datasetVersion.setVersion(version);
// datasetVersion.setUrl(objectName);
// datasetVersion.setFileName(fileName);
// datasetVersion.setFileSize(formattedSize);
//
// //返回插入结果
// DatasetVersion insertedDatasetversion = datasetVersionService.insert(datasetVersion);

Map<String, String> fileResult = new HashMap<>();
fileResult.put("fileName", file.getOriginalFilename());
fileResult.put("url", objectName); // objectName根据实际情况定义
@@ -313,8 +305,8 @@ public class DatasetServiceImpl implements DatasetService {
@Override
@Transactional
public String insertDatasetAndVersion(DatasetVo datasetVo) throws Exception {
List<DatasetVersionVo> datasetVersionVos = datasetVo.getDatasetVersionVos();
if (datasetVersionVos==null||datasetVersionVos.size()==0){
List<VersionVo> datasetVersionVos = datasetVo.getDatasetVersionVos();
if (datasetVersionVos==null || datasetVersionVos.isEmpty()){
throw new Exception("数据集版本信息错误");
}

@@ -329,7 +321,7 @@ public class DatasetServiceImpl implements DatasetService {
throw new Exception("新增数据集失败");
}

for (DatasetVersionVo datasetVersionVo :datasetVersionVos){
for (VersionVo datasetVersionVo :datasetVersionVos){
DatasetVersion datasetVersion = new DatasetVersion();
datasetVersion.setDatasetId(datasetInsert.getId());
datasetVersion.setVersion(datasetVo.getVersion());


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

@@ -138,9 +138,10 @@ public class DatasetVersionServiceImpl implements DatasetVersionService {
Map<String, Object> response = new HashMap<>();

List<DatasetVersion> datasetVersionList = this.datasetVersionDao.queryAllByDatasetVersion(datasetId, version);
datasetVersionList.stream().
findFirst().
ifPresent(datasetVersion -> {
datasetVersionList.stream()
.filter(datasetVersion -> datasetVersion.getUrl() != null && !datasetVersion.getUrl().isEmpty())
.findFirst()
.ifPresent(datasetVersion -> {
String url = datasetVersion.getUrl();
String path = bucketName + '/' + url.substring(0, url.lastIndexOf('/'));
response.put("path", path);


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

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

import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.platform.domain.DatasetVersion;
import com.ruoyi.platform.domain.Models;
import com.ruoyi.platform.domain.ModelsVersion;
import com.ruoyi.platform.mapper.ModelsDao;
@@ -12,16 +11,15 @@ import com.ruoyi.platform.utils.BeansUtils;
import com.ruoyi.platform.utils.FileUtil;
import com.ruoyi.platform.utils.MinioUtil;
import com.ruoyi.platform.vo.ModelsVo;
import com.ruoyi.platform.vo.VersionVo;
import com.ruoyi.system.api.model.LoginUser;
import io.minio.MinioClient;
import io.netty.util.Version;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
@@ -33,7 +31,6 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
@@ -169,6 +166,7 @@ public class ModelsServiceImpl implements ModelsService {
ModelsVersion modelsVersion = this.modelsVersionDao.queryById(id);
if (modelsVersion == null) {
throw new Exception("未找到该模型下版本记录");

}
// 从数据库中获取存储路径(即MinIO中的对象名称)
String objectName = modelsVersion.getUrl();
@@ -199,15 +197,16 @@ public class ModelsServiceImpl implements ModelsService {
* 上传模型
*
* @param files 文件
* @param uuid
* @return 是否成功
*/
@Override
public List<Map<String, String>> uploadModels(MultipartFile[] files) throws Exception {
public List<Map<String, String>> uploadModels(MultipartFile[] files, String uuid) throws Exception {

List<Map<String, String>> results = new ArrayList<>();
//时间戳统一定在外面,一次上传就定好
Date createTime = new Date();
String timestamp = new SimpleDateFormat("yyyyMMdd-HHmmss").format(createTime);
// //时间戳统一定在外面,一次上传就定好
// Date createTime = new Date();
// String timestamp = new SimpleDateFormat("yyyyMMdd-HHmmss").format(createTime);

for (MultipartFile file:files){
if (file.isEmpty()) {
@@ -217,22 +216,18 @@ public class ModelsServiceImpl implements ModelsService {
long sizeInBytes = file.getSize();
String formattedSize = FileUtil.formatFileSize(sizeInBytes); // 格式化文件大小




// 其余操作基于 modelsVersionToUse
String username = SecurityUtils.getLoginUser().getUsername();
String fileName = file.getOriginalFilename();
String objectName = "models/" + username + "/" + timestamp + "/" + fileName;
String objectName = "models/" + username + "/" + uuid + "/" + fileName;

// 上传文件到MinIO并将记录新增到数据库中
try (InputStream inputStream = file.getInputStream()) {
minioUtil.uploadObject(bucketName, objectName, inputStream);
// ModelsVersion modelsVersion = new ModelsVersion();
// modelsVersion.setModelsId(id);
// modelsVersion.setVersion(version);
// modelsVersion.setUrl(objectName);
// modelsVersion.setFileName(fileName);
// modelsVersion.setFileSize(formattedSize);
// //返回插入结果
// ModelsVersion insertedModelsVersion = modelsVersionService.insert(modelsVersion);
//
Map<String, String> fileResult = new HashMap<>();
fileResult.put("fileName", file.getOriginalFilename());
fileResult.put("url", objectName); // objectName根据实际情况定义
@@ -361,6 +356,11 @@ public class ModelsServiceImpl implements ModelsService {
@Override
@Transactional
public String insertModelAndVersion(ModelsVo modelsVo) throws Exception {
List<VersionVo> modelsVersionVos = modelsVo.getModelsVersionVos();

if (modelsVersionVos==null || modelsVersionVos.isEmpty()){
throw new Exception("模型版本信息错误");
}
Models models = new Models();
models.setName(modelsVo.getName());
models.setDescription(modelsVo.getDescription());
@@ -371,16 +371,20 @@ public class ModelsServiceImpl implements ModelsService {
if (modelsInsert == null){
throw new Exception("新增模型失败");
}
ModelsVersion modelsVersion = new ModelsVersion();
modelsVersion.setModelsId(modelsInsert.getId());
modelsVersion.setVersion(modelsVo.getVersion());
modelsVersion.setUrl(modelsVo.getUrl());
modelsVersion.setFileName(modelsVo.getFileName());
modelsVersion.setFileSize(modelsVo.getFileSize());
ModelsVersion modelsVersionInsert = this.modelsVersionService.insert(modelsVersion);
if (modelsVersionInsert == null) {
throw new Exception("新增模型失败");
//遍历版本信息列表,把文件信息插入数据库
for(VersionVo modelsVersionVo : modelsVersionVos){
ModelsVersion modelsVersion = new ModelsVersion();
modelsVersion.setModelsId(modelsInsert.getId());
modelsVersion.setVersion(modelsVo.getVersion());
modelsVersion.setUrl(modelsVersionVo.getUrl());
modelsVersion.setFileName(modelsVersionVo.getFileName());
modelsVersion.setFileSize(modelsVersionVo.getFileSize());
ModelsVersion modelsVersionInsert = this.modelsVersionService.insert(modelsVersion);
if (modelsVersionInsert == null) {
throw new Exception("新增模型版本失败");
}
}

return "新增模型成功";

}


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

@@ -166,9 +166,10 @@ public class ModelsVersionServiceImpl implements ModelsVersionService {
Map<String,Object> response = new HashMap<>();

List<ModelsVersion> modelsVersionList = this.modelsVersionDao.queryAllByModelsVersion(modelsId, version);
modelsVersionList.stream().
findFirst().
ifPresent(modelsVersion -> {
modelsVersionList.stream()
.filter(modelsVersion -> modelsVersion.getUrl() != null && !modelsVersion.getUrl().isEmpty())
.findFirst()
.ifPresent(modelsVersion -> {
String url = modelsVersion.getUrl();
String path = bucketName + '/' + url.substring(0, url.lastIndexOf('/'));
response.put("path", path);


+ 14
- 4
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/TensorBoardServiceImpl.java View File

@@ -1,11 +1,13 @@
package com.ruoyi.platform.service.impl;

import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.platform.domain.PodStatus;
import com.ruoyi.platform.service.TensorBoardService;
import com.ruoyi.platform.utils.K8sClientUtil;
import com.ruoyi.platform.vo.FrameLogPathVo;
import com.ruoyi.platform.vo.TensorboardStatusVo;
import com.ruoyi.system.api.model.LoginUser;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@@ -23,12 +25,16 @@ public class TensorBoardServiceImpl implements TensorBoardService {
@Value("${tensorBoard.masterIp}")
private String masterIp;
@Resource
private RedisService redisService;
@Resource
private K8sClientUtil k8sClientUtil;
@Override
public String getTensorBoardStatus(FrameLogPathVo frameLogPathVo){
public TensorboardStatusVo getTensorBoardStatus(FrameLogPathVo frameLogPathVo){
String status = PodStatus.Terminated.getName();
TensorboardStatusVo tensorboardStatusVo = new TensorboardStatusVo();
tensorboardStatusVo.setStatus(status);
if (StringUtils.isEmpty(frameLogPathVo.getPath())){
return status;
return tensorboardStatusVo;
}
LoginUser loginUser = SecurityUtils.getLoginUser();
String podName = loginUser.getUsername().toLowerCase()+"-"+frameLogPathVo.getPath().split("/")[2]+ "-tensorboard-pod";
@@ -42,9 +48,12 @@ public class TensorBoardServiceImpl implements TensorBoardService {
}
}
} catch (Exception e) {
return PodStatus.Terminated.getName();
return tensorboardStatusVo;
}
return status;
String url = redisService.getCacheObject(podName);
tensorboardStatusVo.setStatus(status);
tensorboardStatusVo.setUrl(url);
return tensorboardStatusVo;
}

@Override
@@ -55,6 +64,7 @@ public class TensorBoardServiceImpl implements TensorBoardService {
LoginUser loginUser = SecurityUtils.getLoginUser();
String podName = loginUser.getUsername().toLowerCase()+"-"+frameLogPathVo.getPath().split("/")[2]+ "-tensorboard-pod";
Integer podPort = k8sClientUtil.createPodWithSubPath(podName, StringUtils.isEmpty(frameLogPathVo.getNamespace())?"default":frameLogPathVo.getNamespace(), port, mountPath,frameLogPathVo.getPath(), frameLogPathVo.getPvcName(), image);
redisService.setCacheObject(podName,masterIp + ":" + podPort);
return masterIp + ":" + podPort;
}
}

+ 5
- 3
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/DatasetVo.java View File

@@ -30,7 +30,9 @@ public class DatasetVo implements Serializable {
*/
@ApiModelProperty(name = "version")
private String version;
private List<DatasetVersionVo> datasetVersionVos;

@ApiModelProperty(name = "dataset_version_vos")
private List<VersionVo> datasetVersionVos;
/**
* 可用集群
*/
@@ -85,11 +87,11 @@ public class DatasetVo implements Serializable {
this.version = version;
}

public List<DatasetVersionVo> getDatasetVersionVos() {
public List<VersionVo> getDatasetVersionVos() {
return datasetVersionVos;
}

public void setDatasetVersionVos(List<DatasetVersionVo> datasetVersionVos) {
public void setDatasetVersionVos(List<VersionVo> datasetVersionVos) {
this.datasetVersionVos = datasetVersionVos;
}



+ 14
- 37
ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/ModelsVo.java View File

@@ -2,9 +2,11 @@ package com.ruoyi.platform.vo;

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.ruoyi.platform.domain.ModelsVersion;
import io.swagger.annotations.ApiModelProperty;

import java.io.Serializable;
import java.util.List;

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class ModelsVo implements Serializable {
@@ -36,27 +38,16 @@ public class ModelsVo implements Serializable {
*/
@ApiModelProperty(name = "version")
private String version;
/**
* 模型存储地址
*/
@ApiModelProperty(name = "url")
private String url;
/**
* 文件名
*/
@ApiModelProperty(name = "file_name")
private String fileName;
/**
* 文件大小
*/
@ApiModelProperty(name = "file_size")
private String fileSize;

/**
* 状态
*/
@ApiModelProperty(name = "status")
private Integer status;

@ApiModelProperty(name = "models_version_vos")
private List<VersionVo> modelsVersionVos;


public String getName() {
return name;
@@ -107,35 +98,21 @@ public class ModelsVo implements Serializable {
this.version = version;
}

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}

public String getFileName() {
return fileName;
public Integer getStatus() {
return status;
}

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

public String getFileSize() {
return fileSize;
public List<VersionVo> getModelsVersionVos() {
return modelsVersionVos;
}

public void setFileSize(String fileSize) {
this.fileSize = fileSize;
public void setModelsVersionVos(List<VersionVo> modelsVersionVos) {
this.modelsVersionVos = modelsVersionVos;
}

public Integer getStatus() {
return status;
}

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

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

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

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

import java.io.Serializable;

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class TensorboardStatusVo implements Serializable {
private String status;
private String url;

public String getStatus() {
return status;
}

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

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}
}

ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/DatasetVersionVo.java → ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/vo/VersionVo.java View File

@@ -7,7 +7,7 @@ import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class DatasetVersionVo implements Serializable {
public class VersionVo implements Serializable {

/**
* 数据集存储地址

Loading…
Cancel
Save