Browse Source

feat: 运行主动学习

pull/198/head
zhaowei 9 months ago
parent
commit
411350d16f
22 changed files with 395 additions and 309 deletions
  1. +12
    -0
      react-ui/config/routes.ts
  2. +1
    -1
      react-ui/src/app.tsx
  3. +3
    -0
      react-ui/src/components/IFramePage/index.tsx
  4. +3
    -3
      react-ui/src/pages/ActiveLearn/Info/index.tsx
  5. +1
    -1
      react-ui/src/pages/ActiveLearn/Instance/index.less
  6. +53
    -74
      react-ui/src/pages/ActiveLearn/Instance/index.tsx
  7. +1
    -1
      react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.less
  8. +15
    -15
      react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx
  9. +41
    -53
      react-ui/src/pages/ActiveLearn/components/CreateForm/ExecuteConfig.tsx
  10. +0
    -145
      react-ui/src/pages/ActiveLearn/components/CreateForm/index.less
  11. +16
    -0
      react-ui/src/pages/ActiveLearn/components/ExperimentLog/index.less
  12. +106
    -0
      react-ui/src/pages/ActiveLearn/components/ExperimentLog/index.tsx
  13. +120
    -0
      react-ui/src/pages/ActiveLearn/data.json
  14. +4
    -4
      react-ui/src/pages/ActiveLearn/types.ts
  15. +2
    -1
      react-ui/src/pages/DevelopmentEnvironment/List/index.tsx
  16. +1
    -4
      react-ui/src/pages/Experiment/components/LogGroup/index.tsx
  17. +1
    -1
      react-ui/src/pages/HyperParameter/Info/index.tsx
  18. +0
    -3
      react-ui/src/pages/HyperParameter/components/ExperimentLog/index.tsx
  19. +1
    -1
      react-ui/src/pages/HyperParameter/types.ts
  20. +12
    -0
      react-ui/src/pages/Knowledge/index.tsx
  21. +1
    -1
      react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx
  22. +1
    -1
      react-ui/src/utils/date.ts

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

@@ -561,6 +561,18 @@ export default [
}, },
], ],
}, },
{
name: '知识图谱',
path: '/knowledge',
routes: [
{
name: '知识图谱',
path: '',
key: 'knowledge',
component: './Knowledge/index',
},
],
},
{ {
path: '*', path: '*',
layout: false, layout: false,


+ 1
- 1
react-ui/src/app.tsx View File

@@ -25,7 +25,7 @@ export { requestConfig as request } from './requestConfig';


/** /**
* @see https://umijs.org/zh-CN/plugins/plugin-initial-state * @see https://umijs.org/zh-CN/plugins/plugin-initial-state
* */
*/
export async function getInitialState(): Promise<GlobalInitialState> { export async function getInitialState(): Promise<GlobalInitialState> {
const fetchUserInfo = async () => { const fetchUserInfo = async () => {
try { try {


+ 3
- 0
react-ui/src/components/IFramePage/index.tsx View File

@@ -15,6 +15,7 @@ export enum IframePageType {
DevEnv = 'DevEnv', // 开发环境 DevEnv = 'DevEnv', // 开发环境
GitLink = 'GitLink', // git link GitLink = 'GitLink', // git link
Aim = 'Aim', // 实验对比 Aim = 'Aim', // 实验对比
Knowledge = 'Knowledge', // 知识图谱
} }


const getRequestAPI = (type: IframePageType): (() => Promise<any>) => { const getRequestAPI = (type: IframePageType): (() => Promise<any>) => {
@@ -37,6 +38,8 @@ const getRequestAPI = (type: IframePageType): (() => Promise<any>) => {
code: 200, code: 200,
data: SessionStorage.getItem(SessionStorage.aimUrlKey) || '', data: SessionStorage.getItem(SessionStorage.aimUrlKey) || '',
}); });
case IframePageType.Knowledge: // git link
return () => Promise.resolve({ code: 200, data: 'http://172.168.15.235:32701' });
} }
}; };




+ 3
- 3
react-ui/src/pages/ActiveLearn/Info/index.tsx View File

@@ -9,7 +9,7 @@ import { safeInvoke } from '@/utils/functional';
import { to } from '@/utils/promise'; import { to } from '@/utils/promise';
import { useParams } from '@umijs/max'; import { useParams } from '@umijs/max';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import BasicInfo from '../components/BasicInfo';
import ActiveLearnBasic from '../components/ActiveLearnBasic';
import { ActiveLearnData } from '../types'; import { ActiveLearnData } from '../types';
import styles from './index.less'; import styles from './index.less';


@@ -24,7 +24,7 @@ function ActiveLearnInfo() {
} }
}, []); }, []);


// 获取主动学习详情
// 获取详情
const getActiveLearnInfo = async () => { const getActiveLearnInfo = async () => {
const [res] = await to(getActiveLearnInfoReq({ id: id })); const [res] = await to(getActiveLearnInfoReq({ id: id }));
if (res && res.data) { if (res && res.data) {
@@ -36,7 +36,7 @@ function ActiveLearnInfo() {
<div className={styles['auto-ml-info']}> <div className={styles['auto-ml-info']}>
<PageTitle title="实验详情"></PageTitle> <PageTitle title="实验详情"></PageTitle>
<div className={styles['auto-ml-info__content']}> <div className={styles['auto-ml-info__content']}>
<BasicInfo info={info} />
<ActiveLearnBasic info={info} />
</div> </div>
</div> </div>
); );


+ 1
- 1
react-ui/src/pages/ActiveLearn/Instance/index.less View File

@@ -1,4 +1,4 @@
.auto-ml-instance {
.active-learn-instance {
height: 100%; height: 100%;


&__tabs { &__tabs {


+ 53
- 74
react-ui/src/pages/ActiveLearn/Instance/index.tsx View File

@@ -1,7 +1,6 @@
import KFIcon from '@/components/KFIcon'; import KFIcon from '@/components/KFIcon';
import { AutoMLTaskType, ExperimentStatus } from '@/enums';
import LogList from '@/pages/Experiment/components/LogList';
import { getExperimentInsReq } from '@/services/autoML';
import { ExperimentStatus } from '@/enums';
import { getActiveLearnInsReq } from '@/services/activeLearn';
import { NodeStatus } from '@/types'; import { NodeStatus } from '@/types';
import { parseJsonText } from '@/utils'; import { parseJsonText } from '@/utils';
import { safeInvoke } from '@/utils/functional'; import { safeInvoke } from '@/utils/functional';
@@ -9,10 +8,11 @@ import { to } from '@/utils/promise';
import { useParams } from '@umijs/max'; import { useParams } from '@umijs/max';
import { Tabs } from 'antd'; import { Tabs } from 'antd';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import BasicInfo from '../components/BasicInfo';
import ActiveLearnBasic from '../components/ActiveLearnBasic';
import ExperimentHistory from '../components/ExperimentHistory'; import ExperimentHistory from '../components/ExperimentHistory';
import ExperimentLog from '../components/ExperimentLog';
import ExperimentResult from '../components/ExperimentResult'; import ExperimentResult from '../components/ExperimentResult';
import { AutoMLInstanceData, HyperparameterData } from '../types';
import { ActiveLearnData, ActiveLearnInstanceData } from '../types';
import styles from './index.less'; import styles from './index.less';


enum TabKeys { enum TabKeys {
@@ -22,12 +22,15 @@ enum TabKeys {
History = 'history', History = 'history',
} }


function AutoMLInstance() {
const [activeTab, setActiveTab] = useState<string>(TabKeys.Params);
const [autoMLInfo, setAutoMLInfo] = useState<HyperparameterData | undefined>(undefined);
const [instanceInfo, setInstanceInfo] = useState<AutoMLInstanceData | undefined>(undefined);
const NodePrefix = 'workflow';

function ActiveLearnInstance() {
const [experimentInfo, setExperimentInfo] = useState<ActiveLearnData | undefined>(undefined);
const [instanceInfo, setInstanceInfo] = useState<ActiveLearnInstanceData | undefined>(undefined);
// 超参数寻优运行有3个节点,运行状态取工作流状态,而不是 auto-hpo 节点状态
const [workflowStatus, setWorkflowStatus] = useState<NodeStatus | undefined>(undefined);
const [nodes, setNodes] = useState<Record<string, NodeStatus> | undefined>(undefined);
const params = useParams(); const params = useParams();
// const autoMLId = safeInvoke(Number)(params.autoMLId);
const instanceId = safeInvoke(Number)(params.id); const instanceId = safeInvoke(Number)(params.id);
const evtSourceRef = useRef<EventSource | null>(null); const evtSourceRef = useRef<EventSource | null>(null);


@@ -38,41 +41,43 @@ function AutoMLInstance() {
return () => { return () => {
closeSSE(); closeSSE();
}; };
}, []);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [instanceId]);


// 获取实验实例详情 // 获取实验实例详情
const getExperimentInsInfo = async (isStatusDetermined: boolean) => { const getExperimentInsInfo = async (isStatusDetermined: boolean) => {
const [res] = await to(getExperimentInsReq(instanceId));
const [res] = await to(getActiveLearnInsReq(instanceId));
if (res && res.data) { if (res && res.data) {
const info = res.data as AutoMLInstanceData;
const info = res.data as ActiveLearnInstanceData;
const { param, node_status, argo_ins_name, argo_ins_ns, status } = info; const { param, node_status, argo_ins_name, argo_ins_ns, status } = info;
// 解析配置参数 // 解析配置参数
const paramJson = parseJsonText(param); const paramJson = parseJsonText(param);
if (paramJson) { if (paramJson) {
setAutoMLInfo(paramJson);
setExperimentInfo(paramJson.data);
} }


setInstanceInfo(info);

// 这个接口返回的状态有延时,SSE 返回的状态是最新的 // 这个接口返回的状态有延时,SSE 返回的状态是最新的
// SSE 调用时,不需要解析 node_status, 也不要重新建立 SSE
// SSE 调用时,不需要解析 node_status,也不要重新建立 SSE
if (isStatusDetermined) { if (isStatusDetermined) {
setInstanceInfo((prev) => ({
...info,
nodeStatus: prev!.nodeStatus,
}));
return; return;
} }


// 进行节点状态 // 进行节点状态
const nodeStatusJson = parseJsonText(node_status); const nodeStatusJson = parseJsonText(node_status);
if (nodeStatusJson) { if (nodeStatusJson) {
Object.keys(nodeStatusJson).forEach((key) => {
if (key.startsWith('auto-ml')) {
const value = nodeStatusJson[key];
info.nodeStatus = value;
setNodes(nodeStatusJson);
Object.keys(nodeStatusJson).some((key) => {
if (key.startsWith(NodePrefix)) {
const workflowStatus = nodeStatusJson[key];
setWorkflowStatus(workflowStatus);
return true;
} }
return false;
}); });
} }
setInstanceInfo(info);
// 运行中或者等待中,开启 SSE // 运行中或者等待中,开启 SSE
if (status === ExperimentStatus.Pending || status === ExperimentStatus.Running) { if (status === ExperimentStatus.Pending || status === ExperimentStatus.Running) {
setupSSE(argo_ins_name, argo_ins_ns); setupSSE(argo_ins_name, argo_ins_ns);
@@ -81,10 +86,7 @@ function AutoMLInstance() {
}; };


const setupSSE = (name: string, namespace: string) => { const setupSSE = (name: string, namespace: string) => {
let { origin } = location;
if (process.env.NODE_ENV === 'development') {
origin = 'http://172.20.32.181:31213';
}
const { origin } = location;
const params = encodeURIComponent(`metadata.namespace=${namespace},metadata.name=${name}`); const params = encodeURIComponent(`metadata.namespace=${namespace},metadata.name=${name}`);
const evtSource = new EventSource( const evtSource = new EventSource(
`${origin}/api/v1/realtimeStatus?listOptions.fieldSelector=${params}`, `${origin}/api/v1/realtimeStatus?listOptions.fieldSelector=${params}`,
@@ -99,19 +101,21 @@ function AutoMLInstance() {
if (dataJson) { if (dataJson) {
const nodes = dataJson?.result?.object?.status?.nodes; const nodes = dataJson?.result?.object?.status?.nodes;
if (nodes) { if (nodes) {
const statusData = Object.values(nodes).find((node: any) =>
node.displayName.startsWith('auto-ml'),
const workflowStatus = Object.values(nodes).find((node: any) =>
node.displayName.startsWith(NodePrefix),
) as NodeStatus; ) as NodeStatus;
if (statusData) {
setInstanceInfo((prev) => ({
...prev!,
nodeStatus: statusData,
}));

// 节点
setNodes(nodes);

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


// 实验结束,关闭 SSE // 实验结束,关闭 SSE
if ( if (
statusData.phase !== ExperimentStatus.Pending &&
statusData.phase !== ExperimentStatus.Running
workflowStatus.phase !== ExperimentStatus.Pending &&
workflowStatus.phase !== ExperimentStatus.Running
) { ) {
closeSSE(); closeSSE();
getExperimentInsInfo(true); getExperimentInsInfo(true);
@@ -140,10 +144,10 @@ function AutoMLInstance() {
label: '基本信息', label: '基本信息',
icon: <KFIcon type="icon-jibenxinxi" />, icon: <KFIcon type="icon-jibenxinxi" />,
children: ( children: (
<BasicInfo
className={styles['auto-ml-instance__basic']}
info={autoMLInfo}
runStatus={instanceInfo?.nodeStatus}
<ActiveLearnBasic
className={styles['active-learn-instance__basic']}
info={experimentInfo}
runStatus={workflowStatus}
isInstance isInstance
/> />
), ),
@@ -153,17 +157,8 @@ function AutoMLInstance() {
label: '日志', label: '日志',
icon: <KFIcon type="icon-rizhi1" />, icon: <KFIcon type="icon-rizhi1" />,
children: ( children: (
<div className={styles['auto-ml-instance__log']}>
{instanceInfo && instanceInfo.nodeStatus && (
<LogList
instanceName={instanceInfo.argo_ins_name}
instanceNamespace={instanceInfo.argo_ins_ns}
pipelineNodeId={instanceInfo.nodeStatus.displayName}
workflowId={instanceInfo.nodeStatus.id}
instanceNodeStartTime={instanceInfo.nodeStatus.startedAt}
instanceNodeStatus={instanceInfo.nodeStatus.phase as ExperimentStatus}
></LogList>
)}
<div className={styles['active-learn-instance__log']}>
{instanceInfo && nodes && <ExperimentLog instanceInfo={instanceInfo} nodes={nodes} />}
</div> </div>
), ),
}, },
@@ -174,24 +169,13 @@ function AutoMLInstance() {
key: TabKeys.Result, key: TabKeys.Result,
label: '实验结果', label: '实验结果',
icon: <KFIcon type="icon-shiyanjieguo1" />, icon: <KFIcon type="icon-shiyanjieguo1" />,
children: (
<ExperimentResult
fileUrl={instanceInfo?.result_path}
imageUrl={instanceInfo?.img_path}
modelPath={instanceInfo?.model_path}
/>
),
children: <ExperimentResult fileUrl={instanceInfo?.result_txt} />,
}, },
{ {
key: TabKeys.History, key: TabKeys.History,
label: 'Trial 列表',
label: '寻优列表',
icon: <KFIcon type="icon-Trialliebiao" />, icon: <KFIcon type="icon-Trialliebiao" />,
children: (
<ExperimentHistory
fileUrl={instanceInfo?.run_history_path}
isClassification={autoMLInfo?.task_type === AutoMLTaskType.Classification}
/>
),
children: <ExperimentHistory trialList={instanceInfo?.trial_list ?? []} />,
}, },
]; ];


@@ -201,15 +185,10 @@ function AutoMLInstance() {
: basicTabItems; : basicTabItems;


return ( return (
<div className={styles['auto-ml-instance']}>
<Tabs
className={styles['auto-ml-instance__tabs']}
items={tabItems}
activeKey={activeTab}
onChange={setActiveTab}
/>
<div className={styles['active-learn-instance']}>
<Tabs className={styles['active-learn-instance__tabs']} items={tabItems} />
</div> </div>
); );
} }


export default AutoMLInstance;
export default ActiveLearnInstance;

react-ui/src/pages/ActiveLearn/components/BasicInfo/index.less → react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.less View File

@@ -1,4 +1,4 @@
.hyper-parameter-basic {
.active-learn-basic {
height: 100%; height: 100%;
padding: 20px @content-padding; padding: 20px @content-padding;
overflow-y: auto; overflow-y: auto;

react-ui/src/pages/ActiveLearn/components/BasicInfo/index.tsx → react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx View File

@@ -73,7 +73,7 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo


const modelInfo = [ const modelInfo = [
{ {
label: '模型',
label: '预训练模型',
value: info.model, value: info.model,
format: formatModel, format: formatModel,
}, },
@@ -85,6 +85,10 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo
label: '模型类名称', label: '模型类名称',
value: info.model_class_name, value: info.model_class_name,
}, },
{
label: 'epochs',
value: info.epochs,
},
]; ];


const lossInfo = [ const lossInfo = [
@@ -96,6 +100,10 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo
label: 'loss类名', label: 'loss类名',
value: info.loss_class_name, value: info.loss_class_name,
}, },
{
label: '学习率',
value: info.lr,
},
]; ];


const algorithmInfo = [ const algorithmInfo = [
@@ -171,15 +179,15 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo
}, },
{ {
label: '初始训练数据量', label: '初始训练数据量',
value: info.ninitial,
value: info.initial_num,
}, },
{ {
label: '查询次数', label: '查询次数',
value: info.nqueries,
value: info.queries_num,
}, },
{ {
label: '每次查询数据量', label: '每次查询数据量',
value: info.ninstances,
value: info.instances_num,
}, },
{ {
label: '查询策略', label: '查询策略',
@@ -187,21 +195,13 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo
format: formatEnum(queryStrategies), format: formatEnum(queryStrategies),
}, },
{ {
label: '轮数',
value: info.ncheckpoint,
label: '检查点轮数',
value: info.checkpoint_num,
}, },
{ {
label: 'batch_size', label: 'batch_size',
value: info.batch_size, value: info.batch_size,
}, },
{
label: 'epochs',
value: info.epochs,
},
{
label: '学习率',
value: info.lr,
},
]; ];
}, [info, getResourceDescription]); }, [info, getResourceDescription]);


@@ -248,7 +248,7 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo
}, [runStatus]); }, [runStatus]);


return ( return (
<div className={classNames(styles['hyper-parameter-basic'], className)}>
<div className={classNames(styles['active-learn-basic'], className)}>
{isInstance && runStatus && ( {isInstance && runStatus && (
<ConfigInfo <ConfigInfo
title="运行信息" title="运行信息"

+ 41
- 53
react-ui/src/pages/ActiveLearn/components/CreateForm/ExecuteConfig.tsx View File

@@ -71,17 +71,7 @@ function ExecuteConfig() {
<> <>
<Row gutter={8}> <Row gutter={8}>
<Col span={10}> <Col span={10}>
<Form.Item
label="模型"
name="model"
rules={[
{
validator: requiredValidator,
message: '请选择模型',
},
]}
required
>
<Form.Item label="预训练模型" name="model">
<ResourceSelect <ResourceSelect
type={ResourceSelectorType.Model} type={ResourceSelectorType.Model}
placeholder="请选择模型" placeholder="请选择模型"
@@ -123,6 +113,22 @@ function ExecuteConfig() {
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>
<Row gutter={8}>
<Col span={10}>
<Form.Item
label="epochs"
name="epochs"
rules={[
{
required: true,
message: '请输入epochs',
},
]}
>
<InputNumber placeholder="请输入epochs" min={0} precision={0} />
</Form.Item>
</Col>
</Row>
{frameworkType === FrameworkType.Pytorch ? ( {frameworkType === FrameworkType.Pytorch ? (
<> <>
<Row gutter={8}> <Row gutter={8}>
@@ -149,7 +155,7 @@ function ExecuteConfig() {
<Row gutter={8}> <Row gutter={8}>
<Col span={10}> <Col span={10}>
<Form.Item <Form.Item
label="loss类名"
label="loss 类名"
name="loss_class_name" name="loss_class_name"
rules={[ rules={[
{ {
@@ -167,6 +173,22 @@ function ExecuteConfig() {
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>
<Row gutter={8}>
<Col span={10}>
<Form.Item
label="学习率"
name="lr"
rules={[
{
required: true,
message: '请输入学习率',
},
]}
>
<InputNumber placeholder="请输入学习率" min={0} />
</Form.Item>
</Col>
</Row>
</> </>
) : null} ) : null}
</> </>
@@ -391,7 +413,7 @@ function ExecuteConfig() {
<Col span={10}> <Col span={10}>
<Form.Item <Form.Item
label="初始训练数据量" label="初始训练数据量"
name="ninitial"
name="initial_num"
rules={[ rules={[
{ {
required: true, required: true,
@@ -408,7 +430,7 @@ function ExecuteConfig() {
<Col span={10}> <Col span={10}>
<Form.Item <Form.Item
label="查询次数" label="查询次数"
name="nqueries"
name="queries_num"
rules={[ rules={[
{ {
required: true, required: true,
@@ -425,7 +447,7 @@ function ExecuteConfig() {
<Col span={10}> <Col span={10}>
<Form.Item <Form.Item
label="每次查询数据量" label="每次查询数据量"
name="ninstances"
name="instances_num"
rules={[ rules={[
{ {
required: true, required: true,
@@ -458,17 +480,17 @@ function ExecuteConfig() {
<Row gutter={8}> <Row gutter={8}>
<Col span={10}> <Col span={10}>
<Form.Item <Form.Item
label="轮数"
name="ncheckpoint"
label="检查点轮数"
name="checkpoint_num"
rules={[ rules={[
{ {
required: true, required: true,
message: '请输入轮数',
message: '请输入检查点轮数',
}, },
]} ]}
tooltip="多少轮查询保存一次模型参数" tooltip="多少轮查询保存一次模型参数"
> >
<InputNumber placeholder="请输入轮数" min={0} precision={0} />
<InputNumber placeholder="请输入检查点轮数" min={0} precision={0} />
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>
@@ -489,40 +511,6 @@ function ExecuteConfig() {
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>

<Row gutter={8}>
<Col span={10}>
<Form.Item
label="epochs"
name="epochs"
rules={[
{
required: true,
message: '请输入epochs',
},
]}
>
<InputNumber placeholder="请输入epochs" min={0} precision={0} />
</Form.Item>
</Col>
</Row>

<Row gutter={8}>
<Col span={10}>
<Form.Item
label="学习率"
name="lr"
rules={[
{
required: true,
message: '请输入学习率',
},
]}
>
<InputNumber placeholder="请输入学习率" min={0} />
</Form.Item>
</Col>
</Row>
</> </>
); );
} }


+ 0
- 145
react-ui/src/pages/ActiveLearn/components/CreateForm/index.less View File

@@ -1,145 +0,0 @@
.metrics-weight {
margin-bottom: 20px;

&:last-child {
margin-bottom: 0;
}
}

.add-weight {
margin-bottom: 0 !important;

// 增加样式权重
& &__button {
border-color: .addAlpha(@primary-color, 0.5) [];
box-shadow: none !important;
&:hover {
border-style: solid;
}
}
}

.hyper-parameter {
width: 83.33%;
margin-bottom: 20px;
border: 1px solid rgba(234, 234, 234, 0.8);
border-radius: 4px;
&__header {
height: 50px;
padding-left: 8px;
color: @text-color;
font-size: @font-size;
background: #f8f8f9;
border-radius: 4px 4px 0px 0px;

&__name,
&__type,
&__space {
flex: 1;
min-width: 0;
margin-right: 15px;

&::before {
display: inline-block;
color: @error-color;
font-size: 14px;
font-family: SimSun, sans-serif;
line-height: 1;
content: '*';
margin-inline-end: 4px;
}

:global {
.anticon-question-circle {
vertical-align: middle;
cursor: help;
}
}
}

&__tooltip {
max-width: 600px;
:global {
.ant-tooltip-inner {
max-height: 400px;
overflow-y: auto;
white-space: pre-line;

&::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.5);
}
}
}
}

&__operation {
flex: none;
width: 100px;
}
}
&__body {
padding: 8px;
border-bottom: 1px solid rgba(234, 234, 234, 0.8);

&:last-child {
border-bottom: none;
}

&__name,
&__type,
&__space {
flex: 1;
min-width: 0;
margin-right: 15px;
margin-bottom: 0 !important;
}

&__operation {
display: flex;
flex: none;
align-items: center;
width: 100px;
height: 46px;
}
}

&__add {
display: flex;
align-items: center;
justify-content: center;
padding: 15px 0;
}
}

.run-parameter {
width: calc(41.66% + 126px);
margin-bottom: 20px;

&__body {
flex: 1;
margin-right: 10px;
padding: 20px 20px 0;
border: 1px dashed #e0e0e0;
border-radius: 8px;

:global {
.ant-form-item-label {
label {
width: calc(100% - 10px);
}
}
}
}

&__operation {
display: flex;
flex: none;
align-items: center;
width: 100px;
}

&__error {
margin-top: -20px;
color: @error-color;
}
}

+ 16
- 0
react-ui/src/pages/ActiveLearn/components/ExperimentLog/index.less View File

@@ -0,0 +1,16 @@
.experiment-log {
height: 100%;
&__tabs {
height: 100%;
:global {
.ant-tabs-nav-list {
padding-left: 0 !important;
background: none !important;
}
}

&__log {
height: 100%;
}
}
}

+ 106
- 0
react-ui/src/pages/ActiveLearn/components/ExperimentLog/index.tsx View File

@@ -0,0 +1,106 @@
import { ExperimentStatus } from '@/enums';
import { ActiveLearnInstanceData } from '@/pages/ActiveLearn/types';
import LogList from '@/pages/Experiment/components/LogList';
import { NodeStatus } from '@/types';
import { Tabs } from 'antd';
import styles from './index.less';

type ExperimentLogProps = {
instanceInfo: ActiveLearnInstanceData;
nodes: Record<string, NodeStatus>;
};

function ExperimentLog({ instanceInfo, nodes }: ExperimentLogProps) {
let hpoNodeStatus: NodeStatus | undefined;
let frameworkCloneNodeStatus: NodeStatus | undefined;
let trainCloneNodeStatus: NodeStatus | undefined;

Object.keys(nodes)
.sort((key1, key2) => {
const node1 = nodes[key1];
const node2 = nodes[key2];
return new Date(node1.startedAt).getTime() - new Date(node2.startedAt).getTime();
})
.forEach((key) => {
const node = nodes[key];
if (node.displayName.startsWith('active-learn')) {
hpoNodeStatus = node;
} else if (node.displayName.startsWith('git-clone') && !frameworkCloneNodeStatus) {
frameworkCloneNodeStatus = node;
} else if (
node.displayName.startsWith('git-clone') &&
frameworkCloneNodeStatus &&
node.displayName !== frameworkCloneNodeStatus?.displayName
) {
trainCloneNodeStatus = node;
}
});

const tabItems = [
// {
// key: 'git-clone-framework',
// label: '框架代码日志',
// // icon: <KFIcon type="icon-rizhi1" />,
// children: (
// <div className={styles['experiment-log__tabs__log']}>
// {frameworkCloneNodeStatus && (
// <LogList
// instanceName={instanceInfo.argo_ins_name}
// instanceNamespace={instanceInfo.argo_ins_ns}
// pipelineNodeId={frameworkCloneNodeStatus.displayName}
// workflowId={frameworkCloneNodeStatus.id}
// instanceNodeStartTime={frameworkCloneNodeStatus.startedAt}
// instanceNodeStatus={frameworkCloneNodeStatus.phase as ExperimentStatus}
// ></LogList>
// )}
// </div>
// ),
// },
{
key: 'git-clone-train',
label: '系统日志',
// icon: <KFIcon type="icon-rizhi1" />,
children: (
<div className={styles['experiment-log__tabs__log']}>
{trainCloneNodeStatus && (
<LogList
instanceName={instanceInfo.argo_ins_name}
instanceNamespace={instanceInfo.argo_ins_ns}
pipelineNodeId={trainCloneNodeStatus.displayName}
workflowId={trainCloneNodeStatus.id}
instanceNodeStartTime={trainCloneNodeStatus.startedAt}
instanceNodeStatus={trainCloneNodeStatus.phase as ExperimentStatus}
></LogList>
)}
</div>
),
},
{
key: 'active-learn',
label: '主动学习日志',
// icon: <KFIcon type="icon-rizhi1" />,
children: (
<div className={styles['experiment-log__tabs__log']}>
{hpoNodeStatus && (
<LogList
instanceName={instanceInfo.argo_ins_name}
instanceNamespace={instanceInfo.argo_ins_ns}
pipelineNodeId={hpoNodeStatus.displayName}
workflowId={hpoNodeStatus.id}
instanceNodeStartTime={hpoNodeStatus.startedAt}
instanceNodeStatus={hpoNodeStatus.phase as ExperimentStatus}
></LogList>
)}
</div>
),
},
];

return (
<div className={styles['experiment-log']}>
<Tabs className={styles['experiment-log__tabs']} items={tabItems} />
</div>
);
}

export default ExperimentLog;

+ 120
- 0
react-ui/src/pages/ActiveLearn/data.json View File

@@ -0,0 +1,120 @@
{
"workflow-xwnb8": {
"id": "workflow-xwnb8",
"name": "workflow-xwnb8",
"type": "DAG",
"phase": "Failed",
"children": [
"workflow-xwnb8-1083129199"
],
"progress": "2/3",
"startedAt": "2025-04-18T06:56:18Z",
"finishedAt": "2025-04-18T06:57:32Z",
"displayName": "workflow-xwnb8",
"templateName": "ml-workflow",
"outboundNodes": [
"workflow-xwnb8-1355608520"
],
"templateScope": "local/workflow-xwnb8",
"resourcesDuration": {
"cpu": 42,
"memory": 851,
"nvidia.com/gpu": 10
}
},
"git-clone-9d0c5965": {
"id": "workflow-xwnb8-514970004",
"name": "workflow-xwnb8.git-clone-9d0c5965",
"type": "Pod",
"phase": "Succeeded",
"outputs": {
"exitCode": "0",
"artifacts": [
{
"s3": {
"key": "workflow-xwnb8/workflow-xwnb8-git-clone-9d0c5965-514970004/main.log"
},
"name": "main-logs"
}
]
},
"children": [
"workflow-xwnb8-1355608520"
],
"progress": "1/1",
"startedAt": "2025-04-18T06:56:38Z",
"boundaryID": "workflow-xwnb8",
"finishedAt": "2025-04-18T06:56:49Z",
"displayName": "git-clone-9d0c5965",
"hostNodeName": "k8s-node01",
"templateName": "git-clone-9d0c5965",
"templateScope": "local/workflow-xwnb8",
"resourcesDuration": {
"cpu": 1,
"memory": 11
}
},
"git-clone-e28c560c": {
"id": "workflow-xwnb8-1083129199",
"name": "workflow-xwnb8.git-clone-e28c560c",
"type": "Pod",
"phase": "Succeeded",
"outputs": {
"exitCode": "0",
"artifacts": [
{
"s3": {
"key": "workflow-xwnb8/workflow-xwnb8-git-clone-e28c560c-1083129199/main.log"
},
"name": "main-logs"
}
]
},
"children": [
"workflow-xwnb8-514970004"
],
"progress": "1/1",
"startedAt": "2025-04-18T06:56:18Z",
"boundaryID": "workflow-xwnb8",
"finishedAt": "2025-04-18T06:56:27Z",
"displayName": "git-clone-e28c560c",
"hostNodeName": "k8s-node01",
"templateName": "git-clone-e28c560c",
"templateScope": "local/workflow-xwnb8",
"resourcesDuration": {
"cpu": 1,
"memory": 11
}
},
"active-learn-b708ed0b": {
"id": "workflow-xwnb8-1355608520",
"name": "workflow-xwnb8.active-learn-b708ed0b",
"type": "Pod",
"phase": "Failed",
"message": "Error (exit code 1)",
"outputs": {
"exitCode": "1",
"artifacts": [
{
"s3": {
"key": "workflow-xwnb8/workflow-xwnb8-active-learn-b708ed0b-1355608520/main.log"
},
"name": "main-logs"
}
]
},
"progress": "0/1",
"startedAt": "2025-04-18T06:57:00Z",
"boundaryID": "workflow-xwnb8",
"finishedAt": "2025-04-18T06:57:27Z",
"displayName": "active-learn-b708ed0b",
"hostNodeName": "k8s-node01",
"templateName": "active-learn-b708ed0b",
"templateScope": "local/workflow-xwnb8",
"resourcesDuration": {
"cpu": 40,
"memory": 829,
"nvidia.com/gpu": 10
}
}
}

+ 4
- 4
react-ui/src/pages/ActiveLearn/types.ts View File

@@ -35,14 +35,14 @@ export type FormData = {
dataset_class_name: string; // dataset类名 dataset_class_name: string; // dataset类名
data_size: number; // 数据量 data_size: number; // 数据量
train_size: number; // 训练集数据量 train_size: number; // 训练集数据量
ninitial: number; // 初始训练数据量
nqueries: number; // 查询次数
ninstances: number; // 每次查询数据量
initial_num: number; // 初始训练数据量
queries_num: number; // 查询次数
instances_num: number; // 每次查询数据量
computing_resource_id: number; // 资源规格 computing_resource_id: number; // 资源规格
image: ParameterInputObject; // 镜像 image: ParameterInputObject; // 镜像
shuffle: boolean; // 是否随机打乱 shuffle: boolean; // 是否随机打乱
query_strategy: string; // 查询策略 query_strategy: string; // 查询策略
ncheckpoint: number; // 多少轮查询保存一次模型参数
checkpoint_num: number; // 多少轮查询保存一次模型参数
batch_size: number; // batch_size batch_size: number; // batch_size
epochs: number; // epochs epochs: number; // epochs
lr: number; // 学习率 lr: number; // 学习率


+ 2
- 1
react-ui/src/pages/DevelopmentEnvironment/List/index.tsx View File

@@ -77,6 +77,7 @@ function EditorList() {
content.forEach((item: EditorData) => { content.forEach((item: EditorData) => {
item.dataset = typeof item.dataset === 'string' ? parseJsonText(item.dataset) : null; item.dataset = typeof item.dataset === 'string' ? parseJsonText(item.dataset) : null;
item.model = typeof item.model === 'string' ? parseJsonText(item.model) : null; item.model = typeof item.model === 'string' ? parseJsonText(item.model) : null;
item.image = typeof item.image === 'string' ? parseJsonText(item.image) : null;
}); });
setTableData(content); setTableData(content);
setTotal(totalElements); setTotal(totalElements);
@@ -224,7 +225,7 @@ function EditorList() {
}, },
{ {
title: '镜像', title: '镜像',
dataIndex: ['image'],
dataIndex: ['image', 'showValue'],
key: 'image', key: 'image',
width: '15%', width: '15%',
render: tableCellRender(true), render: tableCellRender(true),


+ 1
- 4
react-ui/src/pages/Experiment/components/LogGroup/index.tsx View File

@@ -54,10 +54,7 @@ function LogGroup({
useEffect(() => { useEffect(() => {
// 建立 socket 连接 // 建立 socket 连接
const setupSockect = () => { const setupSockect = () => {
let { host } = location;
if (process.env.NODE_ENV === 'development') {
host = '172.20.32.197:31213';
}
const { host } = location;
const socket = new WebSocket( const socket = new WebSocket(
`ws://${host}/newlog/realtimeLog?start=${start_time}&query={pod="${pod_name}"}`, `ws://${host}/newlog/realtimeLog?start=${start_time}&query={pod="${pod_name}"}`,
); );


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

@@ -20,7 +20,7 @@ function HyperparameterInfo() {
undefined, undefined,
); );


// 获取自动机器学习详情
// 获取详情
const getHyperparameterInfo = useCallback(async () => { const getHyperparameterInfo = useCallback(async () => {
const [res] = await to(getRayInfoReq({ id: hyperparameterId })); const [res] = await to(getRayInfoReq({ id: hyperparameterId }));
if (res && res.data) { if (res && res.data) {


+ 0
- 3
react-ui/src/pages/HyperParameter/components/ExperimentLog/index.tsx View File

@@ -3,7 +3,6 @@ import LogList from '@/pages/Experiment/components/LogList';
import { HyperParameterInstanceData } from '@/pages/HyperParameter/types'; import { HyperParameterInstanceData } from '@/pages/HyperParameter/types';
import { NodeStatus } from '@/types'; import { NodeStatus } from '@/types';
import { Tabs } from 'antd'; import { Tabs } from 'antd';
import { useEffect } from 'react';
import styles from './index.less'; import styles from './index.less';


type ExperimentLogProps = { type ExperimentLogProps = {
@@ -97,8 +96,6 @@ function ExperimentLog({ instanceInfo, nodes }: ExperimentLogProps) {
}, },
]; ];


useEffect(() => {}, []);

return ( return (
<div className={styles['experiment-log']}> <div className={styles['experiment-log']}>
<Tabs className={styles['experiment-log__tabs']} items={tabItems} /> <Tabs className={styles['experiment-log__tabs']} items={tabItems} />


+ 1
- 1
react-ui/src/pages/HyperParameter/types.ts View File

@@ -41,7 +41,7 @@ export type HyperParameterData = {
status_list: string; // 最近五次运行状态 status_list: string; // 最近五次运行状态
} & FormData; } & FormData;


// 自动机器学习实验实例
// 实验实例
export type HyperParameterInstanceData = { export type HyperParameterInstanceData = {
id: number; id: number;
ray_id: number; ray_id: number;


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

@@ -0,0 +1,12 @@
/*
* @Author: 赵伟
* @Date: 2025-04-21 16:38:59
* @Description: 知识图谱
*/

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

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

+ 1
- 1
react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx View File

@@ -292,7 +292,7 @@ function ServiceInfo() {
}, },
{ {
title: '版本镜像', title: '版本镜像',
dataIndex: 'image',
dataIndex: ['image', 'showValue'],
key: 'image', key: 'image',
width: '20%', width: '20%',
render: tableCellRender(true), render: tableCellRender(true),


+ 1
- 1
react-ui/src/utils/date.ts View File

@@ -20,7 +20,7 @@ export const elapsedTime = (begin?: string | null, end?: string | null): string


const timestamp = endDate.valueOf() - beginDate.valueOf(); const timestamp = endDate.valueOf() - beginDate.valueOf();
if (timestamp < 0) { if (timestamp < 0) {
return '时间有误';
return '0秒';
} }
const duration = dayjs.duration(timestamp); const duration = dayjs.duration(timestamp);
const years = duration.years(); const years = duration.years();


Loading…
Cancel
Save