From dc4e83447ddab85bf60f705059fbb25976871d02 Mon Sep 17 00:00:00 2001 From: jialin Date: Fri, 6 Sep 2024 16:40:11 +0800 Subject: [PATCH] feat: add schedule type ux --- src/assets/styles/common.less | 16 + src/components/label-selector/inner.tsx | 2 +- .../label-selector/styles/wrapper.less | 4 +- .../seal-form/components/label-info.tsx | 1 + .../seal-form/components/wrapper.less | 36 +- .../seal-form/components/wrapper.tsx | 13 +- src/components/seal-form/password.tsx | 1 + src/components/seal-form/seal-input.tsx | 1 + src/locales/en-US/common.ts | 3 +- src/locales/en-US/models.ts | 14 +- src/locales/en-US/resources.ts | 8 +- src/locales/zh-CN/common.ts | 3 +- src/locales/zh-CN/models.ts | 10 +- src/locales/zh-CN/resources.ts | 9 +- src/pages/llmodels/components/data-form.tsx | 380 ++++++++++++------ src/pages/llmodels/components/gpu-card.tsx | 24 ++ .../llmodels/components/update-modal.tsx | 50 +-- src/pages/llmodels/config/types.ts | 1 + src/pages/llmodels/style/data-form.less | 2 +- src/pages/llmodels/style/gpu-card.less | 20 + .../playground/components/params-settings.tsx | 8 +- 21 files changed, 430 insertions(+), 176 deletions(-) create mode 100644 src/pages/llmodels/components/gpu-card.tsx create mode 100644 src/pages/llmodels/style/gpu-card.less diff --git a/src/assets/styles/common.less b/src/assets/styles/common.less index 8c2700b2..fd0aac2a 100644 --- a/src/assets/styles/common.less +++ b/src/assets/styles/common.less @@ -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; } diff --git a/src/components/label-selector/inner.tsx b/src/components/label-selector/inner.tsx index 55f02a14..4c723edb 100644 --- a/src/components/label-selector/inner.tsx +++ b/src/components/label-selector/inner.tsx @@ -97,7 +97,7 @@ const Inner: React.FC = ({ > {' '} {intl.formatMessage({ - id: 'common.button.addLabel' + id: 'common.button.addSelector' })} diff --git a/src/components/label-selector/styles/wrapper.less b/src/components/label-selector/styles/wrapper.less index cecf89b2..fb973fad 100644 --- a/src/components/label-selector/styles/wrapper.less +++ b/src/components/label-selector/styles/wrapper.less @@ -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); diff --git a/src/components/seal-form/components/label-info.tsx b/src/components/seal-form/components/label-info.tsx index 4e486685..f377cf31 100644 --- a/src/components/seal-form/components/label-info.tsx +++ b/src/components/seal-form/components/label-info.tsx @@ -10,6 +10,7 @@ interface NoteInfoProps { } const NoteInfo: React.FC = (props) => { const { required, description, label } = props || {}; + if (!label) return null; return ( diff --git a/src/components/seal-form/components/wrapper.less b/src/components/seal-form/components/wrapper.less index 88ba100e..b91fe074 100644 --- a/src/components/seal-form/components/wrapper.less +++ b/src/components/seal-form/components/wrapper.less @@ -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; + // } } diff --git a/src/components/seal-form/components/wrapper.tsx b/src/components/seal-form/components/wrapper.tsx index 359ed2f9..5f78552d 100644 --- a/src/components/seal-form/components/wrapper.tsx +++ b/src/components/seal-form/components/wrapper.tsx @@ -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 = ({ extra, variant, addAfter, + hasPrefix, noWrapperStyle, onClick }) => { @@ -41,12 +43,14 @@ const Wrapper: React.FC = ({ 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] : '' )} >
@@ -56,7 +60,10 @@ const Wrapper: React.FC = ({ wrapperStyle['label'], isFocus ? wrapperStyle['isfoucs-has-value'] - : wrapperStyle['blur-no-value'] + : wrapperStyle['blur-no-value'], + { + [wrapperStyle['has-prefix']]: hasPrefix + } )} > = (props) => { required={required} description={description} disabled={props.disabled} + hasPrefix={!!props.prefix} onClick={handleClickWrapper} > = (props) => { description={description} disabled={props.disabled} addAfter={addAfter} + hasPrefix={!!props.prefix} onClick={handleClickWrapper} > = 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 = 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 = forwardRef((props, ref) => { } }; + const renderSelectTips = (list: Array<{ title: string; tips: string }>) => { + return ( +
+ {list.map((item, index) => { + return ( +
+ + {item.title}: + + + {item.tips} + +
+ ); + })} +
+ ); + }; + const collapseItems = useMemo(() => { const children = ( <> - - name="replicas" - rules={[ - { - required: true, - message: intl.formatMessage( - { - id: 'common.form.rule.input' - }, - { - name: intl.formatMessage({ id: 'models.form.replicas' }) - } - ) - } - ]} - > - + + {scheduleType === 'auto' && ( name="placement_strategy"> @@ -259,58 +410,82 @@ const DataForm: React.FC = forwardRef((props, ref) => { id: 'resources.form.placementStrategy' })} options={placementStrategyOptions} + description={renderSelectTips(placementStrategyTips)} + > + + )} + {scheduleType === 'auto' && ( + name="worker_selector"> + -
- - Spread: - - - {intl.formatMessage({ - id: 'resources.form.spread.tips' - })} - -
-
- - Binpack: - - - {intl.formatMessage({ - id: 'resources.form.binpack.tips' - })} - -
-
+ + {intl.formatMessage({ + id: 'resources.form.workerSelector.description' + })} + } - > + > )} -
- + {scheduleType === 'manual' && ( + name="gpu_selector"> + + {gpuOptions.map((item) => ( + + + + ))} + + + )} +
+ + name="partial_offload" + valuePropName="checked" + style={{ padding: '0 10px', marginBottom: 0 }} + noStyle + > + + + + {intl.formatMessage({ + id: 'resources.form.enablePartialOffload' + })} + + + + + +
+ {scheduleType === 'auto' && ( +
- name="partial_offload" + name="distributed_inference_across_workers" valuePropName="checked" style={{ padding: '0 10px', marginBottom: 0 }} + noStyle > - + {intl.formatMessage({ - id: 'resources.form.enablePartialOffload' + id: 'resources.form.enableDistributedInferenceAcrossWorkers' })} = forwardRef((props, ref) => { - -
- {scheduleType === 'auto' && ( -
- - - name="distributed_inference_across_workers" - valuePropName="checked" - style={{ padding: '0 10px', marginBottom: 0 }} - > - - - - {intl.formatMessage({ - id: 'resources.form.enableDistributedInferenceAcrossWorkers' - })} - - - - - -
)} - {scheduleType === 'auto' && ( - name="worker_selector"> - - {intl.formatMessage({ - id: 'resources.form.workerSelector.description' - })} - - } - > - - )} ); return [ @@ -401,6 +529,7 @@ const DataForm: React.FC = 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 = forwardRef((props, ref) => { } {renderFieldsBySource()} + + name="replicas" + rules={[ + { + required: true, + message: intl.formatMessage( + { + id: 'common.form.rule.input' + }, + { + name: intl.formatMessage({ id: 'models.form.replicas' }) + } + ) + } + ]} + > + + name="description"> = forwardRef((props, ref) => { expandIcon={({ isActive }) => ( )} items={collapseItems} diff --git a/src/pages/llmodels/components/gpu-card.tsx b/src/pages/llmodels/components/gpu-card.tsx new file mode 100644 index 00000000..a399c33d --- /dev/null +++ b/src/pages/llmodels/components/gpu-card.tsx @@ -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 ( +
+
+ {data.label}({data.worker_name})[Index:{data.index}] +
+
+ VRAM: + Total {convertFileSize(22906503168)} + Used {convertFileSize(3322640640)} + Utilization {_.round(3.79, 2)}% +
+
+ ); +}; + +export default GPUCard; diff --git a/src/pages/llmodels/components/update-modal.tsx b/src/pages/llmodels/components/update-modal.tsx index 39a1a0c7..f32669bb 100644 --- a/src/pages/llmodels/components/update-modal.tsx +++ b/src/pages/llmodels/components/update-modal.tsx @@ -294,31 +294,6 @@ const UpdateModal: React.FC = (props) => { ), children: ( <> - - name="replicas" - rules={[ - { - required: true, - message: intl.formatMessage( - { - id: 'common.form.rule.input' - }, - { - name: intl.formatMessage({ id: 'models.form.replicas' }) - } - ) - } - ]} - > - - name="placement_strategy"> = (props) => { )} {renderFieldsBySource()} + + name="replicas" + rules={[ + { + required: true, + message: intl.formatMessage( + { + id: 'common.form.rule.input' + }, + { + name: intl.formatMessage({ id: 'models.form.replicas' }) + } + ) + } + ]} + > + + name="description"> = ({ onFinishFailed={handleOnFinishFailed} >
-

+

{intl.formatMessage({ id: 'playground.model' })}

@@ -165,11 +165,7 @@ const ParamsSettings: React.FC = ({ } ]} > - +

{intl.formatMessage({ id: 'playground.parameters' })}