import KFIcon from '@/components/KFIcon'; import { AutoMLTaskType, AutoMLType, ExperimentStatus } from '@/enums'; import { getExperimentInsReq } from '@/services/autoML'; import { NodeStatus } from '@/types'; import { parseJsonText } from '@/utils'; import { safeInvoke } from '@/utils/functional'; import { to } from '@/utils/promise'; import { useParams } from '@umijs/max'; import { Tabs } from 'antd'; import { useEffect, useRef, useState } from 'react'; import AutoMLBasic from '../components/AutoMLBasic'; import ExperimentHistory from '../components/ExperimentHistory'; import ExperimentLog from '../components/ExperimentLog'; import ExperimentResult from '../components/ExperimentResult'; import TensorBoard from '../components/TensorBoard'; import { AutoMLData, AutoMLInstanceData } from '../types'; import styles from './index.less'; enum TabKeys { Params = 'params', Log = 'log', Result = 'result', History = 'history', Visual = 'Visual', } const NodePrefix = 'workflow'; function AutoMLInstance() { const [autoMLInfo, setAutoMLInfo] = useState(undefined); const [instanceInfo, setInstanceInfo] = useState(undefined); const [workflowStatus, setWorkflowStatus] = useState(undefined); const [nodes, setNodes] = useState | undefined>(undefined); const [type, setType] = useState(undefined); const params = useParams(); const instanceId = safeInvoke(Number)(params.id); const evtSourceRef = useRef(null); useEffect(() => { if (instanceId) { getExperimentInsInfo(false); } return () => { closeSSE(); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [instanceId]); // 获取实验实例详情 const getExperimentInsInfo = async (isStatusDetermined: boolean) => { const [res] = await to(getExperimentInsReq(instanceId)); if (res && res.data) { const info = res.data as AutoMLInstanceData; const { param, node_status, argo_ins_name, argo_ins_ns, status, create_time, type } = info; setType(type); // 解析配置参数 const paramJson = parseJsonText(param); if (paramJson) { setAutoMLInfo({ ...paramJson.data, create_time, type, }); } setInstanceInfo(info); // 这个接口返回的状态有延时,SSE 返回的状态是最新的 // SSE 调用时,不需要解析 node_status, 也不要重新建立 SSE if (isStatusDetermined) { return; } // 进行节点状态 const nodeStatusJson = parseJsonText(node_status); if (nodeStatusJson) { setNodes(nodeStatusJson); // 工作流 Object.keys(nodeStatusJson).some((key) => { if (key.startsWith(NodePrefix)) { const workflowStatus = nodeStatusJson[key]; setWorkflowStatus(workflowStatus); return true; } return false; }); } // 运行中或者等待中,开启 SSE if (status === ExperimentStatus.Pending || status === ExperimentStatus.Running) { setupSSE(argo_ins_name, argo_ins_ns); } } }; const setupSSE = (name: string, namespace: string) => { const { origin } = location; const params = encodeURIComponent(`metadata.namespace=${namespace},metadata.name=${name}`); const evtSource = new EventSource( `${origin}/api/v1/realtimeStatus?listOptions.fieldSelector=${params}`, { withCredentials: false }, ); evtSource.onmessage = (event) => { const data = event?.data; if (!data) { return; } const dataJson = parseJsonText(data); if (dataJson) { const nodes = dataJson?.result?.object?.status?.nodes; if (nodes) { const workflowStatus = Object.values(nodes).find((node: any) => node.displayName.startsWith(NodePrefix), ) as NodeStatus; // 节点 setNodes(nodes); if (workflowStatus) { setWorkflowStatus(workflowStatus); // 实验结束,关闭 SSE if ( workflowStatus.phase !== ExperimentStatus.Pending && workflowStatus.phase !== ExperimentStatus.Running ) { closeSSE(); getExperimentInsInfo(true); } } } } }; evtSource.onerror = (error) => { console.error('SSE error: ', error); }; evtSourceRef.current = evtSource; }; const closeSSE = () => { if (evtSourceRef.current) { evtSourceRef.current.close(); evtSourceRef.current = null; } }; const basicTabItems = [ { key: TabKeys.Params, label: '基本信息', icon: , children: ( ), }, { key: TabKeys.Log, label: '日志', icon: , children: (
{instanceInfo && nodes && }
), }, ]; const resultTabItems = [ { key: TabKeys.Result, label: '实验结果', icon: , children: ( ), }, type === AutoMLType.Text ? { key: TabKeys.Visual, label: '可视化结果', icon: , children: ( ), } : { key: TabKeys.History, label: '试验列表', icon: , children: ( ), }, ]; const tabItems = instanceInfo?.status === ExperimentStatus.Succeeded ? [...basicTabItems, ...resultTabItems] : basicTabItems; return (
); } export default AutoMLInstance;