feat: add schedule type ux

main
jialin 1 year ago
parent 5c372bbaa3
commit dc4e83447d

@ -10,6 +10,10 @@
margin-bottom: 5px;
}
.m-b-15 {
margin-bottom: 15px;
}
.m-l-10 {
margin-left: 10px;
}
@ -18,6 +22,10 @@
margin-left: 5px;
}
.m-l-4 {
margin-left: 4px;
}
.m-l-2 {
margin-left: 2px;
}
@ -50,6 +58,14 @@
margin-right: 8px;
}
.m-l-6 {
margin-left: 6px;
}
.p-l-6 {
padding-left: 6px;
}
.flex {
display: flex;
}

@ -97,7 +97,7 @@ const Inner: React.FC<LabelSelectorProps> = ({
>
<PlusOutlined className="font-size-14" />{' '}
{intl.formatMessage({
id: 'common.button.addLabel'
id: 'common.button.addSelector'
})}
</Button>
</div>

@ -1,6 +1,6 @@
.wrapper {
position: relative;
padding: 16px;
padding: 14px;
padding-top: 34px;
border: 1px solid var(--ant-color-border);
border-radius: var(--border-radius-base);
@ -10,7 +10,7 @@
:global {
.label {
position: absolute;
left: 24px;
left: 16px;
line-height: 1;
top: 12px;
color: var(--ant-color-text-tertiary);

@ -10,6 +10,7 @@ interface NoteInfoProps {
}
const NoteInfo: React.FC<NoteInfoProps> = (props) => {
const { required, description, label } = props || {};
if (!label) return null;
return (
<span className="label-text">

@ -5,7 +5,7 @@
display: flex;
justify-content: flex-start;
align-items: center;
padding-inline: 12px;
padding-inline: 8px 12px;
height: 54px;
border-width: var(--ant-line-width);
border-style: var(--ant-line-type);
@ -13,12 +13,12 @@
border-radius: @borderRadius;
background-color: var(--color-white-1);
&.filled {
&.borderless {
border: none;
box-shadow: none;
}
&.borderless {
&.filled {
border: none;
box-shadow: none;
}
@ -86,7 +86,7 @@
@wrapheight: 54px;
@inputheight: 32px;
@borderRadius: 8px;
@input-inner-padding: 12px;
@input-inner-padding: 6px;
@bgColor: transparent;
position: relative;
@ -113,7 +113,7 @@
.label {
position: absolute;
left: 12px;
left: 6px;
color: rgba(0, 0, 0, 45%);
font-size: var(--font-size-base);
line-height: 1;
@ -131,6 +131,10 @@
top: 21px;
transition: all 0.2s var(--seal-transition-func);
}
&.has-prefix {
top: 10px !important;
}
}
// ==================== select ==================
@ -171,6 +175,16 @@
top: 10px;
}
&.no-label {
padding-block: 0;
:global {
.ant-select-arrow {
top: 50%;
}
}
}
:global(
.ant-select-outlined.ant-select-disabled:not(.ant-select-customize-input)
.ant-select-selector
@ -191,7 +205,7 @@
border: none;
box-shadow: none;
padding-block: 5px;
padding-inline: 12px;
padding-inline: @input-inner-padding;
height: @inputheight !important;
background-color: @bgColor;
}
@ -278,9 +292,9 @@
height: @wrapheight - 2px;
}
:global(.ant-input-prefix) {
position: absolute;
top: 1px;
left: -4px;
}
// :global(.ant-input-prefix) {
// position: absolute;
// top: 1px;
// left: -4px;
// }
}

@ -15,6 +15,7 @@ interface WrapperProps {
extra?: React.ReactNode;
addAfter?: React.ReactNode;
variant?: string;
hasPrefix?: boolean;
onClick?: () => void;
}
@ -30,6 +31,7 @@ const Wrapper: React.FC<WrapperProps> = ({
extra,
variant,
addAfter,
hasPrefix,
noWrapperStyle,
onClick
}) => {
@ -41,12 +43,14 @@ const Wrapper: React.FC<WrapperProps> = ({
wrapperStyle[`validate-status-${status}`],
addAfter ? wrapperStyle['seal-input-wrapper-addafter'] : '',
disabled ? wrapperStyle['seal-input-wrapper-disabled'] : '',
className ? wrapperStyle[className] : ''
className ? wrapperStyle[className] : '',
variant ? wrapperStyle[variant] : ''
)}
>
<div
className={classNames(wrapperStyle.wrapper, {
[wrapperStyle['no-wrapper-style']]: noWrapperStyle
[wrapperStyle['no-wrapper-style']]: noWrapperStyle,
[wrapperStyle['no-label']]: !label
})}
onClick={onClick}
>
@ -56,7 +60,10 @@ const Wrapper: React.FC<WrapperProps> = ({
wrapperStyle['label'],
isFocus
? wrapperStyle['isfoucs-has-value']
: wrapperStyle['blur-no-value']
: wrapperStyle['blur-no-value'],
{
[wrapperStyle['has-prefix']]: hasPrefix
}
)}
>
<LabelInfo

@ -62,6 +62,7 @@ const SealPassword: React.FC<InputProps & SealFormItemProps> = (props) => {
required={required}
description={description}
disabled={props.disabled}
hasPrefix={!!props.prefix}
onClick={handleClickWrapper}
>
<Input.Password

@ -77,6 +77,7 @@ const SealInput: React.FC<InputProps & SealFormItemProps> = (props) => {
description={description}
disabled={props.disabled}
addAfter={addAfter}
hasPrefix={!!props.prefix}
onClick={handleClickWrapper}
>
<Input

@ -203,5 +203,6 @@ export default {
'common.button.docs': 'Documentation',
'common.button.version': 'Version',
'common.title.delete.confirm': 'Confirm delete',
'common.button.addLabel': 'Add Label'
'common.button.addLabel': 'Add Labels',
'common.button.addSelector': 'Add Selectors'
};

@ -12,9 +12,9 @@ export default {
'models.form.configurations': 'Configurations',
'models.form.s3address': 'S3 Address',
'models.form.partialoffload.tips':
'refers to the strategy of offloading as many layers of a model to the GPU as possible based on available resources, while offload all layers completely is not possible.',
'Refers to the strategy of offloading as many layers of a model to the GPU as possible based on available resources, while offload all layers completely is not possible.',
'models.form.distribution.tips':
'allows for offloading part of the computation to single or multiple remote workers when the resources of a single GPU or worker are insufficient.',
'Allows for offloading part of the computation to single or multiple remote workers when the resources of a single GPU or worker are insufficient.',
'models.openinplayground': 'Open in Playground',
'models.instances': 'instances',
'models.table.replicas.edit': 'Edit Replicas',
@ -40,5 +40,13 @@ export default {
'models.search.networkerror': 'Network connection exception!',
'models.search.hfvisit': 'Please make sure you can visit',
'models.search.unsupport':
'This model is not supported and may be unusable after deployment.'
'This model is not supported and may be unusable after deployment.',
'models.form.scheduletype': 'Schedule Type',
'models.form.scheduletype.auto': 'Auto',
'models.form.scheduletype.manual': 'Manual',
'models.form.scheduletype.auto.tips':
'Automatically deploys model instances to appropriate GPUs/Workers based on current resource conditions.',
'models.form.scheduletype.manual.tips':
'Allows you to manually specify the GPUs/Workers to deploy the model instances to.',
'models.form.manual.schedule': 'Manual Schedule'
};

@ -8,17 +8,17 @@ export default {
'resources.table.hostname': 'Hostname',
'resources.table.key.tips': 'The same key exists.',
'resources.form.advanced': 'Advanced',
'resources.form.enablePartialOffload': 'Enable Partial Offload',
'resources.form.enablePartialOffload': 'Allow Partial Offload',
'resources.form.placementStrategy': 'Placement Strategy',
'resources.form.workerSelector': 'Matching Worker Labels',
'resources.form.workerSelector': 'Worker Selector',
'resources.form.enableDistributedInferenceAcrossWorkers':
'Enable Distributed Inference Across Workers',
'Allow Distributed Inference Across Workers',
'resources.form.spread.tips':
'Make the resources of the entire cluster relatively evenly distributed among all workers. It may produce more resource fragmentation on a single worker.',
'resources.form.binpack.tips':
'Prioritize the overall utilization of cluster resources, reducing resource fragmentation on Workers/GPUs.',
'resources.form.workerSelector.description':
'The scheduling system selects the most suitable GPU or Worker for deploying model instances based on predefined labels.',
'The system selects the most suitable GPU or Worker for deploying model instances based on predefined labels.',
'resources.table.ip': 'IP',
'resources.table.cpu': 'CPU',
'resources.table.memory': 'RAM',

@ -196,5 +196,6 @@ export default {
'common.button.docs': '文档',
'common.button.version': '版本',
'common.title.delete.confirm': '确认删除',
'common.button.addLabel': '添加标签'
'common.button.addLabel': '添加标签',
'common.button.addSelector': '添加选择器'
};

@ -39,5 +39,13 @@ export default {
'models.search.nofiles': '无可用文件',
'models.search.networkerror': '网络连接异常!',
'models.search.hfvisit': '请确保您可以访问',
'models.search.unsupport': '暂不支持该模型,部署后可能无法使用'
'models.search.unsupport': '暂不支持该模型,部署后可能无法使用',
'models.form.scheduletype': '调度方式',
'models.form.scheduletype.auto': '自动',
'models.form.scheduletype.manual': '手动',
'models.form.scheduletype.auto.tips':
'自动根据当前资源情况部署模型实例到合适的 GPU/Worker。',
'models.form.scheduletype.manual.tips':
'手动调度可指定模型实例部署的 GPU/Worker。',
'models.form.manual.schedule': '手动调度'
};

@ -8,16 +8,17 @@ export default {
'resources.table.key.tips': '存在相同的 key.',
'resources.table.labels': '标签',
'resources.form.advanced': '高级',
'resources.form.enablePartialOffload': '开启半卸载',
'resources.form.enablePartialOffload': '允许半卸载',
'resources.form.placementStrategy': '放置策略',
'resources.form.workerSelector': '匹配的 Worker 标签',
'resources.form.enableDistributedInferenceAcrossWorkers': '跨节点分布式推理',
'resources.form.workerSelector': 'Worker 选择器',
'resources.form.enableDistributedInferenceAcrossWorkers':
'允许跨节点分布式推理',
'resources.form.spread.tips':
'使得集群整体的资源在所有 Worker 之间分配得相对均匀。可能会在单个 Worker 上产生较多资源碎片。',
'resources.form.binpack.tips':
'优先考虑整体集群的资源最大化利用,减少 Worker/GPU 上的资源碎片。',
'resources.form.workerSelector.description':
'调度系统在部署模型实例时,会根据预定义的标签来选择最符合要求的 GPU 或 Worker。',
'系统在部署模型实例时,会根据预定义的标签来选择最符合要求的 GPU 或 Worker。',
'resources.table.ip': 'IP',
'resources.table.cpu': 'CPU',
'resources.table.memory': '内存',

@ -1,13 +1,12 @@
import LabelSelector from '@/components/label-selector';
import SealAutoComplete from '@/components/seal-form/auto-complete';
import FormItemWrapper from '@/components/seal-form/components/wrapper';
import SealInput from '@/components/seal-form/seal-input';
import SealSelect from '@/components/seal-form/seal-select';
import { PageAction } from '@/config';
import { PageActionType } from '@/config/types';
import { InfoCircleOutlined, RightOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Checkbox, Collapse, Form, Tooltip, Typography } from 'antd';
import { Checkbox, Collapse, Form, Select, Tooltip, Typography } from 'antd';
import _ from 'lodash';
import React, {
forwardRef,
@ -23,6 +22,7 @@ import {
} from '../config';
import { FormData } from '../config/types';
import dataformStyles from '../style/data-form.less';
import GPUCard from './gpu-card';
interface DataFormProps {
ref?: any;
@ -45,12 +45,109 @@ const sourceOptions = [
}
];
const gpuOptions = [
{
label: 'NVIDIA A100',
value: '1',
index: 0,
worker_name: 'mbp-1.local',
worker: {
GPU: {
name: 'A100',
count: 1,
memory: 16384
},
CPU: {
count: 16,
memory: 16384
},
os: {
name: 'Ubuntu 20.04',
version: '20.04'
},
name: 'mbp-1.local',
address: '192.168.1.1'
}
},
{
label: 'NVIDIA H100',
value: '2',
index: 1,
worker_name: 'mbp-2.local',
worker: {
GPU: {
name: 'H100',
count: 1,
memory: 16384
},
CPU: {
count: 16,
memory: 16384
},
os: {
name: 'Ubuntu 20.04',
version: '20.04'
},
name: 'mbp-2.local',
address: '192.168.1.2'
}
},
{
label: 'NVIDIA A100',
value: '3',
index: 2,
worker_name: 'mbp-3.local',
worker: {
GPU: {
name: 'A100',
count: 1,
memory: 16384
},
CPU: {
count: 16,
memory: 16384
},
os: {
name: 'Ubuntu 20.04',
version: '20.04'
},
name: 'mbp-3.local',
address: '192.168.1.3'
}
},
{
label: 'NVIDIA H100',
value: '4',
index: 3,
worker_name: 'mbp-4.local',
worker: {
GPU: {
name: 'H100',
count: 1,
memory: 16384
},
CPU: {
count: 16,
memory: 16384
},
os: {
name: 'Ubuntu 20.04',
version: '20.04'
},
name: 'mbp-4.local',
address: '192.168.1.4'
}
}
];
const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
const { action, repo, onOk } = props;
const [form] = Form.useForm();
const intl = useIntl();
const wokerSelector = Form.useWatch('worker_selector', form);
const [scheduleType, setScheduleType] = React.useState('auto');
// const [scheduleType, setScheduleType] = React.useState(false); // false: auto, true: manual
const scheduleType = Form.useWatch('scheduleType', form);
const handleSumit = () => {
form.submit();
@ -75,6 +172,40 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
[]
);
const placementStrategyTips = [
{
title: 'Spread',
tips: intl.formatMessage({
id: 'resources.form.spread.tips'
})
},
{
title: 'Binpack',
tips: intl.formatMessage({
id: 'resources.form.binpack.tips'
})
}
];
const scheduleTypeTips = [
{
title: intl.formatMessage({
id: 'models.form.scheduletype.auto'
}),
tips: intl.formatMessage({
id: 'models.form.scheduletype.auto.tips'
})
},
{
title: intl.formatMessage({
id: 'models.form.scheduletype.manual'
}),
tips: intl.formatMessage({
id: 'models.form.scheduletype.manual.tips'
})
}
];
const handleOnSelectModel = () => {
console.log('repo=============', repo);
if (!repo) {
@ -224,33 +355,53 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
}
};
const renderSelectTips = (list: Array<{ title: string; tips: string }>) => {
return (
<div>
{list.map((item, index) => {
return (
<div className="m-b-8" key={index}>
<Typography.Title
level={5}
style={{
color: 'var(--color-white-1)',
marginRight: 10
}}
>
{item.title}:
</Typography.Title>
<Typography.Text style={{ color: 'var(--color-white-1)' }}>
{item.tips}
</Typography.Text>
</div>
);
})}
</div>
);
};
const collapseItems = useMemo(() => {
const children = (
<>
<Form.Item<FormData>
name="replicas"
rules={[
{
required: true,
message: intl.formatMessage(
{
id: 'common.form.rule.input'
},
{
name: intl.formatMessage({ id: 'models.form.replicas' })
}
)
}
]}
>
<SealInput.Number
style={{ width: '100%' }}
label={intl.formatMessage({
id: 'models.form.replicas'
})}
required
min={0}
></SealInput.Number>
<Form.Item name="scheduleType">
<SealSelect
label={intl.formatMessage({ id: 'models.form.scheduletype' })}
description={renderSelectTips(scheduleTypeTips)}
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">
@ -259,58 +410,82 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
id: 'resources.form.placementStrategy'
})}
options={placementStrategyOptions}
description={renderSelectTips(placementStrategyTips)}
></SealSelect>
</Form.Item>
)}
{scheduleType === 'auto' && (
<Form.Item<FormData> name="worker_selector">
<LabelSelector
label={intl.formatMessage({
id: 'resources.form.workerSelector'
})}
labels={wokerSelector}
onChange={handleWorkerLabelsChange}
description={
<div>
<div className="m-b-8">
<Typography.Title
level={5}
style={{
color: 'var(--color-white-1)',
marginRight: 10
}}
>
Spread:
</Typography.Title>
<Typography.Text style={{ color: 'var(--color-white-1)' }}>
{intl.formatMessage({
id: 'resources.form.spread.tips'
})}
</Typography.Text>
</div>
<div>
<Typography.Title
level={5}
style={{ color: 'var(--color-white-1)', marginRight: 10 }}
>
Binpack:
</Typography.Title>
<Typography.Text style={{ color: 'var(--color-white-1)' }}>
{intl.formatMessage({
id: 'resources.form.binpack.tips'
})}
</Typography.Text>
</div>
</div>
<span>
{intl.formatMessage({
id: 'resources.form.workerSelector.description'
})}
</span>
}
></SealSelect>
></LabelSelector>
</Form.Item>
)}
<div style={{ marginBottom: 24 }}>
<FormItemWrapper noWrapperStyle>
{scheduleType === 'manual' && (
<Form.Item<FormData> name="gpu_selector">
<SealSelect label="GPU Selector">
{gpuOptions.map((item) => (
<Select.Option key={item.value} value={item.value}>
<GPUCard data={item}></GPUCard>
</Select.Option>
))}
</SealSelect>
</Form.Item>
)}
<div style={{ marginBottom: 22, paddingLeft: 10 }}>
<Form.Item<FormData>
name="partial_offload"
valuePropName="checked"
style={{ padding: '0 10px', marginBottom: 0 }}
noStyle
>
<Checkbox className="p-l-6">
<Tooltip
title={intl.formatMessage({
id: 'models.form.partialoffload.tips'
})}
>
<span style={{ color: 'var(--ant-color-text-tertiary)' }}>
{intl.formatMessage({
id: 'resources.form.enablePartialOffload'
})}
</span>
<InfoCircleOutlined
className="m-l-4"
style={{ color: 'var(--ant-color-text-tertiary)' }}
/>
</Tooltip>
</Checkbox>
</Form.Item>
</div>
{scheduleType === 'auto' && (
<div style={{ marginBottom: 22, paddingLeft: 10 }}>
<Form.Item<FormData>
name="partial_offload"
name="distributed_inference_across_workers"
valuePropName="checked"
style={{ padding: '0 10px', marginBottom: 0 }}
noStyle
>
<Checkbox>
<Checkbox className="p-l-6">
<Tooltip
title={intl.formatMessage({
id: 'models.form.partialoffload.tips'
id: 'models.form.distribution.tips'
})}
>
<span style={{ color: 'var(--ant-color-text-tertiary)' }}>
{intl.formatMessage({
id: 'resources.form.enablePartialOffload'
id: 'resources.form.enableDistributedInferenceAcrossWorkers'
})}
</span>
<InfoCircleOutlined
@ -320,55 +495,8 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
</Tooltip>
</Checkbox>
</Form.Item>
</FormItemWrapper>
</div>
{scheduleType === 'auto' && (
<div style={{ marginBottom: 24 }}>
<FormItemWrapper noWrapperStyle>
<Form.Item<FormData>
name="distributed_inference_across_workers"
valuePropName="checked"
style={{ padding: '0 10px', marginBottom: 0 }}
>
<Checkbox>
<Tooltip
title={intl.formatMessage({
id: 'models.form.distribution.tips'
})}
>
<span style={{ color: 'var(--ant-color-text-tertiary)' }}>
{intl.formatMessage({
id: 'resources.form.enableDistributedInferenceAcrossWorkers'
})}
</span>
<InfoCircleOutlined
className="m-l-4"
style={{ color: 'var(--ant-color-text-tertiary)' }}
/>
</Tooltip>
</Checkbox>
</Form.Item>
</FormItemWrapper>
</div>
)}
{scheduleType === 'auto' && (
<Form.Item<FormData> name="worker_selector">
<LabelSelector
label={intl.formatMessage({
id: 'resources.form.workerSelector'
})}
labels={wokerSelector}
onChange={handleWorkerLabelsChange}
description={
<span>
{intl.formatMessage({
id: 'resources.form.workerSelector.description'
})}
</span>
}
></LabelSelector>
</Form.Item>
)}
</>
);
return [
@ -401,6 +529,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
source: props.source,
placement_strategy: 'spread',
partial_offload: true,
scheduleType: 'auto',
distributed_inference_across_workers: true
}}
>
@ -451,6 +580,31 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
}
</Form.Item>
{renderFieldsBySource()}
<Form.Item<FormData>
name="replicas"
rules={[
{
required: true,
message: intl.formatMessage(
{
id: 'common.form.rule.input'
},
{
name: intl.formatMessage({ id: 'models.form.replicas' })
}
)
}
]}
>
<SealInput.Number
style={{ width: '100%' }}
label={intl.formatMessage({
id: 'models.form.replicas'
})}
required
min={0}
></SealInput.Number>
</Form.Item>
<Form.Item<FormData> name="description">
<SealInput.TextArea
label={intl.formatMessage({
@ -467,7 +621,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
expandIcon={({ isActive }) => (
<RightOutlined
rotate={isActive ? 90 : 0}
style={{ fontSize: '12px' }}
style={{ fontSize: '12px', marginLeft: -8 }}
/>
)}
items={collapseItems}

@ -0,0 +1,24 @@
import { convertFileSize } from '@/utils';
import _ from 'lodash';
import React from 'react';
import '../style/gpu-card.less';
const GPUCard: React.FC<{
data: any;
}> = ({ data }) => {
return (
<div className="gpu-card">
<div className="header">
{data.label}({data.worker_name})[Index:{data.index}]
</div>
<div className="info">
<span>VRAM:</span>
<span>Total {convertFileSize(22906503168)}</span>
<span>Used {convertFileSize(3322640640)}</span>
<span>Utilization {_.round(3.79, 2)}%</span>
</div>
</div>
);
};
export default GPUCard;

@ -294,31 +294,6 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
),
children: (
<>
<Form.Item<FormData>
name="replicas"
rules={[
{
required: true,
message: intl.formatMessage(
{
id: 'common.form.rule.input'
},
{
name: intl.formatMessage({ id: 'models.form.replicas' })
}
)
}
]}
>
<SealInput.Number
style={{ width: '100%' }}
label={intl.formatMessage({
id: 'models.form.replicas'
})}
required
min={0}
></SealInput.Number>
</Form.Item>
<Form.Item<FormData> name="placement_strategy">
<SealSelect
label={intl.formatMessage({
@ -528,6 +503,31 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
)}
</Form.Item>
{renderFieldsBySource()}
<Form.Item<FormData>
name="replicas"
rules={[
{
required: true,
message: intl.formatMessage(
{
id: 'common.form.rule.input'
},
{
name: intl.formatMessage({ id: 'models.form.replicas' })
}
)
}
]}
>
<SealInput.Number
style={{ width: '100%' }}
label={intl.formatMessage({
id: 'models.form.replicas'
})}
required
min={0}
></SealInput.Number>
</Form.Item>
<Form.Item<FormData> name="description">
<SealInput.TextArea
label={intl.formatMessage({

@ -25,6 +25,7 @@ export interface FormData {
placement_strategy?: string;
partial_offload?: boolean;
worker_selector?: object;
scheduleType?: string;
name: string;
replicas: number;
description: string;

@ -3,7 +3,7 @@
.ant-collapse-header {
display: flex;
align-items: center;
margin-bottom: 20px !important;
margin-bottom: 10px !important;
padding-inline: 5px !important;
padding-block: 5px !important;
border-radius: var(--border-radius-base) !important;

@ -0,0 +1,20 @@
.gpu-card {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
width: 100%;
border-bottom: 1px solid var(--ant-color-split);
padding-bottom: 10px;
.header {
margin-bottom: 10px;
}
.info {
display: flex;
align-items: center;
gap: 10px;
color: var(--ant-color-text-tertiary);
}
}

@ -148,7 +148,7 @@ const ParamsSettings: React.FC<ParamsSettingsProps> = ({
onFinishFailed={handleOnFinishFailed}
>
<div>
<h3 className="m-b-20 m-l-10 font-size-14">
<h3 className="m-b-15 m-l-10 font-size-14">
{intl.formatMessage({ id: 'playground.model' })}
</h3>
<Form.Item<ParamsSettingsFormProps>
@ -165,11 +165,7 @@ const ParamsSettings: React.FC<ParamsSettingsProps> = ({
}
]}
>
<SealSelect
showSearch
options={ModelList}
label={intl.formatMessage({ id: 'playground.model' })}
></SealSelect>
<SealSelect showSearch options={ModelList}></SealSelect>
</Form.Item>
<h3 className="m-b-20 m-l-10 flex-between flex-center font-size-14">
<span>{intl.formatMessage({ id: 'playground.parameters' })}</span>

Loading…
Cancel
Save