feat: vllm support

This commit is contained in:
jialin
2024-09-25 16:17:25 +08:00
parent 0652f850d6
commit 3cd96ba2e8
47 changed files with 1610 additions and 252 deletions
+97
View File
@@ -0,0 +1,97 @@
import AutoComplete from '@/components/seal-form/auto-complete';
import _ from 'lodash';
import React from 'react';
interface HintInputProps {
value: string;
label?: string;
onChange: (value: string) => void;
sourceOptions?: Global.HintOptions[];
}
const matchReg = /[^=]+=[^=]*$/;
const HintInput: React.FC<HintInputProps> = (props) => {
const { value, label, onChange, sourceOptions } = props;
const cursorPosRef = React.useRef(0);
const contextBeforeCursorRef = React.useRef('');
const [options, setOptions] = React.useState<
Array<Global.BaseOption<string>>
>([]);
const generateOptions = (context: string) => {
if (!context) {
setOptions([]);
return;
}
const match = context.match(matchReg);
if (!match) {
const list = _.filter(sourceOptions, (item: Global.HintOptions) =>
item.label.includes(context)
);
setOptions(list);
return;
}
const [key, value] = _.split(match[0], '=');
const data = _.find(
sourceOptions,
(item: Global.HintOptions) => item.label === key
);
if (!data) {
setOptions([]);
return;
}
const list = _.filter(data.opts, (item: Global.BaseOption<string>) =>
item.label.includes(value)
);
setOptions(list);
};
const replaceLastEqual = (value: string) => {
const matchStr = contextBeforeCursorRef.current.match(matchReg);
if (matchStr) {
const arr = _.split(matchStr[0], '=');
onChange(`${arr[0]}=${value}`);
} else {
onChange(value?.trim());
}
};
const getContextBeforeCursor = _.debounce((e: any) => {
cursorPosRef.current = e.target.selectionStart;
contextBeforeCursorRef.current = e.target.value.slice(
0,
cursorPosRef.current
);
generateOptions(contextBeforeCursorRef.current);
}, 100);
const handleInput = (e: any) => {
getContextBeforeCursor(e);
onChange(e.target.value?.trim());
};
const handleOnChange = (value: string) => {
onChange(value?.trim());
};
const handleOnSelect = (value: string) => {
replaceLastEqual(value);
setOptions([]);
};
return (
<AutoComplete
defaultActiveFirstOption={true}
value={value}
onInput={handleInput}
onSelect={handleOnSelect}
onFocus={getContextBeforeCursor}
label={label}
options={options}
style={{ width: '100%' }}
/>
);
};
export default React.memo(HintInput);
+109
View File
@@ -0,0 +1,109 @@
import { PlusOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Button } from 'antd';
import _ from 'lodash';
import React from 'react';
import Wrapper from '../label-selector/wrapper';
import ListItem from './list-item';
interface ListInputProps {
dataList: string[];
label: string;
description?: string;
btnText?: string;
options?: Global.HintOptions[];
onChange: (data: string[]) => void;
}
const ListInput: React.FC<ListInputProps> = (props) => {
const intl = useIntl();
const { dataList, label, description, onChange, btnText, options } = props;
const [list, setList] = React.useState<{ value: string; uid: number }[]>([]);
const countRef = React.useRef(0);
const buttonRef = React.useRef<HTMLButtonElement>(null);
const updateCountRef = () => {
countRef.current = countRef.current + 1;
};
const handleOnRemove = (index: number) => {
const values = _.cloneDeep(list);
values.splice(index, 1);
const valueList = _.map(values, 'value').filter((val: string) => !!val);
setList(values);
onChange(valueList);
};
const handleOnChange = (value: string, index: number) => {
const values = _.cloneDeep(list);
values[index].value = value;
const valueList = _.map(values, 'value').filter((val: string) => !!val);
setList(values);
onChange(valueList);
};
const handleOnAdd = () => {
updateCountRef();
const values = _.cloneDeep(list);
values.push({
value: '',
uid: countRef.current
});
setList(values);
setTimeout(() => {
buttonRef.current?.scrollIntoView?.({ behavior: 'smooth' });
}, 100);
};
React.useEffect(() => {
const valueList = _.map(list, 'value').filter((val: string) => !!val);
if (!_.isEqual(valueList, dataList)) {
const values = _.map(dataList, (value: string) => {
updateCountRef();
return {
value,
uid: countRef.current
};
});
setList(values);
}
}, [dataList]);
return (
<Wrapper label={label} description={description}>
<>
{_.map(list, (item: any, index: number) => {
return (
<ListItem
options={options}
key={item.uid}
value={item.value}
label={`${index + 1}`}
onRemove={() => handleOnRemove(index)}
onChange={(val) => handleOnChange(val, index)}
/>
);
})}
<div className="flex justify-center">
<Button
ref={buttonRef}
type="text"
block
style={{
marginTop: 16,
backgroundColor: 'var(--ant-color-fill-secondary)'
}}
onClick={handleOnAdd}
>
<PlusOutlined className="font-size-14" />{' '}
{intl.formatMessage({
id: btnText
})}
</Button>
</div>
</>
</Wrapper>
);
};
export default React.memo(ListInput);
+43
View File
@@ -0,0 +1,43 @@
// import AutoComplete from '@/components/seal-form/auto-complete';
import { MinusOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import React from 'react';
import HintInput from './hint-input';
import './styles/list-item.less';
interface LabelItemProps {
onRemove: () => void;
onChange: (value: string) => void;
value: string;
label?: string;
options?: Global.HintOptions[];
}
const ListItem: React.FC<LabelItemProps> = (props) => {
const { onRemove, onChange, label, value, options } = props;
const handleOnChange = (value: any) => {
onChange(value);
};
return (
<div className="list-item">
<HintInput
value={value}
onChange={handleOnChange}
label={label}
sourceOptions={options}
/>
<Button
size="small"
className="btn"
type="default"
shape="circle"
icon={<MinusOutlined />}
onClick={onRemove}
/>
</div>
);
};
export default React.memo(ListItem);
@@ -0,0 +1,15 @@
.list-item {
display: flex;
align-items: center;
justify-content: flex-start;
width: 100%;
margin-bottom: 12px;
.field-wrapper {
flex: 1;
}
.btn {
margin-left: 10px;
}
}