chore: gpu selector, source dropdown
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+20
-2
@@ -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>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user