chore: select multiple gpus by manual

This commit is contained in:
jialin
2024-12-29 18:31:42 +08:00
parent b4e30565d2
commit cb98812444
9 changed files with 131 additions and 69 deletions
+37 -3
View File
@@ -1,3 +1,4 @@
import { CloseOutlined } from '@ant-design/icons';
import { Tag, Tooltip, type TagProps } from 'antd'; import { Tag, Tooltip, type TagProps } from 'antd';
import { throttle } from 'lodash'; import { throttle } from 'lodash';
import React, { import React, {
@@ -20,6 +21,7 @@ interface AutoTooltipProps extends Omit<TagProps, 'title'> {
ghost?: boolean; ghost?: boolean;
title?: React.ReactNode; title?: React.ReactNode;
showTitle?: boolean; showTitle?: boolean;
closable?: boolean;
tooltipProps?: React.ComponentProps<typeof Tooltip>; tooltipProps?: React.ComponentProps<typeof Tooltip>;
} }
@@ -35,7 +37,6 @@ const AutoTooltip: React.FC<AutoTooltipProps> = ({
}) => { }) => {
const contentRef = useRef<HTMLDivElement>(null); const contentRef = useRef<HTMLDivElement>(null);
const [isOverflowing, setIsOverflowing] = useState(false); const [isOverflowing, setIsOverflowing] = useState(false);
const resizeObserver = useRef<ResizeObserver>();
const checkOverflow = useCallback(() => { const checkOverflow = useCallback(() => {
if (contentRef.current) { if (contentRef.current) {
@@ -44,6 +45,22 @@ const AutoTooltip: React.FC<AutoTooltipProps> = ({
} }
}, [contentRef.current]); }, [contentRef.current]);
useEffect(() => {
const element = contentRef.current;
if (!element) return;
const resizeObserver = new ResizeObserver(() => {
checkOverflow();
});
resizeObserver.observe(element);
// Initial check
checkOverflow();
return () => resizeObserver.disconnect();
}, [checkOverflow]);
useEffect(() => { useEffect(() => {
const debouncedCheckOverflow = throttle(checkOverflow, 200); const debouncedCheckOverflow = throttle(checkOverflow, 200);
window.addEventListener('resize', debouncedCheckOverflow); window.addEventListener('resize', debouncedCheckOverflow);
@@ -89,11 +106,28 @@ const AutoTooltip: React.FC<AutoTooltipProps> = ({
{...tooltipProps} {...tooltipProps}
> >
{ghost ? ( {ghost ? (
<div ref={contentRef} style={tagStyle}> <div ref={contentRef} style={tagStyle} data-overflow={isOverflowing}>
{children} {children}
</div> </div>
) : ( ) : (
<Tag {...tagProps} ref={contentRef} style={tagStyle}> <Tag
{...tagProps}
ref={contentRef}
style={{
...tagStyle,
paddingInline: tagProps.closable ? '8px 22px' : 8,
borderRadius: 12
}}
closeIcon={
<CloseOutlined
style={{
position: 'absolute',
right: 8,
top: 8
}}
/>
}
>
{children} {children}
</Tag> </Tag>
)} )}
+5 -1
View File
@@ -81,7 +81,11 @@ const LineChart: React.FC<ChartProps> = (props) => {
}, },
yAxis: { yAxis: {
...options.yAxis, ...options.yAxis,
name: yAxisName name: yAxisName,
nameTextStyle: {
fontSize: 12,
align: 'right'
}
}, },
xAxis: { xAxis: {
...options.xAxis, ...options.xAxis,
+5
View File
@@ -247,6 +247,11 @@ const useSetChunkRequest = () => {
}, []); }, []);
useEffect(() => { useEffect(() => {
console.log(
'chunkrequest===retryCount.current==',
requestReadyState,
retryCount.current
);
if (requestReadyState === 4 && retryCount.current > 0) { if (requestReadyState === 4 && retryCount.current > 0) {
requestConfig.current.beforeReconnect?.(); requestConfig.current.beforeReconnect?.();
clearTimeout(timer.current); clearTimeout(timer.current);
@@ -1,3 +1,4 @@
import AutoTooltip from '@/components/auto-tooltip';
import LabelSelector from '@/components/label-selector'; import LabelSelector from '@/components/label-selector';
import ListInput from '@/components/list-input'; import ListInput from '@/components/list-input';
import SealInput from '@/components/seal-form/seal-input'; import SealInput from '@/components/seal-form/seal-input';
@@ -5,13 +6,11 @@ import SealSelect from '@/components/seal-form/seal-select';
import { PageActionType } from '@/config/types'; import { PageActionType } from '@/config/types';
import { InfoCircleOutlined, RightOutlined } from '@ant-design/icons'; import { InfoCircleOutlined, RightOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { import {
Checkbox, Checkbox,
Collapse, Collapse,
Form, Form,
FormInstance, FormInstance,
Select,
Tooltip, Tooltip,
Typography Typography
} from 'antd'; } from 'antd';
@@ -252,7 +251,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
id: 'common.form.rule.select' id: 'common.form.rule.select'
}, },
{ {
name: 'gpu_selector' name: intl.formatMessage({ id: 'models.form.gpuselector' })
} }
) )
} }
@@ -262,14 +261,24 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
label={intl.formatMessage({ id: 'models.form.gpuselector' })} label={intl.formatMessage({ id: 'models.form.gpuselector' })}
required required
mode="multiple" mode="multiple"
maxLength={1} maxTagCount={1}
> tagRender={(props) => {
{gpuOptions.map((item) => ( return (
<Select.Option key={item.value} value={item.value}> <AutoTooltip
<GPUCard data={item}></GPUCard> className="m-r-0"
</Select.Option> closable={true}
))} onClose={props.onClose}
</SealSelect> maxWidth={240}
>
{props.label}
</AutoTooltip>
);
}}
options={gpuOptions}
optionRender={(props) => {
return <GPUCard data={props.data}></GPUCard>;
}}
></SealSelect>
</Form.Item> </Form.Item>
)} )}
<Form.Item name="backend_version"> <Form.Item name="backend_version">
+3 -2
View File
@@ -85,11 +85,12 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
const list = _.map(data.items, (item: GPUListItem) => { const list = _.map(data.items, (item: GPUListItem) => {
return { return {
...item, ...item,
label: item.name, title: '',
label: ` ${item.name}(${item.worker_name})[
${intl.formatMessage({ id: 'resources.table.index' })}:${item.index}]`,
value: item.id value: item.id
}; };
}); });
console.log('queryGPUList========', list);
setGpuOptions(list); setGpuOptions(list);
}; };
+1 -6
View File
@@ -14,12 +14,7 @@ const GPUCard: React.FC<{
return ( return (
<div className="gpu-card"> <div className="gpu-card">
<div className="header" style={{ width: '100%' }}> <div className="header" style={{ width: '100%' }}>
{header ?? ( {header ?? <AutoTooltip ghost>{data.label}</AutoTooltip>}
<AutoTooltip ghost>
{data.label}({data.worker_name})[
{intl.formatMessage({ id: 'resources.table.index' })}:{data.index}]
</AutoTooltip>
)}
</div> </div>
<div className="info"> <div className="info">
{info ?? ( {info ?? (
+6 -6
View File
@@ -406,7 +406,7 @@ const Models: React.FC<ModelsProps> = ({
const handleLogModalCancel = useCallback(() => { const handleLogModalCancel = useCallback(() => {
setOpenLogModal(false); setOpenLogModal(false);
onCancelViewLogs(); onCancelViewLogs();
}, []); }, [onCancelViewLogs]);
const handleDelete = async (row: any) => { const handleDelete = async (row: any) => {
modalRef.current.show({ modalRef.current.show({
@@ -437,23 +437,23 @@ const Models: React.FC<ModelsProps> = ({
}; };
const handleOpenPlayGround = (row: any) => { const handleOpenPlayGround = (row: any) => {
if (row.image_only) { if (row.categories?.includes(modelCategoriesMap.image)) {
navigate(`/playground/text-to-image?model=${row.name}`); navigate(`/playground/text-to-image?model=${row.name}`);
return; return;
} }
if (row.text_to_speech) { if (row.categories?.includes(modelCategoriesMap.text_to_speech)) {
navigate(`/playground/speech?model=${row.name}&type=tts`); navigate(`/playground/speech?model=${row.name}&type=tts`);
return; return;
} }
if (row.speech_to_text) { if (row.categories?.includes(modelCategoriesMap.speech_to_text)) {
navigate(`/playground/speech?model=${row.name}&type=stt`); navigate(`/playground/speech?model=${row.name}&type=stt`);
return; return;
} }
if (row.reranker) { if (row.categories?.includes(modelCategoriesMap.reranker)) {
navigate(`/playground/rerank?model=${row.name}`); navigate(`/playground/rerank?model=${row.name}`);
return; return;
} }
if (row.embedding_only) { if (row.categories?.includes(modelCategoriesMap.embedding)) {
navigate(`/playground/embedding?model=${row.name}`); navigate(`/playground/embedding?model=${row.name}`);
return; return;
} }
+9 -13
View File
@@ -48,8 +48,10 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
const list = _.map(data.items, (item: GPUListItem) => { const list = _.map(data.items, (item: GPUListItem) => {
return { return {
...item, ...item,
label: item.name, title: '',
value: `${item.worker_name}-${item.name}-${item.index}` label: ` ${item.name}(${item.worker_name})[
${intl.formatMessage({ id: 'resources.table.index' })}:${item.index}]`,
value: item.id
}; };
}); });
setGpuOptions(list); setGpuOptions(list);
@@ -92,9 +94,9 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
? props.data.categories[0] ? props.data.categories[0]
: null, : null,
scheduleType: props.data?.gpu_selector ? 'manual' : 'auto', scheduleType: props.data?.gpu_selector ? 'manual' : 'auto',
gpu_selector: props.data?.gpu_selector gpu_selector: props.data?.gpu_selector || {
? `${props.data?.gpu_selector.worker_name}-${props.data?.gpu_selector.gpu_name}-${props.data?.gpu_selector.gpu_index}` gpu_ids: []
: null }
}; };
form.setFieldsValue(formData); form.setFieldsValue(formData);
} }
@@ -300,19 +302,13 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
}; };
} }
if (formdata.scheduleType === 'manual') { if (formdata.scheduleType === 'manual') {
const gpu = _.find(gpuOptions, (item: any) => {
return item.value === formdata.gpu_selector;
});
onOk({ onOk({
..._.omit(formdata, ['scheduleType']), ..._.omit(formdata, ['scheduleType']),
categories: formdata.categories ? [formdata.categories] : [], categories: formdata.categories ? [formdata.categories] : [],
worker_selector: null, worker_selector: null,
gpu_selector: gpu gpu_selector: formdata.gpu_selector?.gpu_ids?.length
? { ? {
gpu_name: gpu.name, gpu_ids: formdata.gpu_selector.gpu_ids
gpu_index: gpu.index,
worker_name: gpu.worker_name
} }
: null, : null,
...obj ...obj
+45 -27
View File
@@ -13,8 +13,6 @@ import TableList from './components/table-list';
import { ListItem } from './config/types'; import { ListItem } from './config/types';
const Models: React.FC = () => { const Models: React.FC = () => {
console.log('model list====1');
const { setChunkRequest, createAxiosToken } = useSetChunkRequest(); const { setChunkRequest, createAxiosToken } = useSetChunkRequest();
const { setChunkRequest: setModelInstanceChunkRequest } = const { setChunkRequest: setModelInstanceChunkRequest } =
useSetChunkRequest(); useSetChunkRequest();
@@ -33,6 +31,7 @@ const Models: React.FC = () => {
const [firstLoad, setFirstLoad] = useState(true); const [firstLoad, setFirstLoad] = useState(true);
const chunkRequedtRef = useRef<any>(); const chunkRequedtRef = useRef<any>();
const chunkInstanceRequedtRef = useRef<any>(); const chunkInstanceRequedtRef = useRef<any>();
const isPageHidden = useRef(false);
let axiosToken = createAxiosToken(); let axiosToken = createAxiosToken();
const [queryParams, setQueryParams] = useState({ const [queryParams, setQueryParams] = useState({
page: 1, page: 1,
@@ -83,11 +82,13 @@ const Models: React.FC = () => {
total: res.pagination.total total: res.pagination.total
}); });
} catch (error) { } catch (error) {
setDataSource({ if (!isPageHidden.current) {
dataList: [], setDataSource({
loading: false, dataList: [],
total: dataSource.total loading: false,
}); total: dataSource.total
});
}
console.log('error+++', error); console.log('error+++', error);
} finally { } finally {
setFirstLoad(false); setFirstLoad(false);
@@ -115,7 +116,7 @@ const Models: React.FC = () => {
setModelInstances(list); setModelInstances(list);
}; };
const createModelsChunkRequest = () => { const createModelsChunkRequest = useCallback(async () => {
chunkRequedtRef.current?.current?.cancel?.(); chunkRequedtRef.current?.current?.cancel?.();
try { try {
chunkRequedtRef.current = setChunkRequest({ chunkRequedtRef.current = setChunkRequest({
@@ -128,8 +129,8 @@ const Models: React.FC = () => {
} catch (error) { } catch (error) {
// ignore // ignore
} }
}; }, [queryParams]);
const createModelsInstanceChunkRequest = () => { const createModelsInstanceChunkRequest = useCallback(async () => {
chunkInstanceRequedtRef.current?.current?.cancel?.(); chunkInstanceRequedtRef.current?.current?.cancel?.();
try { try {
chunkInstanceRequedtRef.current = setModelInstanceChunkRequest({ chunkInstanceRequedtRef.current = setModelInstanceChunkRequest({
@@ -140,7 +141,7 @@ const Models: React.FC = () => {
} catch (error) { } catch (error) {
// ignore // ignore
} }
}; }, []);
const handleSearch = useCallback( const handleSearch = useCallback(
(e: any) => { (e: any) => {
@@ -160,15 +161,22 @@ const Models: React.FC = () => {
); );
const handleOnViewLogs = useCallback(() => { const handleOnViewLogs = useCallback(() => {
isPageHidden.current = true;
chunkRequedtRef.current?.current?.cancel?.(); chunkRequedtRef.current?.current?.cancel?.();
cacheDataListRef.current = []; cacheDataListRef.current = [];
chunkInstanceRequedtRef.current?.current?.cancel?.(); chunkInstanceRequedtRef.current?.current?.cancel?.();
}, []); }, []);
const handleOnCancelViewLogs = useCallback(() => { const handleOnCancelViewLogs = useCallback(async () => {
createModelsChunkRequest(); isPageHidden.current = false;
createModelsInstanceChunkRequest(); await Promise.all([
}, []); createModelsChunkRequest(),
createModelsInstanceChunkRequest()
]);
setTimeout(() => {
fetchData();
}, 100);
}, [fetchData, createModelsChunkRequest, createModelsInstanceChunkRequest]);
useEffect(() => { useEffect(() => {
fetchData(); fetchData();
@@ -193,22 +201,32 @@ const Models: React.FC = () => {
createModelsChunkRequest(); createModelsChunkRequest();
createModelsInstanceChunkRequest(); createModelsInstanceChunkRequest();
}, 100); }, 100);
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
createModelsChunkRequest();
createModelsInstanceChunkRequest();
} else {
chunkRequedtRef.current?.current?.cancel?.();
cacheDataListRef.current = [];
chunkInstanceRequedtRef.current?.current?.cancel?.();
}
});
} }
}, [firstLoad]);
useEffect(() => {
const handleVisibilityChange = async () => {
if (document.visibilityState === 'visible') {
isPageHidden.current = false;
await Promise.all([
createModelsChunkRequest(),
createModelsInstanceChunkRequest()
]);
fetchData();
} else {
isPageHidden.current = true;
chunkRequedtRef.current?.current?.cancel?.();
cacheDataListRef.current = [];
chunkInstanceRequedtRef.current?.current?.cancel?.();
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => { return () => {
document.removeEventListener('visibilitychange', () => {}); document.removeEventListener('visibilitychange', handleVisibilityChange);
}; };
}, [firstLoad]); }, [fetchData, createModelsChunkRequest, createModelsInstanceChunkRequest]);
return ( return (
<TableContext.Provider <TableContext.Provider