| @@ -0,0 +1,113 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-11-29 09:27:19 | |||||
| * @Description: 用于 BasicInfo 和 BasicTableInfo 组件的子组件 | |||||
| */ | |||||
| import { Link } from '@umijs/max'; | |||||
| import { Typography } from 'antd'; | |||||
| import React from 'react'; | |||||
| import { type BasicInfoData, type BasicInfoLink } from './types'; | |||||
| type BasicInfoItemProps = { | |||||
| data: BasicInfoData; | |||||
| labelWidth: number; | |||||
| classPrefix: string; | |||||
| }; | |||||
| export function BasicInfoItem({ data, labelWidth, classPrefix }: BasicInfoItemProps) { | |||||
| const { label, value, format, ellipsis } = data; | |||||
| const formatValue = format ? format(value) : value; | |||||
| const myClassName = `${classPrefix}__item`; | |||||
| let valueComponent = undefined; | |||||
| if (Array.isArray(formatValue)) { | |||||
| valueComponent = ( | |||||
| <div className={`${myClassName}__value-container`}> | |||||
| {formatValue.map((item: BasicInfoLink) => ( | |||||
| <BasicInfoItemValue | |||||
| key={item.value} | |||||
| value={item.value} | |||||
| link={item.link} | |||||
| url={item.url} | |||||
| ellipsis={ellipsis} | |||||
| classPrefix={classPrefix} | |||||
| /> | |||||
| ))} | |||||
| </div> | |||||
| ); | |||||
| } else if (React.isValidElement(formatValue)) { | |||||
| // 这个判断必须在下面的判断之前 | |||||
| valueComponent = ( | |||||
| <BasicInfoItemValue value={formatValue} ellipsis={ellipsis} classPrefix={classPrefix} /> | |||||
| ); | |||||
| } else if (typeof formatValue === 'object' && formatValue) { | |||||
| valueComponent = ( | |||||
| <BasicInfoItemValue | |||||
| value={formatValue.value} | |||||
| link={formatValue.link} | |||||
| url={formatValue.url} | |||||
| ellipsis={ellipsis} | |||||
| classPrefix={classPrefix} | |||||
| /> | |||||
| ); | |||||
| } else { | |||||
| valueComponent = ( | |||||
| <BasicInfoItemValue value={formatValue} ellipsis={ellipsis} classPrefix={classPrefix} /> | |||||
| ); | |||||
| } | |||||
| return ( | |||||
| <div className={myClassName} key={label}> | |||||
| <div className={`${myClassName}__label`} style={{ width: labelWidth }}> | |||||
| {label} | |||||
| </div> | |||||
| {valueComponent} | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| type BasicInfoItemValueProps = { | |||||
| ellipsis?: boolean; | |||||
| classPrefix: string; | |||||
| value: string | React.ReactNode; | |||||
| link?: string; | |||||
| url?: string; | |||||
| }; | |||||
| export function BasicInfoItemValue({ | |||||
| value, | |||||
| link, | |||||
| url, | |||||
| ellipsis, | |||||
| classPrefix, | |||||
| }: BasicInfoItemValueProps) { | |||||
| const myClassName = `${classPrefix}__item__value`; | |||||
| let component = undefined; | |||||
| if (url && value) { | |||||
| component = ( | |||||
| <a className={`${myClassName}__link`} href={url} target="_blank" rel="noopener noreferrer"> | |||||
| {value} | |||||
| </a> | |||||
| ); | |||||
| } else if (link && value) { | |||||
| component = ( | |||||
| <Link to={link} className={`${myClassName}__link`}> | |||||
| {value} | |||||
| </Link> | |||||
| ); | |||||
| } else if (React.isValidElement(value)) { | |||||
| return value; | |||||
| } else { | |||||
| component = <span className={`${myClassName}__text`}>{value ?? '--'}</span>; | |||||
| } | |||||
| return ( | |||||
| <div className={myClassName}> | |||||
| <Typography.Text | |||||
| ellipsis={ellipsis ? { tooltip: value } : false} | |||||
| style={{ fontSize: 'inherit' }} | |||||
| > | |||||
| {component} | |||||
| </Typography.Text> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| @@ -0,0 +1,48 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-11-29 09:27:19 | |||||
| * @Description: 用于 BasicInfo 和 BasicTableInfo 组件的常用转化格式 | |||||
| */ | |||||
| // 格式化日期 | |||||
| export { formatDate } from '@/utils/date'; | |||||
| /** | |||||
| * 格式化字符串数组 | |||||
| * @param value - 字符串数组 | |||||
| * @returns 逗号分隔的字符串 | |||||
| */ | |||||
| export const formatList = (value: string[] | null | undefined): string => { | |||||
| if ( | |||||
| value === undefined || | |||||
| value === null || | |||||
| Array.isArray(value) === false || | |||||
| value.length === 0 | |||||
| ) { | |||||
| return '--'; | |||||
| } | |||||
| return value.join(','); | |||||
| }; | |||||
| /** | |||||
| * 格式化布尔值 | |||||
| * @param value - 布尔值 | |||||
| * @returns "是" 或 "否" | |||||
| */ | |||||
| export const formatBoolean = (value: boolean): string => { | |||||
| return value ? '是' : '否'; | |||||
| }; | |||||
| type FormatEnum = (value: string | number) => string; | |||||
| /** | |||||
| * 格式化枚举 | |||||
| * @param options - 枚举选项 | |||||
| * @returns 格式化枚举函数 | |||||
| */ | |||||
| export const formatEnum = (options: { value: string | number; label: string }[]): FormatEnum => { | |||||
| return (value: string | number) => { | |||||
| const option = options.find((item) => item.value === value); | |||||
| return option ? option.label : '--'; | |||||
| }; | |||||
| }; | |||||
| @@ -1,21 +1,10 @@ | |||||
| import { Link } from '@umijs/max'; | |||||
| import { Typography } from 'antd'; | |||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import React from 'react'; | import React from 'react'; | ||||
| import { BasicInfoItem } from './components'; | |||||
| import './index.less'; | import './index.less'; | ||||
| export type BasicInfoLink = { | |||||
| value: string; | |||||
| link?: string; | |||||
| url?: string; | |||||
| }; | |||||
| export type BasicInfoData = { | |||||
| label: string; | |||||
| value?: any; | |||||
| ellipsis?: boolean; | |||||
| format?: (_value?: any) => string | BasicInfoLink | BasicInfoLink[] | undefined; | |||||
| }; | |||||
| import type { BasicInfoData, BasicInfoLink } from './types'; | |||||
| export * from './format'; | |||||
| export type { BasicInfoData, BasicInfoLink }; | |||||
| type BasicInfoProps = { | type BasicInfoProps = { | ||||
| datas: BasicInfoData[]; | datas: BasicInfoData[]; | ||||
| @@ -24,20 +13,6 @@ type BasicInfoProps = { | |||||
| labelWidth: number; | labelWidth: number; | ||||
| }; | }; | ||||
| type BasicInfoItemProps = { | |||||
| data: BasicInfoData; | |||||
| labelWidth: number; | |||||
| classPrefix: string; | |||||
| }; | |||||
| type BasicInfoItemValueProps = { | |||||
| ellipsis?: boolean; | |||||
| classPrefix: string; | |||||
| value: string | React.ReactNode; | |||||
| link?: string; | |||||
| url?: string; | |||||
| }; | |||||
| export default function BasicInfo({ datas, className, style, labelWidth }: BasicInfoProps) { | export default function BasicInfo({ datas, className, style, labelWidth }: BasicInfoProps) { | ||||
| return ( | return ( | ||||
| <div className={classNames('kf-basic-info', className)} style={style}> | <div className={classNames('kf-basic-info', className)} style={style}> | ||||
| @@ -52,92 +27,3 @@ export default function BasicInfo({ datas, className, style, labelWidth }: Basic | |||||
| </div> | </div> | ||||
| ); | ); | ||||
| } | } | ||||
| export function BasicInfoItem({ data, labelWidth, classPrefix }: BasicInfoItemProps) { | |||||
| const { label, value, format, ellipsis } = data; | |||||
| const formatValue = format ? format(value) : value; | |||||
| const myClassName = `${classPrefix}__item`; | |||||
| let valueComponent = undefined; | |||||
| if (Array.isArray(formatValue)) { | |||||
| valueComponent = ( | |||||
| <div className={`${myClassName}__value-container`}> | |||||
| {formatValue.map((item: BasicInfoLink) => ( | |||||
| <BasicInfoItemValue | |||||
| key={item.value} | |||||
| value={item.value} | |||||
| link={item.link} | |||||
| url={item.url} | |||||
| ellipsis={ellipsis} | |||||
| classPrefix={classPrefix} | |||||
| /> | |||||
| ))} | |||||
| </div> | |||||
| ); | |||||
| } else if (React.isValidElement(formatValue)) { | |||||
| // 这个判断必须在下面的判断之前 | |||||
| valueComponent = ( | |||||
| <BasicInfoItemValue value={formatValue} ellipsis={ellipsis} classPrefix={classPrefix} /> | |||||
| ); | |||||
| } else if (typeof formatValue === 'object' && formatValue) { | |||||
| valueComponent = ( | |||||
| <BasicInfoItemValue | |||||
| value={formatValue.value} | |||||
| link={formatValue.link} | |||||
| url={formatValue.url} | |||||
| ellipsis={ellipsis} | |||||
| classPrefix={classPrefix} | |||||
| /> | |||||
| ); | |||||
| } else { | |||||
| valueComponent = ( | |||||
| <BasicInfoItemValue value={formatValue} ellipsis={ellipsis} classPrefix={classPrefix} /> | |||||
| ); | |||||
| } | |||||
| return ( | |||||
| <div className={myClassName} key={label}> | |||||
| <div className={`${myClassName}__label`} style={{ width: labelWidth }}> | |||||
| {label} | |||||
| </div> | |||||
| {valueComponent} | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export function BasicInfoItemValue({ | |||||
| value, | |||||
| link, | |||||
| url, | |||||
| ellipsis, | |||||
| classPrefix, | |||||
| }: BasicInfoItemValueProps) { | |||||
| const myClassName = `${classPrefix}__item__value`; | |||||
| let component = undefined; | |||||
| if (url && value) { | |||||
| component = ( | |||||
| <a className={`${myClassName}__link`} href={url} target="_blank" rel="noopener noreferrer"> | |||||
| {value} | |||||
| </a> | |||||
| ); | |||||
| } else if (link && value) { | |||||
| component = ( | |||||
| <Link to={link} className={`${myClassName}__link`}> | |||||
| {value} | |||||
| </Link> | |||||
| ); | |||||
| } else if (React.isValidElement(value)) { | |||||
| return value; | |||||
| } else { | |||||
| component = <span className={`${myClassName}__text`}>{value ?? '--'}</span>; | |||||
| } | |||||
| return ( | |||||
| <div className={myClassName}> | |||||
| <Typography.Text | |||||
| ellipsis={ellipsis ? { tooltip: value } : false} | |||||
| style={{ fontSize: 'inherit' }} | |||||
| > | |||||
| {component} | |||||
| </Typography.Text> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| @@ -0,0 +1,14 @@ | |||||
| // 基础信息 | |||||
| export type BasicInfoData = { | |||||
| label: string; | |||||
| value?: any; | |||||
| ellipsis?: boolean; | |||||
| format?: (_value?: any) => string | BasicInfoLink | BasicInfoLink[] | undefined; | |||||
| }; | |||||
| // 值为链接的类型 | |||||
| export type BasicInfoLink = { | |||||
| value: string; | |||||
| link?: string; | |||||
| url?: string; | |||||
| }; | |||||
| @@ -1,6 +1,8 @@ | |||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import { BasicInfoItem, type BasicInfoData, type BasicInfoLink } from '../BasicInfo'; | |||||
| import { BasicInfoItem } from '../BasicInfo/components'; | |||||
| import { type BasicInfoData, type BasicInfoLink } from '../BasicInfo/types'; | |||||
| import './index.less'; | import './index.less'; | ||||
| export * from '../BasicInfo/format'; | |||||
| export type { BasicInfoData, BasicInfoLink }; | export type { BasicInfoData, BasicInfoLink }; | ||||
| type BasicTableInfoProps = { | type BasicTableInfoProps = { | ||||
| @@ -92,19 +92,29 @@ export enum AutoMLTaskType { | |||||
| Regression = 'regression', | Regression = 'regression', | ||||
| } | } | ||||
| export const autoMLTaskTypeOptions = [ | |||||
| { label: '分类', value: AutoMLTaskType.Classification }, | |||||
| { label: '回归', value: AutoMLTaskType.Regression }, | |||||
| ]; | |||||
| // 自动化任务集成策略 | // 自动化任务集成策略 | ||||
| export enum AutoMLEnsembleClass { | export enum AutoMLEnsembleClass { | ||||
| Default = 'default', | Default = 'default', | ||||
| SingleBest = 'SingleBest', | SingleBest = 'SingleBest', | ||||
| } | } | ||||
| export const autoMLEnsembleClassOptions = [ | |||||
| { label: '集成模型', value: AutoMLEnsembleClass.Default }, | |||||
| { label: '单一最佳模型', value: AutoMLEnsembleClass.SingleBest }, | |||||
| ]; | |||||
| // 自动化任务重采样策略 | // 自动化任务重采样策略 | ||||
| export enum AutoMLResamplingStrategy { | export enum AutoMLResamplingStrategy { | ||||
| Holdout = 'holdout', | Holdout = 'holdout', | ||||
| CrossValid = 'crossValid', | CrossValid = 'crossValid', | ||||
| } | } | ||||
| export const resamplingStrategyOptions = [ | |||||
| export const autoMLResamplingStrategyOptions = [ | |||||
| { label: 'holdout', value: AutoMLResamplingStrategy.Holdout }, | { label: 'holdout', value: AutoMLResamplingStrategy.Holdout }, | ||||
| { label: 'crossValid', value: AutoMLResamplingStrategy.CrossValid }, | { label: 'crossValid', value: AutoMLResamplingStrategy.CrossValid }, | ||||
| ]; | ]; | ||||
| @@ -1,4 +1,4 @@ | |||||
| .create-service-version { | |||||
| .create-automl { | |||||
| height: 100%; | height: 100%; | ||||
| &__content { | &__content { | ||||
| @@ -5,9 +5,9 @@ | |||||
| */ | */ | ||||
| import PageTitle from '@/components/PageTitle'; | import PageTitle from '@/components/PageTitle'; | ||||
| import { AutoMLTaskType } from '@/enums'; | |||||
| import { addAutoMLReq, getDatasetInfoReq, updateAutoMLReq } from '@/services/autoML'; | |||||
| import { parseJsonText, trimCharacter } from '@/utils'; | |||||
| import { AutoMLEnsembleClass, AutoMLTaskType } from '@/enums'; | |||||
| import { addAutoMLReq, getAutoMLInfoReq, updateAutoMLReq } from '@/services/autoML'; | |||||
| import { convertEmptyStringToUndefined, parseJsonText, trimCharacter } from '@/utils'; | |||||
| import { safeInvoke } from '@/utils/functional'; | import { safeInvoke } from '@/utils/functional'; | ||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import SessionStorage from '@/utils/sessionStorage'; | import SessionStorage from '@/utils/sessionStorage'; | ||||
| @@ -49,7 +49,7 @@ function CreateAutoML() { | |||||
| // 获取服务详情 | // 获取服务详情 | ||||
| const getAutoMLInfo = async (id: number, isCopy = false) => { | const getAutoMLInfo = async (id: number, isCopy = false) => { | ||||
| const [res] = await to(getDatasetInfoReq({ id })); | |||||
| const [res] = await to(getAutoMLInfoReq({ id })); | |||||
| if (res && res.data) { | if (res && res.data) { | ||||
| const autoMLInfo: AutoMLData = res.data; | const autoMLInfo: AutoMLData = res.data; | ||||
| const { | const { | ||||
| @@ -96,7 +96,7 @@ function CreateAutoML() { | |||||
| } | } | ||||
| }; | }; | ||||
| // 创建版本 | |||||
| // 创建、更新、复制实验 | |||||
| const createExperiment = async (formData: FormData) => { | const createExperiment = async (formData: FormData) => { | ||||
| const include_classifier = formData['include_classifier']?.join(','); | const include_classifier = formData['include_classifier']?.join(','); | ||||
| const include_feature_preprocessor = formData['include_feature_preprocessor']?.join(','); | const include_feature_preprocessor = formData['include_feature_preprocessor']?.join(','); | ||||
| @@ -113,12 +113,12 @@ function CreateAutoML() { | |||||
| // 根据后台要求,修改表单数据 | // 根据后台要求,修改表单数据 | ||||
| const object = { | const object = { | ||||
| ...omit(formData), | ...omit(formData), | ||||
| include_classifier, | |||||
| include_feature_preprocessor, | |||||
| include_regressor, | |||||
| exclude_classifier, | |||||
| exclude_feature_preprocessor, | |||||
| exclude_regressor, | |||||
| include_classifier: convertEmptyStringToUndefined(include_classifier), | |||||
| include_feature_preprocessor: convertEmptyStringToUndefined(include_feature_preprocessor), | |||||
| include_regressor: convertEmptyStringToUndefined(include_regressor), | |||||
| exclude_classifier: convertEmptyStringToUndefined(exclude_classifier), | |||||
| exclude_feature_preprocessor: convertEmptyStringToUndefined(exclude_feature_preprocessor), | |||||
| exclude_regressor: convertEmptyStringToUndefined(exclude_regressor), | |||||
| metrics: metrics ? JSON.stringify(metrics) : undefined, | metrics: metrics ? JSON.stringify(metrics) : undefined, | ||||
| target_columns, | target_columns, | ||||
| }; | }; | ||||
| @@ -148,7 +148,6 @@ function CreateAutoML() { | |||||
| navigate(-1); | navigate(-1); | ||||
| }; | }; | ||||
| const disabled = id !== null || id !== undefined; | |||||
| let buttonText = '新建'; | let buttonText = '新建'; | ||||
| let title = '新增实验'; | let title = '新增实验'; | ||||
| if (id) { | if (id) { | ||||
| @@ -157,26 +156,28 @@ function CreateAutoML() { | |||||
| } | } | ||||
| return ( | return ( | ||||
| <div className={styles['create-service-version']}> | |||||
| <div className={styles['create-automl']}> | |||||
| <PageTitle title={title}></PageTitle> | <PageTitle title={title}></PageTitle> | ||||
| <div className={styles['create-service-version__content']}> | |||||
| <div className={styles['create-automl__content']}> | |||||
| <div> | <div> | ||||
| <Form | <Form | ||||
| name="create-service-version" | |||||
| name="create-automl" | |||||
| labelCol={{ flex: '160px' }} | labelCol={{ flex: '160px' }} | ||||
| labelAlign="left" | labelAlign="left" | ||||
| form={form} | form={form} | ||||
| onFinish={handleSubmit} | onFinish={handleSubmit} | ||||
| size="large" | size="large" | ||||
| autoComplete="off" | autoComplete="off" | ||||
| scrollToFirstError | |||||
| initialValues={{ | initialValues={{ | ||||
| task_type: AutoMLTaskType.Classification, | task_type: AutoMLTaskType.Classification, | ||||
| shuffle: false, | shuffle: false, | ||||
| ensemble_class: AutoMLEnsembleClass.Default, | |||||
| greater_is_better: true, | greater_is_better: true, | ||||
| }} | }} | ||||
| > | > | ||||
| <BasicConfig /> | <BasicConfig /> | ||||
| <ExecuteConfig disabled={disabled} /> | |||||
| <ExecuteConfig /> | |||||
| <TrialConfig /> | <TrialConfig /> | ||||
| <DatasetConfig /> | <DatasetConfig /> | ||||
| @@ -6,7 +6,7 @@ | |||||
| import KFIcon from '@/components/KFIcon'; | import KFIcon from '@/components/KFIcon'; | ||||
| import PageTitle from '@/components/PageTitle'; | import PageTitle from '@/components/PageTitle'; | ||||
| import { useCacheState } from '@/hooks/pageCacheState'; | import { useCacheState } from '@/hooks/pageCacheState'; | ||||
| import { deleteAutoMLReq, getAutoMLListReq } from '@/services/autoML'; | |||||
| import { deleteAutoMLReq, getAutoMLListReq, runAutoMLReq } from '@/services/autoML'; | |||||
| import themes from '@/styles/theme.less'; | import themes from '@/styles/theme.less'; | ||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import SessionStorage from '@/utils/sessionStorage'; | import SessionStorage from '@/utils/sessionStorage'; | ||||
| @@ -129,6 +129,24 @@ function AutoMLList() { | |||||
| navigate(`/pipeline/autoML/info/${record.id}`); | navigate(`/pipeline/autoML/info/${record.id}`); | ||||
| }; | }; | ||||
| // 启动 | |||||
| const startAutoML = async (record: AutoMLData) => { | |||||
| const [res] = await to(runAutoMLReq(record.id)); | |||||
| if (res) { | |||||
| message.success('操作成功'); | |||||
| getServiceList(); | |||||
| } | |||||
| }; | |||||
| // 停止 | |||||
| const stopAutoML = async (record: AutoMLData) => { | |||||
| const [res] = await to(runAutoMLReq(record.id)); | |||||
| if (res) { | |||||
| message.success('操作成功'); | |||||
| getServiceList(); | |||||
| } | |||||
| }; | |||||
| // 分页切换 | // 分页切换 | ||||
| const handleTableChange: TableProps<AutoMLData>['onChange'] = ( | const handleTableChange: TableProps<AutoMLData>['onChange'] = ( | ||||
| pagination, | pagination, | ||||
| @@ -202,13 +220,10 @@ function AutoMLList() { | |||||
| { | { | ||||
| title: '操作', | title: '操作', | ||||
| dataIndex: 'operation', | dataIndex: 'operation', | ||||
| width: 400, | |||||
| width: 320, | |||||
| key: 'operation', | key: 'operation', | ||||
| render: (_: any, record: AutoMLData) => ( | render: (_: any, record: AutoMLData) => ( | ||||
| <div> | <div> | ||||
| <Button type="link" size="small" key="mirror" icon={<KFIcon type="icon-jingxiang" />}> | |||||
| 镜像 | |||||
| </Button> | |||||
| <Button | <Button | ||||
| type="link" | type="link" | ||||
| size="small" | size="small" | ||||
| @@ -227,9 +242,27 @@ function AutoMLList() { | |||||
| > | > | ||||
| 复制 | 复制 | ||||
| </Button> | </Button> | ||||
| <Button type="link" size="small" key="stop" icon={<KFIcon type="icon-tingzhi" />}> | |||||
| 停止 | |||||
| </Button> | |||||
| {record.run_state === 'Running' ? ( | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="stop" | |||||
| icon={<KFIcon type="icon-tingzhi" />} | |||||
| onClick={() => startAutoML(record)} | |||||
| > | |||||
| 停止 | |||||
| </Button> | |||||
| ) : ( | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="start" | |||||
| icon={<KFIcon type="icon-yunhang" />} | |||||
| onClick={() => stopAutoML(record)} | |||||
| > | |||||
| 运行 | |||||
| </Button> | |||||
| )} | |||||
| <ConfigProvider | <ConfigProvider | ||||
| theme={{ | theme={{ | ||||
| token: { | token: { | ||||
| @@ -4,4 +4,10 @@ | |||||
| overflow-y: auto; | overflow-y: auto; | ||||
| background-color: white; | background-color: white; | ||||
| border-radius: 10px; | border-radius: 10px; | ||||
| :global { | |||||
| .kf-basic-info__item__value__text { | |||||
| white-space: pre; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -1,78 +1,303 @@ | |||||
| import { AutoMLData } from '@/pages/AutoML/types'; | |||||
| import { getAutoMLInfoReq } from '@/services/autoML'; | |||||
| import { safeInvoke } from '@/utils/functional'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import { useParams } from '@umijs/max'; | |||||
| import { Flex } from 'antd'; | import { Flex } from 'antd'; | ||||
| import { useEffect } from 'react'; | |||||
| import ConfigInfo, { type BasicInfoData } from '../ConfigInfo'; | |||||
| import CopyingText from '../CopyingText'; | |||||
| import StatusChart from '../StatusChart'; | |||||
| import { useEffect, useState } from 'react'; | |||||
| import ConfigInfo, { | |||||
| formatBoolean, | |||||
| formatDate, | |||||
| formatEnum, | |||||
| type BasicInfoData, | |||||
| } from '../ConfigInfo'; | |||||
| // import CopyingText from '../CopyingText'; | |||||
| import { AutoMLTaskType, autoMLEnsembleClassOptions, autoMLTaskTypeOptions } from '@/enums'; | |||||
| import { parseJsonText } from '@/utils'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| // 格式化数据集 | |||||
| const formatDataset = (dataset: { name: string; version: string }) => { | |||||
| if (!dataset || !dataset.name || !dataset.version) { | |||||
| return '--'; | |||||
| } | |||||
| return `${dataset.name}:${dataset.version}`; | |||||
| }; | |||||
| // 格式化优化方向 | |||||
| const formatOptimizeMode = (value: boolean) => { | |||||
| return value ? '越大越好' : '越小越好'; | |||||
| }; | |||||
| const formatMetricsWeight = (value: string) => { | |||||
| if (!value) { | |||||
| return '--'; | |||||
| } | |||||
| const json = parseJsonText(value); | |||||
| if (!json) { | |||||
| return '--'; | |||||
| } | |||||
| return Object.entries(json) | |||||
| .map(([key, value]) => `${key}:${value}`) | |||||
| .join('\n'); | |||||
| }; | |||||
| function AutoMLBasic() { | function AutoMLBasic() { | ||||
| useEffect(() => {}, []); | |||||
| const params = useParams(); | |||||
| const id = safeInvoke(Number)(params.id); | |||||
| const [basicDatas, setBasicDatas] = useState<BasicInfoData[]>([]); | |||||
| const [configDatas, setConfigDatas] = useState<BasicInfoData[]>([]); | |||||
| useEffect(() => { | |||||
| if (id) { | |||||
| getAutoMLInfo(id); | |||||
| } | |||||
| }, []); | |||||
| const datas: BasicInfoData[] = [ | |||||
| { | |||||
| label: '项目名称', | |||||
| value: '测试项目名称', | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '项目名称', | |||||
| value: '测试项目名称', | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '项目名称', | |||||
| value: '测试项目名称', | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '项目名称', | |||||
| value: '测试项目名称', | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '项目名称', | |||||
| value: '测试项目名称', | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '项目名称', | |||||
| value: '测试项目名称', | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '项目名称', | |||||
| value: '测试项目名称', | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '项目名称', | |||||
| value: <CopyingText text="测试项目名称测试项目名称测试项目名称"></CopyingText>, | |||||
| ellipsis: false, | |||||
| }, | |||||
| ]; | |||||
| // const basicDatas: BasicInfoData[] = [ | |||||
| // { | |||||
| // label: '项目名称', | |||||
| // value: '测试项目名称', | |||||
| // ellipsis: true, | |||||
| // }, | |||||
| // { | |||||
| // label: '项目名称', | |||||
| // value: '测试项目名称', | |||||
| // ellipsis: true, | |||||
| // }, | |||||
| // { | |||||
| // label: '项目名称', | |||||
| // value: '测试项目名称', | |||||
| // ellipsis: true, | |||||
| // }, | |||||
| // { | |||||
| // label: '项目名称', | |||||
| // value: '测试项目名称', | |||||
| // ellipsis: true, | |||||
| // }, | |||||
| // { | |||||
| // label: '项目名称', | |||||
| // value: '测试项目名称', | |||||
| // ellipsis: true, | |||||
| // }, | |||||
| // { | |||||
| // label: '项目名称', | |||||
| // value: '测试项目名称', | |||||
| // ellipsis: true, | |||||
| // }, | |||||
| // { | |||||
| // label: '项目名称', | |||||
| // value: '测试项目名称', | |||||
| // ellipsis: true, | |||||
| // }, | |||||
| // { | |||||
| // label: '项目名称', | |||||
| // value: <CopyingText text="测试项目名称测试项目名称测试项目名称"></CopyingText>, | |||||
| // ellipsis: false, | |||||
| // }, | |||||
| // ]; | |||||
| // 获取服务详情 | |||||
| const getAutoMLInfo = async (id: number) => { | |||||
| const [res] = await to(getAutoMLInfoReq({ id })); | |||||
| if (res && res.data) { | |||||
| const info: AutoMLData = res.data; | |||||
| const basicDatas: BasicInfoData[] = [ | |||||
| { | |||||
| label: '实验名称', | |||||
| value: info.ml_name, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '实验描述', | |||||
| value: info.ml_description, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '创建人', | |||||
| value: info.create_by, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '创建时间', | |||||
| value: info.create_time, | |||||
| ellipsis: true, | |||||
| format: formatDate, | |||||
| }, | |||||
| { | |||||
| label: '更新时间', | |||||
| value: info.update_time, | |||||
| ellipsis: true, | |||||
| format: formatDate, | |||||
| }, | |||||
| { | |||||
| label: '状态', | |||||
| value: info.run_state, | |||||
| ellipsis: true, | |||||
| }, | |||||
| ]; | |||||
| setBasicDatas(basicDatas); | |||||
| const configDatas: BasicInfoData[] = [ | |||||
| { | |||||
| label: '任务类型', | |||||
| value: info.task_type, | |||||
| ellipsis: true, | |||||
| format: formatEnum(autoMLTaskTypeOptions), | |||||
| }, | |||||
| { | |||||
| label: '特征预处理算法', | |||||
| value: info.include_feature_preprocessor, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '排除的特征预处理算法', | |||||
| value: info.exclude_feature_preprocessor, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: info.task_type === AutoMLTaskType.Regression ? '回归算法' : '分类算法', | |||||
| value: | |||||
| info.task_type === AutoMLTaskType.Regression | |||||
| ? info.include_regressor | |||||
| : info.include_classifier, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: info.task_type === AutoMLTaskType.Regression ? '排除的回归算法' : '排除的分类算法', | |||||
| value: | |||||
| info.task_type === AutoMLTaskType.Regression | |||||
| ? info.exclude_regressor | |||||
| : info.exclude_classifier, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '集成方式', | |||||
| value: info.ensemble_class, | |||||
| ellipsis: true, | |||||
| format: formatEnum(autoMLEnsembleClassOptions), | |||||
| }, | |||||
| { | |||||
| label: '集成模型数量', | |||||
| value: info.ensemble_size, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '集成最佳模型数量', | |||||
| value: info.ensemble_nbest, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '最大数量', | |||||
| value: info.max_models_on_disc, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '内存限制(MB)', | |||||
| value: info.memory_limit, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '时间限制(秒)', | |||||
| value: info.per_run_time_limit, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '搜索时间限制(秒)', | |||||
| value: info.time_left_for_this_task, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '重采样策略', | |||||
| value: info.resampling_strategy, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '交叉验证折数', | |||||
| value: info.folds, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '是否打乱', | |||||
| value: info.shuffle, | |||||
| ellipsis: true, | |||||
| format: formatBoolean, | |||||
| }, | |||||
| { | |||||
| label: '训练集比率', | |||||
| value: info.train_size, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '测试集比率', | |||||
| value: info.test_size, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '计算指标', | |||||
| value: info.scoring_functions, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '随机种子', | |||||
| value: info.seed, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '数据集', | |||||
| value: info.dataset, | |||||
| ellipsis: true, | |||||
| format: formatDataset, | |||||
| }, | |||||
| { | |||||
| label: '预测目标列', | |||||
| value: info.target_columns, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '指标名称', | |||||
| value: info.metric_name, | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '优化方向', | |||||
| value: info.greater_is_better, | |||||
| ellipsis: true, | |||||
| format: formatOptimizeMode, | |||||
| }, | |||||
| { | |||||
| label: '指标权重', | |||||
| value: info.metrics, | |||||
| ellipsis: true, | |||||
| format: formatMetricsWeight, | |||||
| }, | |||||
| ]; | |||||
| setConfigDatas(configDatas); | |||||
| } | |||||
| }; | |||||
| return ( | return ( | ||||
| <div className={styles['auto-ml-basic']}> | <div className={styles['auto-ml-basic']}> | ||||
| <Flex gap={15} align="stretch"> | <Flex gap={15} align="stretch"> | ||||
| <ConfigInfo title="基本信息" data={datas} labelWidth={70} /> | |||||
| <StatusChart | |||||
| <ConfigInfo title="基本信息" data={basicDatas} labelWidth={70} threeColumn /> | |||||
| {/* <StatusChart | |||||
| chartData={{ Failed: 10, Pending: 20, Running: 30, Succeeded: 40, Terminated: 50 }} | chartData={{ Failed: 10, Pending: 20, Running: 30, Succeeded: 40, Terminated: 50 }} | ||||
| /> | |||||
| <ConfigInfo title="Trial 配置" data={datas} labelWidth={70} /> | |||||
| /> */} | |||||
| </Flex> | </Flex> | ||||
| <ConfigInfo | <ConfigInfo | ||||
| title="搜索配置" | |||||
| data={datas} | |||||
| style={{ marginTop: '16px' }} | |||||
| labelWidth={70} | |||||
| title="配置信息" | |||||
| data={configDatas.slice(0, -3)} | |||||
| labelWidth={150} | |||||
| threeColumn | threeColumn | ||||
| style={{ marginTop: '20px' }} | |||||
| /> | /> | ||||
| <ConfigInfo | <ConfigInfo | ||||
| title="执行配置" | |||||
| data={datas} | |||||
| style={{ marginTop: '16px' }} | |||||
| title="优化指标" | |||||
| data={configDatas.slice(-3)} | |||||
| labelWidth={70} | labelWidth={70} | ||||
| threeColumn | threeColumn | ||||
| style={{ marginTop: '20px' }} | |||||
| /> | /> | ||||
| </div> | </div> | ||||
| ); | ); | ||||
| @@ -3,7 +3,8 @@ import classNames from 'classnames'; | |||||
| import { useEffect } from 'react'; | import { useEffect } from 'react'; | ||||
| import ConfigTitle from '../ConfigTitle'; | import ConfigTitle from '../ConfigTitle'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| export { type BasicInfoData }; | |||||
| export * from '@/components/BasicInfo/format'; | |||||
| export type { BasicInfoData }; | |||||
| type ConfigInfoProps = { | type ConfigInfoProps = { | ||||
| title: string; | title: string; | ||||
| @@ -10,7 +10,7 @@ function DatasetConfig() { | |||||
| <> | <> | ||||
| <SubAreaTitle | <SubAreaTitle | ||||
| title="数据集配置" | title="数据集配置" | ||||
| image={require('@/assets/img/search-config-icon.png')} | |||||
| image={require('@/assets/img/dataset-config-icon.png')} | |||||
| style={{ marginTop: '20px', marginBottom: '24px' }} | style={{ marginTop: '20px', marginBottom: '24px' }} | ||||
| ></SubAreaTitle> | ></SubAreaTitle> | ||||
| <Row gutter={8}> | <Row gutter={8}> | ||||
| @@ -3,9 +3,11 @@ import { | |||||
| AutoMLEnsembleClass, | AutoMLEnsembleClass, | ||||
| AutoMLResamplingStrategy, | AutoMLResamplingStrategy, | ||||
| AutoMLTaskType, | AutoMLTaskType, | ||||
| resamplingStrategyOptions, | |||||
| autoMLEnsembleClassOptions, | |||||
| autoMLResamplingStrategyOptions, | |||||
| autoMLTaskTypeOptions, | |||||
| } from '@/enums'; | } from '@/enums'; | ||||
| import { Col, Form, Input, InputNumber, Radio, Row, Select, Switch } from 'antd'; | |||||
| import { Col, Form, InputNumber, Radio, Row, Select, Switch } from 'antd'; | |||||
| // 分类算法 | // 分类算法 | ||||
| const classificationAlgorithms = [ | const classificationAlgorithms = [ | ||||
| @@ -120,10 +122,10 @@ function ExecuteConfig() { | |||||
| name="task_type" | name="task_type" | ||||
| rules={[{ required: true, message: '请选择任务类型' }]} | rules={[{ required: true, message: '请选择任务类型' }]} | ||||
| > | > | ||||
| <Radio.Group onChange={() => form.resetFields(['metrics'])}> | |||||
| <Radio value={AutoMLTaskType.Classification}>分类</Radio> | |||||
| <Radio value={AutoMLTaskType.Regression}>回归</Radio> | |||||
| </Radio.Group> | |||||
| <Radio.Group | |||||
| options={autoMLTaskTypeOptions} | |||||
| onChange={() => form.resetFields(['metrics'])} | |||||
| ></Radio.Group> | |||||
| </Form.Item> | </Form.Item> | ||||
| </Col> | </Col> | ||||
| </Row> | </Row> | ||||
| @@ -259,10 +261,7 @@ function ExecuteConfig() { | |||||
| name="ensemble_class" | name="ensemble_class" | ||||
| tooltip="仅使用单个最佳模型还是集成模型" | tooltip="仅使用单个最佳模型还是集成模型" | ||||
| > | > | ||||
| <Radio.Group> | |||||
| <Radio value={AutoMLEnsembleClass.Default}>集成模型</Radio> | |||||
| <Radio value={AutoMLEnsembleClass.SingleBest}>单一最佳模型</Radio> | |||||
| </Radio.Group> | |||||
| <Radio.Group options={autoMLEnsembleClassOptions}></Radio.Group> | |||||
| </Form.Item> | </Form.Item> | ||||
| </Col> | </Col> | ||||
| </Row> | </Row> | ||||
| @@ -357,7 +356,7 @@ function ExecuteConfig() { | |||||
| <Select | <Select | ||||
| allowClear | allowClear | ||||
| placeholder="请选择重采样策略" | placeholder="请选择重采样策略" | ||||
| options={resamplingStrategyOptions} | |||||
| options={autoMLResamplingStrategyOptions} | |||||
| showSearch | showSearch | ||||
| /> | /> | ||||
| </Form.Item> | </Form.Item> | ||||
| @@ -389,7 +388,7 @@ function ExecuteConfig() { | |||||
| <Row gutter={8}> | <Row gutter={8}> | ||||
| <Col span={10}> | <Col span={10}> | ||||
| <Form.Item label="shuffle" name="shuffle" tooltip="拆分数据前是否进行 shuffle"> | |||||
| <Form.Item label="是否打乱" name="shuffle" tooltip="拆分数据前是否打乱顺序"> | |||||
| <Switch /> | <Switch /> | ||||
| </Form.Item> | </Form.Item> | ||||
| </Col> | </Col> | ||||
| @@ -444,7 +443,7 @@ function ExecuteConfig() { | |||||
| </Col> | </Col> | ||||
| </Row> | </Row> | ||||
| <Row gutter={8}> | |||||
| {/* <Row gutter={8}> | |||||
| <Col span={10}> | <Col span={10}> | ||||
| <Form.Item | <Form.Item | ||||
| label="文件夹路径" | label="文件夹路径" | ||||
| @@ -461,7 +460,7 @@ function ExecuteConfig() { | |||||
| <Input placeholder="请输入文件夹路径" maxLength={64} showCount allowClear /> | <Input placeholder="请输入文件夹路径" maxLength={64} showCount allowClear /> | ||||
| </Form.Item> | </Form.Item> | ||||
| </Col> | </Col> | ||||
| </Row> | |||||
| </Row> */} | |||||
| {/* <Form.List name="hyper-parameter"> | {/* <Form.List name="hyper-parameter"> | ||||
| {(fields, { add, remove }) => ( | {(fields, { add, remove }) => ( | ||||
| @@ -21,7 +21,7 @@ function TrialConfig() { | |||||
| <SubAreaTitle | <SubAreaTitle | ||||
| title="优化指标" | title="优化指标" | ||||
| image={require('@/assets/img/trial-config-icon.png')} | image={require('@/assets/img/trial-config-icon.png')} | ||||
| style={{ marginBottom: '26px' }} | |||||
| style={{ marginTop: '20px', marginBottom: '24px' }} | |||||
| ></SubAreaTitle> | ></SubAreaTitle> | ||||
| <Row gutter={8}> | <Row gutter={8}> | ||||
| <Col span={10}> | <Col span={10}> | ||||
| @@ -37,7 +37,7 @@ function TrialConfig() { | |||||
| {(fields, { add, remove }) => ( | {(fields, { add, remove }) => ( | ||||
| <> | <> | ||||
| {fields.map(({ key, name, ...restField }, index) => ( | {fields.map(({ key, name, ...restField }, index) => ( | ||||
| <Flex key={key} align="flex-start" className={styles['advanced-config']}> | |||||
| <Flex key={key} align="flex-start" className={styles['metrics-weight']}> | |||||
| <Form.Item | <Form.Item | ||||
| style={{ flex: 1, marginBottom: 0, minWidth: 0 }} | style={{ flex: 1, marginBottom: 0, minWidth: 0 }} | ||||
| {...restField} | {...restField} | ||||
| @@ -88,10 +88,11 @@ function TrialConfig() { | |||||
| </Flex> | </Flex> | ||||
| ))} | ))} | ||||
| {fields.length === 0 && ( | {fields.length === 0 && ( | ||||
| <Form.Item style={{ marginBottom: 0 }}> | |||||
| <Form.Item className={styles['add-weight']}> | |||||
| <Button | <Button | ||||
| style={{ background: 'white' }} | |||||
| type="dashed" | |||||
| className={styles['add-weight__button']} | |||||
| color="primary" | |||||
| variant="dashed" | |||||
| onClick={() => add()} | onClick={() => add()} | ||||
| block | block | ||||
| icon={<PlusCircleOutlined />} | icon={<PlusCircleOutlined />} | ||||
| @@ -1,4 +1,4 @@ | |||||
| .advanced-config { | |||||
| .metrics-weight { | |||||
| margin-bottom: 20px; | margin-bottom: 20px; | ||||
| &:last-child { | &:last-child { | ||||
| @@ -6,6 +6,19 @@ | |||||
| } | } | ||||
| } | } | ||||
| .add-weight { | |||||
| margin-bottom: 0; | |||||
| // 增加样式权重 | |||||
| & &__button { | |||||
| border-color: .addAlpha(@primary-color, 0.5) []; | |||||
| box-shadow: none !important; | |||||
| &:hover { | |||||
| border-style: solid; | |||||
| } | |||||
| } | |||||
| } | |||||
| // .command { | // .command { | ||||
| // width: 83.33%; | // width: 83.33%; | ||||
| // margin-bottom: 20px; | // margin-bottom: 20px; | ||||
| @@ -10,32 +10,32 @@ export enum OperationType { | |||||
| export type FormData = { | export type FormData = { | ||||
| ml_name: string; // 实验名称 | ml_name: string; // 实验名称 | ||||
| ml_description: string; // 实验描述 | ml_description: string; // 实验描述 | ||||
| ensemble_class?: string; // 集成构建 | |||||
| ensemble_nbest?: string; | |||||
| ensemble_size?: number; | |||||
| include_classifier?: string[]; | |||||
| include_feature_preprocessor?: string[]; | |||||
| include_regressor?: string[]; | |||||
| ensemble_class?: string; // 集成方式 | |||||
| ensemble_nbest?: string; // 集成最佳模型数量 | |||||
| ensemble_size?: number; // 集成模型数量 | |||||
| include_classifier?: string[]; // 分类算法 | |||||
| include_feature_preprocessor?: string[]; // 特征预处理算法 | |||||
| include_regressor?: string[]; // 回归算法 | |||||
| exclude_classifier?: string[]; | exclude_classifier?: string[]; | ||||
| exclude_feature_preprocessor?: string[]; | exclude_feature_preprocessor?: string[]; | ||||
| exclude_regressor?: string[]; | exclude_regressor?: string[]; | ||||
| max_models_on_disc?: number; | |||||
| memory_limit?: number; | |||||
| metric_name?: string; | |||||
| greater_is_better: boolean; | |||||
| per_run_time_limit?: number; | |||||
| resampling_strategy?: string; | |||||
| scoring_functions?: string; | |||||
| shuffle?: boolean; | |||||
| seed?: number; | |||||
| target_columns: string; | |||||
| task_type: string; | |||||
| test_size?: number; | |||||
| train_size?: number; | |||||
| time_left_for_this_task: number; | |||||
| tmp_folder?: string; | |||||
| metrics?: { name: string; value: number }[]; | |||||
| dataset: ParameterInputObject; // 模型 | |||||
| max_models_on_disc?: number; // 最大数量 | |||||
| memory_limit?: number; // 内存限制(MB) | |||||
| per_run_time_limit?: number; // 时间限制(秒) | |||||
| resampling_strategy?: string; // 重采样策略 | |||||
| folds?: number; // 交叉验证折数 | |||||
| scoring_functions?: string; // 计算指标 | |||||
| shuffle?: boolean; // 是否打乱 | |||||
| seed?: number; // 随机种子 | |||||
| task_type: string; // 任务类型 | |||||
| test_size?: number; // 测试集比率 | |||||
| train_size?: number; // 训练集比率 | |||||
| time_left_for_this_task: number; // 搜索时间限制(秒) | |||||
| metric_name?: string; // 指标名称 | |||||
| greater_is_better: boolean; // 指标优化方向 | |||||
| metrics?: { name: string; value: number }[]; // 指标权重 | |||||
| dataset: ParameterInputObject; // 数据集 | |||||
| target_columns: string; // 预测目标列 | |||||
| }; | }; | ||||
| export type AutoMLData = { | export type AutoMLData = { | ||||
| @@ -51,6 +51,10 @@ export type AutoMLData = { | |||||
| exclude_feature_preprocessor?: string; | exclude_feature_preprocessor?: string; | ||||
| exclude_regressor?: string; | exclude_regressor?: string; | ||||
| dataset?: string; | dataset?: string; | ||||
| create_by?: string; | |||||
| create_time?: string; | |||||
| update_by?: string; | |||||
| update_time?: string; | |||||
| } & Omit< | } & Omit< | ||||
| FormData, | FormData, | ||||
| 'metrics|dataset|include_classifier|include_feature_preprocessor|include_regressor|exclude_classifier|exclude_feature_preprocessor|exclude_regressor' | 'metrics|dataset|include_classifier|include_feature_preprocessor|include_regressor|exclude_classifier|exclude_feature_preprocessor|exclude_regressor' | ||||
| @@ -16,7 +16,7 @@ export function getAutoMLListReq(params) { | |||||
| } | } | ||||
| // 查询自动学习详情 | // 查询自动学习详情 | ||||
| export function getDatasetInfoReq(params) { | |||||
| export function getAutoMLInfoReq(params) { | |||||
| return request(`/api/mmp/autoML/getAutoMlDetail`, { | return request(`/api/mmp/autoML/getAutoMlDetail`, { | ||||
| method: 'GET', | method: 'GET', | ||||
| params, | params, | ||||
| @@ -198,7 +198,7 @@ export const fittingString = (str: string, maxWidth: number, fontSize: number): | |||||
| * @param {any} str - the string to be checked | * @param {any} str - the string to be checked | ||||
| * @return {boolean} true if the string is empty, undefined, or null, false otherwise | * @return {boolean} true if the string is empty, undefined, or null, false otherwise | ||||
| */ | */ | ||||
| export const isEmptyString = (str: any): boolean => { | |||||
| export const isEmpty = (str: any): boolean => { | |||||
| return str === '' || str === undefined || str === null; | return str === '' || str === undefined || str === null; | ||||
| }; | }; | ||||
| @@ -256,3 +256,13 @@ export const trimCharacter = (str: string, ch: string): string => { | |||||
| const reg = new RegExp(`^${ch}|${ch}$`, 'g'); | const reg = new RegExp(`^${ch}|${ch}$`, 'g'); | ||||
| return str.trim().replace(reg, ''); | return str.trim().replace(reg, ''); | ||||
| }; | }; | ||||
| /** | |||||
| * Converts an empty string to undefined. | |||||
| * | |||||
| * @param {string} [value] - The string to convert. | |||||
| * @return {string | undefined} The converted string or undefined. | |||||
| */ | |||||
| export const convertEmptyStringToUndefined = (value?: string): string | undefined => { | |||||
| return value === '' ? undefined : value; | |||||
| }; | |||||