From 5ef733729b4d197f426b955be46cebc6b2efe8ce Mon Sep 17 00:00:00 2001 From: jialin Date: Thu, 5 Jun 2025 19:36:56 +0800 Subject: [PATCH] fix: ui conflicts in update of multiple evalute result --- src/components/alert-info/block.tsx | 12 ++- src/components/markdown-viewer/index.less | 4 +- src/components/overlay-scroller/index.tsx | 3 + .../llmodels/components/advance-config.tsx | 33 +------- .../llmodels/components/column-wrapper.tsx | 8 +- .../llmodels/components/compatible-alert.tsx | 5 ++ .../llmodels/components/deploy-modal.tsx | 77 ++++++++++++++++--- src/pages/llmodels/config/index.ts | 63 ++++++++------- src/pages/llmodels/config/llama-config.ts | 4 - src/pages/llmodels/style/hf-model-item.less | 1 + 10 files changed, 128 insertions(+), 82 deletions(-) diff --git a/src/components/alert-info/block.tsx b/src/components/alert-info/block.tsx index d7270723..774cc87b 100644 --- a/src/components/alert-info/block.tsx +++ b/src/components/alert-info/block.tsx @@ -3,7 +3,7 @@ import { Typography } from 'antd'; import classNames from 'classnames'; import React from 'react'; import styled from 'styled-components'; -import OverlayScroller from '../overlay-scroller'; +import OverlayScroller, { OverlayScrollerOptions } from '../overlay-scroller'; import './block.less'; interface AlertInfoProps { type: Global.MessageType; @@ -15,6 +15,7 @@ interface AlertInfoProps { contentStyle?: React.CSSProperties; title?: React.ReactNode; maxHeight?: number; + overlayScrollerProps?: OverlayScrollerOptions; } const TitleWrapper = styled.div` @@ -41,7 +42,8 @@ const AlertInfo: React.FC = (props) => { title, contentStyle, icon, - maxHeight = 86 + maxHeight = 86, + overlayScrollerProps = {} } = props; return ( @@ -67,7 +69,11 @@ const AlertInfo: React.FC = (props) => { {title && ( {title} )} - + ` width: 100%; `; +// export OverlayScrollerOptions +export type { OverlayScrollerOptions }; + export const OverlayScroller: React.FC< OverlayScrollerOptions & { maxHeight?: number; diff --git a/src/pages/llmodels/components/advance-config.tsx b/src/pages/llmodels/components/advance-config.tsx index fdbdcde1..8178ad5e 100644 --- a/src/pages/llmodels/components/advance-config.tsx +++ b/src/pages/llmodels/components/advance-config.tsx @@ -24,6 +24,7 @@ import { backendLabelMap, backendOptionsMap, backendParamsHolderTips, + getBackendParamsTips, modelCategories, placementStrategyOptions } from '../config'; @@ -120,37 +121,7 @@ const AdvanceConfig: React.FC = (props) => { }, [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', - version: 'v0.0.140' - }; - } - 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', - version: 'v0.8.5' - }; - } - if (backend === backendOptionsMap.ascendMindie) { - return { - backend: 'Ascend MindIE', - releases: '', - link: 'http://docs.gpustack.ai/latest/user-guide/inference-backends/#parameters-reference_2', - version: '1.0.0' - }; - } - - return { - backend: 'vox-box', - releases: 'https://github.com/gpustack/vox-box/releases', - link: '', - version: 'v0.0.13' - }; + return getBackendParamsTips(backend); }, [backend]); const handleWorkerLabelsChange = useCallback( diff --git a/src/pages/llmodels/components/column-wrapper.tsx b/src/pages/llmodels/components/column-wrapper.tsx index 1bc29649..87152fcc 100644 --- a/src/pages/llmodels/components/column-wrapper.tsx +++ b/src/pages/llmodels/components/column-wrapper.tsx @@ -9,7 +9,13 @@ const ColumnWrapper: React.FC = ({ paddingBottom = 50 }) => { const scroller = React.useRef(null); - const { initialize } = useOverlayScroller(); + const { initialize } = useOverlayScroller({ + options: { + scrollbars: { + autoHide: 'move' + } + } + }); React.useEffect(() => { if (scroller.current) { diff --git a/src/pages/llmodels/components/compatible-alert.tsx b/src/pages/llmodels/components/compatible-alert.tsx index b7c81f57..b0ec51b0 100644 --- a/src/pages/llmodels/components/compatible-alert.tsx +++ b/src/pages/llmodels/components/compatible-alert.tsx @@ -119,6 +119,11 @@ const CompatibilityAlert: React.FC = (props) => { contentStyle={contentStyle} type={type || 'warning'} icon={renderIcon} + overlayScrollerProps={{ + scrollbars: { + autoHide: 'move' + } + }} > {showClose && !['transition'].includes(type) && ( diff --git a/src/pages/llmodels/components/deploy-modal.tsx b/src/pages/llmodels/components/deploy-modal.tsx index 77aebe62..bac027dd 100644 --- a/src/pages/llmodels/components/deploy-modal.tsx +++ b/src/pages/llmodels/components/deploy-modal.tsx @@ -38,8 +38,7 @@ const resetFieldsByModel = [ const resetFieldsByFile = [ 'cpu_offloading', - 'distributed_inference_across_workers', - 'backend_parameters' + 'distributed_inference_across_workers' ]; const ModalFooterStyle = { @@ -99,11 +98,12 @@ const AddModal: FC = (props) => { setWarningStatus, handleBackendChangeBefore, cancelEvaluate, - handleOnValuesChange, + handleOnValuesChange: handleOnValuesChangeBefore, handleEvaluateOnChange, warningStatus, submitAnyway } = useCheckCompatibility(); + const { onSelectModel } = useSelectModel({ gpuOptions: props.gpuOptions }); const form = useRef({}); const intl = useIntl(); @@ -118,7 +118,22 @@ const AddModal: FC = (props) => { model: false, file: false }); + const evaluateStateRef = useRef<{ state: 'model' | 'file' | 'form' }>({ + state: 'form' + }); + /** + * + * @param state target to distinguish the evaluate state + */ + const setEvaluteState = (state: 'model' | 'file' | 'form') => { + evaluateStateRef.current.state = state; + }; + + /** + * + * @param flag set the evaluate status of the model or file + */ const setIsHolderRef = (flag: Record) => { isHolderRef.current = { ...isHolderRef.current, @@ -126,6 +141,15 @@ const AddModal: FC = (props) => { }; }; + const handleOnValuesChange = (data: { + changedValues: any; + allValues: any; + source: SourceType; + }) => { + setEvaluteState('form'); + handleOnValuesChangeBefore(data); + }; + const getDefaultSpec = (item: any) => { const defaultSpec = item.evaluateResult?.default_spec || {}; return _.omit(defaultSpec, [ @@ -145,6 +169,10 @@ const AddModal: FC = (props) => { const handleSelectModelFile = async (item: any, evaluate?: boolean) => { form.current?.form?.resetFields(resetFieldsByFile); const modelInfo = onSelectModel(selectedModel, props.source); + + /** display the selected model file information, but not + * unitl the evaluate result is ready + */ form.current?.setFieldsValue?.({ file_name: item.fakeName, ...modelInfo, @@ -158,6 +186,7 @@ const AddModal: FC = (props) => { }); if (item.fakeName) { + setEvaluteState('file'); const evaluateRes = await handleEvaluateOnChange?.({ changedValues: {}, allValues: form.current?.form?.getFieldsValue?.(), @@ -166,31 +195,55 @@ const AddModal: FC = (props) => { const defaultSpec = getDefaultSpec({ evaluateResult: evaluateRes }); - console.log('defaultSpec', defaultSpec); + + /** + * do not reset backend_parameters when select a model file + */ + + const formBackendParameters = + form.current?.getFieldValue?.('backend_parameters') || []; + form.current?.setFieldsValue?.({ file_name: item.fakeName, ...defaultSpec, ...modelInfo, + backend_parameters: + formBackendParameters.length > 0 + ? formBackendParameters + : defaultSpec.backend_parameters || [], categories: getCategory(item) }); } }; const handleOnSelectModel = (item: any, evaluate?: boolean) => { - setSelectedModel(item); - form.current?.form?.resetFields(resetFieldsByModel); - if (!item.isGGUF) { - setIsGGUF(false); + // when select a model not from the evaluate result, + if (!evaluate) { + setEvaluteState('model'); + setSelectedModel(item); + form.current?.form?.resetFields(resetFieldsByModel); const modelInfo = onSelectModel(item, props.source); - if (!isHolderRef.current.model) { - handleShowCompatibleAlert(item.evaluateResult); - } form.current?.setFieldsValue?.({ - ...getDefaultSpec(item), ...modelInfo, categories: getCategory(item) }); } + + if (!item.isGGUF) { + setIsGGUF(false); + const modelInfo = onSelectModel(item, props.source); + if ( + !isHolderRef.current.model && + evaluateStateRef.current.state === 'model' + ) { + handleShowCompatibleAlert(item.evaluateResult); + form.current?.setFieldsValue?.({ + ...getDefaultSpec(item), + ...modelInfo, + categories: getCategory(item) + }); + } + } }; const handleOnOk = async (allValues: FormData) => { diff --git a/src/pages/llmodels/config/index.ts b/src/pages/llmodels/config/index.ts index bdf89f2b..5e009314 100644 --- a/src/pages/llmodels/config/index.ts +++ b/src/pages/llmodels/config/index.ts @@ -416,35 +416,6 @@ export const setbackendParameters = (data: any) => { return result; }; -export const getVllmCliArgs = (inputString: string) => { - const arrayOutput = inputString - .split(/\s*\[\s*|\s*\]\s*/g) // Split by '[' or ']', removing extra spaces - .filter((item) => item) // Remove empty items - .map((item) => item.trim()); // Trim spaces around each item - - const result = arrayOutput.map((item) => { - const parts = item.split(' '); - const label = parts[0].trim(); // Remove leading dashes - const value = parts[0].trim(); - - if (parts.length === 1) { - return { label, value, options: [] }; - } else if (parts.length > 1) { - const optionPart = parts[1]; - if (optionPart.startsWith('{') && optionPart.endsWith('}')) { - const options = optionPart - .slice(1, -1) - .split(',') - .map((opt) => opt.trim()); - return { label, value, options }; - } - } - return { label, value, options: [] }; // Fallback - }); - - return result; -}; - export const modelLabels = [ { label: 'Image', value: 'image_only' }, { label: 'Text-to-speech', value: 'text_to_speech' }, @@ -519,3 +490,37 @@ export const formFields = [ 'scheduleType', 'restart_on_error' ]; + +export const getBackendParamsTips = (backend: string) => { + 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', + version: 'v0.0.140' + }; + } + 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', + version: 'v0.8.5' + }; + } + if (backend === backendOptionsMap.ascendMindie) { + return { + backend: 'Ascend MindIE', + releases: '', + link: 'http://docs.gpustack.ai/latest/user-guide/inference-backends/#parameters-reference_2', + version: '1.0.0' + }; + } + + return { + backend: 'vox-box', + releases: 'https://github.com/gpustack/vox-box/releases', + link: '', + version: 'v0.0.13' + }; +}; diff --git a/src/pages/llmodels/config/llama-config.ts b/src/pages/llmodels/config/llama-config.ts index b01bca48..483828bf 100644 --- a/src/pages/llmodels/config/llama-config.ts +++ b/src/pages/llmodels/config/llama-config.ts @@ -11,10 +11,6 @@ const options = [ label: '--host', value: '--host' }, - { - label: '--port', - value: '--port' - }, { label: '--timeout', value: '--timeout' diff --git a/src/pages/llmodels/style/hf-model-item.less b/src/pages/llmodels/style/hf-model-item.less index 0223d9c6..4f25b343 100644 --- a/src/pages/llmodels/style/hf-model-item.less +++ b/src/pages/llmodels/style/hf-model-item.less @@ -19,6 +19,7 @@ .title { font-size: var(--font-size-base); + word-break: break-all; } .info {