import AutoTooltip from '@/components/auto-tooltip'; import IconFont from '@/components/icon-font'; import LabelSelector from '@/components/label-selector'; import ListInput from '@/components/list-input'; import SealCascader from '@/components/seal-form/seal-cascader'; import SealInput from '@/components/seal-form/seal-input'; import SealSelect from '@/components/seal-form/seal-select'; import TooltipList from '@/components/tooltip-list'; import { PageActionType } from '@/config/types'; import { QuestionCircleOutlined, RightOutlined } from '@ant-design/icons'; import { useIntl } from '@umijs/max'; import { Checkbox, Collapse, Empty, Form, FormInstance, Tooltip, Typography } from 'antd'; import _ from 'lodash'; import React, { useCallback, useMemo } from 'react'; import { backendOptionsMap, backendParamsHolderTips, modelCategories, placementStrategyOptions } from '../config'; import llamaConfig from '../config/llama-config'; import { FormData } from '../config/types'; import vllmConfig from '../config/vllm-config'; import dataformStyles from '../style/data-form.less'; import GPUCard from './gpu-card'; interface AdvanceConfigProps { isGGUF: boolean; form: FormInstance; gpuOptions: Array; action: PageActionType; source: string; } const AdvanceConfig: React.FC = (props) => { const { form, isGGUF, gpuOptions, source } = props; const intl = useIntl(); 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 backend_parameters = Form.useWatch('backend_parameters', form); const categories = Form.useWatch('categories', form); const backend_version = Form.useWatch('backend_version', form); const placement_strategy = Form.useWatch('placement_strategy', form); const gpuSelectorIds = Form.useWatch(['gpu_selector', 'gpu_ids'], form); const worker_selector = Form.useWatch('worker_selector', form); const placementStrategyTips = [ { title: 'Spread', tips: intl.formatMessage({ id: 'resources.form.spread.tips' }) }, { title: 'Binpack', tips: intl.formatMessage({ id: 'resources.form.binpack.tips' }) } ]; const scheduleTypeTips = [ { title: intl.formatMessage({ id: 'models.form.scheduletype.auto' }), tips: intl.formatMessage({ id: 'models.form.scheduletype.auto.tips' }) }, { title: intl.formatMessage({ id: 'models.form.scheduletype.manual' }), tips: intl.formatMessage({ id: 'models.form.scheduletype.manual.tips' }) } ]; const paramsConfig = useMemo(() => { if (backend === backendOptionsMap.llamaBox) { return llamaConfig; } if (backend === backendOptionsMap.vllm) { return vllmConfig; } return []; }, [backend]); const backendParamsTips = useMemo(() => { if (backend === backendOptionsMap.llamaBox) { return { backend: 'llama-box', releases: 'https://github.com/gpustack/llama-box/releases', link: 'https://github.com/gpustack/llama-box?tab=readme-ov-file#usage' }; } if (backend === backendOptionsMap.vllm) { return { backend: 'vLLM', releases: 'https://github.com/vllm-project/vllm/releases', link: 'https://docs.vllm.ai/en/stable/serving/openai_compatible_server.html#cli-reference' }; } return null; }, [backend]); const handleWorkerLabelsChange = useCallback( (labels: Record) => { form.setFieldValue('worker_selector', labels); }, [] ); const handleEnviromentVarsChange = useCallback( (labels: Record) => { form.setFieldValue('env', labels); }, [] ); const handleBackendParametersChange = useCallback((list: string[]) => { form.setFieldValue('backend_parameters', list); }, []); const handleGPUSelectorChange = (gpuIds: any[]) => { // only handle for vllm, pick the last selected group if ( backend === backendOptionsMap.llamaBox || backend === backendOptionsMap.voxBox || !gpuIds?.length ) { return; } const lastGroupName = gpuIds[gpuIds.length - 1][0]; const lastGroupItems = gpuIds.filter((item) => item[0] === lastGroupName); form.setFieldValue(['gpu_selector', 'gpu_ids'], lastGroupItems); }; const gpuOptionRender = (data: any) => { if (data.value === '__EMPTY__') { return ( ); } let width: any = { maxWidth: 140, minWidth: 140 }; if (!data.parent) { width = undefined; } if (data.parent) { return ( {data.label} ); } return ; }; const tagRender = (props: any) => { if (props.isMaxTag) { return props.label; } const parent = _.split(props.value, '__RC_CASCADER_SPLIT__')?.[0]; return `${parent} / ${props?.label}`; }; const collapseItems = useMemo(() => { const children = ( <> name="categories"> } options={[ { label: intl.formatMessage({ id: 'models.form.scheduletype.auto' }), value: 'auto' }, { label: intl.formatMessage({ id: 'models.form.scheduletype.manual' }), value: 'manual' } ]} > {scheduleType === 'auto' && ( <> name="placement_strategy"> } > name="worker_selector" rules={[ ({ getFieldValue }) => ({ validator(rule, value) { if ( getFieldValue('scheduleType') === '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' })} } > )} {scheduleType === 'manual' && ( <> { return ( {tagRender(props)} ); }} optionRender={gpuOptionRender} getPopupContainer={(triggerNode) => triggerNode.parentNode} > )} {intl.formatMessage({ id: 'models.form.releases' })} ) } )} > name="backend_parameters"> {intl.formatMessage( { id: 'models.form.backend_parameters.vllm.tips' }, { backend: backendParamsTips.backend || '' } )}{' '} {intl.formatMessage({ id: 'common.text.here' })} ) } > name="env" rules={[ () => ({ validator(rule, value) { if (_.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: 'common.text.variable' }) } ) ); } } return Promise.resolve(); } }) ]} > {backend === backendOptionsMap.llamaBox && (
name="cpu_offloading" valuePropName="checked" style={{ padding: '0 10px', marginBottom: 0 }} noStyle > {intl.formatMessage({ id: 'resources.form.enablePartialOffload' })}
)} {scheduleType === 'auto' && backend === backendOptionsMap.llamaBox && (
name="distributed_inference_across_workers" valuePropName="checked" style={{ padding: '0 10px', marginBottom: 0 }} noStyle > {intl.formatMessage({ id: 'resources.form.enableDistributedInferenceAcrossWorkers' })}
)} ); return [ { key: '1', label: ( {intl.formatMessage({ id: 'resources.form.advanced' })} ), forceRender: true, children } ]; }, [ form, source, intl, gpuOptions, paramsConfig, scheduleType, wokerSelector, backend, backend_parameters, isGGUF, categories, backend_version, placement_strategy, gpuSelectorIds, EnviromentVars, worker_selector ]); return ( ( )} items={collapseItems} > ); }; export default React.memo(AdvanceConfig);