fix: ui conflicts in update of multiple evalute result

This commit is contained in:
jialin
2025-06-09 18:45:47 +08:00
parent f73e29937c
commit 5ef733729b
10 changed files with 128 additions and 82 deletions
+9 -3
View File
@@ -3,7 +3,7 @@ import { Typography } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import React from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import OverlayScroller from '../overlay-scroller'; import OverlayScroller, { OverlayScrollerOptions } from '../overlay-scroller';
import './block.less'; import './block.less';
interface AlertInfoProps { interface AlertInfoProps {
type: Global.MessageType; type: Global.MessageType;
@@ -15,6 +15,7 @@ interface AlertInfoProps {
contentStyle?: React.CSSProperties; contentStyle?: React.CSSProperties;
title?: React.ReactNode; title?: React.ReactNode;
maxHeight?: number; maxHeight?: number;
overlayScrollerProps?: OverlayScrollerOptions;
} }
const TitleWrapper = styled.div` const TitleWrapper = styled.div`
@@ -41,7 +42,8 @@ const AlertInfo: React.FC<AlertInfoProps> = (props) => {
title, title,
contentStyle, contentStyle,
icon, icon,
maxHeight = 86 maxHeight = 86,
overlayScrollerProps = {}
} = props; } = props;
return ( return (
@@ -67,7 +69,11 @@ const AlertInfo: React.FC<AlertInfoProps> = (props) => {
{title && ( {title && (
<TitleWrapper className="title-text">{title}</TitleWrapper> <TitleWrapper className="title-text">{title}</TitleWrapper>
)} )}
<OverlayScroller maxHeight={maxHeight} style={{ ...contentStyle }}> <OverlayScroller
maxHeight={maxHeight}
style={{ ...contentStyle }}
{...overlayScrollerProps}
>
<ContentWrapper <ContentWrapper
$hasTitle={!!title} $hasTitle={!!title}
className={classNames('content', type)} className={classNames('content', type)}
+2 -2
View File
@@ -87,7 +87,7 @@
font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold);
line-height: 1.5; line-height: 1.5;
padding-inline: 6px; padding-inline: 6px;
border-bottom: 1px solid var(--ant-color-split); border: 1px solid var(--ant-color-split);
word-break: break-word; word-break: break-word;
text-align: left !important; text-align: left !important;
} }
@@ -95,7 +95,7 @@
td { td {
line-height: 1.5; line-height: 1.5;
padding-inline: 6px; padding-inline: 6px;
border-bottom: 1px solid var(--ant-color-split); border: 1px solid var(--ant-color-split);
word-break: break-word; word-break: break-word;
text-align: left !important; text-align: left !important;
} }
@@ -12,6 +12,9 @@ const Wrapper = styled.div<{ $maxHeight?: number }>`
width: 100%; width: 100%;
`; `;
// export OverlayScrollerOptions
export type { OverlayScrollerOptions };
export const OverlayScroller: React.FC< export const OverlayScroller: React.FC<
OverlayScrollerOptions & { OverlayScrollerOptions & {
maxHeight?: number; maxHeight?: number;
@@ -24,6 +24,7 @@ import {
backendLabelMap, backendLabelMap,
backendOptionsMap, backendOptionsMap,
backendParamsHolderTips, backendParamsHolderTips,
getBackendParamsTips,
modelCategories, modelCategories,
placementStrategyOptions placementStrategyOptions
} from '../config'; } from '../config';
@@ -120,37 +121,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
}, [backend]); }, [backend]);
const backendParamsTips = useMemo(() => { const backendParamsTips = useMemo(() => {
if (backend === backendOptionsMap.llamaBox) { return getBackendParamsTips(backend);
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'
};
}, [backend]); }, [backend]);
const handleWorkerLabelsChange = useCallback( const handleWorkerLabelsChange = useCallback(
@@ -9,7 +9,13 @@ const ColumnWrapper: React.FC<any> = ({
paddingBottom = 50 paddingBottom = 50
}) => { }) => {
const scroller = React.useRef<any>(null); const scroller = React.useRef<any>(null);
const { initialize } = useOverlayScroller(); const { initialize } = useOverlayScroller({
options: {
scrollbars: {
autoHide: 'move'
}
}
});
React.useEffect(() => { React.useEffect(() => {
if (scroller.current) { if (scroller.current) {
@@ -119,6 +119,11 @@ const CompatibilityAlert: React.FC<CompatibilityAlertProps> = (props) => {
contentStyle={contentStyle} contentStyle={contentStyle}
type={type || 'warning'} type={type || 'warning'}
icon={renderIcon} icon={renderIcon}
overlayScrollerProps={{
scrollbars: {
autoHide: 'move'
}
}}
></AlertBlockInfo> ></AlertBlockInfo>
{showClose && !['transition'].includes(type) && ( {showClose && !['transition'].includes(type) && (
<CloseWrapper className="close-wrapper"> <CloseWrapper className="close-wrapper">
+59 -6
View File
@@ -38,8 +38,7 @@ const resetFieldsByModel = [
const resetFieldsByFile = [ const resetFieldsByFile = [
'cpu_offloading', 'cpu_offloading',
'distributed_inference_across_workers', 'distributed_inference_across_workers'
'backend_parameters'
]; ];
const ModalFooterStyle = { const ModalFooterStyle = {
@@ -99,11 +98,12 @@ const AddModal: FC<AddModalProps> = (props) => {
setWarningStatus, setWarningStatus,
handleBackendChangeBefore, handleBackendChangeBefore,
cancelEvaluate, cancelEvaluate,
handleOnValuesChange, handleOnValuesChange: handleOnValuesChangeBefore,
handleEvaluateOnChange, handleEvaluateOnChange,
warningStatus, warningStatus,
submitAnyway submitAnyway
} = useCheckCompatibility(); } = useCheckCompatibility();
const { onSelectModel } = useSelectModel({ gpuOptions: props.gpuOptions }); const { onSelectModel } = useSelectModel({ gpuOptions: props.gpuOptions });
const form = useRef<any>({}); const form = useRef<any>({});
const intl = useIntl(); const intl = useIntl();
@@ -118,7 +118,22 @@ const AddModal: FC<AddModalProps> = (props) => {
model: false, model: false,
file: 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<string, boolean>) => { const setIsHolderRef = (flag: Record<string, boolean>) => {
isHolderRef.current = { isHolderRef.current = {
...isHolderRef.current, ...isHolderRef.current,
@@ -126,6 +141,15 @@ const AddModal: FC<AddModalProps> = (props) => {
}; };
}; };
const handleOnValuesChange = (data: {
changedValues: any;
allValues: any;
source: SourceType;
}) => {
setEvaluteState('form');
handleOnValuesChangeBefore(data);
};
const getDefaultSpec = (item: any) => { const getDefaultSpec = (item: any) => {
const defaultSpec = item.evaluateResult?.default_spec || {}; const defaultSpec = item.evaluateResult?.default_spec || {};
return _.omit(defaultSpec, [ return _.omit(defaultSpec, [
@@ -145,6 +169,10 @@ const AddModal: FC<AddModalProps> = (props) => {
const handleSelectModelFile = async (item: any, evaluate?: boolean) => { const handleSelectModelFile = async (item: any, evaluate?: boolean) => {
form.current?.form?.resetFields(resetFieldsByFile); form.current?.form?.resetFields(resetFieldsByFile);
const modelInfo = onSelectModel(selectedModel, props.source); const modelInfo = onSelectModel(selectedModel, props.source);
/** display the selected model file information, but not
* unitl the evaluate result is ready
*/
form.current?.setFieldsValue?.({ form.current?.setFieldsValue?.({
file_name: item.fakeName, file_name: item.fakeName,
...modelInfo, ...modelInfo,
@@ -158,6 +186,7 @@ const AddModal: FC<AddModalProps> = (props) => {
}); });
if (item.fakeName) { if (item.fakeName) {
setEvaluteState('file');
const evaluateRes = await handleEvaluateOnChange?.({ const evaluateRes = await handleEvaluateOnChange?.({
changedValues: {}, changedValues: {},
allValues: form.current?.form?.getFieldsValue?.(), allValues: form.current?.form?.getFieldsValue?.(),
@@ -166,31 +195,55 @@ const AddModal: FC<AddModalProps> = (props) => {
const defaultSpec = getDefaultSpec({ const defaultSpec = getDefaultSpec({
evaluateResult: evaluateRes 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?.({ form.current?.setFieldsValue?.({
file_name: item.fakeName, file_name: item.fakeName,
...defaultSpec, ...defaultSpec,
...modelInfo, ...modelInfo,
backend_parameters:
formBackendParameters.length > 0
? formBackendParameters
: defaultSpec.backend_parameters || [],
categories: getCategory(item) categories: getCategory(item)
}); });
} }
}; };
const handleOnSelectModel = (item: any, evaluate?: boolean) => { const handleOnSelectModel = (item: any, evaluate?: boolean) => {
// when select a model not from the evaluate result,
if (!evaluate) {
setEvaluteState('model');
setSelectedModel(item); setSelectedModel(item);
form.current?.form?.resetFields(resetFieldsByModel); form.current?.form?.resetFields(resetFieldsByModel);
const modelInfo = onSelectModel(item, props.source);
form.current?.setFieldsValue?.({
...modelInfo,
categories: getCategory(item)
});
}
if (!item.isGGUF) { if (!item.isGGUF) {
setIsGGUF(false); setIsGGUF(false);
const modelInfo = onSelectModel(item, props.source); const modelInfo = onSelectModel(item, props.source);
if (!isHolderRef.current.model) { if (
!isHolderRef.current.model &&
evaluateStateRef.current.state === 'model'
) {
handleShowCompatibleAlert(item.evaluateResult); handleShowCompatibleAlert(item.evaluateResult);
}
form.current?.setFieldsValue?.({ form.current?.setFieldsValue?.({
...getDefaultSpec(item), ...getDefaultSpec(item),
...modelInfo, ...modelInfo,
categories: getCategory(item) categories: getCategory(item)
}); });
} }
}
}; };
const handleOnOk = async (allValues: FormData) => { const handleOnOk = async (allValues: FormData) => {
+34 -29
View File
@@ -416,35 +416,6 @@ export const setbackendParameters = (data: any) => {
return result; 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 = [ export const modelLabels = [
{ label: 'Image', value: 'image_only' }, { label: 'Image', value: 'image_only' },
{ label: 'Text-to-speech', value: 'text_to_speech' }, { label: 'Text-to-speech', value: 'text_to_speech' },
@@ -519,3 +490,37 @@ export const formFields = [
'scheduleType', 'scheduleType',
'restart_on_error' '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'
};
};
@@ -11,10 +11,6 @@ const options = [
label: '--host', label: '--host',
value: '--host' value: '--host'
}, },
{
label: '--port',
value: '--port'
},
{ {
label: '--timeout', label: '--timeout',
value: '--timeout' value: '--timeout'
@@ -19,6 +19,7 @@
.title { .title {
font-size: var(--font-size-base); font-size: var(--font-size-base);
word-break: break-all;
} }
.info { .info {