diff --git a/src/config/theme/light.ts b/src/config/theme/light.ts index d9971fd0..0f61c8e4 100644 --- a/src/config/theme/light.ts +++ b/src/config/theme/light.ts @@ -78,6 +78,7 @@ export default { colorText: 'rgba(0,0,0,1)', colorPrimary: '#007BFF', colorSuccess: '#54cc98', + colorBorder: '#d3d0d9', borderRadius: 4, borderRadiusSM: 2, colorBgContainer: '#fff', diff --git a/src/pages/llmodels/components/data-form.tsx b/src/pages/llmodels/components/data-form.tsx index 3571656d..14b1c15a 100644 --- a/src/pages/llmodels/components/data-form.tsx +++ b/src/pages/llmodels/components/data-form.tsx @@ -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[]; sourceList?: Global.BaseOption[]; @@ -38,6 +38,7 @@ const DataForm: React.FC = forwardRef((props, ref) => { const { action, isGGUF, + formKey, initialValues, sourceDisable = true, backendOptions, @@ -77,7 +78,7 @@ const DataForm: React.FC = forwardRef((props, ref) => { }); } form.setFieldsValue({ - ...updates, + backend_version: '', backend_parameters: [], env: null }); @@ -116,11 +117,7 @@ const DataForm: React.FC = 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 = forwardRef((props, ref) => { getFieldsValue: () => { return form.getFieldsValue(); }, - getGPUOptionList(params: { clusterId: number }) { - getGPUOptionList(params); + getGPUOptionList: async (params: { clusterId: number }) => { + return await getGPUOptionList(params); } }; }); return ( -
= forwardRef((props, ref) => { > } - {/* - } - 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 - } - > - */} name="description"> = forwardRef((props, ref) => { handleBackendChange={handleBackendChange} > -
+ ); }); diff --git a/src/pages/llmodels/components/deploy-builtin-modal.tsx b/src/pages/llmodels/components/deploy-builtin-modal.tsx index 514dd027..7b065501 100644 --- a/src/pages/llmodels/components/deploy-builtin-modal.tsx +++ b/src/pages/llmodels/components/deploy-builtin-modal.tsx @@ -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 = (props) => { const [isGGUF, setIsGGUF] = useState(false); const [sourceList, setSourceList] = useState([]); const [backendList, setBackendList] = useState([]); - const [sizeOptions, setSizeOptions] = useState([]); - const [quantizationOptions, setQuantizationOptions] = useState([]); + const [sizeOptions, setSizeOptions] = useState[]>( + [] + ); + const [quantizationOptions, setQuantizationOptions] = useState< + Global.BaseOption[] + >([]); const sourceGroupMap = useRef({}); const axiosToken = useRef(null); const selectSpecRef = useRef({} as CatalogSpec); @@ -529,16 +534,12 @@ const AddModal: React.FC = (props) => { width={width} footer={false} > - @@ -590,10 +591,10 @@ const AddModal: React.FC = (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 = (props) => { - + ); }; diff --git a/src/pages/llmodels/components/deploy-modal.tsx b/src/pages/llmodels/components/deploy-modal.tsx index 26c854e4..3d8ebca8 100644 --- a/src/pages/llmodels/components/deploy-modal.tsx +++ b/src/pages/llmodels/components/deploy-modal.tsx @@ -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 = (props) => { const requestModelIdRef = useRef(0); const currentSelectedModel = useRef({}); - const { run: fetchModelFiles } = useDeferredRequest( - () => modelFileRef.current?.fetchModelFiles?.(), - 100 - ); - const updateSelectedModel = (model: any) => { currentSelectedModel.current = model; setSelectedModel(model); @@ -310,8 +293,8 @@ const AddModal: FC = (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 = (props) => { )} - - - - { - setWarningStatus({ - show: false, - message: '' - }); - }} - warningStatus={warningStatus} - contentStyle={{ paddingInline: 0 }} - > - - {intl.formatMessage({ - id: 'models.form.submit.anyway' - })} - - ) - } - style={ModalFooterStyle} - > - - } - > + + - {SEARCH_SOURCE.includes(source) && - deploymentType === 'modelList' && ( - - {intl.formatMessage({ id: 'models.form.configurations' })} - - )} - + { + setWarningStatus({ + show: false, + message: '' + }); + }} + warningStatus={warningStatus} + contentStyle={{ paddingInline: 0 }} + > + + {intl.formatMessage({ + id: 'models.form.submit.anyway' + })} + + ) + } + style={ModalFooterStyle} + > - - - + } + > + <> + {SEARCH_SOURCE.includes(source) && + deploymentType === 'modelList' && ( + + {intl.formatMessage({ id: 'models.form.configurations' })} + + )} + + + + ); diff --git a/src/pages/llmodels/components/performance.tsx b/src/pages/llmodels/components/performance.tsx index 34f66db4..339990bc 100644 --- a/src/pages/llmodels/components/performance.tsx +++ b/src/pages/llmodels/components/performance.tsx @@ -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 = () => { diff --git a/src/pages/llmodels/components/search-model.tsx b/src/pages/llmodels/components/search-model.tsx index d90b485f..599d5d28 100644 --- a/src/pages/llmodels/components/search-model.tsx +++ b/src/pages/llmodels/components/search-model.tsx @@ -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 = (props) => { const { modelSource, isDownload, - hasLinuxWorker, gpuOptions, clusterId, setLoadingModel, @@ -94,7 +92,6 @@ const SearchModel: React.FC = (props) => { const axiosTokenRef = useRef(null); const checkTokenRef = useRef(null); const searchInputRef = useRef(''); - const filterGGUFRef = useRef(!hasLinuxWorker); const filterTaskRef = useRef(''); const timer = useRef(null); const requestIdRef = useRef(0); @@ -458,15 +455,6 @@ const SearchModel: React.FC = (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 = (props) => { handleOnSelectModel(model, true); }; - const renderGGUFTips = useMemo(() => { - return ( - -
  • {intl.formatMessage({ id: 'models.search.gguf.tips' })}
  • -
  • {intl.formatMessage({ id: 'models.search.vllm.tips' })}
  • -
  • - {intl.formatMessage({ - id: 'models.search.voxbox.tips' - })} -
  • - - } - > - GGUF - -
    - ); - }, [intl]); - const renderHFSearch = () => { return ( <> @@ -562,13 +524,6 @@ const SearchModel: React.FC = (props) => { size="middle" style={{ width: '150px' }} > - {/* - {renderGGUFTips} - */} = ({ 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 = ({ useEffect(() => { const getData = async () => { - const res = await getClusterList(); - const clusterId = res[0]?.value; - await getGPUOptionList({ clusterId }); + await getClusterList(); }; getData(); return () => { diff --git a/src/pages/llmodels/components/update-modal.tsx b/src/pages/llmodels/components/update-modal.tsx index 7cd14f44..aae326fc 100644 --- a/src/pages/llmodels/components/update-modal.tsx +++ b/src/pages/llmodels/components/update-modal.tsx @@ -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 = (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(null); const submitAnyway = useRef(false); const originFormData = useRef(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 = (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 = (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 = (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 = (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 = (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 = (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 = (props) => { } > - - -
    - - name="name" - rules={[ - { - required: true, - message: getRuleMessage('input', 'common.table.name') - } - ]} - > - - - - name="source" - rules={[ - { - required: true, - message: getRuleMessage('select', 'models.form.source') - } - ]} - > - - - - - - - name="cluster_id" - rules={[ - { - required: true, - message: getRuleMessage('select', 'Cluster', false) - } - ]} - > - { - - } - - name="description"> - - - - - -
    -
    + ); diff --git a/src/pages/llmodels/config/form-context.ts b/src/pages/llmodels/config/form-context.ts index e0825acc..a8e7937c 100644 --- a/src/pages/llmodels/config/form-context.ts +++ b/src/pages/llmodels/config/form-context.ts @@ -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[]; - quantizationOptions?: Global.BaseOption[]; 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[]; + quantizationOptions: Global.BaseOption[]; + onSizeChange: (val: number) => void; + onQuantizationChange: (val: string) => void; } export const FormContext = React.createContext( {} as FormContextProps ); -export const FormInnerContext = React.createContext( - {} as FormInnerContextProps +export const CatalogFormContext = React.createContext( + {} 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; diff --git a/src/pages/llmodels/config/index.ts b/src/pages/llmodels/config/index.ts index 18381979..3385c127 100644 --- a/src/pages/llmodels/config/index.ts +++ b/src/pages/llmodels/config/index.ts @@ -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 = sourceRepoConfig[source] || {}; - const result: Record = {}; - 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; -} => { - const config: Record = sourceRepoConfig[source] || {}; - const result: Record = {}; - 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 = { + deployment: 'deployment', + catalog: 'catalog' +}; diff --git a/src/pages/llmodels/config/types.ts b/src/pages/llmodels/config/types.ts index 0663e016..d8fcec7c 100644 --- a/src/pages/llmodels/config/types.ts +++ b/src/pages/llmodels/config/types.ts @@ -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; diff --git a/src/pages/llmodels/config/utils.ts b/src/pages/llmodels/config/utils.ts new file mode 100644 index 00000000..df656b78 --- /dev/null +++ b/src/pages/llmodels/config/utils.ts @@ -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(); + 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 + } + }; +}; diff --git a/src/pages/llmodels/forms/catalog.tsx b/src/pages/llmodels/forms/catalog.tsx index 09194908..243c704f 100644 --- a/src/pages/llmodels/forms/catalog.tsx +++ b/src/pages/llmodels/forms/catalog.tsx @@ -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; } diff --git a/src/pages/llmodels/forms/hugging-face.tsx b/src/pages/llmodels/forms/hugging-face.tsx index 80b33a53..d4a95681 100644 --- a/src/pages/llmodels/forms/hugging-face.tsx +++ b/src/pages/llmodels/forms/hugging-face.tsx @@ -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 ( <> - - name="repo_id" - key="repo_id" - rules={[ - { - required: true, - message: getRuleMessage('input', 'models.form.repoid') - } - ]} - > - -
    + {source === modelSourceMap.huggingface_value ? ( + <> + + name="huggingface_repo_id" + key="huggingface_repo_id" + rules={[ + { + required: true, + message: getRuleMessage('input', 'models.form.repoid') + } + ]} + > + + + + hidden + name="huggingface_filename" + key="huggingface_filename" + > + + + + ) : ( + <> + + name="model_scope_model_id" + key="model_scope_model_id" + rules={[ + { + required: true, + message: getRuleMessage('input', 'models.form.repoid') + } + ]} + > + + + + hidden + name="model_scope_file_path" + key="model_scope_file_path" + > + + + + )} ); }; diff --git a/src/pages/llmodels/forms/local-path.tsx b/src/pages/llmodels/forms/local-path.tsx index d939df4c..ddb6cbdf 100644 --- a/src/pages/llmodels/forms/local-path.tsx +++ b/src/pages/llmodels/forms/local-path.tsx @@ -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(form.getFieldValue('local_path') || ''); - if (![modelSourceMap.local_path_value].includes(source) || byBuiltIn) { + if ( + ![modelSourceMap.local_path_value].includes(source) || + formKey === deployFormKeyMap.catalog + ) { return null; } diff --git a/src/pages/llmodels/hooks/index.ts b/src/pages/llmodels/hooks/index.ts index af0a014f..9302ded4 100644 --- a/src/pages/llmodels/hooks/index.ts +++ b/src/pages/llmodels/hooks/index.ts @@ -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 diff --git a/src/pages/llmodels/hooks/use-form-initial-values.ts b/src/pages/llmodels/hooks/use-form-initial-values.ts index 0dc09dfd..16905d88 100644 --- a/src/pages/llmodels/hooks/use-form-initial-values.ts +++ b/src/pages/llmodels/hooks/use-form-initial-values.ts @@ -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; @@ -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(); - 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 }; }