chore: gpu selector, source dropdown

main
jialin 1 year ago
parent f6bbbc56ba
commit 35a5733e82

@ -6,20 +6,22 @@ import _ from 'lodash';
import { memo } from 'react';
import './index.less';
type Trigger = 'click' | 'hover';
interface DropdownButtonsProps {
items: MenuProps['items'];
size?: 'small' | 'middle' | 'large';
trigger?: Trigger[];
onSelect: (val: any, item?: any) => void;
}
const DropdownButtons: React.FC<DropdownButtonsProps> = ({
items,
size = 'middle',
trigger = ['hover'],
onSelect
}) => {
const intl = useIntl();
const handleMenuClick = (item: any) => {
console.log('menu click', item.key);
const selectItem = _.find(items, { key: item.key });
onSelect(item.key, selectItem);
};
@ -48,6 +50,7 @@ const DropdownButtons: React.FC<DropdownButtonsProps> = ({
</Tooltip>
) : (
<Dropdown.Button
trigger={trigger}
dropdownRender={(menus: any) => {
return (
<div

@ -12,6 +12,16 @@ class AnsiParser {
private uid: number = 0;
private isProcessing: boolean = false;
private taskQueue: string[] = [];
private colorMap = {
'30': 'black',
'31': 'red',
'32': 'green',
'33': 'yellow',
'34': 'blue',
'35': 'magenta',
'36': 'cyan',
'37': 'white'
};
constructor() {
this.reset();
@ -82,7 +92,12 @@ class AnsiParser {
this.reset();
}
break;
case 'm': // style: do not handle now
case 'm':
// if (match[1] === '0') {
// currentStyle = '';
// } else if (colorMap[match[1]]) {
// currentStyle = `color: ${colorMap[match[1]]};`;
// }
break;
}

@ -782,6 +782,23 @@ body {
}
.cascader-popup-wrapper {
width: 100%;
&.gpu-selector {
.ant-cascader-menu:last-child {
flex: auto;
.ant-cascader-menu-item {
display: flex;
.ant-cascader-checkbox {
align-self: flex-start;
margin-top: 5px;
}
}
}
}
.ant-cascader-menu {
overflow-x: hidden;
@ -805,8 +822,9 @@ body {
}
}
.ant-cascader-checkbox.ant-cascader-checkbox-disabled {
display: none;
.ant-cascader-menu-item-content {
width: 100%;
padding-right: 11px;
}
}
}

@ -123,13 +123,31 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
form.setFieldValue('backend_parameters', list);
}, []);
const handleGPUSelectorChange = (gpuIds: any[]) => {
console.log('GPU Selector Change:', gpuIds);
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);
console.log('Last Group Items:', lastGroupItems);
form.setFieldValue(['gpu_selector', 'gpu_ids'], lastGroupItems);
};
const gpuOptionRender = (data: any) => {
let width = {
maxWidth: 180,
minWidth: 180
let width: any = {
maxWidth: 140,
minWidth: 140
};
if (!data.parent) {
width = { maxWidth: 180, minWidth: 180 };
width = undefined;
}
if (data.parent) {
return (
@ -234,47 +252,6 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
)}
{scheduleType === 'manual' && (
<>
{/* <Form.Item<FormData>
name={['gpu_selector', 'gpu_ids']}
rules={[
{
required: true,
message: intl.formatMessage(
{
id: 'common.form.rule.select'
},
{
name: intl.formatMessage({
id: 'models.form.gpuselector'
})
}
)
}
]}
>
<SealSelect
label={intl.formatMessage({ id: 'models.form.gpuselector' })}
required
mode="multiple"
maxTagCount={1}
tagRender={(props) => {
return (
<AutoTooltip
className="m-r-4"
closable={props.closable}
onClose={props.onClose}
maxWidth={240}
>
{props.label}
</AutoTooltip>
);
}}
options={gpuOptions}
optionRender={(props) => {
return <GPUCard data={props.data}></GPUCard>;
}}
></SealSelect>
</Form.Item> */}
<Form.Item
name={['gpu_selector', 'gpu_ids']}
rules={[
@ -295,14 +272,14 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
>
<SealCascader
required
onChange={handleGPUSelectorChange}
multiple={backend !== backendOptionsMap.voxBox}
popupClassName="cascader-popup-wrapper"
maxTagCount="responsive"
popupClassName="cascader-popup-wrapper gpu-selector"
maxTagCount={1}
label={intl.formatMessage({ id: 'models.form.gpuselector' })}
options={gpuOptions.map((item) => {
item.disableCheckbox = backend !== backendOptionsMap.llamaBox;
return item;
})}
options={gpuOptions}
showCheckedStrategy="SHOW_CHILD"
value={form.getFieldValue(['gpu_selector', 'gpu_ids'])}
tagRender={(props) => {
return (
<AutoTooltip
@ -316,6 +293,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
);
}}
optionRender={gpuOptionRender}
getPopupContainer={(triggerNode) => triggerNode.parentNode}
></SealCascader>
</Form.Item>
</>

@ -129,12 +129,11 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
label: `${value[0].worker_name}`,
value: value[0].worker_name,
parent: true,
disableCheckbox: true,
disableCheckbox: false,
..._.pick(value[0], workerFields),
children: _.map(value, (item: GPUListItem) => {
return {
label: `[
${intl.formatMessage({ id: 'resources.table.index' })}:${item.index}] ${item.name}`,
label: `${item.name}`,
value: item.id,
disableCheckbox: false,
..._.omit(item, workerFields)
@ -484,6 +483,20 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
return null;
}, [props.source, isGGUF, byBuiltIn, intl]);
const handleSetGPUIds = (backend: string) => {
if (backend === backendOptionsMap.llamaBox) {
return;
}
const gpuids = form.getFieldValue(['gpu_selector', 'gpu_ids']);
if (!gpuids?.length) {
return;
}
if (gpuids.length > 1 && Array.isArray(gpuids[0])) {
form.setFieldValue(['gpu_selector', 'gpu_ids'], [gpuids[0]]);
}
};
const handleBackendChange = useCallback((val: string) => {
if (val === backendOptionsMap.llamaBox) {
form.setFieldsValue({
@ -492,6 +505,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
});
}
form.setFieldValue('backend_version', '');
handleSetGPUIds(val);
props.onBackendChange?.(val);
}, []);
@ -500,17 +514,12 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
if (!gpu_ids.length) {
return {};
}
const result: string[] = [];
_.each(gpu_ids, (item: string[]) => {
if (item.length > 1) {
result.push(..._.tail(item));
}
if (item.length === 1) {
const worker = _.find(gpuOptions, { value: item[0] });
const gpus = _.map(worker?.children, 'value');
result.push(...gpus);
const result = _.map(gpu_ids, (item: string[][] | string[]) => {
if (Array.isArray(item)) {
return item[1];
}
return item;
});
if (result.length) {

@ -0,0 +1,27 @@
import React from 'react';
import '../style/deploy-dropdown.less';
interface DeployDropdownProps {
items: { label: string; value: string; key: string; icon: React.ReactNode }[];
onSelect: (item: {
label: string;
value: string;
key: string;
icon: React.ReactNode;
}) => void;
}
const DeployDropdown: React.FC<DeployDropdownProps> = ({ items, onSelect }) => {
return (
<div className="deploy-dropdown">
{items.map((item) => (
<div key={item.key} onClick={() => onSelect(item)} className="item">
<span className="icon">{item.icon}</span>
<span className="label">{item.label}</span>
</div>
))}
</div>
);
};
export default DeployDropdown;

@ -129,6 +129,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
closeIcon={false}
maskClosable={false}
keyboard={false}
zIndex={2000}
styles={{
body: {
height: 'calc(100vh - 57px)',

@ -14,7 +14,12 @@ const GPUCard: React.FC<{
return (
<div className="gpu-card">
<div className="header" style={{ width: '100%' }}>
{header ?? <AutoTooltip ghost>{data.label}</AutoTooltip>}
{header ?? (
<AutoTooltip ghost>
<span className="font-700">[{data.index}] </span>
{data.label}
</AutoTooltip>
)}
</div>
<div className="info">
{info ?? (

@ -52,6 +52,7 @@ import {
modelSourceMap
} from '../config';
import { FormData, ListItem, ModelInstanceListItem } from '../config/types';
import DeployDropdown from './deploy-dropdown';
import DeployModal from './deploy-modal';
import InstanceItem from './instance-item';
import UpdateModel from './update-modal';
@ -787,6 +788,13 @@ const Models: React.FC<ModelsProps> = ({
items: sourceOptions,
onClick: handleClickDropdown
}}
trigger={['hover']}
dropdownRender={() => (
<DeployDropdown
items={sourceOptions}
onSelect={handleClickDropdown}
></DeployDropdown>
)}
placement="bottomRight"
>
<Button

@ -88,8 +88,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
..._.pick(value[0], workerFields),
children: _.map(value, (item: GPUListItem) => {
return {
label: `[
${intl.formatMessage({ id: 'resources.table.index' })}:${item.index}] ${item.name}`,
label: `${item.name}`,
value: item.id,
..._.omit(item, workerFields)
};
@ -111,23 +110,17 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
if (gpu_ids.length === 0) {
return [];
}
const dataList = _.reduce(
gpuOptions,
(list: string[], item: any) => {
const gpuIds = _.filter(
gpu_ids,
(id: string) => id.indexOf(item.worker_name) > -1
);
if (gpuIds.length && gpuIds.length === item.children.length) {
list.push(item.worker_name);
} else if (gpuIds.length) {
list.push(item.worker_name, ...gpuIds);
const gpuids: string[][] = [];
gpuOptions?.forEach((item) => {
item.children?.forEach((child: any) => {
if (gpu_ids.includes(child.value)) {
gpuids.push([item.value, child.value]);
}
return list;
},
{}
);
return dataList;
});
});
return data.backend === backendOptionsMap.voxBox ? gpuids[0] : gpuids;
};
useEffect(() => {
@ -137,10 +130,6 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
props.data
);
const gpu_ids = generateGPUSelector(props.data);
console.log('gpu_ids+++++++++', gpu_ids);
const formData = {
...result.values,
..._.omit(props.data, result.omits),
@ -148,9 +137,11 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
? props.data.categories[0]
: null,
scheduleType: props.data?.gpu_selector ? 'manual' : 'auto',
gpu_selector: props.data?.gpu_selector || {
gpu_ids: gpu_ids
}
gpu_selector: props.data?.gpu_selector?.gpu_ids.length
? {
gpu_ids: generateGPUSelector(props.data)
}
: []
};
form.setFieldsValue(formData);
}
@ -160,6 +151,20 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
setIsGGUF(props.data?.backend === backendOptionsMap.llamaBox);
}, [props.data?.backend]);
const handleSetGPUIds = (backend: string) => {
if (backend === backendOptionsMap.llamaBox) {
return;
}
const gpuids = form.getFieldValue(['gpu_selector', 'gpu_ids']);
if (!gpuids?.length) {
return;
}
if (gpuids.length > 1 && Array.isArray(gpuids[0])) {
form.setFieldValue(['gpu_selector', 'gpu_ids'], [gpuids[0]]);
}
};
const handleBackendChange = useCallback((val: string) => {
if (val === backendOptionsMap.llamaBox) {
form.setFieldsValue({
@ -168,6 +173,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
});
}
form.setFieldValue('backend_version', '');
handleSetGPUIds(val);
}, []);
const handleOnFocus = () => {
@ -367,6 +373,29 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
form.submit();
};
const generateGPUIds = (data: FormData) => {
const gpu_ids = _.get(data, 'gpu_selector.gpu_ids', []);
if (!gpu_ids.length) {
return {};
}
const result = _.map(gpu_ids, (item: string[][] | string[]) => {
if (Array.isArray(item)) {
return item[1];
}
return item;
});
if (result.length) {
return {
gpu_selector: {
gpu_ids: result
}
};
}
return {};
};
const handleOk = (formdata: FormData) => {
let obj = {};
if (
@ -380,6 +409,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
};
}
if (formdata.scheduleType === 'manual') {
const gpuSelector = generateGPUIds(formdata);
onOk({
..._.omit(formdata, ['scheduleType']),
categories: formdata.categories ? [formdata.categories] : [],
@ -389,7 +419,8 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
gpu_ids: formdata.gpu_selector.gpu_ids
}
: null,
...obj
...obj,
...gpuSelector
});
} else {
onOk({

@ -0,0 +1,28 @@
.deploy-dropdown {
display: flex;
justify-content: flex-start;
padding: var(--ant-padding-xxs);
background-color: var(--ant-color-bg-elevated);
background-clip: padding-box;
border-radius: var(--ant-border-radius-lg);
outline: none;
box-shadow: var(--ant-box-shadow-secondary);
.item {
cursor: pointer;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: var(--ant-dropdown-padding-block)
var(--ant-control-padding-horizontal);
&:hover {
background-color: var(--ant-control-item-bg-hover);
}
.icon {
font-size: 20px;
}
}
}

@ -365,10 +365,10 @@ const Resources: React.FC = () => {
maxWidth: 200
}}
>
{_.map(record.labels, (item: any, index: string) => {
{_.map(record.labels, (value: any, key: string) => {
return (
<AutoTooltip
key={index}
key={key}
className="m-r-0"
maxWidth={120}
style={{
@ -376,7 +376,8 @@ const Resources: React.FC = () => {
borderRadius: 12
}}
>
{index}:{item}
<span className="font-700">{key}</span>
<span className="text-tertiary">:{value}</span>
</AutoTooltip>
);
})}

Loading…
Cancel
Save