feat: dynamic backends
This commit is contained in:
@@ -23,3 +23,13 @@ export const clusterListAtom = atom<
|
||||
value: number;
|
||||
}[]
|
||||
>([]);
|
||||
|
||||
export const backendOptionsAtom = atom<
|
||||
{
|
||||
value: string;
|
||||
label: string;
|
||||
default_backend_param: string[];
|
||||
default_version: string;
|
||||
versions: { label: string; value: string }[];
|
||||
}[]
|
||||
>([]);
|
||||
|
||||
@@ -12,7 +12,12 @@ import { SealFormItemProps } from './types';
|
||||
import Wrapper from './wrapper';
|
||||
import InputWrapper from './wrapper/input';
|
||||
|
||||
const LabelWrapper = styled.div`
|
||||
const LabelWrapper = styled.div.attrs({
|
||||
className: 'seal-textarea-label'
|
||||
})`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
background-color: var(--ant-color-bg-container);
|
||||
`;
|
||||
|
||||
@@ -110,7 +115,7 @@ const SealTextArea: React.FC<InputTextareaProps & SealFormItemProps> = (
|
||||
<InputWrapper>
|
||||
<Wrapper
|
||||
status={status}
|
||||
label={<LabelWrapper>{label}</LabelWrapper>}
|
||||
label={label}
|
||||
isFocus={isFocus}
|
||||
required={required}
|
||||
description={description}
|
||||
|
||||
@@ -154,7 +154,9 @@ export const Label = styled.div.attrs<{
|
||||
`;
|
||||
|
||||
// inner
|
||||
const Inner = styled.div`
|
||||
const Inner = styled.div.attrs({
|
||||
className: '__inner__'
|
||||
})`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
@@ -163,6 +163,9 @@ const InputWrapper = styled.div`
|
||||
height: auto;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.ant-input-textarea-allow-clear.ant-input-affix-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
export default InputWrapper;
|
||||
|
||||
@@ -97,10 +97,10 @@ const SelectWrapper = styled.div`
|
||||
align-items: center;
|
||||
height: 54px;
|
||||
|
||||
.ant-select-selection-search {
|
||||
// top: 20px !important;
|
||||
// inset-inline-start: ${INPUT_INNER_PADDING}px;
|
||||
.ant-select-selection-wrap {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&.ant-select-auto-complete {
|
||||
.ant-select-selection-search {
|
||||
padding-inline-start: ${INPUT_INNER_PADDING}px;
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
const MODEL_EVALUATIONS = '/model-evaluations';
|
||||
|
||||
let controller = new AbortController();
|
||||
let signal = controller.signal;
|
||||
|
||||
self.onmessage = async (event) => {
|
||||
const { list, modelSource, modelSourceMap } = event.data;
|
||||
|
||||
const repoList = list.map((item: any) => ({
|
||||
source: modelSource,
|
||||
...(modelSource === modelSourceMap.huggingface_value
|
||||
? { huggingface_repo_id: item.name }
|
||||
: { model_scope_model_id: item.name })
|
||||
}));
|
||||
|
||||
try {
|
||||
controller?.abort();
|
||||
controller = new AbortController();
|
||||
signal = controller.signal;
|
||||
const response = await fetch(`v1/${MODEL_EVALUATIONS}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
signal,
|
||||
body: JSON.stringify({ model_specs: repoList })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
|
||||
const evaluations = await response.json();
|
||||
const { results } = evaluations;
|
||||
const resultList = list.map((item: any, index: number) => {
|
||||
return {
|
||||
...item,
|
||||
evaluateResult: results[index] || null
|
||||
};
|
||||
});
|
||||
|
||||
self.postMessage({ success: true, resultList });
|
||||
} catch (error) {
|
||||
self.postMessage({ success: false, resultList: list });
|
||||
}
|
||||
};
|
||||
|
||||
self.onmessage = (event) => {
|
||||
if (event.data === 'abort') {
|
||||
controller.abort();
|
||||
}
|
||||
};
|
||||
@@ -20,6 +20,8 @@ export const MODEL_INSTANCE_API = '/model-instances';
|
||||
|
||||
export const MODEL_EVALUATIONS = '/model-evaluations';
|
||||
|
||||
export const BACKEND_LIST_API = '/inference-backend/list';
|
||||
|
||||
const setProxyUrl = (url: string) => {
|
||||
return `/proxy?url=${encodeURIComponent(url)}`;
|
||||
};
|
||||
@@ -396,3 +398,54 @@ export async function evaluationsModelSpec(
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
export async function queryBackendList() {
|
||||
// return request<{
|
||||
// items: {
|
||||
// backend_name: string;
|
||||
// backend_show_name: string;
|
||||
// from_config: boolean;
|
||||
// default_version: string;
|
||||
// default_backend_param: string[];
|
||||
// versions: string[];
|
||||
// }[];
|
||||
// }>(BACKEND_LIST_API, {
|
||||
// method: 'GET'
|
||||
// });
|
||||
return {
|
||||
items: [
|
||||
{
|
||||
backend_name: 'vllm',
|
||||
backend_show_name: 'vLLM',
|
||||
from_config: false,
|
||||
default_version: '0.10.1.1',
|
||||
default_backend_param: null,
|
||||
versions: ['0.10.1.1', '0.10.0', '0.9.2', '0.8.5', '0.8.3']
|
||||
},
|
||||
{
|
||||
backend_name: 'ascend-mindie',
|
||||
backend_show_name: 'Ascend MindIE',
|
||||
from_config: false,
|
||||
default_version: null,
|
||||
default_backend_param: null,
|
||||
versions: null
|
||||
},
|
||||
{
|
||||
backend_name: 'custom',
|
||||
backend_show_name: 'Custom',
|
||||
from_config: false,
|
||||
default_version: null,
|
||||
default_backend_param: null,
|
||||
versions: null
|
||||
},
|
||||
{
|
||||
backend_name: 'test',
|
||||
backend_show_name: null,
|
||||
from_config: true,
|
||||
default_version: 'v1',
|
||||
default_backend_param: ['--host=0.0.0.0'],
|
||||
versions: ['v1']
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,22 +2,17 @@ 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 SealInput from '@/components/seal-form/seal-input';
|
||||
import SealSelect from '@/components/seal-form/seal-select';
|
||||
import TooltipList from '@/components/tooltip-list';
|
||||
import { PageAction } from '@/config';
|
||||
import { PageActionType } from '@/config/types';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Collapse, Form, FormInstance, Typography } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import {
|
||||
backendLabelMap,
|
||||
backendParamsHolderTips,
|
||||
backendTipsList,
|
||||
getBackendParamsTips,
|
||||
modelCategories,
|
||||
modelSourceMap,
|
||||
placementStrategyOptions,
|
||||
ScheduleValueMap
|
||||
} from '../config';
|
||||
@@ -26,6 +21,7 @@ import BackendParameters, {
|
||||
} from '../config/backend-parameters';
|
||||
import { useFormContext } from '../config/form-context';
|
||||
import { FormData } from '../config/types';
|
||||
import BackendFields from '../forms/backend-fields';
|
||||
import dataformStyles from '../style/data-form.less';
|
||||
import Performance from './performance';
|
||||
|
||||
@@ -35,8 +31,6 @@ interface AdvanceConfigProps {
|
||||
gpuOptions: Array<any>;
|
||||
action: PageActionType;
|
||||
source: string;
|
||||
backendOptions?: Global.BaseOption<string>[];
|
||||
handleBackendChange?: (value: string) => void;
|
||||
}
|
||||
|
||||
const placementStrategyTips = [
|
||||
@@ -51,7 +45,7 @@ const placementStrategyTips = [
|
||||
];
|
||||
|
||||
const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
||||
const { form, isGGUF, gpuOptions, source, backendOptions, action } = props;
|
||||
const { form, isGGUF, gpuOptions, source, action } = props;
|
||||
const intl = useIntl();
|
||||
const wokerSelector = Form.useWatch('worker_selector', form);
|
||||
const EnviromentVars = Form.useWatch('env', form);
|
||||
@@ -63,7 +57,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
||||
const placement_strategy = Form.useWatch('placement_strategy', form);
|
||||
const gpuSelectorIds = Form.useWatch(['gpu_selector', 'gpu_ids'], form);
|
||||
const worker_selector = Form.useWatch('worker_selector', form);
|
||||
const { onValuesChange } = useFormContext();
|
||||
const { onValuesChange, onBackendChange, backendOptions } = useFormContext();
|
||||
|
||||
const paramsConfig = useMemo(() => {
|
||||
return _.get(BackendParameters, backend, []);
|
||||
@@ -154,47 +148,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
||||
options={modelCategories}
|
||||
></SealSelect>
|
||||
</Form.Item>
|
||||
<Form.Item name="backend" rules={[{ required: true }]}>
|
||||
<SealSelect
|
||||
required
|
||||
onChange={props.handleBackendChange}
|
||||
label={intl.formatMessage({ id: 'models.form.backend' })}
|
||||
description={<TooltipList list={backendTipsList}></TooltipList>}
|
||||
options={
|
||||
backendOptions ?? [
|
||||
{
|
||||
label: backendLabelMap[backendOptionsMap.vllm],
|
||||
value: backendOptionsMap.vllm,
|
||||
disabled:
|
||||
props.source === modelSourceMap.local_path_value
|
||||
? false
|
||||
: isGGUF
|
||||
},
|
||||
{
|
||||
label: backendLabelMap[backendOptionsMap.ascendMindie],
|
||||
value: backendOptionsMap.ascendMindie,
|
||||
disabled:
|
||||
props.source === modelSourceMap.local_path_value
|
||||
? false
|
||||
: isGGUF
|
||||
},
|
||||
{
|
||||
label: backendLabelMap[backendOptionsMap.voxBox],
|
||||
value: backendOptionsMap.voxBox,
|
||||
disabled:
|
||||
props.source === modelSourceMap.local_path_value
|
||||
? false
|
||||
: props.source === modelSourceMap.ollama_library_value ||
|
||||
isGGUF
|
||||
}
|
||||
]
|
||||
}
|
||||
disabled={
|
||||
action === PageAction.EDIT &&
|
||||
props.source !== modelSourceMap.local_path_value
|
||||
}
|
||||
></SealSelect>
|
||||
</Form.Item>
|
||||
<BackendFields></BackendFields>
|
||||
{scheduleType === ScheduleValueMap.Auto && (
|
||||
<>
|
||||
<Form.Item<FormData> name="placement_strategy">
|
||||
@@ -257,51 +211,6 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
||||
</>
|
||||
)}
|
||||
|
||||
<Form.Item name="backend_version">
|
||||
<SealInput.Input
|
||||
placeholder={
|
||||
backendParamsTips?.version
|
||||
? `${intl.formatMessage({ id: 'common.help.eg' })} ${backendParamsTips?.version}`
|
||||
: ''
|
||||
}
|
||||
onBlur={handleBackendVersionOnBlur}
|
||||
label={intl.formatMessage({ id: 'models.form.backendVersion' })}
|
||||
description={intl.formatMessage(
|
||||
{
|
||||
id: 'models.form.backendVersion.tips'
|
||||
},
|
||||
{
|
||||
backend: backendLabelMap[backend],
|
||||
version: backendParamsTips?.version
|
||||
? `(${intl.formatMessage({ id: 'common.help.eg' })} ${backendParamsTips?.version})`
|
||||
: '',
|
||||
link: backendParamsTips?.releases && (
|
||||
<span
|
||||
style={{
|
||||
marginLeft: 5
|
||||
}}
|
||||
>
|
||||
<Typography.Link
|
||||
className="flex-center"
|
||||
style={{ display: 'inline' }}
|
||||
href={backendParamsTips?.releases}
|
||||
target="_blank"
|
||||
>
|
||||
<span>
|
||||
{intl.formatMessage({ id: 'models.form.releases' })}
|
||||
</span>
|
||||
<IconFont
|
||||
type="icon-external-link"
|
||||
className="font-size-14 m-l-4"
|
||||
></IconFont>
|
||||
</Typography.Link>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
)}
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item<FormData> name="backend_parameters">
|
||||
<ListInput
|
||||
placeholder={
|
||||
|
||||
@@ -9,7 +9,12 @@ import React, { forwardRef, useImperativeHandle } from 'react';
|
||||
import { excludeFields, ScheduleValueMap, sourceOptions } from '../config';
|
||||
import { backendOptionsMap } from '../config/backend-parameters';
|
||||
import { FormContext } from '../config/form-context';
|
||||
import { DeployFormKey, FormData, SourceType } from '../config/types';
|
||||
import {
|
||||
BackendOption,
|
||||
DeployFormKey,
|
||||
FormData,
|
||||
SourceType
|
||||
} from '../config/types';
|
||||
import CatalogFrom from '../forms/catalog';
|
||||
import HuggingFaceForm from '../forms/hugging-face';
|
||||
import LocalPathForm from '../forms/local-path';
|
||||
@@ -24,7 +29,7 @@ interface DataFormProps {
|
||||
isGGUF: boolean;
|
||||
formKey: DeployFormKey;
|
||||
sourceDisable?: boolean;
|
||||
backendOptions?: Global.BaseOption<string>[];
|
||||
backendOptions: BackendOption[];
|
||||
sourceList?: Global.BaseOption<string>[];
|
||||
clusterList: Global.BaseOption<number>[];
|
||||
fields?: string[];
|
||||
@@ -41,7 +46,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
||||
formKey,
|
||||
initialValues,
|
||||
sourceDisable = true,
|
||||
backendOptions,
|
||||
backendOptions = [],
|
||||
sourceList,
|
||||
clusterList = [],
|
||||
fields = ['source'],
|
||||
@@ -174,8 +179,10 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
||||
value={{
|
||||
isGGUF: isGGUF,
|
||||
formKey: formKey,
|
||||
source: props.source,
|
||||
pageAction: action,
|
||||
gpuOptions: gpuOptions,
|
||||
backendOptions: backendOptions,
|
||||
onValuesChange: onValuesChange,
|
||||
onBackendChange: handleBackendChange
|
||||
}}
|
||||
@@ -276,8 +283,6 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
||||
isGGUF={isGGUF}
|
||||
action={action}
|
||||
source={props.source}
|
||||
backendOptions={backendOptions}
|
||||
handleBackendChange={handleBackendChange}
|
||||
></AdvanceConfig>
|
||||
</Form>
|
||||
</FormContext.Provider>
|
||||
|
||||
@@ -9,7 +9,7 @@ import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { defaultFormValues, deployFormKeyMap, modelSourceMap } from '../config';
|
||||
import { backendOptionsMap } from '../config/backend-parameters';
|
||||
import { FormData, SourceType } from '../config/types';
|
||||
import { BackendOption, FormData, SourceType } from '../config/types';
|
||||
import {
|
||||
MessageStatus,
|
||||
WarningStausOptions,
|
||||
@@ -58,6 +58,7 @@ type AddModalProps = {
|
||||
width?: string | number;
|
||||
initialValues?: any;
|
||||
deploymentType?: 'modelList' | 'modelFiles';
|
||||
backendOptions: BackendOption[];
|
||||
clusterList: Global.BaseOption<
|
||||
number,
|
||||
{ provider: string; state: string | number }
|
||||
@@ -541,6 +542,7 @@ const AddModal: FC<AddModalProps> = (props) => {
|
||||
onOk={handleOnOk}
|
||||
ref={form}
|
||||
isGGUF={isGGUF}
|
||||
backendOptions={props.backendOptions}
|
||||
onBackendChange={handleBackendChange}
|
||||
onValuesChange={onValuesChange}
|
||||
></DataForm>
|
||||
|
||||
@@ -57,6 +57,7 @@ import {
|
||||
} from '../config/types';
|
||||
import useFormInitialValues from '../hooks/use-form-initial-values';
|
||||
import useModelsColumns from '../hooks/use-models-columns';
|
||||
import useQueryBackends from '../hooks/use-query-backends';
|
||||
import APIAccessInfoModal from './api-access-info';
|
||||
import DeployModal from './deploy-modal';
|
||||
import Instances from './instances';
|
||||
@@ -123,6 +124,7 @@ const Models: React.FC<ModelsProps> = ({
|
||||
loadend,
|
||||
total
|
||||
}) => {
|
||||
const { backendOptions } = useQueryBackends();
|
||||
const { generateFormValues, clusterList, getClusterList } =
|
||||
useFormInitialValues();
|
||||
const { saveScrollHeight, restoreScrollHeight } = useBodyScroll();
|
||||
@@ -686,6 +688,7 @@ const Models: React.FC<ModelsProps> = ({
|
||||
clusterList={clusterList}
|
||||
onCancel={handleModalCancel}
|
||||
onOk={handleModalOk}
|
||||
backendOptions={backendOptions}
|
||||
></UpdateModel>
|
||||
<DeployModal
|
||||
open={openDeployModal.show}
|
||||
@@ -696,6 +699,7 @@ const Models: React.FC<ModelsProps> = ({
|
||||
isGGUF={openDeployModal.isGGUF}
|
||||
hasLinuxWorker={openDeployModal.hasLinuxWorker}
|
||||
clusterList={clusterList}
|
||||
backendOptions={backendOptions}
|
||||
onCancel={handleDeployModalCancel}
|
||||
onOk={handleCreateModel}
|
||||
></DeployModal>
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
updateIgnoreFields
|
||||
} from '../config';
|
||||
import { backendOptionsMap } from '../config/backend-parameters';
|
||||
import { FormData } from '../config/types';
|
||||
import { BackendOption, FormData } from '../config/types';
|
||||
import { generateGPUSelector } from '../config/utils';
|
||||
import { useCheckCompatibility } from '../hooks';
|
||||
import ColumnWrapper from './column-wrapper';
|
||||
@@ -26,6 +26,7 @@ type AddModalProps = {
|
||||
data: FormData;
|
||||
isGGUF: boolean;
|
||||
};
|
||||
backendOptions: BackendOption[];
|
||||
clusterList: Global.BaseOption<
|
||||
number,
|
||||
{ provider: string; state: string | number }
|
||||
@@ -325,6 +326,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
||||
onOk={handleOk}
|
||||
ref={formRef}
|
||||
isGGUF={isGGUF}
|
||||
backendOptions={props.backendOptions}
|
||||
onBackendChange={handleAsyncBackendChange}
|
||||
onValuesChange={handleManulOnValuesChange}
|
||||
></DataForm>
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { PageActionType } from '@/config/types';
|
||||
import React from 'react';
|
||||
import { DeployFormKey } from './types';
|
||||
import { BackendOption, DeployFormKey } from './types';
|
||||
|
||||
interface FormContextProps {
|
||||
isGGUF?: boolean;
|
||||
formKey: DeployFormKey;
|
||||
source?: string;
|
||||
source: string;
|
||||
pageAction: PageActionType;
|
||||
gpuOptions?: any[];
|
||||
backendOptions: BackendOption[];
|
||||
onValuesChange?: (changedValues: any, allValues: any) => void;
|
||||
onBackendChange?: (backend: string) => void;
|
||||
onBackendChange: (backend: string) => void;
|
||||
}
|
||||
|
||||
interface CatalogFormContextProps {
|
||||
@@ -19,6 +20,10 @@ interface CatalogFormContextProps {
|
||||
onQuantizationChange: (val: string) => void;
|
||||
}
|
||||
|
||||
interface FormOuterContextProps {
|
||||
sourceList?: Global.BaseOption<string>[];
|
||||
}
|
||||
|
||||
export const FormContext = React.createContext<FormContextProps>(
|
||||
{} as FormContextProps
|
||||
);
|
||||
@@ -27,6 +32,10 @@ export const CatalogFormContext = React.createContext<CatalogFormContextProps>(
|
||||
{} as CatalogFormContextProps
|
||||
);
|
||||
|
||||
export const FormOuterContext = React.createContext<FormOuterContextProps>(
|
||||
{} as FormOuterContextProps
|
||||
);
|
||||
|
||||
export const useFormContext = () => {
|
||||
const context = React.useContext(FormContext);
|
||||
if (!context) {
|
||||
@@ -44,3 +53,13 @@ export const useCatalogFormContext = () => {
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
export const useFormOuterContext = () => {
|
||||
const context = React.useContext(FormOuterContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
'useFormOuterContext must be used within a FormOuterProvider'
|
||||
);
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
@@ -324,7 +324,9 @@ export const excludeFields = [
|
||||
'scheduleType',
|
||||
'placement_strategy',
|
||||
'backend',
|
||||
'gpu_selector'
|
||||
'gpu_selector',
|
||||
'run_command',
|
||||
'image_name'
|
||||
];
|
||||
|
||||
// ingore fields when compare old and new data
|
||||
|
||||
@@ -39,6 +39,8 @@ export type SourceType =
|
||||
| 'ollama_library';
|
||||
|
||||
export interface FormData {
|
||||
image_name?: string;
|
||||
run_command?: string;
|
||||
backend: string;
|
||||
restart_on_error?: boolean;
|
||||
env?: Record<string, any>;
|
||||
@@ -242,3 +244,11 @@ export interface EvaluateResult {
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface BackendOption {
|
||||
value: string;
|
||||
label: string;
|
||||
default_backend_param: string[];
|
||||
default_version: string;
|
||||
versions: { label: string; value: string }[];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
import IconFont from '@/components/icon-font';
|
||||
import AutoComplete from '@/components/seal-form/auto-complete';
|
||||
import SealInput from '@/components/seal-form/seal-input';
|
||||
import SealSelect from '@/components/seal-form/seal-select';
|
||||
import TooltipList from '@/components/tooltip-list';
|
||||
import { PageAction } from '@/config';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Form, Typography } from 'antd';
|
||||
import React, { useMemo } from 'react';
|
||||
import {
|
||||
backendLabelMap,
|
||||
backendTipsList,
|
||||
getBackendParamsTips,
|
||||
modelSourceMap
|
||||
} from '../config';
|
||||
import { backendOptionsMap } from '../config/backend-parameters';
|
||||
import { useFormContext } from '../config/form-context';
|
||||
import { FormData } from '../config/types';
|
||||
|
||||
const BackendFields: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const form = Form.useFormInstance();
|
||||
const {
|
||||
isGGUF,
|
||||
formKey,
|
||||
pageAction: action,
|
||||
source,
|
||||
gpuOptions,
|
||||
onValuesChange,
|
||||
backendOptions,
|
||||
onBackendChange
|
||||
} = useFormContext();
|
||||
const backend = Form.useWatch('backend', form);
|
||||
|
||||
const handleBackendVersionOnBlur = () => {
|
||||
onValuesChange?.({}, form.getFieldsValue());
|
||||
};
|
||||
|
||||
const backendParamsTips = useMemo(() => {
|
||||
return getBackendParamsTips(backend);
|
||||
}, [backend]);
|
||||
|
||||
const backendVersions = useMemo(() => {
|
||||
if (!backend || backend === backendOptionsMap.custom) {
|
||||
return [];
|
||||
}
|
||||
return (
|
||||
backendOptions.find((item) => item.value === backend)?.versions || []
|
||||
);
|
||||
}, [backend]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item name="backend" rules={[{ required: true }]}>
|
||||
<SealSelect
|
||||
required
|
||||
onChange={onBackendChange}
|
||||
label={intl.formatMessage({ id: 'models.form.backend' })}
|
||||
description={<TooltipList list={backendTipsList}></TooltipList>}
|
||||
options={backendOptions}
|
||||
disabled={
|
||||
action === PageAction.EDIT &&
|
||||
source !== modelSourceMap.local_path_value
|
||||
}
|
||||
></SealSelect>
|
||||
</Form.Item>
|
||||
{backendOptionsMap.custom !== backend && (
|
||||
<Form.Item name="backend_version">
|
||||
<AutoComplete
|
||||
options={backendVersions}
|
||||
placeholder="enter or select a version"
|
||||
onBlur={handleBackendVersionOnBlur}
|
||||
label={intl.formatMessage({ id: 'models.form.backendVersion' })}
|
||||
description={intl.formatMessage(
|
||||
{
|
||||
id: 'models.form.backendVersion.tips'
|
||||
},
|
||||
{
|
||||
backend: backendLabelMap[backend],
|
||||
version: backendParamsTips?.version
|
||||
? `(${intl.formatMessage({ id: 'common.help.eg' })} ${backendParamsTips?.version})`
|
||||
: '',
|
||||
link: backendParamsTips?.releases && (
|
||||
<span
|
||||
style={{
|
||||
marginLeft: 5
|
||||
}}
|
||||
>
|
||||
<Typography.Link
|
||||
className="flex-center"
|
||||
style={{ display: 'inline' }}
|
||||
href={backendParamsTips?.releases}
|
||||
target="_blank"
|
||||
>
|
||||
<span>
|
||||
{intl.formatMessage({ id: 'models.form.releases' })}
|
||||
</span>
|
||||
<IconFont
|
||||
type="icon-external-link"
|
||||
className="font-size-14 m-l-4"
|
||||
></IconFont>
|
||||
</Typography.Link>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
)}
|
||||
></AutoComplete>
|
||||
</Form.Item>
|
||||
)}
|
||||
{backend === backendOptionsMap.custom && (
|
||||
<>
|
||||
<Form.Item<FormData> name="image_name" rules={[{ required: true }]}>
|
||||
<SealInput.Input
|
||||
required
|
||||
allowClear
|
||||
scaleSize={true}
|
||||
label="Image Name"
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
<Form.Item<FormData> name="run_command" rules={[{ required: true }]}>
|
||||
<SealInput.TextArea
|
||||
required
|
||||
scaleSize={true}
|
||||
allowClear
|
||||
label="Execution Command"
|
||||
></SealInput.TextArea>
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BackendFields;
|
||||
@@ -128,10 +128,6 @@ export const checkCurrentbackend = (data: {
|
||||
return backendOptionsMap.voxBox;
|
||||
}
|
||||
|
||||
if (isGGUF) {
|
||||
return backendOptionsMap.llamaBox;
|
||||
}
|
||||
|
||||
if (checkOnlyAscendNPU(gpuOptions)) {
|
||||
return backendOptionsMap.ascendMindie;
|
||||
}
|
||||
@@ -229,11 +225,6 @@ export const useCheckCompatibility = () => {
|
||||
return clusterNames.join(', ');
|
||||
};
|
||||
|
||||
const getCurrentCluster = (id: number) => {
|
||||
const cluster = clusterList.find?.((item) => item.value === id);
|
||||
return cluster?.label || '';
|
||||
};
|
||||
|
||||
const handleCheckCompatibility = (
|
||||
evaluateResult: EvaluateResult | null
|
||||
): MessageStatus => {
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { backendOptionsAtom } from '@/atoms/models';
|
||||
import { useAtom } from 'jotai';
|
||||
import { useEffect } from 'react';
|
||||
import { queryBackendList } from '../apis';
|
||||
|
||||
export default function useQueryBackends() {
|
||||
const [backendOptions, setBackendOptions] = useAtom(backendOptionsAtom);
|
||||
|
||||
const getBackendOptions = async () => {
|
||||
try {
|
||||
const res = await queryBackendList();
|
||||
const list = res?.items?.map((item) => {
|
||||
return {
|
||||
value: item.backend_name,
|
||||
label: item.backend_show_name,
|
||||
default_backend_param: item.default_backend_param || [],
|
||||
default_version: item.default_version,
|
||||
versions: (item.versions || []).map((version) => ({
|
||||
label: version,
|
||||
value: version
|
||||
}))
|
||||
};
|
||||
});
|
||||
if (res?.items) {
|
||||
setBackendOptions(list || []);
|
||||
}
|
||||
} catch (error) {
|
||||
// ignore
|
||||
setBackendOptions([]);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getBackendOptions();
|
||||
}, []);
|
||||
|
||||
return {
|
||||
backendOptions,
|
||||
getBackendOptions
|
||||
};
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
import { SourceType } from '@/pages/llmodels/config/types';
|
||||
import DownloadModal from '@/pages/llmodels/download';
|
||||
import { useGenerateWorkerOptions } from '@/pages/llmodels/hooks/use-form-initial-values';
|
||||
import useQueryBackends from '@/pages/llmodels/hooks/use-query-backends';
|
||||
import { PageContainer } from '@ant-design/pro-components';
|
||||
import { useIntl, useNavigate } from '@umijs/max';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
@@ -64,7 +65,7 @@ const ModelFiles = () => {
|
||||
watch: true,
|
||||
contentForDelete: 'resources.modelfiles.modelfile'
|
||||
});
|
||||
|
||||
const { backendOptions } = useQueryBackends();
|
||||
const intl = useIntl();
|
||||
const { showSuccess } = useAppUtils();
|
||||
const [downloadModalStatus, setDownlaodMoalStatus] = useState<{
|
||||
@@ -106,9 +107,15 @@ const ModelFiles = () => {
|
||||
worker_id: value
|
||||
});
|
||||
};
|
||||
const generateInitialValues = (record: ListItem, gpuOptions: any[]) => {
|
||||
|
||||
const checkIsGGUF = (record: ListItem) => {
|
||||
const isGGUF = _.includes(record.resolved_paths?.[0], 'gguf');
|
||||
const isOllama = !!record.ollama_library_model_name;
|
||||
return isGGUF || isOllama;
|
||||
};
|
||||
|
||||
const generateInitialValues = (record: ListItem, gpuOptions: any[]) => {
|
||||
const isGGUF = checkIsGGUF(record);
|
||||
const audioModelTag = identifyModelTask(
|
||||
record.source,
|
||||
record.resolved_paths?.[0]
|
||||
@@ -140,12 +147,12 @@ const ModelFiles = () => {
|
||||
: {},
|
||||
name: extractFileName(name),
|
||||
backend: checkCurrentbackend({
|
||||
isGGUF: !audioModelTag && (isGGUF || isOllama),
|
||||
isGGUF: !audioModelTag && isGGUF,
|
||||
isAudio: !!audioModelTag,
|
||||
gpuOptions: gpuOptions,
|
||||
defaultBackend: backendOptionsMap.vllm
|
||||
}),
|
||||
isGGUF: !audioModelTag && (isGGUF || isOllama)
|
||||
isGGUF: !audioModelTag && isGGUF
|
||||
};
|
||||
};
|
||||
|
||||
@@ -338,6 +345,7 @@ const ModelFiles = () => {
|
||||
workerOptions={readyWorkers}
|
||||
></DownloadModal>
|
||||
<DeployModal
|
||||
backendOptions={backendOptions}
|
||||
deploymentType="modelFiles"
|
||||
title={intl.formatMessage({ id: 'models.button.deploy' })}
|
||||
onCancel={handleDeployModalCancel}
|
||||
|
||||
Reference in New Issue
Block a user