From 7514f04f0c1a33070dc7148cff0584148de616ac Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Mon, 24 Jun 2024 09:01:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E9=AA=8C=E5=AF=B9=E6=AF=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/config/routes.ts | 5 + .../components/ResourceIntro/index.tsx | 2 +- .../DevelopmentEnvironment/List/index.tsx | 10 +- .../pages/Experiment/Comparison/index.less | 21 ++ .../src/pages/Experiment/Comparison/index.tsx | 212 ++++++++++++++++++ react-ui/src/pages/Experiment/index.jsx | 33 ++- react-ui/src/pages/Experiment/index.less | 2 +- react-ui/src/requestConfig.ts | 2 +- react-ui/src/services/experiment/index.js | 14 ++ react-ui/src/services/session.ts | 11 +- 10 files changed, 298 insertions(+), 14 deletions(-) create mode 100644 react-ui/src/pages/Experiment/Comparison/index.less create mode 100644 react-ui/src/pages/Experiment/Comparison/index.tsx diff --git a/react-ui/config/routes.ts b/react-ui/config/routes.ts index 7edf6db2..74390abf 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', + }, ], }, ], 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/List/index.tsx b/react-ui/src/pages/DevelopmentEnvironment/List/index.tsx index 9c4badb6..76f0dcb9 100644 --- a/react-ui/src/pages/DevelopmentEnvironment/List/index.tsx +++ b/react-ui/src/pages/DevelopmentEnvironment/List/index.tsx @@ -38,6 +38,7 @@ export type EditorData = { computing_resource: string; update_by: string; create_time: string; + url: string; }; function EditorList() { @@ -140,7 +141,14 @@ function EditorList() { dataIndex: 'name', key: 'name', width: '30%', - render: CommonTableCell(), + render: (text, record) => + record.url ? ( + + {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..5fca638d --- /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..7c7e3eaa 100644 --- a/react-ui/src/pages/Experiment/index.jsx +++ b/react-ui/src/pages/Experiment/index.jsx @@ -18,11 +18,12 @@ 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 AddExperimentModal from './components/AddExperimentModal'; +import { ComparisonType } from './components/ComparisonModal/config'; import TensorBoardStatus, { TensorBoardStatusEnum } from './components/TensorBoardStatus'; import Styles from './index.less'; import { experimentStatusInfo } from './status'; @@ -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()}> + + + 实验对比 + + + { 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/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); } }