-
diff --git a/react-ui/src/pages/HyperParameter/Instance/index.tsx b/react-ui/src/pages/HyperParameter/Instance/index.tsx
index d38b0ee6..21f5dfe3 100644
--- a/react-ui/src/pages/HyperParameter/Instance/index.tsx
+++ b/react-ui/src/pages/HyperParameter/Instance/index.tsx
@@ -191,7 +191,7 @@ function HyperParameterInstance() {
},
{
key: TabKeys.History,
- label: 'Trial 列表',
+ label: '寻优列表',
icon:
,
children:
,
},
diff --git a/react-ui/src/pages/HyperParameter/components/ExperimentHistory/index.less b/react-ui/src/pages/HyperParameter/components/ExperimentHistory/index.less
index 8e3e29a2..04160e95 100644
--- a/react-ui/src/pages/HyperParameter/components/ExperimentHistory/index.less
+++ b/react-ui/src/pages/HyperParameter/components/ExperimentHistory/index.less
@@ -8,7 +8,8 @@
border-radius: 10px;
&__table {
- height: 100%;
+ height: calc(100% - 52px);
+ margin-top: 20px;
}
:global {
@@ -43,16 +44,31 @@
&__best-tag {
margin-left: 8px;
padding: 1px 10px;
- color: @primary-color;
+ color: @success-color;
font-weight: normal;
font-size: 13px;
- background-color: .addAlpha(@primary-color, 0.1) [];
- border: 1px solid .addAlpha(@primary-color, 0.5) [];
+ background-color: .addAlpha(@success-color, 0.1) [];
+ // border: 1px solid .addAlpha(@success-color, 0.5) [];
border-radius: 2px;
}
}
.table-best-row {
- color: @primary-color;
+ color: @success-color;
font-weight: bold;
}
+
+.trail-result {
+ :global {
+ .ant-tree-node-selected {
+ .trail-result__icon {
+ color: white;
+ }
+ }
+
+ .trail-result__icon {
+ margin-left: 8px;
+ color: @primary-color;
+ }
+ }
+}
diff --git a/react-ui/src/pages/HyperParameter/components/ExperimentHistory/index.tsx b/react-ui/src/pages/HyperParameter/components/ExperimentHistory/index.tsx
index 41a897d1..0263bd69 100644
--- a/react-ui/src/pages/HyperParameter/components/ExperimentHistory/index.tsx
+++ b/react-ui/src/pages/HyperParameter/components/ExperimentHistory/index.tsx
@@ -1,23 +1,33 @@
+import InfoGroup from '@/components/InfoGroup';
import KFIcon from '@/components/KFIcon';
-import { HyperParameterFileList, HyperParameterTrialList } from '@/pages/HyperParameter/types';
+import TrialStatusCell from '@/pages/HyperParameter/components/TrialStatusCell';
+import { HyperParameterFile, HyperParameterTrial } from '@/pages/HyperParameter/types';
+import { getExpMetricsReq } from '@/services/hyperParameter';
import { downLoadZip } from '@/utils/downloadfile';
+import { to } from '@/utils/promise';
import tableCellRender, { TableCellValueType } from '@/utils/table';
-import { Button, Table, Tooltip, type TableProps } from 'antd';
+import { App, Button, Table, Tooltip, Tree, type TableProps, type TreeDataNode } from 'antd';
import classNames from 'classnames';
+import { useState } from 'react';
import styles from './index.less';
+const { DirectoryTree } = Tree;
+
type ExperimentHistoryProps = {
- trialList?: HyperParameterTrialList[];
+ trialList?: HyperParameterTrial[];
};
function ExperimentHistory({ trialList = [] }: ExperimentHistoryProps) {
- const first: HyperParameterTrialList | undefined = trialList[0];
+ const [selectedRowKeys, setSelectedRowKeys] = useState
([]);
+ const { message } = App.useApp();
+
+ const first: HyperParameterTrial | undefined = trialList[0];
const config: Record = first?.config ?? {};
const metricAnalysis: Record = first?.metric_analysis ?? {};
const paramsNames = Object.keys(config);
const metricNames = Object.keys(metricAnalysis);
- const trialColumns: TableProps['columns'] = [
+ const trialColumns: TableProps['columns'] = [
{
title: '序号',
dataIndex: 'index',
@@ -55,7 +65,7 @@ function ExperimentHistory({ trialList = [] }: ExperimentHistoryProps) {
dataIndex: 'status',
key: 'status',
width: 120,
- render: tableCellRender(false),
+ render: TrialStatusCell,
},
];
@@ -105,7 +115,7 @@ function ExperimentHistory({ trialList = [] }: ExperimentHistoryProps) {
});
}
- const fileColumns: TableProps['columns'] = [
+ const fileColumns: TableProps['columns'] = [
{
title: '文件名称',
dataIndex: 'name',
@@ -124,7 +134,7 @@ function ExperimentHistory({ trialList = [] }: ExperimentHistoryProps) {
dataIndex: 'option',
width: 160,
key: 'option',
- render: (_: any, record: HyperParameterFileList) => {
+ render: (_: any, record: HyperParameterFile) => {
return (
(
+ const expandedRowRender = (record: HyperParameterTrial) => (
);
+ const expandedRowRender2 = (record: HyperParameterTrial) => {
+ const filesToTreeData = (
+ files: HyperParameterFile[],
+ parent?: HyperParameterFile,
+ ): TreeDataNode[] =>
+ files.map((file) => {
+ const key = parent ? `${parent.name}/${file.name}` : file.name;
+ return {
+ ...file,
+ key,
+ title: file.name,
+ children: file.children ? filesToTreeData(file.children, file) : undefined,
+ };
+ });
+
+ const treeData: TreeDataNode[] = filesToTreeData([record.file]);
+ return (
+
+ {
+ const label = record.title + (record.isFile ? `(${record.size})` : '');
+ return (
+ <>
+ {label}
+ {
+ e.stopPropagation();
+ downLoadZip(
+ record.isFile
+ ? `/api/mmp/minioStorage/downloadFile`
+ : `/api/mmp/minioStorage/download`,
+ { path: record.url },
+ );
+ }}
+ />
+ >
+ );
+ }}
+ />
+
+ );
+ };
+
+ // 选择行
+ const rowSelection: TableProps['rowSelection'] = {
+ type: 'checkbox',
+ columnWidth: 48,
+ fixed: 'left',
+ selectedRowKeys,
+ onChange: (selectedRowKeys: React.Key[]) => {
+ setSelectedRowKeys(selectedRowKeys);
+ },
+ };
+
+ const handleComparisonClick = () => {
+ if (selectedRowKeys.length < 1) {
+ message.error('请至少选择一项');
+ return;
+ }
+ getExpMetrics();
+ };
+
+ // 获取对比 url
+ const getExpMetrics = async () => {
+ const [res] = await to(getExpMetricsReq(selectedRowKeys));
+ if (res && res.data) {
+ const url = res.data;
+ window.open(url, '_blank');
+ }
+ };
+
return (
diff --git a/react-ui/src/pages/HyperParameter/components/TrialStatusCell/index.less b/react-ui/src/pages/HyperParameter/components/TrialStatusCell/index.less
new file mode 100644
index 00000000..6bdaf5bc
--- /dev/null
+++ b/react-ui/src/pages/HyperParameter/components/TrialStatusCell/index.less
@@ -0,0 +1,3 @@
+.trial-status-cell {
+ height: 100%;
+}
diff --git a/react-ui/src/pages/HyperParameter/components/TrialStatusCell/index.tsx b/react-ui/src/pages/HyperParameter/components/TrialStatusCell/index.tsx
new file mode 100644
index 00000000..8838e175
--- /dev/null
+++ b/react-ui/src/pages/HyperParameter/components/TrialStatusCell/index.tsx
@@ -0,0 +1,67 @@
+/*
+ * @Author: 赵伟
+ * @Date: 2024-04-18 18:35:41
+ * @Description: 实验状态
+ */
+
+import { HyperParameterTrailStatus } from '@/enums';
+import { ExperimentStatusInfo } from '@/pages/Experiment/status';
+import themes from '@/styles/theme.less';
+import styles from './index.less';
+
+export const statusInfo: Record = {
+ [HyperParameterTrailStatus.RUNNING]: {
+ label: '运行中',
+ color: themes.primaryColor,
+ icon: '/assets/images/experiment-status/running-icon.png',
+ },
+ [HyperParameterTrailStatus.TERMINATED]: {
+ label: '成功',
+ color: themes.successColor,
+ icon: '/assets/images/experiment-status/success-icon.png',
+ },
+ [HyperParameterTrailStatus.PENDING]: {
+ label: '挂起',
+ color: themes.pendingColor,
+ icon: '/assets/images/experiment-status/pending-icon.png',
+ },
+ [HyperParameterTrailStatus.ERROR]: {
+ label: '失败',
+ color: themes.errorColor,
+ icon: '/assets/images/experiment-status/fail-icon.png',
+ },
+ [HyperParameterTrailStatus.PAUSED]: {
+ label: '暂停',
+ color: themes.abortColor,
+ icon: '/assets/images/experiment-status/omitted-icon.png',
+ },
+ [HyperParameterTrailStatus.RESTORING]: {
+ label: '恢复中',
+ color: themes.textColor,
+ icon: '/assets/images/experiment-status/omitted-icon.png',
+ },
+};
+
+function TrialStatusCell(status?: HyperParameterTrailStatus | null) {
+ if (status === null || status === undefined) {
+ return --;
+ }
+ return (
+
+ {/*

*/}
+
+ {statusInfo[status] ? statusInfo[status].label : status}
+
+
+ );
+}
+
+export default TrialStatusCell;
diff --git a/react-ui/src/pages/HyperParameter/types.ts b/react-ui/src/pages/HyperParameter/types.ts
index bff6d046..fc32bf3f 100644
--- a/react-ui/src/pages/HyperParameter/types.ts
+++ b/react-ui/src/pages/HyperParameter/types.ts
@@ -59,11 +59,11 @@ export type HyperParameterInstanceData = {
update_time: string;
finish_time: string;
nodeStatus?: NodeStatus; // json之后的节点状态
- trial_list?: HyperParameterTrialList[];
- file_list?: HyperParameterFileList[];
+ trial_list?: HyperParameterTrial[];
+ file_list?: HyperParameterFile[];
};
-export type HyperParameterTrialList = {
+export type HyperParameterTrial = {
trial_id?: string;
training_iteration?: number;
time?: number;
@@ -71,14 +71,14 @@ export type HyperParameterTrialList = {
config?: Record;
metric_analysis?: Record;
metric: string;
- file: HyperParameterFileList;
+ file: HyperParameterFile;
is_best?: boolean;
};
-export type HyperParameterFileList = {
+export type HyperParameterFile = {
name: string;
size: string;
url: string;
isFile: boolean;
- children?: HyperParameterFileList[];
+ children: HyperParameterFile[];
};
diff --git a/react-ui/src/services/hyperParameter/index.js b/react-ui/src/services/hyperParameter/index.js
index c97e617d..96ea52e1 100644
--- a/react-ui/src/services/hyperParameter/index.js
+++ b/react-ui/src/services/hyperParameter/index.js
@@ -91,3 +91,10 @@ export function batchDeleteRayInsReq(data) {
});
}
+// 获取当前实验的指标对比地址
+export function getExpMetricsReq(data) {
+ return request(`/api/mmp/rayIns/getExpMetrics`, {
+ method: 'POST',
+ data
+ });
+}