| @@ -16,6 +16,7 @@ | |||||
| &__label { | &__label { | ||||
| position: relative; | position: relative; | ||||
| flex: none; | |||||
| color: @text-color-secondary; | color: @text-color-secondary; | ||||
| text-align: justify; | text-align: justify; | ||||
| text-align-last: justify; | text-align-last: justify; | ||||
| @@ -26,6 +27,13 @@ | |||||
| } | } | ||||
| } | } | ||||
| &__list-value { | |||||
| display: flex; | |||||
| flex: 1; | |||||
| flex-direction: column; | |||||
| gap: 5px 0; | |||||
| } | |||||
| &__value { | &__value { | ||||
| flex: 1; | flex: 1; | ||||
| margin-left: 16px; | margin-left: 16px; | ||||
| @@ -1,14 +1,17 @@ | |||||
| import { isEmptyString } from '@/utils'; | |||||
| import { Link } from '@umijs/max'; | import { Link } from '@umijs/max'; | ||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import './index.less'; | import './index.less'; | ||||
| export type BasicInfoLink = { | |||||
| value: string; | |||||
| link?: string; | |||||
| url?: string; | |||||
| }; | |||||
| export type BasicInfoData = { | export type BasicInfoData = { | ||||
| label: string; | label: string; | ||||
| value?: any; | value?: any; | ||||
| link?: string; | |||||
| externalLink?: string; | |||||
| format?: (_value?: any) => string | undefined; | |||||
| format?: (_value?: any) => string | BasicInfoLink | BasicInfoLink[] | undefined; | |||||
| }; | }; | ||||
| type BasicInfoProps = { | type BasicInfoProps = { | ||||
| @@ -33,32 +36,23 @@ type BasicInfoItemProps = { | |||||
| labelWidth?: number; | labelWidth?: number; | ||||
| }; | }; | ||||
| function BasicInfoItem({ data, labelWidth = 100 }: BasicInfoItemProps) { | function BasicInfoItem({ data, labelWidth = 100 }: BasicInfoItemProps) { | ||||
| const { label, value, externalLink, link, format } = data; | |||||
| const showValue = format ? format(value) : value; | |||||
| const { label, value, format } = data; | |||||
| const formatValue = format ? format(value) : value; | |||||
| let valueComponent = undefined; | let valueComponent = undefined; | ||||
| if (externalLink && showValue) { | |||||
| if (Array.isArray(formatValue)) { | |||||
| valueComponent = ( | valueComponent = ( | ||||
| <a | |||||
| className="kf-basic-info-item__value kf-basic-info-item__link" | |||||
| href={externalLink} | |||||
| target="_blank" | |||||
| rel="noopener noreferrer" | |||||
| > | |||||
| {showValue} | |||||
| </a> | |||||
| <div className="kf-basic-info-item__list-value"> | |||||
| {formatValue.map((item: BasicInfoLink) => ( | |||||
| <BasicInfoItemValue key={item.value} value={item.value} link={item.link} url={item.url} /> | |||||
| ))} | |||||
| </div> | |||||
| ); | ); | ||||
| } else if (link && showValue) { | |||||
| } else if (typeof formatValue === 'object' && formatValue) { | |||||
| valueComponent = ( | valueComponent = ( | ||||
| <Link to={link} className="kf-basic-info-item__value kf-basic-info-item__link"> | |||||
| {showValue} | |||||
| </Link> | |||||
| <BasicInfoItemValue value={formatValue.value} link={formatValue.link} url={formatValue.url} /> | |||||
| ); | ); | ||||
| } else { | } else { | ||||
| valueComponent = ( | |||||
| <div className="kf-basic-info-item__value kf-basic-info-item__text"> | |||||
| {isEmptyString(showValue) ? '--' : showValue} | |||||
| </div> | |||||
| ); | |||||
| valueComponent = <BasicInfoItemValue value={formatValue} />; | |||||
| } | } | ||||
| return ( | return ( | ||||
| <div className="kf-basic-info-item" key={label}> | <div className="kf-basic-info-item" key={label}> | ||||
| @@ -70,4 +64,35 @@ function BasicInfoItem({ data, labelWidth = 100 }: BasicInfoItemProps) { | |||||
| ); | ); | ||||
| } | } | ||||
| type BasicInfoItemValueProps = { | |||||
| value: string; | |||||
| link?: string; | |||||
| url?: string; | |||||
| }; | |||||
| function BasicInfoItemValue({ value, link, url }: BasicInfoItemValueProps) { | |||||
| if (url && value) { | |||||
| return ( | |||||
| <a | |||||
| className="kf-basic-info-item__value kf-basic-info-item__link" | |||||
| href={url} | |||||
| target="_blank" | |||||
| rel="noopener noreferrer" | |||||
| > | |||||
| {value} | |||||
| </a> | |||||
| ); | |||||
| } else if (link && value) { | |||||
| return ( | |||||
| <Link to={link} className="kf-basic-info-item__value kf-basic-info-item__link"> | |||||
| {value} | |||||
| </Link> | |||||
| ); | |||||
| } else { | |||||
| return ( | |||||
| <div className="kf-basic-info-item__value kf-basic-info-item__text">{value || '--'}</div> | |||||
| ); | |||||
| } | |||||
| } | |||||
| export default BasicInfo; | export default BasicInfo; | ||||
| @@ -1,6 +1,14 @@ | |||||
| import BasicInfo, { BasicInfoData } from '@/components/BasicInfo'; | import BasicInfo, { BasicInfoData } from '@/components/BasicInfo'; | ||||
| import SubAreaTitle from '@/components/SubAreaTitle'; | import SubAreaTitle from '@/components/SubAreaTitle'; | ||||
| import { DatasetData, ModelData, ResourceType } from '@/pages/Dataset/config'; | |||||
| import { ResourceInfoTabKeys } from '@/pages/Dataset/components/ResourceInfo'; | |||||
| import { | |||||
| DataSource, | |||||
| DatasetData, | |||||
| ModelData, | |||||
| ProjectDependency, | |||||
| ResourceType, | |||||
| TrainTask, | |||||
| } from '@/pages/Dataset/config'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| type ResourceIntroProps = { | type ResourceIntroProps = { | ||||
| @@ -8,29 +16,80 @@ type ResourceIntroProps = { | |||||
| info: DatasetData | ModelData; | info: DatasetData | ModelData; | ||||
| }; | }; | ||||
| // const formatArray = (arr?: ResourceData[]) => { | |||||
| // if (!arr || arr.length === 0) { | |||||
| // return '--'; | |||||
| // } | |||||
| // return arr.map((item) => item.name).join('\n'); | |||||
| // }; | |||||
| const formatDataset = (datasets?: DatasetData[]) => { | |||||
| if (!datasets || datasets.length === 0) { | |||||
| return undefined; | |||||
| } | |||||
| return datasets.map((item) => ({ | |||||
| value: item.name, | |||||
| url: `${origin}/dataset/dataset/info/${item.id}?tab=${ResourceInfoTabKeys.Version}&version=${item.version}&name=${item.name}&owner=${item.owner}&identifier=${item.identifier}`, | |||||
| })); | |||||
| }; | |||||
| const formatDataset = (arr?: DatasetData[]) => { | |||||
| if (!arr || arr.length === 0) { | |||||
| const formatParams = (map?: Record<string, string>, space: string = '') => { | |||||
| if (!map || Object.keys(map).length === 0) { | |||||
| return undefined; | return undefined; | ||||
| } | } | ||||
| return arr.map((item) => item.name).join('\n'); | |||||
| return Object.entries(map) | |||||
| .map(([key, value]) => `${space}${key} : ${value}`) | |||||
| .join('\n'); | |||||
| }; | }; | ||||
| const formatMap = (map?: Record<string, string>) => { | |||||
| const formatMetrics = (map?: Record<string, string>) => { | |||||
| if (!map || Object.keys(map).length === 0) { | if (!map || Object.keys(map).length === 0) { | ||||
| return undefined; | return undefined; | ||||
| } | } | ||||
| return Object.entries(map) | return Object.entries(map) | ||||
| .map(([key, value]) => `${key} = ${value}`) | |||||
| .map(([key, value]) => { | |||||
| if (typeof value === 'object' && value !== null) { | |||||
| return `${key} : \n${formatParams(value, ' ')}`; | |||||
| } | |||||
| return `${key} : ${value}`; | |||||
| }) | |||||
| .join('\n'); | .join('\n'); | ||||
| }; | }; | ||||
| const getProjectUrl = (project?: ProjectDependency) => { | |||||
| if (!project || !project.url || !project.branch) { | |||||
| return undefined; | |||||
| } | |||||
| const { url, branch } = project; | |||||
| if (url.endsWith('.git')) { | |||||
| return `${url.substring(0, url.length - 4)}/tree/${branch}`; | |||||
| } | |||||
| }; | |||||
| const formatProject = (project?: ProjectDependency) => { | |||||
| if (!project) { | |||||
| return undefined; | |||||
| } | |||||
| return { | |||||
| value: project.name, | |||||
| url: getProjectUrl(project), | |||||
| }; | |||||
| }; | |||||
| const formatTrainTask = (task?: TrainTask) => { | |||||
| if (!task) { | |||||
| return undefined; | |||||
| } | |||||
| return { | |||||
| value: task.name, | |||||
| url: `${origin}/pipeline/experiment/instance/${task.workflow_id}/${task.ins_id}`, | |||||
| }; | |||||
| }; | |||||
| const formatSource = (source?: string) => { | |||||
| if (source === DataSource.Create) { | |||||
| return '用户上传'; | |||||
| } else if (source === DataSource.HandExport) { | |||||
| return '手动导入'; | |||||
| } else if (source === DataSource.AtuoExport) { | |||||
| return '自动导入'; | |||||
| } | |||||
| return source; | |||||
| }; | |||||
| const getDatasetDatas = (data: DatasetData): BasicInfoData[] => [ | const getDatasetDatas = (data: DatasetData): BasicInfoData[] => [ | ||||
| { | { | ||||
| label: '数据集名称', | label: '数据集名称', | ||||
| @@ -51,6 +110,12 @@ const getDatasetDatas = (data: DatasetData): BasicInfoData[] => [ | |||||
| { | { | ||||
| label: '数据来源', | label: '数据来源', | ||||
| value: data.dataset_source, | value: data.dataset_source, | ||||
| format: formatSource, | |||||
| }, | |||||
| { | |||||
| label: '训练任务', | |||||
| value: data.train_task, | |||||
| format: formatTrainTask, | |||||
| }, | }, | ||||
| { | { | ||||
| label: '处理代码', | label: '处理代码', | ||||
| @@ -97,7 +162,8 @@ const getModelDatas = (data: ModelData): BasicInfoData[] => [ | |||||
| }, | }, | ||||
| { | { | ||||
| label: '训练代码', | label: '训练代码', | ||||
| value: data.code, | |||||
| value: data.project_depency, | |||||
| format: formatProject, | |||||
| }, | }, | ||||
| { | { | ||||
| label: '训练数据集', | label: '训练数据集', | ||||
| @@ -112,24 +178,22 @@ const getModelDatas = (data: ModelData): BasicInfoData[] => [ | |||||
| { | { | ||||
| label: '参数', | label: '参数', | ||||
| value: data.params, | value: data.params, | ||||
| format: formatMap, | |||||
| format: formatParams, | |||||
| }, | }, | ||||
| { | { | ||||
| label: '指标', | label: '指标', | ||||
| value: data.metrics, | value: data.metrics, | ||||
| format: formatMap, | |||||
| }, | |||||
| { | |||||
| label: '训练任务', | |||||
| value: data.train_task, | |||||
| format: (value?: any) => value?.name, | |||||
| externalLink: data.train_task | |||||
| ? `${location.origin}/pipeline/experiment/instance/${data.train_task.task_id}/${data.train_task.ins_id}` | |||||
| : '', | |||||
| format: formatMetrics, | |||||
| }, | }, | ||||
| { | { | ||||
| label: '模型来源', | label: '模型来源', | ||||
| value: data.model_source, | value: data.model_source, | ||||
| format: formatSource, | |||||
| }, | |||||
| { | |||||
| label: '训练任务', | |||||
| value: data.train_task, | |||||
| format: formatTrainTask, | |||||
| }, | }, | ||||
| { | { | ||||
| label: '模型框架', | label: '模型框架', | ||||
| @@ -22,7 +22,8 @@ export enum ResourceType { | |||||
| } | } | ||||
| export enum DataSource { | export enum DataSource { | ||||
| Export = 'export', // 导出 | |||||
| AtuoExport = 'auto_export', // 自动导出 | |||||
| HandExport = 'hand_export', // 手动导出 | |||||
| Create = 'add', // 新增 | Create = 'add', // 新增 | ||||
| } | } | ||||
| @@ -137,6 +138,7 @@ export type CategoryData = { | |||||
| // 数据集、模型列表数据 | // 数据集、模型列表数据 | ||||
| export interface ResourceData { | export interface ResourceData { | ||||
| resourceType: ResourceType.Dataset | ResourceType.Model; // 用于 ts 类型判断 | |||||
| id: number; | id: number; | ||||
| name: string; | name: string; | ||||
| identifier: string; | identifier: string; | ||||
| @@ -150,7 +152,7 @@ export interface ResourceData { | |||||
| version_desc?: string; | version_desc?: string; | ||||
| usage?: string; | usage?: string; | ||||
| relative_paths?: string; | relative_paths?: string; | ||||
| resourceType: ResourceType.Dataset | ResourceType.Model; | |||||
| train_task?: TrainTask; // 训练任务 | |||||
| } | } | ||||
| // 数据集数据 | // 数据集数据 | ||||
| @@ -174,7 +176,7 @@ export interface ModelData extends ResourceData { | |||||
| test_datasets?: DatasetData[]; // 测试数据集 | test_datasets?: DatasetData[]; // 测试数据集 | ||||
| params?: Record<string, string>; // 参数 | params?: Record<string, string>; // 参数 | ||||
| metrics?: Record<string, string>; // 指标 | metrics?: Record<string, string>; // 指标 | ||||
| train_task?: TrainTask; // 训练任务 | |||||
| project_depency?: ProjectDependency; // 项目依赖 | |||||
| model_source?: string; // 模型来源 | model_source?: string; // 模型来源 | ||||
| model_version_vos?: ResourceFileData[]; | model_version_vos?: ResourceFileData[]; | ||||
| } | } | ||||
| @@ -199,5 +201,13 @@ export type ResourceFileData = { | |||||
| export type TrainTask = { | export type TrainTask = { | ||||
| ins_id: number; | ins_id: number; | ||||
| name: string; | name: string; | ||||
| task_id: string; | |||||
| experiment_id: number; | |||||
| workflow_id: number; | |||||
| }; | |||||
| // 项目依赖 | |||||
| export type ProjectDependency = { | |||||
| url: string; | |||||
| name: string; | |||||
| branch: string; | |||||
| }; | }; | ||||
| @@ -504,6 +504,9 @@ function ExperimentText() { | |||||
| key={experimentNodeData.id} | key={experimentNodeData.id} | ||||
| open={propsDrawerOpen} | open={propsDrawerOpen} | ||||
| onClose={closePropsDrawer} | onClose={closePropsDrawer} | ||||
| pipelineId={Number(locationParams.workflowId)} | |||||
| experimentId={experimentIns.experiment_id} | |||||
| experimentName={experimentIns.experiment_name} | |||||
| instanceId={experimentIns.id} | instanceId={experimentIns.id} | ||||
| instanceName={experimentIns.argo_ins_name} | instanceName={experimentIns.argo_ins_name} | ||||
| instanceNamespace={experimentIns.argo_ins_ns} | instanceNamespace={experimentIns.argo_ins_ns} | ||||
| @@ -13,6 +13,9 @@ import styles from './index.less'; | |||||
| type ExperimentDrawerProps = { | type ExperimentDrawerProps = { | ||||
| open: boolean; | open: boolean; | ||||
| onClose: () => void; | onClose: () => void; | ||||
| pipelineId: number; // 流水线 id | |||||
| experimentId: number; // 实验 id | |||||
| experimentName: string; // 实验 name | |||||
| instanceId: number; // 实验实例 id | instanceId: number; // 实验实例 id | ||||
| instanceName: string; // 实验实例 name | instanceName: string; // 实验实例 name | ||||
| instanceNamespace: string; // 实验实例 namespace | instanceNamespace: string; // 实验实例 namespace | ||||
| @@ -26,6 +29,9 @@ type ExperimentDrawerProps = { | |||||
| const ExperimentDrawer = ({ | const ExperimentDrawer = ({ | ||||
| open, | open, | ||||
| onClose, | onClose, | ||||
| pipelineId, | |||||
| experimentId, | |||||
| experimentName, | |||||
| instanceId, | instanceId, | ||||
| instanceName, | instanceName, | ||||
| instanceNamespace, | instanceNamespace, | ||||
| @@ -64,6 +70,9 @@ const ExperimentDrawer = ({ | |||||
| label: '输出结果', | label: '输出结果', | ||||
| children: ( | children: ( | ||||
| <ExperimentResult | <ExperimentResult | ||||
| pipelineId={pipelineId} | |||||
| experimentId={experimentId} | |||||
| experimentName={experimentName} | |||||
| experimentInsId={instanceId} | experimentInsId={instanceId} | ||||
| pipelineNodeId={instanceNodeData.id} | pipelineNodeId={instanceNodeData.id} | ||||
| ></ExperimentResult> | ></ExperimentResult> | ||||
| @@ -8,6 +8,9 @@ import ExportModelModal from '../ExportModelModal'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| type ExperimentResultProps = { | type ExperimentResultProps = { | ||||
| pipelineId: number; // 流水线 id | |||||
| experimentId: number; // 实验 id | |||||
| experimentName: string; // 实验 name | |||||
| experimentInsId: number; // 实验实例 id | experimentInsId: number; // 实验实例 id | ||||
| pipelineNodeId: string; // 流水线节点 id | pipelineNodeId: string; // 流水线节点 id | ||||
| }; | }; | ||||
| @@ -22,7 +25,13 @@ type ExperimentResultData = { | |||||
| }[]; | }[]; | ||||
| }; | }; | ||||
| function ExperimentResult({ experimentInsId, pipelineNodeId }: ExperimentResultProps) { | |||||
| function ExperimentResult({ | |||||
| pipelineId, | |||||
| experimentId, | |||||
| experimentName, | |||||
| experimentInsId, | |||||
| pipelineNodeId, | |||||
| }: ExperimentResultProps) { | |||||
| const { message } = App.useApp(); | const { message } = App.useApp(); | ||||
| const [experimentResults, setExperimentResults] = useState<ExperimentResultData[]>([]); | const [experimentResults, setExperimentResults] = useState<ExperimentResultData[]>([]); | ||||
| @@ -46,6 +55,11 @@ function ExperimentResult({ experimentInsId, pipelineNodeId }: ExperimentResultP | |||||
| // 导出到模型库 | // 导出到模型库 | ||||
| const exportToModel = (path: string) => { | const exportToModel = (path: string) => { | ||||
| const { close } = openAntdModal(ExportModelModal, { | const { close } = openAntdModal(ExportModelModal, { | ||||
| pipelineId, | |||||
| experimentId, | |||||
| experimentName, | |||||
| experimentInsId, | |||||
| pipelineNodeId, | |||||
| path, | path, | ||||
| onOk: () => { | onOk: () => { | ||||
| message.success('导出成功'); | message.success('导出成功'); | ||||
| @@ -1,12 +1,7 @@ | |||||
| import editExperimentIcon from '@/assets/img/edit-experiment.png'; | import editExperimentIcon from '@/assets/img/edit-experiment.png'; | ||||
| import KFModal from '@/components/KFModal'; | import KFModal from '@/components/KFModal'; | ||||
| import { ResourceVersionData, type ResourceData } from '@/pages/Dataset/config'; | |||||
| import { | |||||
| addModelVersion, | |||||
| exportModelReq, | |||||
| getModelList, | |||||
| getModelVersionList, | |||||
| } from '@/services/dataset'; | |||||
| import { DataSource, ResourceVersionData, type ResourceData } from '@/pages/Dataset/config'; | |||||
| import { addModelVersion, getModelList, getModelVersionList } from '@/services/dataset'; | |||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import { InfoCircleOutlined } from '@ant-design/icons'; | import { InfoCircleOutlined } from '@ant-design/icons'; | ||||
| import { Form, Input, ModalProps, Select } from 'antd'; | import { Form, Input, ModalProps, Select } from 'antd'; | ||||
| @@ -15,34 +10,48 @@ import { useEffect, useState } from 'react'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| type FormData = { | type FormData = { | ||||
| models_id: string; | |||||
| id: number; | |||||
| version: string; | version: string; | ||||
| description: string; | |||||
| version_desc: string; | |||||
| }; | }; | ||||
| type ExportModelResponce = { | |||||
| fileName: string; | |||||
| fileSize: string; | |||||
| url: string; | |||||
| }; | |||||
| // type ExportModelResponce = { | |||||
| // fileName: string; | |||||
| // fileSize: string; | |||||
| // url: string; | |||||
| // }; | |||||
| type CreateModelVersionParams = FormData & { | |||||
| file_name: string; | |||||
| file_size: string; | |||||
| url: string; | |||||
| // name: string; | |||||
| }; | |||||
| // type CreateModelVersionParams = FormData & { | |||||
| // file_name: string; | |||||
| // file_size: string; | |||||
| // url: string; | |||||
| // // name: string; | |||||
| // }; | |||||
| interface ExportModelModalProps extends Omit<ModalProps, 'onOk'> { | interface ExportModelModalProps extends Omit<ModalProps, 'onOk'> { | ||||
| path: string; | |||||
| pipelineId: number; // 流水线 id | |||||
| experimentId: number; // 实验 id | |||||
| experimentName: string; // 实验 name | |||||
| experimentInsId: number; // 实验实例 id | |||||
| pipelineNodeId: string; // 流水线节点 id | |||||
| path: string; // 文件路径 | |||||
| onOk: () => void; | onOk: () => void; | ||||
| } | } | ||||
| function ExportModelModal({ path, onOk, ...rest }: ExportModelModalProps) { | |||||
| function ExportModelModal({ | |||||
| pipelineId, | |||||
| experimentId, | |||||
| experimentName, | |||||
| experimentInsId, | |||||
| pipelineNodeId, | |||||
| path, | |||||
| onOk, | |||||
| ...rest | |||||
| }: ExportModelModalProps) { | |||||
| const [form] = Form.useForm(); | const [form] = Form.useForm(); | ||||
| const [models, setModels] = useState<ResourceData[]>([]); | const [models, setModels] = useState<ResourceData[]>([]); | ||||
| const [versions, setVersions] = useState<ResourceVersionData[]>([]); | const [versions, setVersions] = useState<ResourceVersionData[]>([]); | ||||
| const [uuid] = useState(Date.now()); | |||||
| // const [uuid] = useState(Date.now()); | |||||
| const layout = { | const layout = { | ||||
| labelCol: { span: 24 }, | labelCol: { span: 24 }, | ||||
| @@ -53,10 +62,19 @@ function ExportModelModal({ path, onOk, ...rest }: ExportModelModalProps) { | |||||
| requestModelList(); | requestModelList(); | ||||
| }, []); | }, []); | ||||
| // 模型版本tooltip | |||||
| // 获取选中的模型 | |||||
| const getSelectedModel = (id: number | undefined) => { | |||||
| if (id) { | |||||
| return models.find((item) => item.id === id); | |||||
| } | |||||
| return undefined; | |||||
| }; | |||||
| // 模型版本 tooltip | |||||
| const getTooltip = () => { | const getTooltip = () => { | ||||
| const id = form.getFieldValue('models_id'); | |||||
| const name = models.find((item) => item.id === id)?.name ?? ''; | |||||
| const id = form.getFieldValue('id'); | |||||
| const model = getSelectedModel(id); | |||||
| const name = model?.name ?? ''; | |||||
| const versionNames = versions.map((item: ResourceVersionData) => item.name).join('、'); | const versionNames = versions.map((item: ResourceVersionData) => item.name).join('、'); | ||||
| const tooltip = | const tooltip = | ||||
| versions.length > 0 ? `${name}有以下版本:\n${versionNames}\n注意不能重复` : undefined; | versions.length > 0 ? `${name}有以下版本:\n${versionNames}\n注意不能重复` : undefined; | ||||
| @@ -87,7 +105,7 @@ function ExportModelModal({ path, onOk, ...rest }: ExportModelModalProps) { | |||||
| // 获取模型版本列表 | // 获取模型版本列表 | ||||
| const getModelVersions = async (id: number) => { | const getModelVersions = async (id: number) => { | ||||
| const model = models.find((item) => item.id === id); | |||||
| const model = getSelectedModel(id); | |||||
| if (!model) { | if (!model) { | ||||
| return; | return; | ||||
| } | } | ||||
| @@ -104,26 +122,26 @@ function ExportModelModal({ path, onOk, ...rest }: ExportModelModalProps) { | |||||
| // 导出到模型 | // 导出到模型 | ||||
| const exportToModel = async (formData: FormData) => { | const exportToModel = async (formData: FormData) => { | ||||
| const id = form.getFieldValue('id'); | |||||
| const model = getSelectedModel(id); | |||||
| const params = { | const params = { | ||||
| uuid: String(uuid), | |||||
| path, | |||||
| ...formData, | |||||
| identifier: model?.identifier, | |||||
| name: model?.name, | |||||
| model_source: DataSource.HandExport, | |||||
| train_task: { | |||||
| workflow_id: pipelineId, | |||||
| experiment_id: experimentId, | |||||
| name: experimentName, | |||||
| ins_id: experimentInsId, | |||||
| task_id: pipelineNodeId, | |||||
| }, | |||||
| model_version_vos: [ | |||||
| { | |||||
| url: path, | |||||
| }, | |||||
| ], | |||||
| }; | }; | ||||
| const [res] = await to(exportModelReq(params)); | |||||
| if (res && res.data) { | |||||
| const files = res.data as ExportModelResponce[]; | |||||
| const params: CreateModelVersionParams[] = files.map((item) => ({ | |||||
| ...formData, | |||||
| file_name: item.fileName, | |||||
| file_size: item.fileSize, | |||||
| url: item.url, | |||||
| })); | |||||
| createModelVersion(params); | |||||
| } | |||||
| }; | |||||
| // 创建模型版本 | |||||
| const createModelVersion = async (params: CreateModelVersionParams[]) => { | |||||
| const [res] = await to(addModelVersion(params)); | const [res] = await to(addModelVersion(params)); | ||||
| if (res) { | if (res) { | ||||
| onOk(); | onOk(); | ||||
| @@ -152,11 +170,7 @@ function ExportModelModal({ path, onOk, ...rest }: ExportModelModalProps) { | |||||
| labelAlign="left" | labelAlign="left" | ||||
| labelWrap | labelWrap | ||||
| > | > | ||||
| <Form.Item | |||||
| label="模型名称" | |||||
| name="models_id" | |||||
| rules={[{ required: true, message: '请选择模型' }]} | |||||
| > | |||||
| <Form.Item label="模型名称" name="id" rules={[{ required: true, message: '请选择模型' }]}> | |||||
| <Select | <Select | ||||
| placeholder="请选择模型" | placeholder="请选择模型" | ||||
| onChange={handleModelChange} | onChange={handleModelChange} | ||||
| @@ -194,7 +208,7 @@ function ExportModelModal({ path, onOk, ...rest }: ExportModelModalProps) { | |||||
| </Form.Item> | </Form.Item> | ||||
| <Form.Item | <Form.Item | ||||
| label="版本描述" | label="版本描述" | ||||
| name="description" | |||||
| name="version_desc" | |||||
| rules={[{ required: true, message: '请输入版本描述' }]} | rules={[{ required: true, message: '请输入版本描述' }]} | ||||
| > | > | ||||
| <Input.TextArea | <Input.TextArea | ||||
| @@ -16,7 +16,7 @@ function ModelInfo({ resourceId, data, onVersionChange }: ModelInfoProps) { | |||||
| const gotoExperimentPage = () => { | const gotoExperimentPage = () => { | ||||
| if (data.model_meta.train_task?.ins_id) { | if (data.model_meta.train_task?.ins_id) { | ||||
| const { origin } = location; | const { origin } = location; | ||||
| const url = `${origin}/pipeline/experiment/instance/${data.model_meta.train_task.task_id}/${data.model_meta.train_task.ins_id}`; | |||||
| const url = `${origin}/pipeline/experiment/instance/${data.model_meta.train_task.workflow_id}/${data.model_meta.train_task.ins_id}`; | |||||
| window.open(url, '_blank'); | window.open(url, '_blank'); | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -60,12 +60,12 @@ function ModelInfo({ resourceId, data, onVersionChange }: ModelInfoProps) { | |||||
| {data.model_meta.model_type || '--'} | {data.model_meta.model_type || '--'} | ||||
| </span> | </span> | ||||
| </div> | </div> | ||||
| <div className={styles['node-tooltips__row']}> | |||||
| {/* <div className={styles['node-tooltips__row']}> | |||||
| <span className={styles['node-tooltips__row__title']}>模型大小:</span> | <span className={styles['node-tooltips__row__title']}>模型大小:</span> | ||||
| <span className={styles['node-tooltips__row__value']}> | <span className={styles['node-tooltips__row__value']}> | ||||
| {data.model_meta.file_size || '--'} | {data.model_meta.file_size || '--'} | ||||
| </span> | </span> | ||||
| </div> | |||||
| </div> */} | |||||
| <div className={styles['node-tooltips__row']}> | <div className={styles['node-tooltips__row']}> | ||||
| <span className={styles['node-tooltips__row__title']}>创建时间:</span> | <span className={styles['node-tooltips__row__title']}>创建时间:</span> | ||||
| <span className={styles['node-tooltips__row__value']}> | <span className={styles['node-tooltips__row__value']}> | ||||
| @@ -126,8 +126,12 @@ function DatasetInfo({ data }: { data: TrainDataset }) { | |||||
| function ProjectInfo({ data }: { data: ProjectDependency }) { | function ProjectInfo({ data }: { data: ProjectDependency }) { | ||||
| const gotoProjectPage = () => { | const gotoProjectPage = () => { | ||||
| const { url } = data; | |||||
| window.open(url, '_blank'); | |||||
| const { url, branch } = data; | |||||
| let projectUrl = url; | |||||
| if (url.endsWith('.git')) { | |||||
| projectUrl = `${url.substring(0, url.length - 4)}/tree/${branch}`; | |||||
| } | |||||
| window.open(projectUrl, '_blank'); | |||||
| }; | }; | ||||
| return ( | return ( | ||||