diff --git a/react-ui/config/routes.ts b/react-ui/config/routes.ts
index 7edf6db2..3a58d07b 100644
--- a/react-ui/config/routes.ts
+++ b/react-ui/config/routes.ts
@@ -96,6 +96,11 @@ export default [
path: ':workflowId/:id',
component: './Experiment/training/index',
},
+ {
+ name: '实验对比',
+ path: 'compare',
+ component: './Experiment/Comparison/index',
+ },
],
},
],
@@ -107,13 +112,18 @@ export default [
{
name: '开发环境',
path: '',
- component: './DevelopmentEnvironment/List',
- },
- {
- name: '创建编辑器',
- path: 'create',
- component: './DevelopmentEnvironment/Create',
+ component: './DevelopmentEnvironment/Editor',
},
+ // {
+ // name: '创建编辑器',
+ // path: 'create',
+ // component: './DevelopmentEnvironment/Create',
+ // },
+ // {
+ // name: '编辑器',
+ // path: 'editor',
+ // component: './DevelopmentEnvironment/Editor',
+ // },
],
},
{
diff --git a/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx b/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx
index bcbd123f..e8bed08c 100644
--- a/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx
+++ b/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx
@@ -58,7 +58,7 @@ const ResourceIntro = ({ resourceType }: ResourceIntroProps) => {
};
}),
);
- if (versionParam) {
+ if (versionParam && res.data.includes(versionParam)) {
setVersion(versionParam);
versionParam = null;
} else {
diff --git a/react-ui/src/pages/DevelopmentEnvironment/index.tsx b/react-ui/src/pages/DevelopmentEnvironment/Editor/index.tsx
similarity index 63%
rename from react-ui/src/pages/DevelopmentEnvironment/index.tsx
rename to react-ui/src/pages/DevelopmentEnvironment/Editor/index.tsx
index c2e09d35..0b2c63de 100644
--- a/react-ui/src/pages/DevelopmentEnvironment/index.tsx
+++ b/react-ui/src/pages/DevelopmentEnvironment/Editor/index.tsx
@@ -1,10 +1,16 @@
+// import { editorUrl, getSessionStorageItem, removeSessionStorageItem } from '@/utils/sessionStorage';
import { getJupyterUrl } from '@/services/developmentEnvironment';
import { to } from '@/utils/promise';
import { useEffect, useState } from 'react';
-const DevelopmentEnvironment = () => {
+function DevEditor() {
const [iframeUrl, setIframeUrl] = useState('');
useEffect(() => {
+ // const url = getSessionStorageItem(editorUrl) || '';
+ // setIframeUrl(url);
+ // return () => {
+ // removeSessionStorageItem(editorUrl);
+ // };
requestJupyterUrl();
}, []);
@@ -18,5 +24,5 @@ const DevelopmentEnvironment = () => {
};
return ;
-};
-export default DevelopmentEnvironment;
+}
+export default DevEditor;
diff --git a/react-ui/src/pages/DevelopmentEnvironment/List/index.tsx b/react-ui/src/pages/DevelopmentEnvironment/List/index.tsx
index 9c4badb6..c7b22c6a 100644
--- a/react-ui/src/pages/DevelopmentEnvironment/List/index.tsx
+++ b/react-ui/src/pages/DevelopmentEnvironment/List/index.tsx
@@ -16,6 +16,7 @@ import {
} from '@/services/developmentEnvironment';
import themes from '@/styles/theme.less';
import { to } from '@/utils/promise';
+import { editorUrl, setSessionStorageItem } from '@/utils/sessionStorage';
import { modalConfirm } from '@/utils/ui';
import { useNavigate } from '@umijs/max';
import {
@@ -38,6 +39,7 @@ export type EditorData = {
computing_resource: string;
update_by: string;
create_time: string;
+ url: string;
};
function EditorList() {
@@ -127,6 +129,16 @@ function EditorList() {
});
};
+ // 跳转编辑器页面
+ const gotoEditorPage = (e: React.MouseEvent, record: EditorData) => {
+ e.stopPropagation();
+ setSessionStorageItem(editorUrl, record.url);
+ navigate(`/developmentEnvironment/editor`);
+ setCacheState({
+ pagination,
+ });
+ };
+
// 分页切换
const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter, { action }) => {
if (action === 'paginate') {
@@ -140,7 +152,12 @@ function EditorList() {
dataIndex: 'name',
key: 'name',
width: '30%',
- render: CommonTableCell(),
+ render: (text, record) =>
+ record.url ? (
+ gotoEditorPage(e, record)}>{text}
+ ) : (
+ {text ?? '--'}
+ ),
},
{
title: '状态',
diff --git a/react-ui/src/pages/Experiment/Comparison/index.less b/react-ui/src/pages/Experiment/Comparison/index.less
new file mode 100644
index 00000000..288ce2ed
--- /dev/null
+++ b/react-ui/src/pages/Experiment/Comparison/index.less
@@ -0,0 +1,21 @@
+.experiment-comparison {
+ height: 100%;
+ &__header {
+ display: flex;
+ align-items: center;
+ height: 50px;
+ margin-bottom: 10px;
+ padding: 0 30px;
+ background-image: url(@/assets/img/page-title-bg.png);
+ background-repeat: no-repeat;
+ background-position: top center;
+ background-size: 100% 100%;
+ }
+
+ &__table {
+ height: calc(100% - 60px);
+ padding: 20px 30px 0;
+ background-color: white;
+ border-radius: 10px;
+ }
+}
diff --git a/react-ui/src/pages/Experiment/Comparison/index.tsx b/react-ui/src/pages/Experiment/Comparison/index.tsx
new file mode 100644
index 00000000..c53a0a94
--- /dev/null
+++ b/react-ui/src/pages/Experiment/Comparison/index.tsx
@@ -0,0 +1,212 @@
+import CommonTableCell from '@/components/CommonTableCell';
+import { useCacheState } from '@/hooks/pageCacheState';
+import { getExpEvaluateInfosReq, getExpTrainInfosReq } from '@/services/experiment';
+import { to } from '@/utils/promise';
+import { useSearchParams } from '@umijs/max';
+import { Button, Table, TablePaginationConfig, TableProps } from 'antd';
+import classNames from 'classnames';
+import { useEffect, useState } from 'react';
+import styles from './index.less';
+
+export enum ComparisonType {
+ Train = 'train', // 训练
+ Evaluate = 'evaluate', // 评估
+}
+
+function ExperimentComparison() {
+ const [searchParams] = useSearchParams();
+ const comparisonType = searchParams.get('type');
+ const experimentId = searchParams.get('experimentId');
+ const [tableData, setTableData] = useState([]);
+ const [cacheState, setCacheState] = useCacheState();
+ const [total, setTotal] = useState(0);
+ const [selectedRowKeys, setSelectedRowKeys] = useState([]);
+ const [pagination, setPagination] = useState(
+ cacheState?.pagination ?? {
+ current: 1,
+ pageSize: 10,
+ },
+ );
+
+ useEffect(() => {
+ getComparisonData();
+ }, [experimentId]);
+
+ // 获取对比数据列表
+ const getComparisonData = async () => {
+ const request =
+ comparisonType === ComparisonType.Train ? getExpTrainInfosReq : getExpEvaluateInfosReq;
+ const [res] = await to(request(experimentId));
+ if (res && res.data) {
+ const { content = [], totalElements = 0 } = res.data;
+ setTableData(content);
+ setTotal(totalElements);
+ }
+ };
+
+ // 分页切换
+ const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter, { action }) => {
+ if (action === 'paginate') {
+ setPagination(pagination);
+ }
+ // console.log(pagination, filters, sorter, action);
+ };
+
+ const rowSelection: TableProps['rowSelection'] = {
+ type: 'checkbox',
+ selectedRowKeys,
+ onChange: (selectedRowKeys: React.Key[], selectedRows: any[]) => {
+ console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
+ setSelectedRowKeys(selectedRowKeys);
+ },
+ };
+
+ const columns: TableProps['columns'] = [
+ {
+ title: '基本信息',
+ children: [
+ {
+ title: '实例ID',
+ dataIndex: 'name',
+ key: 'name',
+ width: '30%',
+ render: CommonTableCell(),
+ },
+ {
+ title: '运行时间',
+ dataIndex: 'name',
+ key: 'name',
+ width: '30%',
+ render: CommonTableCell(),
+ },
+ {
+ title: '运行状态',
+ dataIndex: 'name',
+ key: 'name',
+ width: '30%',
+ render: CommonTableCell(),
+ },
+ {
+ title: '训练数据集',
+ dataIndex: 'name',
+ key: 'name',
+ width: '30%',
+ render: CommonTableCell(),
+ },
+ {
+ title: '增量训练',
+ dataIndex: 'name',
+ key: 'name',
+ width: '30%',
+ render: CommonTableCell(),
+ },
+ ],
+ },
+ {
+ title: '训练参数',
+ children: [
+ {
+ title: 'batchsize',
+ dataIndex: 'name',
+ key: 'name',
+ width: '30%',
+ render: CommonTableCell(),
+ },
+ {
+ title: 'config',
+ dataIndex: 'name',
+ key: 'name',
+ width: '30%',
+ render: CommonTableCell(),
+ },
+ {
+ title: 'epoch',
+ dataIndex: 'name',
+ key: 'name',
+ width: '30%',
+ render: CommonTableCell(),
+ },
+ {
+ title: 'lr',
+ dataIndex: 'name',
+ key: 'name',
+ width: '30%',
+ render: CommonTableCell(),
+ },
+ {
+ title: 'warmup_iters',
+ dataIndex: 'name',
+ key: 'name',
+ width: '30%',
+ render: CommonTableCell(),
+ },
+ ],
+ },
+ {
+ title: '训练指标',
+ children: [
+ {
+ title: 'metrc_name',
+ dataIndex: 'name',
+ key: 'name',
+ width: '30%',
+ render: CommonTableCell(),
+ },
+ {
+ title: 'test_1',
+ dataIndex: 'name',
+ key: 'name',
+ width: '30%',
+ render: CommonTableCell(),
+ },
+ {
+ title: 'test_2',
+ dataIndex: 'name',
+ key: 'name',
+ width: '30%',
+ render: CommonTableCell(),
+ },
+ {
+ title: 'test_3',
+ dataIndex: 'name',
+ key: 'name',
+ width: '30%',
+ render: CommonTableCell(),
+ },
+ {
+ title: 'test_4',
+ dataIndex: 'name',
+ key: 'name',
+ width: '30%',
+ render: CommonTableCell(),
+ },
+ ],
+ },
+ ];
+
+ return (
+
+ );
+}
+
+export default ExperimentComparison;
diff --git a/react-ui/src/pages/Experiment/index.jsx b/react-ui/src/pages/Experiment/index.jsx
index 69648b49..8793da19 100644
--- a/react-ui/src/pages/Experiment/index.jsx
+++ b/react-ui/src/pages/Experiment/index.jsx
@@ -18,10 +18,11 @@ import themes from '@/styles/theme.less';
import { elapsedTime, formatDate } from '@/utils/date';
import { to } from '@/utils/promise';
import { modalConfirm } from '@/utils/ui';
-import { App, Button, ConfigProvider, Space, Table, Tooltip } from 'antd';
+import { App, Button, ConfigProvider, Dropdown, Space, Table, Tooltip } from 'antd';
import classNames from 'classnames';
import { useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
+import { ComparisonType } from './Comparison';
import AddExperimentModal from './components/AddExperimentModal';
import TensorBoardStatus, { TensorBoardStatusEnum } from './components/TensorBoardStatus';
import Styles from './index.less';
@@ -270,6 +271,26 @@ function Experiment() {
window.open(experimentIn.tensorboardUrl, '_blank');
}
};
+
+ // 实验对比菜单
+ const getComparisonMenu = (experimentId) => {
+ return {
+ items: [
+ {
+ label: 训练对比,
+ key: ComparisonType.Train,
+ },
+ {
+ label: 评估对比,
+ key: ComparisonType.Evaluate,
+ },
+ ],
+ onClick: ({ key }) => {
+ navgite(`/pipeline/experiment/compare?type=${key}&id=${experimentId}`);
+ },
+ };
+ };
+
const columns = [
{
title: '实验名称',
@@ -320,7 +341,7 @@ function Experiment() {
{
title: '操作',
key: 'action',
- width: 300,
+ width: 350,
render: (_, record) => (
+
+ e.preventDefault()}>
+
+
+ 实验对比
+
+
+
{
return;
}
- // const [propsRes, propsError] = await to(propsRef.current.getFieldsValue());
- // if (propsError) {
- // message.error('基本信息必填项需配置');
- // return;
- // }
+ const [propsRes, propsError] = await to(propsRef.current.getFieldsValue());
+ if (propsError) {
+ message.error('节点必填项必须配置');
+ return;
+ }
propsRef.current.propClose();
setTimeout(() => {
const data = graph.save();
diff --git a/react-ui/src/requestConfig.ts b/react-ui/src/requestConfig.ts
index 4934396c..9529922d 100644
--- a/react-ui/src/requestConfig.ts
+++ b/react-ui/src/requestConfig.ts
@@ -40,7 +40,7 @@ export const requestConfig: RequestConfig = {
[
(response: AxiosResponse) => {
const { status, data } = response || {};
- console.log(message, data);
+ // console.log(message, data);
if (status >= 200 && status < 300) {
if (data && (data instanceof Blob || data.code === 200)) {
return response;
diff --git a/react-ui/src/services/developmentEnvironment/index.ts b/react-ui/src/services/developmentEnvironment/index.ts
index dbe2717a..330f76d3 100644
--- a/react-ui/src/services/developmentEnvironment/index.ts
+++ b/react-ui/src/services/developmentEnvironment/index.ts
@@ -1,9 +1,8 @@
import { request } from '@umijs/max';
// 查询开发环境url
-export function getJupyterUrl(params: any) {
+export function getJupyterUrl() {
return request(`/api/mmp/jupyter/getURL`, {
method: 'GET',
- params,
});
}
diff --git a/react-ui/src/services/experiment/index.js b/react-ui/src/services/experiment/index.js
index 9d388b71..89028b24 100644
--- a/react-ui/src/services/experiment/index.js
+++ b/react-ui/src/services/experiment/index.js
@@ -116,3 +116,17 @@ export function getTensorBoardStatusReq(data) {
data,
});
}
+
+// 获取当前实验的模型推理指标信息
+export function getExpEvaluateInfosReq(experimentId) {
+ return request(`/api/mmp/aim/getExpEvaluateInfos/${experimentId}`, {
+ method: 'GET',
+ });
+}
+
+// 获取当前实验的模型训练指标信息
+export function getExpTrainInfosReq(experimentId) {
+ return request(`/api/mmp//aim/getExpTrainInfos/${experimentId}`, {
+ method: 'GET',
+ });
+}
diff --git a/react-ui/src/services/session.ts b/react-ui/src/services/session.ts
index 8430b21b..e1f00d75 100644
--- a/react-ui/src/services/session.ts
+++ b/react-ui/src/services/session.ts
@@ -60,8 +60,8 @@ function patchRouteItems(route: any, menu: any, parentPath: string) {
element: React.createElement(lazy(() => import('@/pages/' + path))),
path: parentPath + menuItem.path,
};
- console.log(newRoute);
-
+ // console.log(newRoute);
+
route.children.push(newRoute);
route.routes.push(newRoute);
}
@@ -74,10 +74,7 @@ export function patchRouteWithRemoteMenus(routes: any) {
}
let proLayout = null;
for (const routeItem of routes) {
-
if (routeItem.id === 'ant-design-pro-layout') {
-
-
proLayout = routeItem;
break;
}
@@ -101,7 +98,6 @@ export async function refreshToken() {
}
export function convertCompatRouters(childrens: API.RoutersMenuItem[]): any[] {
-
return childrens.map((item: API.RoutersMenuItem) => {
return {
path: item.path,
@@ -149,12 +145,11 @@ export function getMatchMenuItem(
const subpath = path.substr(item.path.length + 1);
const subItem: MenuDataItem[] = getMatchMenuItem(subpath, item.routes);
items = items.concat(subItem);
-
} else {
const paths = path.split('/');
if (paths.length >= 2 && paths[0] === item.path && paths[1] === 'index') {
console.log(item);
-
+
items.push(item);
}
}
diff --git a/react-ui/src/utils/sessionStorage.ts b/react-ui/src/utils/sessionStorage.ts
index 6018dbe7..a8632070 100644
--- a/react-ui/src/utils/sessionStorage.ts
+++ b/react-ui/src/utils/sessionStorage.ts
@@ -2,6 +2,8 @@
export const mirrorNameKey = 'mirror-name';
// 模型部署
export const modelDeploymentInfoKey = 'model-deployment-info';
+// 编辑器 url
+export const editorUrl = 'editor-url';
export const getSessionStorageItem = (key: string, isObject: boolean = false) => {
const jsonStr = sessionStorage.getItem(key);
diff --git a/react-ui/tsconfig.json b/react-ui/tsconfig.json
index 9922437a..0afa8788 100644
--- a/react-ui/tsconfig.json
+++ b/react-ui/tsconfig.json
@@ -20,6 +20,7 @@
"noUnusedParameters": true, // 报告未使用的参数错误
"incremental": true, // 通过读写磁盘上的文件来启用增量编译
"noFallthroughCasesInSwitch": true, // 报告switch语句中的fallthrough案例错误
+ "strictNullChecks": true, // 启用严格的null检查
"baseUrl": "./",
"paths": {
"@/*": ["src/*"],
diff --git a/ruoyi-modules/management-platform/pom.xml b/ruoyi-modules/management-platform/pom.xml
index 4cb1ae7d..37234ad0 100644
--- a/ruoyi-modules/management-platform/pom.xml
+++ b/ruoyi-modules/management-platform/pom.xml
@@ -205,6 +205,17 @@
org.springframework.boot
spring-boot-starter-websocket
+
+ org.json
+ json
+ 20210307
+
+
+ org.apache.dubbo
+ dubbo
+ 3.0.8
+ compile
+
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/aim/AimController.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/aim/AimController.java
index f1750133..f6b0b863 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/aim/AimController.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/aim/AimController.java
@@ -4,16 +4,16 @@ import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.GenericsAjaxResult;
import com.ruoyi.platform.service.AimService;
import com.ruoyi.platform.vo.FrameLogPathVo;
+import com.ruoyi.platform.vo.InsMetricInfoVo;
import com.ruoyi.platform.vo.PodStatusVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
+import java.util.List;
+
@RestController
@RequestMapping("aim")
@Api("Aim管理")
@@ -22,17 +22,25 @@ public class AimController extends BaseController {
@Resource
private AimService aimService;
- /**
- * 启动tensorBoard接口
- *
- * @param frameLogPathVo 存储路径
- * @return url
- */
- @PostMapping("/run")
- @ApiOperation("启动aim`")
+
+ @GetMapping("/getExpTrainInfos/{experiment_id}")
+ @ApiOperation("获取当前实验的模型训练指标信息")
@ApiResponse
- public GenericsAjaxResult runAim(@RequestBody FrameLogPathVo frameLogPathVo) throws Exception {
- return genericsSuccess(aimService.runAim(frameLogPathVo));
+ public GenericsAjaxResult> getExpTrainInfos(@PathVariable("experiment_id") Integer experimentId) throws Exception {
+ return genericsSuccess(aimService.getExpTrainInfos(experimentId));
}
+ @GetMapping("/getExpEvaluateInfos/{experiment_id}")
+ @ApiOperation("获取当前实验的模型推理指标信息")
+ @ApiResponse
+ public GenericsAjaxResult> getExpEvaluateInfos(@PathVariable("experiment_id") Integer experimentId) throws Exception {
+ return genericsSuccess(aimService.getExpEvaluateInfos(experimentId));
+ }
+
+ @PostMapping("/getExpMetrics")
+ @ApiOperation("获取当前实验的指标对比地址")
+ @ApiResponse
+ public GenericsAjaxResult getExpMetrics(@RequestBody List runIds) throws Exception {
+ return genericsSuccess(aimService.getExpMetrics(runIds));
+ }
}
\ No newline at end of file
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/mapper/ModelDependencyDao.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/mapper/ModelDependencyDao.java
index 3a999886..ba1bc40b 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/mapper/ModelDependencyDao.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/mapper/ModelDependencyDao.java
@@ -84,5 +84,9 @@ public interface ModelDependencyDao {
List queryByModelDependency(@Param("modelDependency") ModelDependency modelDependency);
List queryChildrenByVersionId(@Param("model_id")String modelId, @Param("version")String version);
+
+ List queryByIns(@Param("expInsId")Integer expInsId);
+
+ ModelDependency queryByInsAndTrainTaskId(@Param("expInsId")Integer expInsId,@Param("taskId") String taskId);
}
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ExperimentInstanceStatusTask.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ExperimentInstanceStatusTask.java
index 4680285e..131dca48 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ExperimentInstanceStatusTask.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/scheduling/ExperimentInstanceStatusTask.java
@@ -7,20 +7,15 @@ 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.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.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
@Component()
public class ExperimentInstanceStatusTask {
@@ -34,7 +29,7 @@ public class ExperimentInstanceStatusTask {
private ModelDependencyDao modelDependencyDao;
private List experimentIds = new ArrayList<>();
- @Scheduled(cron = "0/14 * * * * ?") // 每30S执行一次
+ @Scheduled(cron = "0/30 * * * * ?") // 每30S执行一次
public void executeExperimentInsStatus() throws IOException {
// 首先查到所有非终止态的实验实例
List experimentInsList = experimentInsService.queryByExperimentIsNotTerminated();
@@ -46,95 +41,94 @@ public class ExperimentInstanceStatusTask {
String oldStatus = experimentIns.getStatus();
try {
experimentIns = experimentInsService.queryStatusFromArgo(experimentIns);
- }catch (Exception e){
+ } catch (Exception e) {
experimentIns.setStatus("Failed");
}
-// if (!StringUtils.equals(oldStatus,experimentIns.getStatus())){
- experimentIns.setUpdateTime(new Date());
- // 线程安全的添加操作
- synchronized (experimentIds) {
- experimentIds.add(experimentIns.getExperimentId());
- }
- updateList.add(experimentIns);
-
-// }
-// experimentInsDao.update(experimentIns);
+ experimentIns.setUpdateTime(new Date());
+ // 线程安全的添加操作
+ synchronized (experimentIds) {
+ experimentIds.add(experimentIns.getExperimentId());
+ }
+ updateList.add(experimentIns);
}
-
}
- if (updateList.size() > 0){
+ if (updateList.size() > 0) {
experimentInsDao.insertOrUpdateBatch(updateList);
//遍历模型关系表,找到
List modelDependencyList = new ArrayList();
- for (ExperimentIns experimentIns : updateList){
+ for (ExperimentIns experimentIns : updateList) {
ModelDependency modelDependencyquery = new ModelDependency();
modelDependencyquery.setExpInsId(experimentIns.getId());
modelDependencyquery.setState(2);
List modelDependencyListquery = modelDependencyDao.queryByModelDependency(modelDependencyquery);
- if (modelDependencyListquery==null||modelDependencyListquery.size()==0){
+ if (modelDependencyListquery == null || modelDependencyListquery.size() == 0) {
continue;
}
ModelDependency modelDependency = modelDependencyListquery.get(0);
//查看状态,
- if (StringUtils.equals("Failed",experimentIns.getStatus())){
+ if (StringUtils.equals("Failed", experimentIns.getStatus())) {
//取出节点状态
String trainTask = modelDependency.getTrainTask();
Map trainMap = JacksonUtil.parseJSONStr2Map(trainTask);
String task_id = (String) trainMap.get("task_id");
- if (StringUtils.isEmpty(task_id)){
+ if (StringUtils.isEmpty(task_id)) {
continue;
}
String nodesStatus = experimentIns.getNodesStatus();
Map nodeMaps = JacksonUtil.parseJSONStr2Map(nodesStatus);
Map nodeMap = JacksonUtil.parseJSONStr2Map(JacksonUtil.toJSONString(nodeMaps.get(task_id)));
- if (nodeMap==null){
+ if (nodeMap == null) {
continue;
}
- if (!StringUtils.equals("Succeeded",(String)nodeMap.get("phase"))){
+ if (!StringUtils.equals("Succeeded", (String) nodeMap.get("phase"))) {
modelDependency.setState(0);
modelDependencyList.add(modelDependency);
}
}
}
- if (modelDependencyList.size()>0) {
+ if (modelDependencyList.size() > 0) {
modelDependencyDao.insertOrUpdateBatch(modelDependencyList);
}
}
-
}
- @Scheduled(cron = "0/17 * * * * ?") // / 每30S执行一次
+
+ @Scheduled(cron = "0/30 * * * * ?") // / 每30S执行一次
public void executeExperimentStatus() throws IOException {
- if (experimentIds.size()==0){
+ if (experimentIds.size() == 0) {
return;
}
// 存储需要更新的实验对象列表
List updateExperiments = new ArrayList<>();
- for (Integer experimentId : experimentIds){
+ for (Integer experimentId : experimentIds) {
// 获取当前实验的所有实例列表
List insList = experimentInsService.getByExperimentId(experimentId);
List statusList = new ArrayList();
// 更新实验状态列表
- for (int i=0;i iterator = experimentIds.iterator();
+ while (iterator.hasNext()) {
+ Integer experimentId = iterator.next();
+ for (Experiment experiment : updateExperiments) {
+ if (experiment.getId().equals(experimentId)) {
+ iterator.remove();
+ }
}
}
}
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/AimService.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/AimService.java
index 60f74b90..c83a42af 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/AimService.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/AimService.java
@@ -1,7 +1,14 @@
package com.ruoyi.platform.service;
-import com.ruoyi.platform.vo.FrameLogPathVo;
+import com.ruoyi.platform.vo.InsMetricInfoVo;
+
+import java.util.List;
public interface AimService {
- String runAim(FrameLogPathVo frameLogPathVo);
+
+ List getExpTrainInfos(Integer experimentId) throws Exception;
+
+ List getExpEvaluateInfos(Integer experimentId) throws Exception;
+
+ String getExpMetrics(List runIds) throws Exception;
}
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ModelDependencyService.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ModelDependencyService.java
index 5c8b9d1d..049d87d1 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ModelDependencyService.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ModelDependencyService.java
@@ -62,4 +62,8 @@ public interface ModelDependencyService {
List queryByModelDependency(ModelDependency modelDependency) throws IOException;
ModelDependcyTreeVo getModelDependencyTree(ModelDependency modelDependency) throws Exception;
+
+ List queryByIns(Integer expInsId);
+
+ ModelDependency queryByInsAndTrainTaskId(Integer expInsId, String taskId);
}
diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AimServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AimServiceImpl.java
index f66dc178..6ec8f43c 100644
--- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AimServiceImpl.java
+++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/AimServiceImpl.java
@@ -1,13 +1,175 @@
package com.ruoyi.platform.service.impl;
+import com.ruoyi.platform.domain.ExperimentIns;
+import com.ruoyi.platform.domain.ModelDependency;
import com.ruoyi.platform.service.AimService;
-import com.ruoyi.platform.vo.FrameLogPathVo;
+import com.ruoyi.platform.service.ExperimentInsService;
+import com.ruoyi.platform.service.ModelDependencyService;
+import com.ruoyi.platform.utils.AIM64EncoderUtil;
+import com.ruoyi.platform.utils.HttpUtils;
+import com.ruoyi.platform.utils.JacksonUtil;
+import com.ruoyi.platform.utils.JsonUtils;
+import com.ruoyi.platform.vo.InsMetricInfoVo;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import java.net.URLEncoder;
+import java.util.*;
+import java.util.stream.Collectors;
+
@Service
public class AimServiceImpl implements AimService {
+ @Resource
+ private ExperimentInsService experimentInsService;
+ @Resource
+ private ModelDependencyService modelDependencyService;
+
+ @Value("${aim.url}")
+ private String aimUrl;
+ @Value("${aim.proxyUrl}")
+ private String aimProxyUrl;
+
@Override
- public String runAim(FrameLogPathVo frameLogPathVo) {
- return null;
+ public List getExpTrainInfos(Integer experimentId) throws Exception {
+ return getAimRunInfos(true,experimentId);
}
+
+ @Override
+ public List getExpEvaluateInfos(Integer experimentId) throws Exception {
+ return getAimRunInfos(false,experimentId);
+ }
+
+ @Override
+ public String getExpMetrics(List runIds) throws Exception {
+ String decode = AIM64EncoderUtil.decode(runIds);
+ return aimUrl+"/api/runs/search/run?query="+decode;
+ }
+
+ private List getAimRunInfos(boolean isTrain,Integer experimentId) throws Exception {
+ String experimentName = "experiment-"+experimentId+"-train";
+ if (!isTrain){
+ experimentName = "experiment-"+experimentId+"-evaluate";
+ }
+ String encodedUrlString = URLEncoder.encode("run.experiment==\""+experimentName+"\"", "UTF-8");
+ String url = aimProxyUrl+"/api/runs/search/run?query="+encodedUrlString;
+ String s = HttpUtils.sendGetRequest(url);
+ List