fix: adjust gpus_per_replicas ux

This commit is contained in:
jialin
2025-10-28 17:21:22 +08:00
parent a86bed294e
commit 646d235c65
11 changed files with 80 additions and 85 deletions
@@ -98,6 +98,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
setWarningStatus, setWarningStatus,
handleDoEvalute, handleDoEvalute,
cancelEvaluate, cancelEvaluate,
clearCacheFormValues,
submitAnyway, submitAnyway,
handleOnValuesChange, handleOnValuesChange,
warningStatus warningStatus
@@ -609,6 +610,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
onBackendChange={handleBackendChange} onBackendChange={handleBackendChange}
onSourceChange={handleSourceChange} onSourceChange={handleSourceChange}
onValuesChange={onValuesChange} onValuesChange={onValuesChange}
clearCacheFormValues={clearCacheFormValues}
></DataForm> ></DataForm>
</> </>
</ColumnWrapper> </ColumnWrapper>
@@ -116,7 +116,7 @@ const AddModal: FC<AddModalProps> = (props) => {
cancelEvaluate, cancelEvaluate,
unlockWarningStatus, unlockWarningStatus,
handleOnValuesChange: handleOnValuesChangeBefore, handleOnValuesChange: handleOnValuesChangeBefore,
clearCahceFormValues, clearCacheFormValues,
warningStatus, warningStatus,
submitAnyway submitAnyway
} = useCheckCompatibility(); } = useCheckCompatibility();
@@ -314,7 +314,7 @@ const AddModal: FC<AddModalProps> = (props) => {
} }
console.log('handleOnSelectModel:', item, selectedModel); console.log('handleOnSelectModel:', item, selectedModel);
setIsGGUF(item.isGGUF); setIsGGUF(item.isGGUF);
clearCahceFormValues(); clearCacheFormValues();
unlockWarningStatus(); unlockWarningStatus();
setEvaluteState({ setEvaluteState({
state: EvaluateProccess.model, state: EvaluateProccess.model,
@@ -511,7 +511,7 @@ const AddModal: FC<AddModalProps> = (props) => {
handleOnOpen(); handleOnOpen();
} else { } else {
cancelEvaluate(); cancelEvaluate();
clearCahceFormValues(); clearCacheFormValues();
} }
return () => { return () => {
setSelectedModel({}); setSelectedModel({});
@@ -645,6 +645,7 @@ const AddModal: FC<AddModalProps> = (props) => {
isGGUF={isGGUF} isGGUF={isGGUF}
onBackendChange={handleBackendChange} onBackendChange={handleBackendChange}
onValuesChange={onValuesChange} onValuesChange={onValuesChange}
clearCacheFormValues={clearCacheFormValues}
></DataForm> ></DataForm>
</> </>
</ColumnWrapper> </ColumnWrapper>
@@ -22,6 +22,7 @@ interface FormContextProps {
workerLabelOptions: CascaderOption[]; workerLabelOptions: CascaderOption[];
backendOptions: BackendOption[]; backendOptions: BackendOption[];
initialValues?: FormData; // for editing model initialValues?: FormData; // for editing model
clearCacheFormValues?: () => void;
onValuesChange?: (changedValues: any, allValues: any) => void; onValuesChange?: (changedValues: any, allValues: any) => void;
onBackendChange: (backend: string, option: any) => void; onBackendChange: (backend: string, option: any) => void;
} }
+1 -7
View File
@@ -212,11 +212,6 @@ export const ScheduleValueMap = {
SpecificGPUType: 'specific_gpu_type' SpecificGPUType: 'specific_gpu_type'
}; };
export const gpusCountTypeMap = {
Auto: 'auto',
Custom: 'custom'
};
export const scheduleList = [ export const scheduleList = [
{ {
label: 'models.form.scheduletype.auto', label: 'models.form.scheduletype.auto',
@@ -347,10 +342,9 @@ export const excludeFields = [
'backend_version', 'backend_version',
'ollama_library_model_name', 'ollama_library_model_name',
'scheduleType', 'scheduleType',
'gpusCountType',
'placement_strategy', 'placement_strategy',
'backend', 'backend',
'gpu_selector', 'gpu_selector.gpu_ids',
'run_command', 'run_command',
'image_name', 'image_name',
'extended_kv_cache.enabled' 'extended_kv_cache.enabled'
-1
View File
@@ -70,7 +70,6 @@ export interface FormData {
cpu_offloading?: boolean; cpu_offloading?: boolean;
worker_selector?: object; worker_selector?: object;
scheduleType?: string; scheduleType?: string;
gpusCountType?: string;
name: string; name: string;
replicas: number; replicas: number;
description: string; description: string;
+5 -9
View File
@@ -1,5 +1,4 @@
import _ from 'lodash'; import _ from 'lodash';
import { gpusCountTypeMap } from '.';
import { backendOptionsMap } from '../config/backend-parameters'; import { backendOptionsMap } from '../config/backend-parameters';
import { FormData } from './types'; import { FormData } from './types';
@@ -60,17 +59,14 @@ export const generateGPUIds = (data: FormData) => {
}, },
[] []
); );
if (gpusCountTypeMap.Auto === data.gpusCountType) {
return {
gpu_selector: {
gpu_ids: result || []
}
};
}
return { return {
gpu_selector: { gpu_selector: {
gpu_ids: result || [], gpu_ids: result || [],
gpus_per_replica: data.gpu_selector?.gpus_per_replica || null gpus_per_replica:
data.gpu_selector?.gpus_per_replica === -1
? null
: data.gpu_selector?.gpus_per_replica
} }
}; };
}; };
+10 -7
View File
@@ -9,7 +9,6 @@ import styled from 'styled-components';
import { import {
deployFormKeyMap, deployFormKeyMap,
excludeFields, excludeFields,
gpusCountTypeMap,
modelSourceMap, modelSourceMap,
ScheduleValueMap ScheduleValueMap
} from '../config'; } from '../config';
@@ -65,6 +64,7 @@ interface DataFormProps {
sourceList?: Global.BaseOption<string>[]; sourceList?: Global.BaseOption<string>[];
clusterList: Global.BaseOption<number>[]; clusterList: Global.BaseOption<number>[];
fields?: string[]; fields?: string[];
clearCacheFormValues?: () => void;
onValuesChange?: (changedValues: any, allValues: any) => void; onValuesChange?: (changedValues: any, allValues: any) => void;
onSourceChange?: (value: string) => void; onSourceChange?: (value: string) => void;
onOk: (values: FormData) => void; onOk: (values: FormData) => void;
@@ -82,6 +82,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
sourceList, sourceList,
clusterList = [], clusterList = [],
fields = ['source'], fields = ['source'],
clearCacheFormValues,
onBackendChange, onBackendChange,
onSourceChange, onSourceChange,
onValuesChange, onValuesChange,
@@ -154,9 +155,9 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
if (backend === backendOptionsMap.voxBox && gpuids.length > 0) { if (backend === backendOptionsMap.voxBox && gpuids.length > 0) {
return { return {
gpusCountType: gpusCountTypeMap.Auto,
gpu_selector: { gpu_selector: {
gpu_ids: [gpuids[0]] gpu_ids: [gpuids[0]],
gpus_per_replica: -1
} }
}; };
} }
@@ -217,7 +218,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
data.categories = data.categories ? [data.categories] : []; data.categories = data.categories ? [data.categories] : [];
const gpuSelector = generateGPUIds(data); const gpuSelector = generateGPUIds(data);
const allValues = { const allValues = {
..._.omit(data, ['scheduleType', 'gpusCountType']), ..._.omit(data, ['scheduleType']),
...gpuSelector ...gpuSelector
}; };
@@ -235,7 +236,9 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
const getFieldPaths = (obj: Record<string, any>, prefix = ''): string => { const getFieldPaths = (obj: Record<string, any>, prefix = ''): string => {
const result = Object.entries(obj).flatMap(([key, value]) => { const result = Object.entries(obj).flatMap(([key, value]) => {
const path = prefix ? `${prefix}.${key}` : key; const path = prefix ? `${prefix}.${key}` : key;
return typeof value === 'object' && value !== null return typeof value === 'object' &&
value !== null &&
!Array.isArray(value)
? getFieldPaths(value, path) ? getFieldPaths(value, path)
: [path]; : [path];
}); });
@@ -328,6 +331,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
backendOptions: backendOptions, backendOptions: backendOptions,
workerLabelOptions: workerLabelOptions, workerLabelOptions: workerLabelOptions,
initialValues: initialValues, initialValues: initialValues,
clearCacheFormValues: clearCacheFormValues,
onValuesChange: onValuesChange, onValuesChange: onValuesChange,
onBackendChange: handleBackendChange onBackendChange: handleBackendChange
}} }}
@@ -344,7 +348,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
name="deployModel" name="deployModel"
form={form} form={form}
onFinish={handleOk} onFinish={handleOk}
preserve={false} preserve={true}
clearOnDestroy={true} clearOnDestroy={true}
onValuesChange={handleOnValuesChange} onValuesChange={handleOnValuesChange}
onFinishFailed={handleOnFinishFailed} onFinishFailed={handleOnFinishFailed}
@@ -355,7 +359,6 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
placement_strategy: 'spread', placement_strategy: 'spread',
cpu_offloading: true, cpu_offloading: true,
scheduleType: ScheduleValueMap.Auto, scheduleType: ScheduleValueMap.Auto,
gpusCountType: gpusCountTypeMap.Auto,
categories: null, categories: null,
restart_on_error: true, restart_on_error: true,
distributed_inference_across_workers: true, distributed_inference_across_workers: true,
+4 -3
View File
@@ -16,13 +16,14 @@ const KVCacheForm = () => {
const backend = Form.useWatch('backend', form); const backend = Form.useWatch('backend', form);
const handleOnChange = async (e: any) => { const handleOnChange = async (e: any) => {
const extendedKVCache = form.getFieldValue('extended_kv_cache');
if (e.target.checked) { if (e.target.checked) {
form.setFieldsValue({ form.setFieldsValue({
extended_kv_cache: { extended_kv_cache: {
enabled: true, enabled: true,
chunk_size: 256, chunk_size: extendedKVCache?.chunk_size || 256,
max_local_cpu_size: 10, max_local_cpu_size: extendedKVCache?.max_local_cpu_size || 10,
remote_url: '' remote_url: extendedKVCache?.remote_url || ''
} }
}); });
} }
+48 -47
View File
@@ -1,18 +1,16 @@
import LabelSelector from '@/components/label-selector'; import LabelSelector from '@/components/label-selector';
import { LabelSelectorContext } from '@/components/label-selector/context'; import { LabelSelectorContext } from '@/components/label-selector/context';
import SealInputNumber from '@/components/seal-form/input-number';
import SealCascader from '@/components/seal-form/seal-cascader'; import SealCascader from '@/components/seal-form/seal-cascader';
import SealSelect from '@/components/seal-form/seal-select'; import SealSelect from '@/components/seal-form/seal-select';
import TooltipList from '@/components/tooltip-list'; import TooltipList from '@/components/tooltip-list';
import { PageAction } from '@/config';
import useAppUtils from '@/hooks/use-app-utils'; import useAppUtils from '@/hooks/use-app-utils';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Form } from 'antd'; import { Form, InputNumber } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
import React from 'react'; import React from 'react';
import styled from 'styled-components';
import GPUCard from '../components/gpu-card'; import GPUCard from '../components/gpu-card';
import { import {
gpusCountTypeMap,
placementStrategyOptions, placementStrategyOptions,
scheduleList, scheduleList,
ScheduleValueMap ScheduleValueMap
@@ -21,6 +19,10 @@ import { backendOptionsMap } from '../config/backend-parameters';
import { useFormContext } from '../config/form-context'; import { useFormContext } from '../config/form-context';
import { FormData } from '../config/types'; import { FormData } from '../config/types';
const InputWrapper = styled.div`
padding: 8px 4px;
`;
const placementStrategyTips = [ const placementStrategyTips = [
{ {
title: 'Spread', title: 'Spread',
@@ -73,24 +75,30 @@ const ScheduleTypeForm: React.FC = () => {
action, action,
gpuOptions, gpuOptions,
workerLabelOptions, workerLabelOptions,
clearCacheFormValues,
initialValues initialValues
} = useFormContext(); } = useFormContext();
const { getRuleMessage } = useAppUtils(); const { getRuleMessage } = useAppUtils();
const form = Form.useFormInstance(); const form = Form.useFormInstance();
const scheduleType = Form.useWatch('scheduleType', form); const scheduleType = Form.useWatch('scheduleType', form);
const gpusCountType = Form.useWatch('gpusCountType', form); const workerSelector = Form.useWatch('worker_selector', form);
const wokerSelector = Form.useWatch('worker_selector', form); const GPUsPerReplicas = Form.useWatch(
['gpu_selector', 'gpus_per_replica'],
form
);
const handleScheduleTypeChange = (value: string) => { const handleScheduleTypeChange = (value: string) => {
if (value === ScheduleValueMap.Auto) { if (value === ScheduleValueMap.Auto) {
onValuesChange?.({}, form.getFieldsValue()); onValuesChange?.({}, form.getFieldsValue());
return;
}
if (value === ScheduleValueMap.Manual) {
form.setFieldValue(['gpu_selector', 'gpus_per_replica'], -1);
} }
}; };
const handleGpusCountTypeChange = (val: string) => { const handleGpusPerReplicasChange = (val: string | number | null) => {
if (val === gpusCountTypeMap.Custom) { form.setFieldValue(['gpu_selector', 'gpus_per_replica'], val);
form.setFieldValue(['gpu_selector', 'gpus_per_replica'], 1);
}
onValuesChange?.({}, form.getFieldsValue()); onValuesChange?.({}, form.getFieldsValue());
}; };
@@ -98,6 +106,8 @@ const ScheduleTypeForm: React.FC = () => {
const handleGpuSelectorChange = (value: any[]) => { const handleGpuSelectorChange = (value: any[]) => {
if (value.length > 0) { if (value.length > 0) {
onValuesChange?.({}, form.getFieldsValue()); onValuesChange?.({}, form.getFieldsValue());
} else {
clearCacheFormValues?.();
} }
}; };
@@ -221,50 +231,41 @@ const ScheduleTypeForm: React.FC = () => {
onChange={handleGpuSelectorChange} onChange={handleGpuSelectorChange}
></SealCascader> ></SealCascader>
</Form.Item> </Form.Item>
<Form.Item <Form.Item name={['gpu_selector', 'gpus_per_replica']}>
name="gpusCountType"
hidden={
action === PageAction.EDIT &&
!!initialValues?.gpu_selector?.gpus_per_replica
}
>
<SealSelect <SealSelect
onChange={handleGpusCountTypeChange}
label={intl.formatMessage({ label={intl.formatMessage({
id: 'models.form.gpusAllocationType' id: 'models.form.gpusperreplica'
})} })}
description={
<TooltipList list={gpuAllocateTypeTips}></TooltipList>
}
options={[ options={[
{ {
label: intl.formatMessage({ label: intl.formatMessage({ id: 'common.options.auto' }),
id: 'models.form.gpusAllocationType.auto' value: -1
}),
value: gpusCountTypeMap.Auto
}, },
{ { label: '1', value: 1 },
label: intl.formatMessage({ { label: '2', value: 2 },
id: 'models.form.gpusAllocationType.custom' { label: '4', value: 4 },
}), { label: '8', value: 8 }
value: gpusCountTypeMap.Custom
}
]} ]}
></SealSelect> popupRender={(originNode) => (
<div>
{originNode}
<InputWrapper>
<InputNumber
step={1}
style={{ width: '100%' }}
defaultValue={
GPUsPerReplicas === null ? -1 : GPUsPerReplicas
}
value={GPUsPerReplicas === -1 ? null : GPUsPerReplicas}
onChange={handleGpusPerReplicasChange}
onStep={handleOnStepReplicaStep}
/>
</InputWrapper>
</div>
)}
onChange={handleOnStepReplica}
/>
</Form.Item> </Form.Item>
{gpusCountType === gpusCountTypeMap.Custom && (
<Form.Item name={['gpu_selector', 'gpus_per_replica']}>
<SealInputNumber
label={intl.formatMessage({
id: 'models.form.gpusperreplica'
})}
min={1}
step={1}
onChange={handleOnStepReplica}
onStep={handleOnStepReplicaStep}
/>
</Form.Item>
)}
</> </>
)} )}
{scheduleType === ScheduleValueMap.Auto && ( {scheduleType === ScheduleValueMap.Auto && (
@@ -317,7 +318,7 @@ const ScheduleTypeForm: React.FC = () => {
label={intl.formatMessage({ label={intl.formatMessage({
id: 'resources.form.workerSelector' id: 'resources.form.workerSelector'
})} })}
labels={wokerSelector} labels={workerSelector}
onChange={handleWorkerLabelsChange} onChange={handleWorkerLabelsChange}
onBlur={handleSelectorOnBlur} onBlur={handleSelectorOnBlur}
onDelete={handleDeleteWorkerSelector} onDelete={handleDeleteWorkerSelector}
+3 -3
View File
@@ -375,7 +375,7 @@ export const useCheckCompatibility = () => {
return null; return null;
}; };
const clearCahceFormValues = () => { const clearCacheFormValues = () => {
cacheFormValuesRef.current = {}; cacheFormValuesRef.current = {};
}; };
@@ -437,7 +437,7 @@ export const useCheckCompatibility = () => {
useEffect(() => { useEffect(() => {
return () => { return () => {
cancelEvaluate(); cancelEvaluate();
clearCahceFormValues(); clearCacheFormValues();
}; };
}, []); }, []);
@@ -452,7 +452,7 @@ export const useCheckCompatibility = () => {
handleBackendChangeBefore, handleBackendChangeBefore,
handleOnValuesChange: handleOnValuesChange, handleOnValuesChange: handleOnValuesChange,
handleEvaluateOnChange: handleOnValuesChange, handleEvaluateOnChange: handleOnValuesChange,
clearCahceFormValues, clearCacheFormValues,
warningStatus, warningStatus,
checkTokenRef, checkTokenRef,
submitAnyway submitAnyway
@@ -10,7 +10,7 @@ import { ListItem as WorkerListItem } from '@/pages/resources/config/types';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import { useState } from 'react'; import { useState } from 'react';
import { queryGPUList } from '../apis'; import { queryGPUList } from '../apis';
import { gpusCountTypeMap, ScheduleValueMap } from '../config'; import { ScheduleValueMap } from '../config';
import { GPUListItem, ListItem } from '../config/types'; import { GPUListItem, ListItem } from '../config/types';
type EmptyObject = Record<never, never>; type EmptyObject = Record<never, never>;
@@ -276,10 +276,7 @@ export default function useFormInitialValues() {
categories: data?.categories?.length ? data.categories[0] : null, categories: data?.categories?.length ? data.categories[0] : null,
scheduleType: data?.gpu_selector scheduleType: data?.gpu_selector
? ScheduleValueMap.Manual ? ScheduleValueMap.Manual
: ScheduleValueMap.Auto, : ScheduleValueMap.Auto
gpusCountType: data?.gpu_selector?.gpus_per_replica
? gpusCountTypeMap.Custom
: gpusCountTypeMap.Auto
}; };
return formData; return formData;
}; };