diff --git a/src/locales/en-US/models.ts b/src/locales/en-US/models.ts index a458ed62..35133761 100644 --- a/src/locales/en-US/models.ts +++ b/src/locales/en-US/models.ts @@ -212,5 +212,6 @@ export default { 'models.form.kvCache.tips': 'Available only with built-in backends (vLLM / SGLang) — switch backend in Advanced to enable.', 'models.form.kvCache.tips2': - 'KV cache is only supported when using built-in inference backends (vLLM or SGLang).' + 'KV cache is only supported when using built-in inference backends (vLLM or SGLang).', + 'models.form.scheduling': 'Scheduling' }; diff --git a/src/locales/ja-JP/models.ts b/src/locales/ja-JP/models.ts index 4dfca12e..429aca80 100644 --- a/src/locales/ja-JP/models.ts +++ b/src/locales/ja-JP/models.ts @@ -209,7 +209,8 @@ export default { 'models.form.kvCache.tips': 'Available only with built-in backends (vLLM / SGLang) — switch backend in Advanced to enable.', 'models.form.kvCache.tips2': - 'KV cache is only supported when using built-in inference backends (vLLM or SGLang).' + 'KV cache is only supported when using built-in inference backends (vLLM or SGLang).', + 'models.form.scheduling': 'Scheduling' }; // ========== To-Do: Translate Keys (Remove After Translation) ========== @@ -255,5 +256,6 @@ export default { // 42. 'models.mymodels.status.active': 'Active' // 43. 'models.form.remoteURL.tips': 'Refer to the configuration documentation for details.', // 44. 'models.form.kvCache.tips': 'Available only with built-in backends (vLLM / SGLang) — switch backend in Advanced to enable.' -// 45. 'models.form.kvCache.tips2': 'KV cache is only supported when using built-in inference backends (vLLM or SGLang).' +// 45. 'models.form.kvCache.tips2': 'KV cache is only supported when using built-in inference backends (vLLM or SGLang).', +// 46. 'models.form.scheduling': 'Scheduling' // ========== End of To-Do List ========== diff --git a/src/locales/ru-RU/models.ts b/src/locales/ru-RU/models.ts index 19e67e9d..5f1d73f9 100644 --- a/src/locales/ru-RU/models.ts +++ b/src/locales/ru-RU/models.ts @@ -212,7 +212,8 @@ export default { 'models.form.kvCache.tips': 'Available only with built-in backends (vLLM / SGLang) — switch backend in Advanced to enable.', 'models.form.kvCache.tips2': - 'KV cache is only supported when using built-in inference backends (vLLM or SGLang).' + 'KV cache is only supported when using built-in inference backends (vLLM or SGLang).', + 'models.form.scheduling': 'Scheduling' }; // ========== To-Do: Translate Keys (Remove After Translation) ========== @@ -222,4 +223,5 @@ export default { // 5. 'models.form.remoteURL.tips': 'Refer to the configuration documentation for details.', // 6. 'models.form.kvCache.tips': 'Available only with built-in backends (vLLM / SGLang) — switch backend in Advanced to enable.' // 7. 'models.form.kvCache.tips2': 'KV cache is only supported when using built-in inference backends (vLLM or SGLang).'; +// 8. 'models.form.scheduling': 'Scheduling' // ========== End of To-Do List ========== diff --git a/src/locales/zh-CN/models.ts b/src/locales/zh-CN/models.ts index 736ce4f7..a7c2383d 100644 --- a/src/locales/zh-CN/models.ts +++ b/src/locales/zh-CN/models.ts @@ -200,5 +200,6 @@ export default { 'models.form.kvCache.tips': '仅在内置后端(vLLM / SGLang)可用 —— 请在高级配置中切换后端以启用。', 'models.form.kvCache.tips2': - '仅在使用内置推理后端(vLLM 或 SGLang)时支持 KV 缓存。' + '仅在使用内置推理后端(vLLM 或 SGLang)时支持 KV 缓存。', + 'models.form.scheduling': '调度' }; diff --git a/src/pages/llmodels/forms/advance-config.tsx b/src/pages/llmodels/forms/advance-config.tsx index aad9e1d5..681e03e5 100644 --- a/src/pages/llmodels/forms/advance-config.tsx +++ b/src/pages/llmodels/forms/advance-config.tsx @@ -1,50 +1,25 @@ import LabelSelector from '@/components/label-selector'; -import { LabelSelectorContext } from '@/components/label-selector/context'; import CheckboxField from '@/components/seal-form/checkbox-field'; import SealSelect from '@/components/seal-form/seal-select'; -import TooltipList from '@/components/tooltip-list'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; import { useCallback } from 'react'; -import { - modelCategories, - placementStrategyOptions, - ScheduleValueMap -} from '../config'; +import { modelCategories, ScheduleValueMap } from '../config'; import { backendOptionsMap } from '../config/backend-parameters'; import { useFormContext } from '../config/form-context'; import { FormData } from '../config/types'; import Backend from '../forms/backend'; import BackendParametersList from '../forms/backend-parameters-list'; -import ScheduleTypeForm from '../forms/schedule-type'; - -const placementStrategyTips = [ - { - title: 'Spread', - tips: 'resources.form.spread.tips' - }, - { - title: 'Binpack', - tips: 'resources.form.binpack.tips' - } -]; const AdvanceConfig = () => { const intl = useIntl(); const form = Form.useFormInstance(); - const wokerSelector = Form.useWatch('worker_selector', form); const EnviromentVars = Form.useWatch('env', form); const scheduleType = Form.useWatch('scheduleType', form); const backend = Form.useWatch('backend', form); - const { onValuesChange, workerLabelOptions } = useFormContext(); + const { onValuesChange } = useFormContext(); - const handleWorkerLabelsChange = useCallback( - (labels: Record) => { - form.setFieldValue('worker_selector', labels); - }, - [] - ); const handleEnviromentVarsChange = useCallback( (labels: Record) => { form.setFieldValue('env', labels); @@ -63,14 +38,6 @@ const AdvanceConfig = () => { } }; - const handleSelectorOnBlur = () => { - onSelectorChange('worker_selector'); - }; - - const handleDeleteWorkerSelector = (index: number) => { - onValuesChange?.({}, form.getFieldsValue()); - }; - const handleEnvSelectorOnBlur = () => { onSelectorChange('env', true); }; @@ -96,75 +63,7 @@ const AdvanceConfig = () => { options={modelCategories} > - - {scheduleType === ScheduleValueMap.Auto && ( - <> - name="placement_strategy"> - - } - > - - - - name="worker_selector" - rules={[ - ({ getFieldValue }) => ({ - validator(rule, value) { - if ( - getFieldValue('scheduleType') === ScheduleValueMap.Auto && - _.keys(value).length > 0 - ) { - if (_.some(_.keys(value), (k: string) => !value[k])) { - return Promise.reject( - intl.formatMessage( - { - id: 'common.validate.value' - }, - { - name: intl.formatMessage({ - id: 'models.form.selector' - }) - } - ) - ); - } - } - return Promise.resolve(); - } - }) - ]} - > - - {intl.formatMessage({ - id: 'resources.form.workerSelector.description' - })} - - } - > - - - - )} - name="env"> = forwardRef((props, ref) => { label: intl.formatMessage({ id: 'common.title.basicInfo' }), field: 'name' }, + { + value: 'scheduling', + label: intl.formatMessage({ id: 'models.form.scheduling' }), + field: 'scheduleType' + }, { value: 'performance', label: intl.formatMessage({ id: 'models.form.performance' }), @@ -378,18 +384,22 @@ const DataForm: React.FC = forwardRef((props, ref) => { accordion={false} onChange={handleOnCollapseChange} items={[ + { + key: 'scheduling', + label: intl.formatMessage({ id: 'models.form.scheduling' }), + forceRender: true, + children: + }, { key: 'performance', label: intl.formatMessage({ id: 'models.form.performance' }), forceRender: true, - extra:
, children: }, { key: 'advanced', label: intl.formatMessage({ id: 'resources.form.advanced' }), forceRender: true, - extra:
, children: } ]} diff --git a/src/pages/llmodels/forms/schedule-type.tsx b/src/pages/llmodels/forms/schedule-type.tsx index ce48eb95..8c7841dd 100644 --- a/src/pages/llmodels/forms/schedule-type.tsx +++ b/src/pages/llmodels/forms/schedule-type.tsx @@ -1,3 +1,5 @@ +import LabelSelector from '@/components/label-selector'; +import { LabelSelectorContext } from '@/components/label-selector/context'; import SealInputNumber from '@/components/seal-form/input-number'; import SealCascader from '@/components/seal-form/seal-cascader'; import SealSelect from '@/components/seal-form/seal-select'; @@ -5,11 +7,29 @@ import TooltipList from '@/components/tooltip-list'; import useAppUtils from '@/hooks/use-app-utils'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; +import _ from 'lodash'; import React from 'react'; import GPUCard from '../components/gpu-card'; -import { gpusCountTypeMap, scheduleList, ScheduleValueMap } from '../config'; +import { + gpusCountTypeMap, + placementStrategyOptions, + scheduleList, + ScheduleValueMap +} from '../config'; import { backendOptionsMap } from '../config/backend-parameters'; import { useFormContext } from '../config/form-context'; +import { FormData } from '../config/types'; + +const placementStrategyTips = [ + { + title: 'Spread', + tips: 'resources.form.spread.tips' + }, + { + title: 'Binpack', + tips: 'resources.form.binpack.tips' + } +]; const scheduleTypeTips = [ { @@ -47,11 +67,12 @@ const gpuAllocateTypeTips = [ const ScheduleTypeForm: React.FC = () => { const intl = useIntl(); - const { onValuesChange, gpuOptions } = useFormContext(); + const { onValuesChange, gpuOptions, workerLabelOptions } = useFormContext(); const { getRuleMessage } = useAppUtils(); const form = Form.useFormInstance(); const scheduleType = Form.useWatch('scheduleType', form); const gpusCountType = Form.useWatch('gpusCountType', form); + const wokerSelector = Form.useWatch('worker_selector', form); const handleScheduleTypeChange = (value: string) => { if (value === ScheduleValueMap.Auto) { @@ -105,9 +126,32 @@ const ScheduleTypeForm: React.FC = () => { } }; + const onSelectorChange = (field: string, allowEmpty?: boolean) => { + const workerSelector = form.getFieldValue(field); + // check if all keys have values + const hasEmptyValue = _.some(_.keys(workerSelector), (k: string) => { + return !workerSelector[k]; + }); + if (!hasEmptyValue || allowEmpty) { + onValuesChange?.({}, form.getFieldsValue()); + } + }; + + const handleWorkerLabelsChange = (labels: Record) => { + form.setFieldValue('worker_selector', labels); + }; + + const handleSelectorOnBlur = () => { + onSelectorChange('worker_selector'); + }; + + const handleDeleteWorkerSelector = (index: number) => { + onValuesChange?.({}, form.getFieldsValue()); + }; + return ( <> - + { )} )} + {scheduleType === ScheduleValueMap.Auto && ( + <> + name="placement_strategy"> + + } + > + + + + name="worker_selector" + rules={[ + ({ getFieldValue }) => ({ + validator(rule, value) { + if ( + scheduleType === ScheduleValueMap.Auto && + _.keys(value).length > 0 + ) { + if (_.some(_.keys(value), (k: string) => !value[k])) { + return Promise.reject( + intl.formatMessage( + { + id: 'common.validate.value' + }, + { + name: intl.formatMessage({ + id: 'models.form.selector' + }) + } + ) + ); + } + } + return Promise.resolve(); + } + }) + ]} + > + + {intl.formatMessage({ + id: 'resources.form.workerSelector.description' + })} + + } + > + + + + )} ); };