| @@ -561,6 +561,18 @@ export default [ | |||
| }, | |||
| ], | |||
| }, | |||
| { | |||
| name: '知识图谱', | |||
| path: '/knowledge', | |||
| routes: [ | |||
| { | |||
| name: '知识图谱', | |||
| path: '', | |||
| key: 'knowledge', | |||
| component: './Knowledge/index', | |||
| }, | |||
| ], | |||
| }, | |||
| { | |||
| path: '*', | |||
| layout: false, | |||
| @@ -25,7 +25,7 @@ export { requestConfig as request } from './requestConfig'; | |||
| /** | |||
| * @see https://umijs.org/zh-CN/plugins/plugin-initial-state | |||
| * */ | |||
| */ | |||
| export async function getInitialState(): Promise<GlobalInitialState> { | |||
| const fetchUserInfo = async () => { | |||
| try { | |||
| @@ -15,6 +15,7 @@ export enum IframePageType { | |||
| DevEnv = 'DevEnv', // 开发环境 | |||
| GitLink = 'GitLink', // git link | |||
| Aim = 'Aim', // 实验对比 | |||
| Knowledge = 'Knowledge', // 知识图谱 | |||
| } | |||
| const getRequestAPI = (type: IframePageType): (() => Promise<any>) => { | |||
| @@ -37,6 +38,8 @@ const getRequestAPI = (type: IframePageType): (() => Promise<any>) => { | |||
| code: 200, | |||
| data: SessionStorage.getItem(SessionStorage.aimUrlKey) || '', | |||
| }); | |||
| case IframePageType.Knowledge: // git link | |||
| return () => Promise.resolve({ code: 200, data: 'http://172.168.15.235:32701' }); | |||
| } | |||
| }; | |||
| @@ -9,7 +9,7 @@ import { safeInvoke } from '@/utils/functional'; | |||
| import { to } from '@/utils/promise'; | |||
| import { useParams } from '@umijs/max'; | |||
| import { useEffect, useState } from 'react'; | |||
| import BasicInfo from '../components/BasicInfo'; | |||
| import ActiveLearnBasic from '../components/ActiveLearnBasic'; | |||
| import { ActiveLearnData } from '../types'; | |||
| import styles from './index.less'; | |||
| @@ -24,7 +24,7 @@ function ActiveLearnInfo() { | |||
| } | |||
| }, []); | |||
| // 获取主动学习详情 | |||
| // 获取详情 | |||
| const getActiveLearnInfo = async () => { | |||
| const [res] = await to(getActiveLearnInfoReq({ id: id })); | |||
| if (res && res.data) { | |||
| @@ -36,7 +36,7 @@ function ActiveLearnInfo() { | |||
| <div className={styles['auto-ml-info']}> | |||
| <PageTitle title="实验详情"></PageTitle> | |||
| <div className={styles['auto-ml-info__content']}> | |||
| <BasicInfo info={info} /> | |||
| <ActiveLearnBasic info={info} /> | |||
| </div> | |||
| </div> | |||
| ); | |||
| @@ -1,4 +1,4 @@ | |||
| .auto-ml-instance { | |||
| .active-learn-instance { | |||
| height: 100%; | |||
| &__tabs { | |||
| @@ -1,7 +1,6 @@ | |||
| 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 { parseJsonText } from '@/utils'; | |||
| import { safeInvoke } from '@/utils/functional'; | |||
| @@ -9,10 +8,11 @@ import { to } from '@/utils/promise'; | |||
| import { useParams } from '@umijs/max'; | |||
| import { Tabs } from 'antd'; | |||
| import { useEffect, useRef, useState } from 'react'; | |||
| import BasicInfo from '../components/BasicInfo'; | |||
| import ActiveLearnBasic from '../components/ActiveLearnBasic'; | |||
| import ExperimentHistory from '../components/ExperimentHistory'; | |||
| import ExperimentLog from '../components/ExperimentLog'; | |||
| import ExperimentResult from '../components/ExperimentResult'; | |||
| import { AutoMLInstanceData, HyperparameterData } from '../types'; | |||
| import { ActiveLearnData, ActiveLearnInstanceData } from '../types'; | |||
| import styles from './index.less'; | |||
| enum TabKeys { | |||
| @@ -22,12 +22,15 @@ enum TabKeys { | |||
| 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 autoMLId = safeInvoke(Number)(params.autoMLId); | |||
| const instanceId = safeInvoke(Number)(params.id); | |||
| const evtSourceRef = useRef<EventSource | null>(null); | |||
| @@ -38,41 +41,43 @@ function AutoMLInstance() { | |||
| return () => { | |||
| closeSSE(); | |||
| }; | |||
| }, []); | |||
| // eslint-disable-next-line react-hooks/exhaustive-deps | |||
| }, [instanceId]); | |||
| // 获取实验实例详情 | |||
| const getExperimentInsInfo = async (isStatusDetermined: boolean) => { | |||
| const [res] = await to(getExperimentInsReq(instanceId)); | |||
| const [res] = await to(getActiveLearnInsReq(instanceId)); | |||
| 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 paramJson = parseJsonText(param); | |||
| if (paramJson) { | |||
| setAutoMLInfo(paramJson); | |||
| setExperimentInfo(paramJson.data); | |||
| } | |||
| setInstanceInfo(info); | |||
| // 这个接口返回的状态有延时,SSE 返回的状态是最新的 | |||
| // SSE 调用时,不需要解析 node_status, 也不要重新建立 SSE | |||
| // SSE 调用时,不需要解析 node_status,也不要重新建立 SSE | |||
| if (isStatusDetermined) { | |||
| setInstanceInfo((prev) => ({ | |||
| ...info, | |||
| nodeStatus: prev!.nodeStatus, | |||
| })); | |||
| return; | |||
| } | |||
| // 进行节点状态 | |||
| const nodeStatusJson = parseJsonText(node_status); | |||
| 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 | |||
| if (status === ExperimentStatus.Pending || status === ExperimentStatus.Running) { | |||
| setupSSE(argo_ins_name, argo_ins_ns); | |||
| @@ -81,10 +86,7 @@ function AutoMLInstance() { | |||
| }; | |||
| 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 evtSource = new EventSource( | |||
| `${origin}/api/v1/realtimeStatus?listOptions.fieldSelector=${params}`, | |||
| @@ -99,19 +101,21 @@ function AutoMLInstance() { | |||
| if (dataJson) { | |||
| const nodes = dataJson?.result?.object?.status?.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; | |||
| if (statusData) { | |||
| setInstanceInfo((prev) => ({ | |||
| ...prev!, | |||
| nodeStatus: statusData, | |||
| })); | |||
| // 节点 | |||
| setNodes(nodes); | |||
| // 设置工作流状态 | |||
| if (workflowStatus) { | |||
| setWorkflowStatus(workflowStatus); | |||
| // 实验结束,关闭 SSE | |||
| if ( | |||
| statusData.phase !== ExperimentStatus.Pending && | |||
| statusData.phase !== ExperimentStatus.Running | |||
| workflowStatus.phase !== ExperimentStatus.Pending && | |||
| workflowStatus.phase !== ExperimentStatus.Running | |||
| ) { | |||
| closeSSE(); | |||
| getExperimentInsInfo(true); | |||
| @@ -140,10 +144,10 @@ function AutoMLInstance() { | |||
| label: '基本信息', | |||
| icon: <KFIcon type="icon-jibenxinxi" />, | |||
| 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 | |||
| /> | |||
| ), | |||
| @@ -153,17 +157,8 @@ function AutoMLInstance() { | |||
| label: '日志', | |||
| icon: <KFIcon type="icon-rizhi1" />, | |||
| 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> | |||
| ), | |||
| }, | |||
| @@ -174,24 +169,13 @@ function AutoMLInstance() { | |||
| key: TabKeys.Result, | |||
| label: '实验结果', | |||
| 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, | |||
| label: 'Trial 列表', | |||
| label: '寻优列表', | |||
| 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; | |||
| 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> | |||
| ); | |||
| } | |||
| export default AutoMLInstance; | |||
| export default ActiveLearnInstance; | |||
| @@ -1,4 +1,4 @@ | |||
| .hyper-parameter-basic { | |||
| .active-learn-basic { | |||
| height: 100%; | |||
| padding: 20px @content-padding; | |||
| overflow-y: auto; | |||
| @@ -73,7 +73,7 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo | |||
| const modelInfo = [ | |||
| { | |||
| label: '模型', | |||
| label: '预训练模型', | |||
| value: info.model, | |||
| format: formatModel, | |||
| }, | |||
| @@ -85,6 +85,10 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo | |||
| label: '模型类名称', | |||
| value: info.model_class_name, | |||
| }, | |||
| { | |||
| label: 'epochs', | |||
| value: info.epochs, | |||
| }, | |||
| ]; | |||
| const lossInfo = [ | |||
| @@ -96,6 +100,10 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo | |||
| label: 'loss类名', | |||
| value: info.loss_class_name, | |||
| }, | |||
| { | |||
| label: '学习率', | |||
| value: info.lr, | |||
| }, | |||
| ]; | |||
| const algorithmInfo = [ | |||
| @@ -171,15 +179,15 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo | |||
| }, | |||
| { | |||
| label: '初始训练数据量', | |||
| value: info.ninitial, | |||
| value: info.initial_num, | |||
| }, | |||
| { | |||
| label: '查询次数', | |||
| value: info.nqueries, | |||
| value: info.queries_num, | |||
| }, | |||
| { | |||
| label: '每次查询数据量', | |||
| value: info.ninstances, | |||
| value: info.instances_num, | |||
| }, | |||
| { | |||
| label: '查询策略', | |||
| @@ -187,21 +195,13 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo | |||
| format: formatEnum(queryStrategies), | |||
| }, | |||
| { | |||
| label: '轮数', | |||
| value: info.ncheckpoint, | |||
| label: '检查点轮数', | |||
| value: info.checkpoint_num, | |||
| }, | |||
| { | |||
| label: 'batch_size', | |||
| value: info.batch_size, | |||
| }, | |||
| { | |||
| label: 'epochs', | |||
| value: info.epochs, | |||
| }, | |||
| { | |||
| label: '学习率', | |||
| value: info.lr, | |||
| }, | |||
| ]; | |||
| }, [info, getResourceDescription]); | |||
| @@ -248,7 +248,7 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo | |||
| }, [runStatus]); | |||
| return ( | |||
| <div className={classNames(styles['hyper-parameter-basic'], className)}> | |||
| <div className={classNames(styles['active-learn-basic'], className)}> | |||
| {isInstance && runStatus && ( | |||
| <ConfigInfo | |||
| title="运行信息" | |||
| @@ -71,17 +71,7 @@ function ExecuteConfig() { | |||
| <> | |||
| <Row gutter={8}> | |||
| <Col span={10}> | |||
| <Form.Item | |||
| label="模型" | |||
| name="model" | |||
| rules={[ | |||
| { | |||
| validator: requiredValidator, | |||
| message: '请选择模型', | |||
| }, | |||
| ]} | |||
| required | |||
| > | |||
| <Form.Item label="预训练模型" name="model"> | |||
| <ResourceSelect | |||
| type={ResourceSelectorType.Model} | |||
| placeholder="请选择模型" | |||
| @@ -123,6 +113,22 @@ function ExecuteConfig() { | |||
| </Form.Item> | |||
| </Col> | |||
| </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 ? ( | |||
| <> | |||
| <Row gutter={8}> | |||
| @@ -149,7 +155,7 @@ function ExecuteConfig() { | |||
| <Row gutter={8}> | |||
| <Col span={10}> | |||
| <Form.Item | |||
| label="loss类名" | |||
| label="loss 类名" | |||
| name="loss_class_name" | |||
| rules={[ | |||
| { | |||
| @@ -167,6 +173,22 @@ function ExecuteConfig() { | |||
| </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> | |||
| </> | |||
| ) : null} | |||
| </> | |||
| @@ -391,7 +413,7 @@ function ExecuteConfig() { | |||
| <Col span={10}> | |||
| <Form.Item | |||
| label="初始训练数据量" | |||
| name="ninitial" | |||
| name="initial_num" | |||
| rules={[ | |||
| { | |||
| required: true, | |||
| @@ -408,7 +430,7 @@ function ExecuteConfig() { | |||
| <Col span={10}> | |||
| <Form.Item | |||
| label="查询次数" | |||
| name="nqueries" | |||
| name="queries_num" | |||
| rules={[ | |||
| { | |||
| required: true, | |||
| @@ -425,7 +447,7 @@ function ExecuteConfig() { | |||
| <Col span={10}> | |||
| <Form.Item | |||
| label="每次查询数据量" | |||
| name="ninstances" | |||
| name="instances_num" | |||
| rules={[ | |||
| { | |||
| required: true, | |||
| @@ -458,17 +480,17 @@ function ExecuteConfig() { | |||
| <Row gutter={8}> | |||
| <Col span={10}> | |||
| <Form.Item | |||
| label="轮数" | |||
| name="ncheckpoint" | |||
| label="检查点轮数" | |||
| name="checkpoint_num" | |||
| rules={[ | |||
| { | |||
| required: true, | |||
| message: '请输入轮数', | |||
| message: '请输入检查点轮数', | |||
| }, | |||
| ]} | |||
| tooltip="多少轮查询保存一次模型参数" | |||
| > | |||
| <InputNumber placeholder="请输入轮数" min={0} precision={0} /> | |||
| <InputNumber placeholder="请输入检查点轮数" min={0} precision={0} /> | |||
| </Form.Item> | |||
| </Col> | |||
| </Row> | |||
| @@ -489,40 +511,6 @@ function ExecuteConfig() { | |||
| </Form.Item> | |||
| </Col> | |||
| </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> | |||
| </> | |||
| ); | |||
| } | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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%; | |||
| } | |||
| } | |||
| } | |||
| @@ -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; | |||
| @@ -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 | |||
| } | |||
| } | |||
| } | |||
| @@ -35,14 +35,14 @@ export type FormData = { | |||
| dataset_class_name: string; // dataset类名 | |||
| data_size: number; // 数据量 | |||
| train_size: number; // 训练集数据量 | |||
| ninitial: number; // 初始训练数据量 | |||
| nqueries: number; // 查询次数 | |||
| ninstances: number; // 每次查询数据量 | |||
| initial_num: number; // 初始训练数据量 | |||
| queries_num: number; // 查询次数 | |||
| instances_num: number; // 每次查询数据量 | |||
| computing_resource_id: number; // 资源规格 | |||
| image: ParameterInputObject; // 镜像 | |||
| shuffle: boolean; // 是否随机打乱 | |||
| query_strategy: string; // 查询策略 | |||
| ncheckpoint: number; // 多少轮查询保存一次模型参数 | |||
| checkpoint_num: number; // 多少轮查询保存一次模型参数 | |||
| batch_size: number; // batch_size | |||
| epochs: number; // epochs | |||
| lr: number; // 学习率 | |||
| @@ -77,6 +77,7 @@ function EditorList() { | |||
| content.forEach((item: EditorData) => { | |||
| item.dataset = typeof item.dataset === 'string' ? parseJsonText(item.dataset) : null; | |||
| item.model = typeof item.model === 'string' ? parseJsonText(item.model) : null; | |||
| item.image = typeof item.image === 'string' ? parseJsonText(item.image) : null; | |||
| }); | |||
| setTableData(content); | |||
| setTotal(totalElements); | |||
| @@ -224,7 +225,7 @@ function EditorList() { | |||
| }, | |||
| { | |||
| title: '镜像', | |||
| dataIndex: ['image'], | |||
| dataIndex: ['image', 'showValue'], | |||
| key: 'image', | |||
| width: '15%', | |||
| render: tableCellRender(true), | |||
| @@ -54,10 +54,7 @@ function LogGroup({ | |||
| useEffect(() => { | |||
| // 建立 socket 连接 | |||
| const setupSockect = () => { | |||
| let { host } = location; | |||
| if (process.env.NODE_ENV === 'development') { | |||
| host = '172.20.32.197:31213'; | |||
| } | |||
| const { host } = location; | |||
| const socket = new WebSocket( | |||
| `ws://${host}/newlog/realtimeLog?start=${start_time}&query={pod="${pod_name}"}`, | |||
| ); | |||
| @@ -20,7 +20,7 @@ function HyperparameterInfo() { | |||
| undefined, | |||
| ); | |||
| // 获取自动机器学习详情 | |||
| // 获取详情 | |||
| const getHyperparameterInfo = useCallback(async () => { | |||
| const [res] = await to(getRayInfoReq({ id: hyperparameterId })); | |||
| if (res && res.data) { | |||
| @@ -3,7 +3,6 @@ import LogList from '@/pages/Experiment/components/LogList'; | |||
| import { HyperParameterInstanceData } from '@/pages/HyperParameter/types'; | |||
| import { NodeStatus } from '@/types'; | |||
| import { Tabs } from 'antd'; | |||
| import { useEffect } from 'react'; | |||
| import styles from './index.less'; | |||
| type ExperimentLogProps = { | |||
| @@ -97,8 +96,6 @@ function ExperimentLog({ instanceInfo, nodes }: ExperimentLogProps) { | |||
| }, | |||
| ]; | |||
| useEffect(() => {}, []); | |||
| return ( | |||
| <div className={styles['experiment-log']}> | |||
| <Tabs className={styles['experiment-log__tabs']} items={tabItems} /> | |||
| @@ -41,7 +41,7 @@ export type HyperParameterData = { | |||
| status_list: string; // 最近五次运行状态 | |||
| } & FormData; | |||
| // 自动机器学习实验实例 | |||
| // 实验实例 | |||
| export type HyperParameterInstanceData = { | |||
| id: number; | |||
| ray_id: number; | |||
| @@ -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; | |||
| @@ -292,7 +292,7 @@ function ServiceInfo() { | |||
| }, | |||
| { | |||
| title: '版本镜像', | |||
| dataIndex: 'image', | |||
| dataIndex: ['image', 'showValue'], | |||
| key: 'image', | |||
| width: '20%', | |||
| render: tableCellRender(true), | |||
| @@ -20,7 +20,7 @@ export const elapsedTime = (begin?: string | null, end?: string | null): string | |||
| const timestamp = endDate.valueOf() - beginDate.valueOf(); | |||
| if (timestamp < 0) { | |||
| return '时间有误'; | |||
| return '0秒'; | |||
| } | |||
| const duration = dayjs.duration(timestamp); | |||
| const years = duration.years(); | |||