Browse Source

Merge pull request '合并dev' (#225) from dev into dev-check

pull/227/head
cp3hnu 8 months ago
parent
commit
7fc016c3a0
7 changed files with 62 additions and 16 deletions
  1. +5
    -0
      react-ui/config/routes.ts
  2. +3
    -2
      react-ui/src/pages/AutoML/components/CreateForm/ExecuteConfig.tsx
  3. +2
    -2
      react-ui/src/pages/Dataset/components/AddModelModal/index.tsx
  4. +33
    -10
      react-ui/src/pages/Experiment/Info/index.jsx
  5. +12
    -0
      react-ui/src/pages/Experiment/Tensorboard/index.tsx
  6. +6
    -2
      react-ui/src/pages/Experiment/index.jsx
  7. +1
    -0
      react-ui/src/pages/Mirror/Info/index.tsx

+ 5
- 0
react-ui/config/routes.ts View File

@@ -148,6 +148,11 @@ export default [
path: 'compare-visual', path: 'compare-visual',
component: './Experiment/Aim/index', component: './Experiment/Aim/index',
}, },
{
name: '可视化',
path: 'visual',
component: './Experiment/Tensorboard/index',
},
], ],
}, },
{ {


+ 3
- 2
react-ui/src/pages/AutoML/components/CreateForm/ExecuteConfig.tsx View File

@@ -292,7 +292,7 @@ function ExecuteConfig() {
<Form.Item <Form.Item
label="集成最佳模型数量" label="集成最佳模型数量"
name="ensemble_nbest" name="ensemble_nbest"
tooltip="仅集成最佳的N个模型"
tooltip="仅集成最佳的N个模型,必须是大于等于1的整数"
> >
<InputNumber placeholder="请输入集成最佳模型数量" min={1} precision={0} /> <InputNumber placeholder="请输入集成最佳模型数量" min={1} precision={0} />
</Form.Item> </Form.Item>
@@ -419,6 +419,7 @@ function ExecuteConfig() {
<Form.Item <Form.Item
label="交叉验证折数" label="交叉验证折数"
name="folds" name="folds"
tooltip="交叉验证折数必须是大于等于2的整数"
rules={[ rules={[
{ {
required: true, required: true,
@@ -426,7 +427,7 @@ function ExecuteConfig() {
}, },
]} ]}
> >
<InputNumber placeholder="请输入交叉验证折数" min={1} precision={0} />
<InputNumber placeholder="请输入交叉验证折数" min={2} precision={0} />
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>


+ 2
- 2
react-ui/src/pages/Dataset/components/AddModelModal/index.tsx View File

@@ -126,7 +126,7 @@ function AddModelModal({ typeList, tagList, onOk, ...rest }: AddModelModalProps)
<Form.Item label="模型框架" name="model_type"> <Form.Item label="模型框架" name="model_type">
<Select <Select
allowClear allowClear
placeholder="请选择模型类型"
placeholder="请选择模型框架"
options={typeList} options={typeList}
fieldNames={{ label: 'name', value: 'name' }} fieldNames={{ label: 'name', value: 'name' }}
optionFilterProp="name" optionFilterProp="name"
@@ -136,7 +136,7 @@ function AddModelModal({ typeList, tagList, onOk, ...rest }: AddModelModalProps)
<Form.Item label="模型能力" name="model_tag"> <Form.Item label="模型能力" name="model_tag">
<Select <Select
allowClear allowClear
placeholder="请选择模型标签"
placeholder="请选择模型能力"
options={tagList} options={tagList}
fieldNames={{ label: 'name', value: 'name' }} fieldNames={{ label: 'name', value: 'name' }}
optionFilterProp="name" optionFilterProp="name"


+ 33
- 10
react-ui/src/pages/Experiment/Info/index.jsx View File

@@ -18,10 +18,12 @@ import { experimentStatusInfo } from '../status';
import styles from './index.less'; import styles from './index.less';


let graph = null; let graph = null;
const NodePrefix = 'workflow';


function ExperimentText() { function ExperimentText() {
const [experimentIns, setExperimentIns] = useState(undefined); const [experimentIns, setExperimentIns] = useState(undefined);
const [experimentNodeData, setExperimentNodeData, experimentNodeDataRef] = useStateRef(undefined); const [experimentNodeData, setExperimentNodeData, experimentNodeDataRef] = useStateRef(undefined);
const [workflowStatus, setWorkflowStatus] = useState(undefined);
const graphRef = useRef(); const graphRef = useRef();
const workflowRef = useRef(); const workflowRef = useRef();
const locationParams = useParams(); // 新版本获取路由参数接口 const locationParams = useParams(); // 新版本获取路由参数接口
@@ -89,10 +91,22 @@ function ExperimentText() {
const { status, nodes_status, argo_ins_ns, argo_ins_name, finish_time } = res.data; const { status, nodes_status, argo_ins_ns, argo_ins_name, finish_time } = res.data;
const workflowData = workflowRef.current; const workflowData = workflowRef.current;
const experimentStatusObjs = parseJsonText(nodes_status); const experimentStatusObjs = parseJsonText(nodes_status);
workflowData.nodes.forEach((item) => {
const experimentNode = experimentStatusObjs?.[item.id];
updateWorkflowNode(item, experimentNode);
});
if (experimentStatusObjs) {
workflowData.nodes.forEach((item) => {
const experimentNode = experimentStatusObjs?.[item.id];
updateWorkflowNode(item, experimentNode);
});

// 处理workflow状态
Object.keys(experimentStatusObjs).some((key) => {
if (key.startsWith(NodePrefix)) {
const workflowStatus = experimentStatusObjs[key];
setWorkflowStatus(workflowStatus);
return true;
}
return false;
});
}


// 绘制图 // 绘制图
getGraphData(workflowData, true); getGraphData(workflowData, true);
@@ -147,6 +161,15 @@ function ExperimentText() {
status: phase, status: phase,
})); }));


const workflowStatus = Object.values(nodes).find((node) =>
node.displayName.startsWith(NodePrefix),
);

// 设置工作流状态
if (workflowStatus) {
setWorkflowStatus(workflowStatus);
}

const workflowData = workflowRef.current; const workflowData = workflowRef.current;
workflowData.nodes.forEach((item) => { workflowData.nodes.forEach((item) => {
const experimentNode = Object.values(nodes).find((node) => node.displayName === item.id); const experimentNode = Object.values(nodes).find((node) => node.displayName === item.id);
@@ -471,13 +494,13 @@ function ExperimentText() {
<div className={styles['pipeline-container']}> <div className={styles['pipeline-container']}>
<div className={styles['pipeline-container__top']}> <div className={styles['pipeline-container__top']}>
<div className={styles['pipeline-container__top__info']}> <div className={styles['pipeline-container__top__info']}>
启动时间:{formatDate(experimentIns?.create_time)}
启动时间:{formatDate(workflowStatus?.startedAt)}
</div> </div>
<div className={styles['pipeline-container__top__info']}> <div className={styles['pipeline-container__top__info']}>
执行时长: 执行时长:
<RunDuration <RunDuration
createTime={experimentIns?.create_time}
finishTime={experimentIns?.finish_time}
createTime={workflowStatus?.startedAt}
finishTime={workflowStatus?.finishedAt}
/> />
</div> </div>
<div className={styles['pipeline-container__top__info']}> <div className={styles['pipeline-container__top__info']}>
@@ -488,11 +511,11 @@ function ExperimentText() {
height: '8px', height: '8px',
borderRadius: '50%', borderRadius: '50%',
marginRight: '6px', marginRight: '6px',
backgroundColor: experimentStatusInfo[experimentIns?.status]?.color,
backgroundColor: experimentStatusInfo[workflowStatus?.phase]?.color,
}} }}
></div> ></div>
<span style={{ color: experimentStatusInfo[experimentIns?.status]?.color }}>
{experimentStatusInfo[experimentIns?.status]?.label}
<span style={{ color: experimentStatusInfo[workflowStatus?.phase]?.color }}>
{experimentStatusInfo[workflowStatus?.phase]?.label}
</span> </span>
</div> </div>
<Button <Button


+ 12
- 0
react-ui/src/pages/Experiment/Tensorboard/index.tsx View File

@@ -0,0 +1,12 @@
/*
* @Author: 赵伟
* @Date: 2025-03-31 16:38:59
* @Description: 实验可视化 Tensorboard
*/

import IframePage, { IframePageType } from '@/components/IFramePage';

function TensorboardPage() {
return <IframePage type={IframePageType.TensorBoard}></IframePage>;
}
export default TensorboardPage;

+ 6
- 2
react-ui/src/pages/Experiment/index.jsx View File

@@ -2,6 +2,7 @@ import KFIcon from '@/components/KFIcon';
import PageTitle from '@/components/PageTitle'; import PageTitle from '@/components/PageTitle';
import { ExperimentStatus, TensorBoardStatus } from '@/enums'; import { ExperimentStatus, TensorBoardStatus } from '@/enums';
import { useCacheState } from '@/hooks/useCacheState'; import { useCacheState } from '@/hooks/useCacheState';
import { useServerTime } from '@/hooks/useServerTime';
import { import {
deleteExperimentById, deleteExperimentById,
getExperiment, getExperiment,
@@ -17,6 +18,7 @@ import { getWorkflow } from '@/services/pipeline/index.js';
import themes from '@/styles/theme.less'; import themes from '@/styles/theme.less';
import { ExperimentCompleted } from '@/utils/constant'; import { ExperimentCompleted } from '@/utils/constant';
import { to } from '@/utils/promise'; import { to } from '@/utils/promise';
import SessionStorage from '@/utils/sessionStorage';
import tableCellRender, { TableCellValueType } from '@/utils/table'; import tableCellRender, { TableCellValueType } from '@/utils/table';
import { modalConfirm } from '@/utils/ui'; import { modalConfirm } from '@/utils/ui';
import { App, Button, ConfigProvider, Dropdown, Input, Space, Table, Tooltip } from 'antd'; import { App, Button, ConfigProvider, Dropdown, Input, Space, Table, Tooltip } from 'antd';
@@ -28,7 +30,6 @@ import AddExperimentModal from './components/AddExperimentModal';
import ExperimentInstanceList from './components/ExperimentInstanceList'; import ExperimentInstanceList from './components/ExperimentInstanceList';
import styles from './index.less'; import styles from './index.less';
import { experimentStatusInfo } from './status'; import { experimentStatusInfo } from './status';
import { useServerTime } from '@/hooks/useServerTime';


// 定时器 // 定时器
const timerIds = new Map(); const timerIds = new Map();
@@ -372,7 +373,10 @@ function Experiment() {
experimentIn.tensorBoardStatus === TensorBoardStatus.Running && experimentIn.tensorBoardStatus === TensorBoardStatus.Running &&
experimentIn.tensorboardUrl experimentIn.tensorboardUrl
) { ) {
window.open(experimentIn.tensorboardUrl, '_blank');
const url = experimentIn.tensorboardUrl;
SessionStorage.setItem(SessionStorage.tensorBoardUrlKey, url);
navigateToUrl(`/pipeline/experiment/visual`);
// window.open(experimentIn.tensorboardUrl, '_blank');
} }
}; };




+ 1
- 0
react-ui/src/pages/Mirror/Info/index.tsx View File

@@ -125,6 +125,7 @@ function MirrorInfo() {
current: tableData.length === 1 ? Math.max(1, prev.current! - 1) : prev.current, current: tableData.length === 1 ? Math.max(1, prev.current! - 1) : prev.current,
}; };
}); });
getMirrorInfo();
} }
}; };




Loading…
Cancel
Save