fix: edit gpu_selector failed

This commit is contained in:
jialin
2025-09-17 19:53:40 +08:00
parent 4d9dec8511
commit bf400547e1
17 changed files with 296 additions and 544 deletions
+1
View File
@@ -78,6 +78,7 @@ export default {
colorText: 'rgba(0,0,0,1)',
colorPrimary: '#007BFF',
colorSuccess: '#54cc98',
colorBorder: '#d3d0d9',
borderRadius: 4,
borderRadiusSM: 2,
colorBgContainer: '#fff',
+15 -56
View File
@@ -8,8 +8,8 @@ import _ from 'lodash';
import React, { forwardRef, useImperativeHandle } from 'react';
import { excludeFields, ScheduleValueMap, sourceOptions } from '../config';
import { backendOptionsMap } from '../config/backend-parameters';
import { FormInnerContext } from '../config/form-context';
import { FormData, SourceType } from '../config/types';
import { FormContext } from '../config/form-context';
import { DeployFormKey, FormData, SourceType } from '../config/types';
import CatalogFrom from '../forms/catalog';
import HuggingFaceForm from '../forms/hugging-face';
import LocalPathForm from '../forms/local-path';
@@ -21,8 +21,8 @@ interface DataFormProps {
ref?: any;
source: SourceType;
action: PageActionType;
selectedModel: any;
isGGUF: boolean;
formKey: DeployFormKey;
sourceDisable?: boolean;
backendOptions?: Global.BaseOption<string>[];
sourceList?: Global.BaseOption<string>[];
@@ -38,6 +38,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
const {
action,
isGGUF,
formKey,
initialValues,
sourceDisable = true,
backendOptions,
@@ -77,7 +78,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
});
}
form.setFieldsValue({
...updates,
backend_version: '',
backend_parameters: [],
env: null
});
@@ -116,11 +117,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
// generate the data is available for the backend including the gpu_ids
const handleOk = async (formdata: FormData) => {
let data = _.cloneDeep(formdata);
data.categories = Array.isArray(data.categories)
? data.categories
: data.categories
? [data.categories]
: [];
data.categories = data.categories ? [data.categories] : [];
const gpuSelector = generateGPUIds(data);
const allValues = {
..._.omit(data, ['scheduleType']),
@@ -166,18 +163,21 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
getFieldsValue: () => {
return form.getFieldsValue();
},
getGPUOptionList(params: { clusterId: number }) {
getGPUOptionList(params);
getGPUOptionList: async (params: { clusterId: number }) => {
return await getGPUOptionList(params);
}
};
});
return (
<FormInnerContext.Provider
<FormContext.Provider
value={{
onBackendChange: handleBackendChange,
isGGUF: isGGUF,
formKey: formKey,
pageAction: action,
gpuOptions: gpuOptions,
onValuesChange: onValuesChange,
gpuOptions: gpuOptions
onBackendChange: handleBackendChange
}}
>
<Form
@@ -261,47 +261,6 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
></SealSelect>
}
</Form.Item>
{/* <Form.Item name="backend" rules={[{ required: true }]}>
<SealSelect
required
onChange={handleBackendChange}
label={intl.formatMessage({ id: 'models.form.backend' })}
description={<TooltipList list={backendTipsList}></TooltipList>}
options={
backendOptions ?? [
{
label: backendLabelMap[backendOptionsMap.vllm],
value: backendOptionsMap.vllm,
disabled:
props.source === modelSourceMap.local_path_value
? false
: isGGUF
},
{
label: backendLabelMap[backendOptionsMap.ascendMindie],
value: backendOptionsMap.ascendMindie,
disabled:
props.source === modelSourceMap.local_path_value
? false
: isGGUF
},
{
label: backendLabelMap[backendOptionsMap.voxBox],
value: backendOptionsMap.voxBox,
disabled:
props.source === modelSourceMap.local_path_value
? false
: props.source === modelSourceMap.ollama_library_value ||
isGGUF
}
]
}
disabled={
action === PageAction.EDIT &&
props.source !== modelSourceMap.local_path_value
}
></SealSelect>
</Form.Item> */}
<CatalogFrom></CatalogFrom>
<Form.Item<FormData> name="description">
<SealInput.TextArea
@@ -321,7 +280,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
handleBackendChange={handleBackendChange}
></AdvanceConfig>
</Form>
</FormInnerContext.Provider>
</FormContext.Provider>
);
});
@@ -11,11 +11,12 @@ import styled from 'styled-components';
import { queryCatalogItemSpec } from '../apis';
import {
defaultFormValues,
deployFormKeyMap,
modelCategoriesMap,
sourceOptions
} from '../config';
import { backendOptionsMap } from '../config/backend-parameters';
import { FormContext } from '../config/form-context';
import { CatalogFormContext } from '../config/form-context';
import { CatalogSpec, FormData, ListItem, SourceType } from '../config/types';
import { useCheckCompatibility } from '../hooks';
import useFormInitialValues from '../hooks/use-form-initial-values';
@@ -107,8 +108,12 @@ const AddModal: React.FC<AddModalProps> = (props) => {
const [isGGUF, setIsGGUF] = useState<boolean>(false);
const [sourceList, setSourceList] = useState<any[]>([]);
const [backendList, setBackendList] = useState<any[]>([]);
const [sizeOptions, setSizeOptions] = useState<any[]>([]);
const [quantizationOptions, setQuantizationOptions] = useState<any[]>([]);
const [sizeOptions, setSizeOptions] = useState<Global.BaseOption<number>[]>(
[]
);
const [quantizationOptions, setQuantizationOptions] = useState<
Global.BaseOption<string>[]
>([]);
const sourceGroupMap = useRef<any>({});
const axiosToken = useRef<any>(null);
const selectSpecRef = useRef<CatalogSpec>({} as CatalogSpec);
@@ -529,16 +534,12 @@ const AddModal: React.FC<AddModalProps> = (props) => {
width={width}
footer={false}
>
<FormContext.Provider
<CatalogFormContext.Provider
value={{
isGGUF: isGGUF,
byBuiltIn: true,
sizeOptions: sizeOptions,
quantizationOptions: quantizationOptions,
pageAction: action,
onSizeChange: handleOnSizeChange,
onQuantizationChange: handleOnQuantizationChange,
onValuesChange: onValuesChange
onQuantizationChange: handleOnQuantizationChange
}}
>
<FormWrapper>
@@ -590,10 +591,10 @@ const AddModal: React.FC<AddModalProps> = (props) => {
fields={[]}
source={source}
action={action}
selectedModel={{}}
onOk={handleOk}
ref={form}
isGGUF={isGGUF}
formKey={deployFormKeyMap.catalog}
sourceDisable={false}
backendOptions={backendList}
sourceList={sourceList}
@@ -605,7 +606,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
</>
</ColumnWrapper>
</FormWrapper>
</FormContext.Provider>
</CatalogFormContext.Provider>
</GSDrawer>
);
};
+61 -86
View File
@@ -1,20 +1,14 @@
import ModalFooter from '@/components/modal-footer';
import GSDrawer from '@/components/scroller-modal/gs-drawer';
import { PageActionType } from '@/config/types';
import useDeferredRequest from '@/hooks/use-deferred-request';
import { ProviderValueMap } from '@/pages/cluster-management/config';
import { useIntl } from '@umijs/max';
import { Button } from 'antd';
import _ from 'lodash';
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import styled from 'styled-components';
import {
defaultFormValues,
getSourceRepoConfigValue,
modelSourceMap
} from '../config';
import { defaultFormValues, deployFormKeyMap, modelSourceMap } from '../config';
import { backendOptionsMap } from '../config/backend-parameters';
import { FormContext } from '../config/form-context';
import { FormData, SourceType } from '../config/types';
import {
MessageStatus,
@@ -32,16 +26,10 @@ import SearchModel from './search-model';
import Separator from './separator';
import TitleWrapper from './title-wrapper';
const resetFieldsByModel = ['backend_version', 'backend_parameters', 'env'];
const pickFieldsFromSpec = ['backend_version', 'backend_parameters', 'env'];
const dropFieldsFromForm = ['name', 'file_name', 'repo_id', 'backend'];
const resetFields = ['worker_selector', 'env'];
const resetFieldsByFile = [
'cpu_offloading',
'distributed_inference_across_workers'
];
const ModalFooterStyle = {
padding: '16px 24px',
display: 'flex',
@@ -133,11 +121,6 @@ const AddModal: FC<AddModalProps> = (props) => {
const requestModelIdRef = useRef<number>(0);
const currentSelectedModel = useRef<any>({});
const { run: fetchModelFiles } = useDeferredRequest(
() => modelFileRef.current?.fetchModelFiles?.(),
100
);
const updateSelectedModel = (model: any) => {
currentSelectedModel.current = model;
setSelectedModel(model);
@@ -310,8 +293,8 @@ const AddModal: FC<AddModalProps> = (props) => {
};
const handleOnOk = async (allValues: FormData) => {
const result = getSourceRepoConfigValue(props.source, allValues).values;
onOk(result);
console.log('handleOnOk:', allValues);
onOk(allValues);
};
const handleSubmitAnyway = async () => {
@@ -503,74 +486,66 @@ const AddModal: FC<AddModalProps> = (props) => {
</>
)}
<FormContext.Provider
value={{
isGGUF: isGGUF,
pageAction: action,
onValuesChange: onValuesChange
}}
>
<FormWrapper>
<ColumnWrapper
paddingBottom={warningStatus.show ? 170 : 50}
footer={
<>
<CompatibilityAlert
showClose={true}
onClose={() => {
setWarningStatus({
show: false,
message: ''
});
}}
warningStatus={warningStatus}
contentStyle={{ paddingInline: 0 }}
></CompatibilityAlert>
<ModalFooter
onCancel={handleCancel}
onOk={handleSumit}
showOkBtn={!showExtraButton}
extra={
showExtraButton && (
<Button
type="primary"
onClick={handleSubmitAnyway}
disabled={isGGUF}
>
{intl.formatMessage({
id: 'models.form.submit.anyway'
})}
</Button>
)
}
style={ModalFooterStyle}
></ModalFooter>
</>
}
>
<FormWrapper>
<ColumnWrapper
paddingBottom={warningStatus.show ? 170 : 50}
footer={
<>
{SEARCH_SOURCE.includes(source) &&
deploymentType === 'modelList' && (
<TitleWrapper>
{intl.formatMessage({ id: 'models.form.configurations' })}
</TitleWrapper>
)}
<DataForm
initialValues={initialValues}
source={source}
action={action}
clusterList={clusterList}
selectedModel={selectedModel}
onOk={handleOnOk}
ref={form}
isGGUF={isGGUF}
onBackendChange={handleBackendChange}
onValuesChange={onValuesChange}
></DataForm>
<CompatibilityAlert
showClose={true}
onClose={() => {
setWarningStatus({
show: false,
message: ''
});
}}
warningStatus={warningStatus}
contentStyle={{ paddingInline: 0 }}
></CompatibilityAlert>
<ModalFooter
onCancel={handleCancel}
onOk={handleSumit}
showOkBtn={!showExtraButton}
extra={
showExtraButton && (
<Button
type="primary"
onClick={handleSubmitAnyway}
disabled={isGGUF}
>
{intl.formatMessage({
id: 'models.form.submit.anyway'
})}
</Button>
)
}
style={ModalFooterStyle}
></ModalFooter>
</>
</ColumnWrapper>
</FormWrapper>
</FormContext.Provider>
}
>
<>
{SEARCH_SOURCE.includes(source) &&
deploymentType === 'modelList' && (
<TitleWrapper>
{intl.formatMessage({ id: 'models.form.configurations' })}
</TitleWrapper>
)}
<DataForm
formKey={deployFormKeyMap.deployment}
initialValues={initialValues}
source={source}
action={action}
clusterList={clusterList}
onOk={handleOnOk}
ref={form}
isGGUF={isGGUF}
onBackendChange={handleBackendChange}
onValuesChange={onValuesChange}
></DataForm>
</>
</ColumnWrapper>
</FormWrapper>
</div>
</GSDrawer>
);
+4 -25
View File
@@ -7,7 +7,7 @@ import { Form } from 'antd';
import React from 'react';
import { scheduleList, ScheduleValueMap } from '../config';
import { backendOptionsMap } from '../config/backend-parameters';
import { useFormContext, useFormInnerContext } from '../config/form-context';
import { useCatalogFormContext, useFormContext } from '../config/form-context';
import GPUCard from './gpu-card';
const scheduleTypeTips = [
@@ -29,8 +29,8 @@ const scheduleTypeTips = [
const Performance: React.FC = () => {
const intl = useIntl();
const { gpuOptions } = useFormInnerContext();
const { onValuesChange, onQuantizationChange } = useFormContext();
const { onValuesChange, gpuOptions } = useFormContext();
const { onQuantizationChange } = useCatalogFormContext();
const { getRuleMessage } = useAppUtils();
const form = Form.useFormInstance();
@@ -62,28 +62,7 @@ const Performance: React.FC = () => {
<Form.Item name={['gpu_selector', 'gpu_type']}>
<SealSelect
label={intl.formatMessage({ id: 'models.form.gpuType' })}
options={[
{
label: 'NVIDIA 4090',
value: 'nvidia-4090'
},
{
label: 'NVIDIA A100',
value: 'nvidia-a100'
},
{
label: 'NVIDIA H100',
value: 'nvidia-h100'
},
{
label: 'Huawei 910B',
value: 'huawei-910b'
},
{
label: 'Huawei 910C',
value: 'huawei-910c'
}
]}
options={[]}
></SealSelect>
</Form.Item>
<Form.Item name={['gpu_selector', 'gpu_count']}>
+2 -47
View File
@@ -1,11 +1,10 @@
import { getRequestId, setRquestId } from '@/atoms/models';
import BaseSelect from '@/components/seal-form/base/select';
import { createAxiosToken } from '@/hooks/use-chunk-request';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Pagination, Tooltip } from 'antd';
import { Pagination } from 'antd';
import _ from 'lodash';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import styled from 'styled-components';
import {
evaluationsModelSpec,
@@ -62,7 +61,6 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
const {
modelSource,
isDownload,
hasLinuxWorker,
gpuOptions,
clusterId,
setLoadingModel,
@@ -94,7 +92,6 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
const axiosTokenRef = useRef<any>(null);
const checkTokenRef = useRef<any>(null);
const searchInputRef = useRef<any>('');
const filterGGUFRef = useRef<boolean | undefined>(!hasLinuxWorker);
const filterTaskRef = useRef<string>('');
const timer = useRef<any>(null);
const requestIdRef = useRef<number>(0);
@@ -458,15 +455,6 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
});
};
const handleFilterGGUFChange = (e: any) => {
filterGGUFRef.current = e.target.checked;
handleOnSearchRepo({
sortType: dataSource.sortType,
page: 1,
perPage: query.perPage
});
};
const handleOnPageChange = (page: number) => {
if (modelSource === modelSourceMap.huggingface_value) {
const currentList = getCurrentPage(page);
@@ -507,32 +495,6 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
handleOnSelectModel(model, true);
};
const renderGGUFTips = useMemo(() => {
return (
<Tooltip
styles={{
body: {
width: 'max-content'
}
}}
title={
<UL>
<li>{intl.formatMessage({ id: 'models.search.gguf.tips' })}</li>
<li>{intl.formatMessage({ id: 'models.search.vllm.tips' })}</li>
<li>
{intl.formatMessage({
id: 'models.search.voxbox.tips'
})}
</li>
</UL>
}
>
GGUF
<QuestionCircleOutlined className="m-l-4" />
</Tooltip>
);
}, [intl]);
const renderHFSearch = () => {
return (
<>
@@ -562,13 +524,6 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
size="middle"
style={{ width: '150px' }}
></BaseSelect>
{/* <Checkbox
onChange={handleFilterGGUFChange}
className="m-l-8"
checked={filterGGUFRef.current}
>
{renderGGUFTips}
</Checkbox> */}
</span>
<PaginationMain
simple={{ readOnly: true }}
+2 -4
View File
@@ -123,7 +123,7 @@ const Models: React.FC<ModelsProps> = ({
loadend,
total
}) => {
const { getGPUOptionList, generateFormValues, clusterList, getClusterList } =
const { generateFormValues, clusterList, getClusterList } =
useFormInitialValues();
const { saveScrollHeight, restoreScrollHeight } = useBodyScroll();
const [updateFormInitials, setUpdateFormInitials] = useState<{
@@ -188,9 +188,7 @@ const Models: React.FC<ModelsProps> = ({
useEffect(() => {
const getData = async () => {
const res = await getClusterList();
const clusterId = res[0]?.value;
await getGPUOptionList({ clusterId });
await getClusterList();
};
getData();
return () => {
+46 -160
View File
@@ -1,38 +1,29 @@
import ModalFooter from '@/components/modal-footer';
import SealInput from '@/components/seal-form/seal-input';
import SealSelect from '@/components/seal-form/seal-select';
import { PageAction } from '@/config';
import { PageActionType } from '@/config/types';
import useAppUtils from '@/hooks/use-app-utils';
import { useIntl } from '@umijs/max';
import { Button, Form, Modal } from 'antd';
import { Button, Modal } from 'antd';
import _ from 'lodash';
import React, { useEffect, useMemo, useRef } from 'react';
import {
updateExcludeFields as excludeFields,
getSourceRepoConfigValue,
deployFormKeyMap,
modelSourceMap,
ScheduleValueMap,
sourceOptions,
updateIgnoreFields
} from '../config';
import { backendOptionsMap } from '../config/backend-parameters';
import { FormContext, FormInnerContext } from '../config/form-context';
import { FormData, ListItem } from '../config/types';
import HuggingFaceForm from '../forms/hugging-face';
import LocalPathForm from '../forms/local-path';
import { FormData } from '../config/types';
import { generateGPUSelector } from '../config/utils';
import { useCheckCompatibility } from '../hooks';
import { useGenerateGPUOptions } from '../hooks/use-form-initial-values';
import AdvanceConfig from './advance-config';
import ColumnWrapper from './column-wrapper';
import CompatibilityAlert from './compatible-alert';
import DataForm from './data-form';
type AddModalProps = {
title: string;
action: PageActionType;
open: boolean;
updateFormInitials: {
data?: ListItem;
data: FormData;
isGGUF: boolean;
};
clusterList: Global.BaseOption<
@@ -56,22 +47,15 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
const intl = useIntl();
const {
setWarningStatus,
generateGPUIds,
handleBackendChangeBefore,
checkTokenRef,
warningStatus
} = useCheckCompatibility();
const { getGPUOptionList, gpuOptions } = useGenerateGPUOptions();
const { getRuleMessage } = useAppUtils();
const [form] = Form.useForm();
const formRef = useRef<any>(null);
const submitAnyway = useRef<boolean>(false);
const originFormData = useRef<any>(null);
const handleClusterChange = (value: number) => {
getGPUOptionList({ clusterId: value });
};
const setOriginalFormData = () => {
if (!originFormData.current) {
originFormData.current = _.cloneDeep(formData);
@@ -91,7 +75,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
};
const handleOnValuesChange = _.debounce((data: any) => {
const formdata = form.getFieldsValue?.();
const formdata = formRef.current?.getFieldsValue?.();
console.log('handleOnValuesChange:', formdata);
let alldata = {};
@@ -138,10 +122,11 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
// voxbox is not support multi gpu
const handleSetGPUIds = (backend: string) => {
const gpuids = form.getFieldValue(['gpu_selector', 'gpu_ids']) || [];
const gpuids =
formRef.current?.getFieldValue(['gpu_selector', 'gpu_ids']) || [];
if (backend === backendOptionsMap.voxBox && gpuids.length > 0) {
form.setFieldValue(['gpu_selector', 'gpu_ids'], [gpuids[0]]);
formRef.current?.setFieldValue(['gpu_selector', 'gpu_ids'], [gpuids[0]]);
}
};
@@ -155,10 +140,14 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
cpu_offloading: true
});
}
form.setFieldsValue({ ...updates, backend_parameters: [], env: null });
formRef.current?.setFieldsValue({
...updates,
backend_parameters: [],
env: null
});
handleSetGPUIds(backend);
const data = form.getFieldsValue?.();
const data = formRef.current?.getFieldsValue?.();
const res = handleBackendChangeBefore(data);
if (res.show) {
return;
@@ -185,23 +174,20 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
};
const handleSumit = () => {
form.submit();
formRef.current?.submit();
};
const handleSubmitAnyway = async () => {
submitAnyway.current = true;
form.submit?.();
formRef.current?.submit?.();
};
const handleOk = async (data: FormData) => {
const formdata = getSourceRepoConfigValue(data.source, data).values;
const handleOk = async (formdata: FormData) => {
let submitData = {} as FormData;
const isVoxBox = [backendOptionsMap.voxBox].includes(formdata.backend);
submitData = {
..._.omit(formdata, ['scheduleType']),
categories: formdata.categories ? [formdata.categories] : [],
worker_selector:
formdata.scheduleType === ScheduleValueMap.Manual
? null
@@ -211,25 +197,13 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
distributed_inference_across_workers: false,
cpu_offloading: false
}
: {}),
...generateGPUIds(formdata)
: {})
};
onOk(submitData);
};
const onValuesChange = (changedValues: any, allValues: any) => {
const fieldName = Object.keys(changedValues)[0];
if (excludeFields.includes(fieldName)) {
return;
}
handleOnValuesChange({
changedValues,
allValues,
source: formData?.source as string
});
};
const handleManulOnValuesChange = (changedValues: any, allValues: any) => {
console.log('handleManulOnValuesChange:', { changedValues, allValues });
handleOnValuesChange({
changedValues,
allValues,
@@ -249,17 +223,20 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
);
}, [warningStatus.show, warningStatus.type, warningStatus.isDefault]);
const isVllmOrAscend = useMemo(() => {
return (
formData?.backend === backendOptionsMap.vllm ||
formData?.backend === backendOptionsMap.ascendMindie
);
}, [formData?.backend]);
useEffect(() => {
const initGPUSelector = async () => {
const gpuOptions = await formRef.current?.getGPUOptionList({
clusterId: formData.cluster_id
});
const gpuSelector = generateGPUSelector(formData, gpuOptions);
formRef.current?.setFieldsValue(gpuSelector);
};
if (open && formData) {
setOriginalFormData();
getGPUOptionList({ clusterId: formData.cluster_id });
setTimeout(() => {
setOriginalFormData();
initGPUSelector();
}, 100);
}
if (!open) {
checkTokenRef.current?.cancel?.();
@@ -339,109 +316,18 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
</>
}
>
<FormContext.Provider
value={{
isGGUF: isGGUF,
pageAction: action,
onValuesChange: handleManulOnValuesChange
}}
>
<FormInnerContext.Provider
value={{
onBackendChange: handleBackendChange,
gpuOptions: gpuOptions
}}
>
<Form
name="updateModalForm"
form={form}
onFinish={handleOk}
onValuesChange={onValuesChange}
scrollToFirstError={true}
preserve={false}
clearOnDestroy={true}
initialValues={{
...formData
}}
style={{
padding: 'var(--ant-modal-content-padding)',
paddingBlock: 0
}}
>
<Form.Item<FormData>
name="name"
rules={[
{
required: true,
message: getRuleMessage('input', 'common.table.name')
}
]}
>
<SealInput.Input
label={intl.formatMessage({
id: 'common.table.name'
})}
required
></SealInput.Input>
</Form.Item>
<Form.Item<FormData>
name="source"
rules={[
{
required: true,
message: getRuleMessage('select', 'models.form.source')
}
]}
>
<SealSelect
disabled={true}
label={intl.formatMessage({
id: 'models.form.source'
})}
options={sourceOptions}
required
></SealSelect>
</Form.Item>
<HuggingFaceForm></HuggingFaceForm>
<LocalPathForm></LocalPathForm>
<Form.Item<FormData>
name="cluster_id"
rules={[
{
required: true,
message: getRuleMessage('select', 'Cluster', false)
}
]}
>
{
<SealSelect
onChange={handleClusterChange}
label="Cluster"
options={clusterList}
required
></SealSelect>
}
</Form.Item>
<Form.Item<FormData> name="description">
<SealInput.TextArea
scaleSize={true}
label={intl.formatMessage({
id: 'common.table.description'
})}
></SealInput.TextArea>
</Form.Item>
<AdvanceConfig
form={form}
gpuOptions={gpuOptions}
action={PageAction.EDIT}
source={formData?.source || ''}
isGGUF={formData?.backend === backendOptionsMap.llamaBox}
></AdvanceConfig>
</Form>
</FormInnerContext.Provider>
</FormContext.Provider>
<DataForm
formKey={deployFormKeyMap.deployment}
initialValues={formData}
source={formData.source || ''}
action={action}
clusterList={clusterList}
onOk={handleOk}
ref={formRef}
isGGUF={isGGUF}
onBackendChange={handleAsyncBackendChange}
onValuesChange={handleManulOnValuesChange}
></DataForm>
</ColumnWrapper>
</Modal>
);
+13 -14
View File
@@ -1,31 +1,30 @@
import { PageActionType } from '@/config/types';
import React from 'react';
import { DeployFormKey } from './types';
interface FormContextProps {
isGGUF?: boolean;
byBuiltIn?: boolean;
formKey: DeployFormKey;
source?: string;
pageAction: PageActionType;
sizeOptions?: Global.BaseOption<number>[];
quantizationOptions?: Global.BaseOption<string>[];
gpuOptions?: any[];
onSizeChange?: (val: number) => void;
onQuantizationChange?: (val: string) => void;
onValuesChange?: (changedValues: any, allValues: any) => void;
onBackendChange?: (backend: string) => void;
}
interface FormInnerContextProps {
onBackendChange?: (backend: string) => void;
onValuesChange?: (changedValues: any, allValues: any) => void;
gpuOptions?: any[];
interface CatalogFormContextProps {
sizeOptions: Global.BaseOption<number>[];
quantizationOptions: Global.BaseOption<string>[];
onSizeChange: (val: number) => void;
onQuantizationChange: (val: string) => void;
}
export const FormContext = React.createContext<FormContextProps>(
{} as FormContextProps
);
export const FormInnerContext = React.createContext<FormInnerContextProps>(
{} as FormInnerContextProps
export const CatalogFormContext = React.createContext<CatalogFormContextProps>(
{} as CatalogFormContextProps
);
export const useFormContext = () => {
@@ -36,11 +35,11 @@ export const useFormContext = () => {
return context;
};
export const useFormInnerContext = () => {
const context = React.useContext(FormInnerContext);
export const useCatalogFormContext = () => {
const context = React.useContext(CatalogFormContext);
if (!context) {
throw new Error(
'useFormInnerContext must be used within a FormInnerProvider'
'useCatalogFormContext must be used within a CatalogFormProvider'
);
}
return context;
+6 -54
View File
@@ -1,7 +1,7 @@
import { StatusMaps } from '@/config';
import { EditOutlined } from '@ant-design/icons';
import _ from 'lodash';
import { backendOptionsMap } from './backend-parameters';
import { DeployFormKey } from './types';
export const backendTipsList = [
{
@@ -277,59 +277,6 @@ export const modelCategories = [
...categoryOptions
];
export const sourceRepoConfig = {
[modelSourceMap.huggingface_value]: {
repo_id: 'huggingface_repo_id',
file_name: 'huggingface_filename'
},
[modelSourceMap.modelscope_value]: {
repo_id: 'model_scope_model_id',
file_name: 'model_scope_file_path'
}
};
export const getSourceRepoConfigValue = (
source: string,
data: any
): {
values: typeof data;
} => {
const config: Record<string, any> = sourceRepoConfig[source] || {};
const result: Record<string, any> = {};
const omits: string[] = [];
Object.keys(config)?.forEach((key: string) => {
if (config[key]) {
result[config[key]] = data[key];
omits.push(key);
}
});
return {
values: { ...result, ..._.omit(data, omits) }
};
};
export const setSourceRepoConfigValue = (
source: string,
data: any
): {
values: Record<string, any>;
} => {
const config: Record<string, any> = sourceRepoConfig[source] || {};
const result: Record<string, any> = {};
const omits: string[] = [];
Object.keys(config)?.forEach((key: string) => {
if (config[key]) {
result[key] = data[config[key]];
omits.push(config[key]);
}
});
return {
values: { ...result, ..._.omit(data, omits) }
};
};
export const getbackendParameters = (data: any) => {
const backendParameters = data.backend_parameters || {};
const result: string[] = [];
@@ -487,3 +434,8 @@ export const scheduleTypeTips = [
tips: 'models.form.scheduletype.manual.tips'
}
];
export const deployFormKeyMap: Record<string, DeployFormKey> = {
deployment: 'deployment',
catalog: 'catalog'
};
+3 -1
View File
@@ -30,6 +30,8 @@ export interface ListItem {
worker_selector?: object;
}
export type DeployFormKey = 'deployment' | 'catalog';
export type SourceType =
| 'huggingface'
| 'model_scope'
@@ -45,7 +47,7 @@ export interface FormData {
categories?: string[];
backend_parameters?: string[];
backend_version?: string;
source: string;
source: SourceType;
repo_id: string;
file_name: string;
huggingface_repo_id: string;
+33
View File
@@ -0,0 +1,33 @@
import _ from 'lodash';
import { backendOptionsMap } from '../config/backend-parameters';
export const generateGPUSelector = (data: any, gpuOptions: any[]) => {
const gpu_ids = _.get(data, 'gpu_selector.gpu_ids', []);
if (gpu_ids.length === 0) {
return {
gpu_selector: null
};
}
const valueMap = new Map<string, string>();
gpuOptions?.forEach((item) => {
item.children?.forEach((child: any) => {
valueMap.set(child.value, item.value);
});
});
const gpuids: string[][] = gpu_ids
.map((id: string) => {
const parent = valueMap.get(id);
return parent ? [parent, id] : null;
})
.filter(Boolean) as string[][];
const result = data.backend === backendOptionsMap.voxBox ? gpuids[0] : gpuids;
return {
gpu_selector: {
gpu_ids: result
}
};
};
+10 -8
View File
@@ -2,25 +2,27 @@ import SealSelect from '@/components/seal-form/seal-select';
import useAppUtils from '@/hooks/use-app-utils';
import { Form } from 'antd';
import React from 'react';
import { useFormContext } from '../config/form-context';
import { deployFormKeyMap } from '../config';
import { useCatalogFormContext, useFormContext } from '../config/form-context';
import { FormData } from '../config/types';
const CatalogForm: React.FC = () => {
const formCtx = useFormContext();
const catalogFormCtx = useCatalogFormContext();
const { getRuleMessage } = useAppUtils();
const { formKey } = formCtx;
const {
isGGUF,
byBuiltIn,
sizeOptions,
quantizationOptions,
onSizeChange,
onQuantizationChange
} = formCtx;
const source = Form.useWatch('source');
} = catalogFormCtx;
console.log('HuggingFaceForm', { source, isGGUF });
if (!byBuiltIn && !sizeOptions?.length && !quantizationOptions?.length) {
if (
formKey !== deployFormKeyMap.catalog &&
!sizeOptions?.length &&
!quantizationOptions?.length
) {
return null;
}
+62 -24
View File
@@ -1,10 +1,9 @@
import SealInput from '@/components/seal-form/seal-input';
import { PageAction } from '@/config';
import useAppUtils from '@/hooks/use-app-utils';
import { useIntl } from '@umijs/max';
import { Form } from 'antd';
import React from 'react';
import { modelSourceMap } from '../config';
import { deployFormKeyMap, modelSourceMap } from '../config';
import { useFormContext } from '../config/form-context';
import { FormData } from '../config/types';
@@ -12,18 +11,15 @@ const HuggingFaceForm: React.FC = () => {
const formInstance = Form.useFormInstance();
const formCtx = useFormContext();
const { getRuleMessage } = useAppUtils();
const intl = useIntl();
const { isGGUF, byBuiltIn, pageAction, onValuesChange } = formCtx;
const { formKey, pageAction, onValuesChange } = formCtx;
const source = Form.useWatch('source');
console.log('HuggingFaceForm', { source, isGGUF });
if (
![
modelSourceMap.huggingface_value,
modelSourceMap.modelscope_value
].includes(source) ||
byBuiltIn
formKey === deployFormKeyMap.catalog
) {
return null;
}
@@ -34,23 +30,65 @@ const HuggingFaceForm: React.FC = () => {
return (
<>
<Form.Item<FormData>
name="repo_id"
key="repo_id"
rules={[
{
required: true,
message: getRuleMessage('input', 'models.form.repoid')
}
]}
>
<SealInput.Input
label="Base Model"
required
disabled={pageAction === PageAction.CREATE}
onBlur={handleOnBlur}
></SealInput.Input>
</Form.Item>
{source === modelSourceMap.huggingface_value ? (
<>
<Form.Item<FormData>
name="huggingface_repo_id"
key="huggingface_repo_id"
rules={[
{
required: true,
message: getRuleMessage('input', 'models.form.repoid')
}
]}
>
<SealInput.Input
label="Base Model"
required
disabled={pageAction === PageAction.CREATE}
onBlur={handleOnBlur}
></SealInput.Input>
</Form.Item>
<Form.Item<FormData>
hidden
name="huggingface_filename"
key="huggingface_filename"
>
<SealInput.Input
disabled={pageAction === PageAction.CREATE}
></SealInput.Input>
</Form.Item>
</>
) : (
<>
<Form.Item<FormData>
name="model_scope_model_id"
key="model_scope_model_id"
rules={[
{
required: true,
message: getRuleMessage('input', 'models.form.repoid')
}
]}
>
<SealInput.Input
label="Base Model"
required
disabled={pageAction === PageAction.CREATE}
onBlur={handleOnBlur}
></SealInput.Input>
</Form.Item>
<Form.Item<FormData>
hidden
name="model_scope_file_path"
key="model_scope_file_path"
>
<SealInput.Input
disabled={pageAction === PageAction.CREATE}
></SealInput.Input>
</Form.Item>
</>
)}
</>
);
};
+7 -6
View File
@@ -5,24 +5,25 @@ import { useIntl } from '@umijs/max';
import { Form } from 'antd';
import _ from 'lodash';
import React, { useRef } from 'react';
import { localPathTipsList, modelSourceMap } from '../config';
import { deployFormKeyMap, localPathTipsList, modelSourceMap } from '../config';
import { backendOptionsMap } from '../config/backend-parameters';
import { useFormContext, useFormInnerContext } from '../config/form-context';
import { useFormContext } from '../config/form-context';
import { FormData } from '../config/types';
import { checkOnlyAscendNPU } from '../hooks';
const LocalPathForm: React.FC = () => {
const form = Form.useFormInstance();
const formCtx = useFormContext();
const formInnerCtx = useFormInnerContext();
const source = Form.useWatch('source', form);
const { onBackendChange, onValuesChange, gpuOptions } = formInnerCtx;
const { byBuiltIn } = formCtx;
const { formKey, gpuOptions, onValuesChange, onBackendChange } = formCtx;
const { getRuleMessage } = useAppUtils();
const intl = useIntl();
const localPathCache = useRef<string>(form.getFieldValue('local_path') || '');
if (![modelSourceMap.local_path_value].includes(source) || byBuiltIn) {
if (
![modelSourceMap.local_path_value].includes(source) ||
formKey === deployFormKeyMap.catalog
) {
return null;
}
+12 -11
View File
@@ -8,11 +8,7 @@ import { useAtomValue } from 'jotai';
import _ from 'lodash';
import { useEffect, useRef, useState } from 'react';
import { evaluationsModelSpec } from '../apis';
import {
getSourceRepoConfigValue,
modelSourceMap,
modelTaskMap
} from '../config';
import { modelSourceMap, modelTaskMap } from '../config';
import { handleRecognizeAudioModel } from '../config/audio-catalog';
import { backendOptionsMap } from '../config/backend-parameters';
import { EvaluateResult, FormData } from '../config/types';
@@ -394,6 +390,7 @@ export const useCheckCompatibility = () => {
const generateGPUIds = (data: FormData) => {
const gpu_ids = _.get(data, 'gpu_selector.gpu_ids', []);
console.log('generateGPUIds', gpu_ids);
if (!gpu_ids.length) {
return {
gpu_selector: null
@@ -454,11 +451,10 @@ export const useCheckCompatibility = () => {
return;
}
cacheFormValuesRef.current = allValues;
const data = getSourceRepoConfigValue(source, allValues);
const gpuSelector = generateGPUIds(data.values);
cacheFormValuesRef.current = _.cloneDeep(allValues);
const gpuSelector = generateGPUIds(allValues);
return await handleDoEvalute({
...data.values,
...allValues,
...gpuSelector,
replicas: allValues.replicas || 0
});
@@ -534,8 +530,13 @@ export const useSelectModel = (data: { gpuOptions: any[] }) => {
});
return {
repo_id: selectModel.name,
file_name: '',
...(source === modelSourceMap.huggingface_value
? { huggingface_repo_id: selectModel.name }
: {}),
...(source === modelSourceMap.modelscope_value
? { model_scope_model_id: selectModel.name }
: {}),
...modelTaskData,
name: name,
source: source,
backend: backend
@@ -8,11 +8,9 @@ import {
} from '@/pages/resources/config';
import { ListItem as WorkerListItem } from '@/pages/resources/config/types';
import { useAtom } from 'jotai';
import _ from 'lodash';
import { useState } from 'react';
import { queryGPUList } from '../apis';
import { ScheduleValueMap, setSourceRepoConfigValue } from '../config';
import { backendOptionsMap } from '../config/backend-parameters';
import { ScheduleValueMap } from '../config';
import { GPUListItem, ListItem } from '../config/types';
type EmptyObject = Record<never, never>;
@@ -100,6 +98,7 @@ export const useGenerateGPUOptions = () => {
setGpuOptions(gpuList);
return gpuList;
};
return {
getGPUOptionList,
gpuOptions
@@ -190,7 +189,7 @@ export const useGenerateWorkerOptions = () => {
};
export default function useFormInitialValues() {
const { getGPUOptionList } = useGenerateGPUOptions();
const { getGPUOptionList, gpuOptions } = useGenerateGPUOptions();
const [, setClusterListAtom] = useAtom(clusterListAtom);
const [clusterList, setClusterList] = useState<
@@ -220,43 +219,13 @@ export default function useFormInitialValues() {
}
};
const generateGPUSelector = (data: any, gpuOptions: any[]) => {
const gpu_ids = _.get(data, 'gpu_selector.gpu_ids', []);
if (gpu_ids.length === 0) {
return [];
}
const valueMap = new Map<string, string>();
gpuOptions?.forEach((item) => {
item.children?.forEach((child: any) => {
valueMap.set(child.value, item.value);
});
});
const gpuids: string[][] = gpu_ids
.map((id: string) => {
const parent = valueMap.get(id);
return parent ? [parent, id] : null;
})
.filter(Boolean) as string[][];
return data.backend === backendOptionsMap.voxBox ? gpuids[0] : gpuids;
};
const generateFormValues = (data: ListItem, gpuOptions: any[]) => {
const result = setSourceRepoConfigValue(data?.source || '', data);
const formData = {
...result.values,
...data,
categories: data?.categories?.length ? data.categories[0] : null,
scheduleType: data?.gpu_selector
? ScheduleValueMap.Manual
: ScheduleValueMap.Auto,
gpu_selector: data?.gpu_selector?.gpu_ids?.length
? {
gpu_ids: generateGPUSelector(data, gpuOptions)
}
: null
: ScheduleValueMap.Auto
};
return formData;
};
@@ -265,6 +234,7 @@ export default function useFormInitialValues() {
getGPUOptionList,
generateFormValues,
getClusterList,
clusterList
clusterList,
gpuOptions
};
}