chore: adjust deployment modal form
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import IconFont from '@/components/icon-font';
|
||||
import LabelSelector from '@/components/label-selector';
|
||||
import ListInput from '@/components/list-input';
|
||||
import CheckboxField from '@/components/seal-form/checkbox-field';
|
||||
import SealCascader from '@/components/seal-form/seal-cascader';
|
||||
import SealInput from '@/components/seal-form/seal-input';
|
||||
import SealSelect from '@/components/seal-form/seal-select';
|
||||
@@ -8,17 +9,8 @@ import TooltipList from '@/components/tooltip-list';
|
||||
import { PageAction } from '@/config';
|
||||
import { PageActionType } from '@/config/types';
|
||||
import useAppUtils from '@/hooks/use-app-utils';
|
||||
import { QuestionCircleOutlined } from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import {
|
||||
Checkbox,
|
||||
Collapse,
|
||||
Form,
|
||||
FormInstance,
|
||||
Tooltip,
|
||||
Typography
|
||||
} from 'antd';
|
||||
import { CheckboxChangeEvent } from 'antd/es/checkbox';
|
||||
import { Collapse, Form, FormInstance, Typography } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import {
|
||||
@@ -32,7 +24,6 @@ import {
|
||||
placementStrategyOptions
|
||||
} from '../config';
|
||||
import { useFormContext } from '../config/form-context';
|
||||
import llamaConfig from '../config/llama-config';
|
||||
import mindieConfig from '../config/mindie-config';
|
||||
import { FormData } from '../config/types';
|
||||
import vllmConfig from '../config/vllm-config';
|
||||
@@ -62,42 +53,6 @@ const placementStrategyTips = [
|
||||
}
|
||||
];
|
||||
|
||||
const scheduleTypeTips = [
|
||||
{
|
||||
title: {
|
||||
text: 'models.form.scheduletype.auto',
|
||||
locale: true
|
||||
},
|
||||
tips: 'models.form.scheduletype.auto.tips'
|
||||
},
|
||||
{
|
||||
title: {
|
||||
text: 'models.form.scheduletype.manual',
|
||||
locale: true
|
||||
},
|
||||
tips: 'models.form.scheduletype.manual.tips'
|
||||
}
|
||||
];
|
||||
|
||||
const CheckboxField: React.FC<{
|
||||
title: string;
|
||||
label: string;
|
||||
checked?: boolean;
|
||||
onChange?: (e: CheckboxChangeEvent) => void;
|
||||
}> = ({ title, label, checked, onChange }) => {
|
||||
return (
|
||||
<Checkbox className="p-l-6" checked={checked} onChange={onChange}>
|
||||
<Tooltip title={title}>
|
||||
<span style={{ color: 'var(--ant-color-text-tertiary)' }}>{label}</span>
|
||||
<QuestionCircleOutlined
|
||||
className="m-l-4"
|
||||
style={{ color: 'var(--ant-color-text-tertiary)' }}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Checkbox>
|
||||
);
|
||||
};
|
||||
|
||||
const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
||||
const { form, isGGUF, gpuOptions, source, backendOptions, action } = props;
|
||||
const { getRuleMessage } = useAppUtils();
|
||||
@@ -115,9 +70,6 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
||||
const { onValuesChange } = useFormContext();
|
||||
|
||||
const paramsConfig = useMemo(() => {
|
||||
if (backend === backendOptionsMap.llamaBox) {
|
||||
return llamaConfig;
|
||||
}
|
||||
if (backend === backendOptionsMap.vllm) {
|
||||
return vllmConfig;
|
||||
}
|
||||
@@ -220,14 +172,6 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
||||
description={<TooltipList list={backendTipsList}></TooltipList>}
|
||||
options={
|
||||
backendOptions ?? [
|
||||
{
|
||||
label: backendLabelMap[backendOptionsMap.llamaBox],
|
||||
value: backendOptionsMap.llamaBox,
|
||||
disabled:
|
||||
props.source === modelSourceMap.local_path_value
|
||||
? false
|
||||
: !isGGUF
|
||||
},
|
||||
{
|
||||
label: backendLabelMap[backendOptionsMap.vllm],
|
||||
value: backendOptionsMap.vllm,
|
||||
@@ -261,27 +205,6 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
||||
}
|
||||
></SealSelect>
|
||||
</Form.Item>
|
||||
{/* <Form.Item name="scheduleType">
|
||||
<SealSelect
|
||||
onChange={handleScheduleTypeChange}
|
||||
label={intl.formatMessage({ id: 'models.form.scheduletype' })}
|
||||
description={<TooltipList list={scheduleTypeTips}></TooltipList>}
|
||||
options={[
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: 'models.form.scheduletype.auto'
|
||||
}),
|
||||
value: 'auto'
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: 'models.form.scheduletype.manual'
|
||||
}),
|
||||
value: 'manual'
|
||||
}
|
||||
]}
|
||||
></SealSelect>
|
||||
</Form.Item> */}
|
||||
{scheduleType === 'auto' && (
|
||||
<>
|
||||
<Form.Item<FormData> name="placement_strategy">
|
||||
@@ -482,31 +405,10 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
||||
></LabelSelector>
|
||||
</Form.Item>
|
||||
|
||||
{backend === backendOptionsMap.llamaBox && (
|
||||
<div style={{ paddingBottom: 22, paddingLeft: 10 }}>
|
||||
<Form.Item<FormData>
|
||||
name="cpu_offloading"
|
||||
valuePropName="checked"
|
||||
style={{ padding: '0 10px', marginBottom: 0 }}
|
||||
noStyle
|
||||
>
|
||||
<CheckboxField
|
||||
title={intl.formatMessage({
|
||||
id: 'models.form.partialoffload.tips'
|
||||
})}
|
||||
label={intl.formatMessage({
|
||||
id: 'resources.form.enablePartialOffload'
|
||||
})}
|
||||
></CheckboxField>
|
||||
</Form.Item>
|
||||
</div>
|
||||
)}
|
||||
{scheduleType === 'auto' &&
|
||||
[
|
||||
backendOptionsMap.llamaBox,
|
||||
backendOptionsMap.vllm,
|
||||
backendOptionsMap.ascendMindie
|
||||
].includes(backend) && (
|
||||
[backendOptionsMap.vllm, backendOptionsMap.ascendMindie].includes(
|
||||
backend
|
||||
) && (
|
||||
<div style={{ paddingBottom: 22, paddingLeft: 10 }}>
|
||||
<Form.Item<FormData>
|
||||
name="distributed_inference_across_workers"
|
||||
@@ -515,7 +417,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
||||
noStyle
|
||||
>
|
||||
<CheckboxField
|
||||
title={intl.formatMessage({
|
||||
description={intl.formatMessage({
|
||||
id: 'models.form.distribution.tips'
|
||||
})}
|
||||
label={intl.formatMessage({
|
||||
@@ -533,7 +435,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
||||
noStyle
|
||||
>
|
||||
<CheckboxField
|
||||
title={intl.formatMessage({
|
||||
description={intl.formatMessage({
|
||||
id: 'models.form.restart.onerror.tips'
|
||||
})}
|
||||
label={intl.formatMessage({
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import CatalogSkelton from '@/components/templates/card-skelton';
|
||||
import breakpoints from '@/config/breakpoints';
|
||||
import { Col, FloatButton, Row, Spin } from 'antd';
|
||||
import _ from 'lodash';
|
||||
@@ -6,7 +7,6 @@ import React, { useCallback } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { CatalogItem as CatalogItemType } from '../config/types';
|
||||
import CatalogItem from './catalog-item';
|
||||
import CatalogSkelton from './catalog-skelton';
|
||||
|
||||
const SpinWrapper = styled.div`
|
||||
width: 100%;
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import { Col, Row, Skeleton } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
interface CatalogSkeltonProps {
|
||||
span: number;
|
||||
}
|
||||
|
||||
const CatalogSkelton: React.FC<CatalogSkeltonProps> = (props) => {
|
||||
return (
|
||||
<Row gutter={[16, 16]}>
|
||||
{Array(6)
|
||||
.fill(1)
|
||||
.map((_, index) => {
|
||||
return (
|
||||
<Col span={props.span} key={index}>
|
||||
<Skeleton
|
||||
avatar={{
|
||||
size: 32
|
||||
}}
|
||||
paragraph={{ rows: 2 }}
|
||||
style={{
|
||||
border: '1px solid var(--ant-color-border)',
|
||||
borderRadius: 'var(--border-radius-base)',
|
||||
padding: '16px 16px'
|
||||
}}
|
||||
></Skeleton>
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(CatalogSkelton);
|
||||
@@ -258,14 +258,6 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
||||
description={<TooltipList list={backendTipsList}></TooltipList>}
|
||||
options={
|
||||
backendOptions ?? [
|
||||
{
|
||||
label: backendLabelMap[backendOptionsMap.llamaBox],
|
||||
value: backendOptionsMap.llamaBox,
|
||||
disabled:
|
||||
props.source === modelSourceMap.local_path_value
|
||||
? false
|
||||
: !isGGUF
|
||||
},
|
||||
{
|
||||
label: backendLabelMap[backendOptionsMap.vllm],
|
||||
value: backendOptionsMap.vllm,
|
||||
@@ -300,28 +292,6 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
||||
></SealSelect>
|
||||
</Form.Item> */}
|
||||
<CatalogFrom></CatalogFrom>
|
||||
{/* <Form.Item<FormData>
|
||||
name="replicas"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: getRuleMessage('input', 'models.form.replicas')
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealInput.Number
|
||||
style={{ width: '100%' }}
|
||||
label={intl.formatMessage({
|
||||
id: 'models.form.replicas'
|
||||
})}
|
||||
required
|
||||
description={intl.formatMessage(
|
||||
{ id: 'models.form.replicas.tips' },
|
||||
{ api: `${window.location.origin}/v1` }
|
||||
)}
|
||||
min={0}
|
||||
></SealInput.Number>
|
||||
</Form.Item> */}
|
||||
<Form.Item<FormData> name="description">
|
||||
<SealInput.TextArea
|
||||
scaleSize={true}
|
||||
@@ -343,4 +313,4 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
||||
);
|
||||
});
|
||||
|
||||
export default React.memo(DataForm);
|
||||
export default DataForm;
|
||||
|
||||
@@ -568,6 +568,7 @@ const AddModal: FC<AddModalProps> = (props) => {
|
||||
isGGUF: isGGUF,
|
||||
pageAction: action,
|
||||
modelFileOptions: props.modelFileOptions,
|
||||
gpuOptions: props.gpuOptions,
|
||||
onValuesChange: onValuesChange
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,18 +1,145 @@
|
||||
import IconFont from '@/components/icon-font';
|
||||
import StatusTag from '@/components/status-tag';
|
||||
import ThemeTag from '@/components/tags-wrapper/theme-tag';
|
||||
import Card from '@/components/templates/card';
|
||||
import { Button } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
InstanceStatusMap,
|
||||
InstanceStatusMapValue,
|
||||
modelCategories,
|
||||
modelSourceMap,
|
||||
status
|
||||
} from '../config';
|
||||
|
||||
const ModelItem: React.FC<{ model: any; onDeploy: (model: any) => void }> = (
|
||||
props
|
||||
) => {
|
||||
const { model, onDeploy } = props;
|
||||
const ModelItemContent = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
cursor: default;
|
||||
.title {
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-bottom: 8px;
|
||||
.anticon {
|
||||
font-size: 16px;
|
||||
color: var(--ant-color-text-secondary);
|
||||
}
|
||||
.text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: var(--font-size-middle);
|
||||
font-weight: 500;
|
||||
color: var(--ant-color-text);
|
||||
}
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
flex: 1;
|
||||
}
|
||||
.footer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
.btn {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
.btn {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.time {
|
||||
color: var(--ant-color-text-secondary);
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: 400;
|
||||
}
|
||||
.extra-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
.tag-item {
|
||||
margin-right: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
height: 22px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const sourceIconMap = {
|
||||
[modelSourceMap.local_path_value]: 'icon-hard-disk',
|
||||
[modelSourceMap.huggingface_value]: 'icon-huggingface',
|
||||
[modelSourceMap.modelscope_value]: 'icon-modelscope'
|
||||
};
|
||||
|
||||
const ModelItem: React.FC<{
|
||||
model: Record<string, any>;
|
||||
onClick: (model: any) => void;
|
||||
}> = (props) => {
|
||||
const { model, onClick } = props;
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<div className="model-item" onClick={() => onDeploy(model)}>
|
||||
<h3>{model.name}</h3>
|
||||
<p>{model.description}</p>
|
||||
<span>Deploy</span>
|
||||
</div>
|
||||
<Card onClick={() => onClick(model)} clickable={false} ghost>
|
||||
<ModelItemContent>
|
||||
<div className="title">
|
||||
<span className="text">
|
||||
<IconFont
|
||||
type={sourceIconMap[model.source]}
|
||||
style={{ marginRight: 8 }}
|
||||
/>
|
||||
<span>{model.name}</span>
|
||||
</span>
|
||||
<StatusTag
|
||||
maxTooltipWidth={400}
|
||||
statusValue={{
|
||||
status: status[InstanceStatusMap.Running] as any,
|
||||
text: InstanceStatusMapValue[InstanceStatusMap.Running],
|
||||
message: model.state_message
|
||||
}}
|
||||
></StatusTag>
|
||||
</div>
|
||||
<div className="content">
|
||||
<div className="extra-info">
|
||||
<ThemeTag className="tag-item" color="blue">
|
||||
{_.find(modelCategories, { value: model.categories?.[0] })
|
||||
?.label || model.categories?.[0]}
|
||||
</ThemeTag>
|
||||
<ThemeTag className="tag-item" color="purple">
|
||||
128K context
|
||||
</ThemeTag>
|
||||
</div>
|
||||
<div className="footer">
|
||||
<span className="time">
|
||||
{dayjs(model.created_at).format('YYYY-MM-DD HH:mm:ss')}
|
||||
</span>
|
||||
<Button
|
||||
size="middle"
|
||||
className="btn"
|
||||
variant="filled"
|
||||
color="default"
|
||||
>
|
||||
Go to Playground
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</ModelItemContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
import AlertBlockInfo from '@/components/alert-info/block';
|
||||
import IconFont from '@/components/icon-font';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Button } from 'antd';
|
||||
import { useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
padding-inline: 24px;
|
||||
`;
|
||||
|
||||
const Tips = styled.div`
|
||||
margin-top: 8px !important;
|
||||
ul {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
margin-top: 8px !important;
|
||||
li {
|
||||
position: relative;
|
||||
list-style: none;
|
||||
line-height: 24px;
|
||||
margin: 0 !important;
|
||||
padding-inline: 16px 0 !important;
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background-color: var(--ant-color-text-secondary);
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.bold {
|
||||
font-weight: 700;
|
||||
color: var(--ant-color-text);
|
||||
}
|
||||
.notice {
|
||||
margin-top: 8px !important;
|
||||
}
|
||||
`;
|
||||
|
||||
const TitleWrapper = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 700;
|
||||
color: var(--ant-color-text);
|
||||
justify-content: space-between;
|
||||
`;
|
||||
|
||||
const RenderMessage = () => {
|
||||
const intl = useIntl();
|
||||
return (
|
||||
<Tips>
|
||||
<div className="notice">
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: intl.formatMessage({
|
||||
id: 'models.ollama.deprecated.notice'
|
||||
})
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
</Tips>
|
||||
);
|
||||
};
|
||||
|
||||
const OllamaTips = () => {
|
||||
const intl = useIntl();
|
||||
const [maxHeight, setMaxHeight] = useState(1);
|
||||
const handleShowMore = () => {
|
||||
setMaxHeight(maxHeight === 1 ? 600 : 1);
|
||||
};
|
||||
return (
|
||||
<Wrapper>
|
||||
<AlertBlockInfo
|
||||
contentStyle={{ paddingInline: 0 }}
|
||||
maxHeight={maxHeight}
|
||||
ellipsis={false}
|
||||
message={<RenderMessage></RenderMessage>}
|
||||
title={
|
||||
<TitleWrapper>
|
||||
<div>
|
||||
{intl.formatMessage({ id: 'models.ollama.deprecated.title' })}
|
||||
</div>
|
||||
<Button
|
||||
onClick={handleShowMore}
|
||||
size="small"
|
||||
type="text"
|
||||
icon={<IconFont type="icon-down"></IconFont>}
|
||||
></Button>
|
||||
</TitleWrapper>
|
||||
}
|
||||
type={'warning'}
|
||||
></AlertBlockInfo>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default OllamaTips;
|
||||
@@ -1,12 +1,15 @@
|
||||
import CheckboxField from '@/components/seal-form/checkbox-field';
|
||||
import SealCascader from '@/components/seal-form/seal-cascader';
|
||||
import SealSelect from '@/components/seal-form/seal-select';
|
||||
import TooltipList from '@/components/tooltip-list';
|
||||
import useAppUtils from '@/hooks/use-app-utils';
|
||||
import { QuestionCircleOutlined } from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Checkbox, Form, Tooltip } from 'antd';
|
||||
import { CheckboxChangeEvent } from 'antd/es/checkbox';
|
||||
import { Form } from 'antd';
|
||||
import React from 'react';
|
||||
import { backendOptionsMap } from '../config';
|
||||
import { useFormContext } from '../config/form-context';
|
||||
import { FormData } from '../config/types';
|
||||
import GPUCard from './gpu-card';
|
||||
|
||||
const scheduleTypeTips = [
|
||||
{
|
||||
@@ -25,29 +28,15 @@ const scheduleTypeTips = [
|
||||
}
|
||||
];
|
||||
|
||||
const CheckboxField: React.FC<{
|
||||
title: string;
|
||||
label: string;
|
||||
checked?: boolean;
|
||||
onChange?: (e: CheckboxChangeEvent) => void;
|
||||
}> = ({ title, label, checked, onChange }) => {
|
||||
return (
|
||||
<Checkbox className="p-l-6" checked={checked} onChange={onChange}>
|
||||
<Tooltip title={title}>
|
||||
<span style={{ color: 'var(--ant-color-text-tertiary)' }}>{label}</span>
|
||||
<QuestionCircleOutlined
|
||||
className="m-l-4"
|
||||
style={{ color: 'var(--ant-color-text-tertiary)' }}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Checkbox>
|
||||
);
|
||||
};
|
||||
|
||||
const Performance: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const { onValuesChange, onQuantizationChange, source, quantizationOptions } =
|
||||
useFormContext();
|
||||
const {
|
||||
onValuesChange,
|
||||
onQuantizationChange,
|
||||
gpuOptions,
|
||||
source,
|
||||
quantizationOptions
|
||||
} = useFormContext();
|
||||
const { getRuleMessage } = useAppUtils();
|
||||
const form = Form.useFormInstance();
|
||||
|
||||
@@ -61,6 +50,8 @@ const Performance: React.FC = () => {
|
||||
onQuantizationChange?.(val);
|
||||
};
|
||||
|
||||
const handleGpuSelectorChange = (value: any) => {};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item name="scheduleType">
|
||||
@@ -80,30 +71,102 @@ const Performance: React.FC = () => {
|
||||
id: 'models.form.scheduletype.manual'
|
||||
}),
|
||||
value: 'manual'
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: 'models.form.scheduletype.gpuType'
|
||||
}),
|
||||
value: 'specific_gpu_type'
|
||||
}
|
||||
]}
|
||||
></SealSelect>
|
||||
</Form.Item>
|
||||
<Form.Item<FormData>
|
||||
name="quantization"
|
||||
key="quantization"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: getRuleMessage('select', 'quantization', false)
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealSelect
|
||||
filterOption
|
||||
defaultActiveFirstOption
|
||||
disabled={false}
|
||||
options={quantizationOptions}
|
||||
onChange={handleOnQuantizationChange}
|
||||
label="Quantization"
|
||||
required
|
||||
></SealSelect>
|
||||
</Form.Item>
|
||||
{form.getFieldValue('scheduleType') === 'specific_gpu_type' && (
|
||||
<>
|
||||
<Form.Item name={['gpu_selector', 'gpu_type']}>
|
||||
<SealSelect
|
||||
label={intl.formatMessage({ id: 'models.form.gpuType' })}
|
||||
options={[
|
||||
{
|
||||
label: 'NVIDIA 4090',
|
||||
value: 'nvidia-4090'
|
||||
},
|
||||
{
|
||||
label: 'NVIDIA A100',
|
||||
value: 'nvidia-a100'
|
||||
},
|
||||
{
|
||||
label: 'NVIDIA H100',
|
||||
value: 'nvidia-h100'
|
||||
},
|
||||
{
|
||||
label: 'Huawei 910B',
|
||||
value: 'huawei-910b'
|
||||
},
|
||||
{
|
||||
label: 'Huawei 910C',
|
||||
value: 'huawei-910c'
|
||||
}
|
||||
]}
|
||||
></SealSelect>
|
||||
</Form.Item>
|
||||
<Form.Item name={['gpu_selector', 'gpu_count']}>
|
||||
<SealSelect
|
||||
label={intl.formatMessage({ id: 'models.form.gpuCount' })}
|
||||
options={[
|
||||
{
|
||||
label: 'Auto',
|
||||
value: 'auto'
|
||||
},
|
||||
{
|
||||
label: '1',
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: '2',
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
label: '4',
|
||||
value: 4
|
||||
}
|
||||
]}
|
||||
></SealSelect>
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
{form.getFieldValue('scheduleType') === 'manual' &&
|
||||
!form.getFieldValue('fix_gpu_type') && (
|
||||
<>
|
||||
<Form.Item
|
||||
name={['gpu_selector', 'gpu_ids']}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: getRuleMessage('select', 'models.form.gpuselector')
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealCascader
|
||||
required
|
||||
showSearch
|
||||
expandTrigger="hover"
|
||||
multiple={
|
||||
form.getFieldValue('backend') !== backendOptionsMap.voxBox
|
||||
}
|
||||
popupClassName="cascader-popup-wrapper gpu-selector"
|
||||
maxTagCount={1}
|
||||
label={intl.formatMessage({ id: 'models.form.gpuselector' })}
|
||||
options={gpuOptions}
|
||||
showCheckedStrategy="SHOW_CHILD"
|
||||
value={form.getFieldValue(['gpu_selector', 'gpu_ids'])}
|
||||
optionNode={GPUCard}
|
||||
getPopupContainer={(triggerNode) => triggerNode.parentNode}
|
||||
onChange={handleGpuSelectorChange}
|
||||
></SealCascader>
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
<div style={{ paddingBottom: 22, paddingLeft: 10 }}>
|
||||
<Form.Item<FormData>
|
||||
name="optimize_long_prompt"
|
||||
@@ -112,8 +175,7 @@ const Performance: React.FC = () => {
|
||||
noStyle
|
||||
>
|
||||
<CheckboxField
|
||||
title="Optimize long prompt tips"
|
||||
label="Optimize Long Prompt"
|
||||
label={intl.formatMessage({ id: 'models.form.optimizeLongPrompt' })}
|
||||
></CheckboxField>
|
||||
</Form.Item>
|
||||
</div>
|
||||
@@ -125,8 +187,9 @@ const Performance: React.FC = () => {
|
||||
noStyle
|
||||
>
|
||||
<CheckboxField
|
||||
title="Enable speculative decoding tips"
|
||||
label="Enable Speculative Decoding"
|
||||
label={intl.formatMessage({
|
||||
id: 'models.form.enableSpeculativeDecoding'
|
||||
})}
|
||||
></CheckboxField>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
@@ -111,6 +111,36 @@ interface ModelsProps {
|
||||
total: number;
|
||||
}
|
||||
|
||||
const clusterList = [
|
||||
{
|
||||
label: 'Custom',
|
||||
value: 'custom'
|
||||
},
|
||||
{
|
||||
label: 'Kubernetes',
|
||||
value: 'kubernetes'
|
||||
},
|
||||
{
|
||||
label: 'Digital Ocean',
|
||||
value: 'digital_ocean'
|
||||
}
|
||||
];
|
||||
|
||||
const statusList = [
|
||||
{
|
||||
label: 'Running',
|
||||
value: 'running'
|
||||
},
|
||||
{
|
||||
label: 'Stopped',
|
||||
value: 'stopped'
|
||||
},
|
||||
{
|
||||
label: 'Error',
|
||||
value: 'error'
|
||||
}
|
||||
];
|
||||
|
||||
const getFormattedData = (record: any, extraData = {}) => ({
|
||||
id: record.id,
|
||||
data: {
|
||||
@@ -605,7 +635,6 @@ const Models: React.FC<ModelsProps> = ({
|
||||
title: intl.formatMessage({ id: 'common.table.name' }),
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: 400,
|
||||
span: 5,
|
||||
render: (text: string, record: ListItem) => (
|
||||
<span className="flex-center" style={{ maxWidth: '100%' }}>
|
||||
@@ -620,10 +649,10 @@ const Models: React.FC<ModelsProps> = ({
|
||||
title: 'Cluster',
|
||||
dataIndex: 'cluster',
|
||||
key: 'cluster',
|
||||
span: 4,
|
||||
span: 3,
|
||||
render: (text: string, record: ListItem) => (
|
||||
<span className="flex flex-column" style={{ width: '100%' }}>
|
||||
Custom
|
||||
{['Custom', 'Kubernetes', 'Digital Ocean'][record.id] || 'Custom'}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
@@ -631,7 +660,7 @@ const Models: React.FC<ModelsProps> = ({
|
||||
title: intl.formatMessage({ id: 'models.form.source' }),
|
||||
dataIndex: 'source',
|
||||
key: 'source',
|
||||
span: 4,
|
||||
span: 5,
|
||||
render: (text: string, record: ListItem) => (
|
||||
<span className="flex flex-column" style={{ width: '100%' }}>
|
||||
<AutoTooltip ghost>{generateSource(record)}</AutoTooltip>
|
||||
@@ -778,7 +807,7 @@ const Models: React.FC<ModelsProps> = ({
|
||||
<Space>
|
||||
<Input
|
||||
placeholder={intl.formatMessage({ id: 'common.filter.name' })}
|
||||
style={{ width: 200 }}
|
||||
style={{ width: 160 }}
|
||||
size="large"
|
||||
allowClear
|
||||
onChange={handleNameChange}
|
||||
@@ -789,7 +818,7 @@ const Models: React.FC<ModelsProps> = ({
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'models.filter.category'
|
||||
})}
|
||||
style={{ width: 180 }}
|
||||
style={{ width: 160 }}
|
||||
size="large"
|
||||
maxTagCount={1}
|
||||
onChange={handleCategoryChange}
|
||||
@@ -798,11 +827,20 @@ const Models: React.FC<ModelsProps> = ({
|
||||
<Select
|
||||
allowClear
|
||||
showSearch={false}
|
||||
placeholder="Filter by worker"
|
||||
style={{ width: 180 }}
|
||||
placeholder="Filter by cluster"
|
||||
style={{ width: 160 }}
|
||||
size="large"
|
||||
maxTagCount={1}
|
||||
options={[]}
|
||||
options={clusterList}
|
||||
></Select>
|
||||
<Select
|
||||
allowClear
|
||||
showSearch={false}
|
||||
placeholder="Running Replicas"
|
||||
style={{ width: 140 }}
|
||||
size="large"
|
||||
maxTagCount={1}
|
||||
options={statusList}
|
||||
></Select>
|
||||
<Button
|
||||
type="text"
|
||||
|
||||
@@ -23,7 +23,6 @@ import { FormContext, FormInnerContext } from '../config/form-context';
|
||||
import { FormData, ListItem } from '../config/types';
|
||||
import HuggingFaceForm from '../forms/hugging-face';
|
||||
import LocalPathForm from '../forms/local-path';
|
||||
import OllamaForm from '../forms/ollama_library';
|
||||
import { useCheckCompatibility } from '../hooks';
|
||||
import AdvanceConfig from './advance-config';
|
||||
import ColumnWrapper from './column-wrapper';
|
||||
@@ -396,7 +395,6 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
||||
}}
|
||||
>
|
||||
<HuggingFaceForm></HuggingFaceForm>
|
||||
<OllamaForm></OllamaForm>
|
||||
<LocalPathForm></LocalPathForm>
|
||||
</FormInnerContext.Provider>
|
||||
<Form.Item name="backend" rules={[{ required: true }]}>
|
||||
@@ -447,30 +445,6 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
||||
}
|
||||
></SealSelect>
|
||||
</Form.Item>
|
||||
<Form.Item<FormData>
|
||||
name="replicas"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: getRuleMessage('input', 'models.form.replicas')
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealInput.Number
|
||||
style={{ width: '100%' }}
|
||||
label={intl.formatMessage({
|
||||
id: 'models.form.replicas'
|
||||
})}
|
||||
required
|
||||
description={intl.formatMessage(
|
||||
{
|
||||
id: 'models.form.replicas.tips'
|
||||
},
|
||||
{ api: `${window.location.origin}/v1` }
|
||||
)}
|
||||
min={0}
|
||||
></SealInput.Number>
|
||||
</Form.Item>
|
||||
<Form.Item<FormData> name="description">
|
||||
<SealInput.TextArea
|
||||
scaleSize={true}
|
||||
|
||||
Reference in New Issue
Block a user