diff --git a/src/components/seal-form/base/select.tsx b/src/components/seal-form/base/select.tsx
index 4575e188..85d0046a 100644
--- a/src/components/seal-form/base/select.tsx
+++ b/src/components/seal-form/base/select.tsx
@@ -48,6 +48,7 @@ const BaseSelect: React.FC<
notFoundContent={
}
+ placeholder={props.placeholder}
ref={inputRef}
onFocus={handleFocus}
onBlur={handleBlur}
diff --git a/src/locales/zh-CN/routes.ts b/src/locales/zh-CN/routes.ts
index d2532c74..ad168308 100644
--- a/src/locales/zh-CN/routes.ts
+++ b/src/locales/zh-CN/routes.ts
@@ -3,15 +3,15 @@ export default {
'routes.button.add': '添加路由',
'routes.table.routeTargets': '路由目标',
'routes.table.traffic': '流量',
- 'routes.table.setAsFallback': '降级',
+ 'routes.table.setAsFallback': 'Fallback',
'routes.form.target.title': '路由目标',
'routes.form.target.add': '添加路由目标',
- 'routes.form.target.fallback': '降级路由目标',
+ 'routes.form.target.fallback': 'Fallback 路由目标',
'routes.form.target.weight': '权重',
'routes.form.target.model': '模型',
'routes.form.metadata.title': '元数据',
'routes.form.metadata.add': '添加元数据',
- 'routes.table.label.fallback': '降级',
+ 'routes.table.label.fallback': 'Fallback',
'routes.form.metadata.size': '参数量',
'routes.form.metadata.activeSize': '激活参数量',
'routes.form.metadata.tags': '标签',
diff --git a/src/pages/maas-provider/components/provider-models.tsx b/src/pages/maas-provider/components/provider-models.tsx
index 97ff6612..fb38ccf9 100644
--- a/src/pages/maas-provider/components/provider-models.tsx
+++ b/src/pages/maas-provider/components/provider-models.tsx
@@ -5,6 +5,7 @@ import {
WarningOutlined
} from '@ant-design/icons';
import { Flex, Tag } from 'antd';
+import _ from 'lodash';
import React from 'react';
import { categoryConfig } from '../../_components/model-tag';
import { ProviderModel } from '../config/types';
@@ -26,7 +27,7 @@ const ProviderModels: React.FC = ({ dataList }) => {
-
+
{
<>
- },
+ // {
+ // key: 'fallback',
+ // label: 'routes.table.setAsFallback',
+ // icon:
+ // },
{
key: 'delete',
label: 'common.button.delete',
@@ -108,7 +107,7 @@ const RouteItem: React.FC = ({
diff --git a/src/pages/model-routes/forms/targets.tsx b/src/pages/model-routes/forms/targets.tsx
index 60777da0..7934c8ba 100644
--- a/src/pages/model-routes/forms/targets.tsx
+++ b/src/pages/model-routes/forms/targets.tsx
@@ -5,29 +5,9 @@ import { useIntl } from '@umijs/max';
import { Form } from 'antd';
import _ from 'lodash';
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
-import styled from 'styled-components';
import { FormData } from '../config/types';
import useTargetSourceModels from '../hooks/use-target-source-models';
-const Inner = styled.div`
- display: flex;
- align-items: center;
- width: 100%;
- ul.ant-cascader-menu:first-child {
- li[data-path-key='deployments'] {
- position: relative;
- &::after {
- content: '';
- position: absolute;
- left: 0;
- right: 0;
- bottom: 0;
- border-bottom: 1px solid var(--ant-color-split);
- }
- }
- }
-`;
-
const TargetsForm = forwardRef((props, ref) => {
const intl = useIntl();
const { sourceModels, loading, fetchSourceModels } = useTargetSourceModels();
@@ -58,6 +38,14 @@ const TargetsForm = forwardRef((props, ref) => {
}));
const handleTargetsChange = (value: any[], index: number, options: any[]) => {
+ console.log(
+ 'handleTargetsChange:',
+ value,
+ index,
+ options,
+ dataList,
+ sourceModels
+ );
const selectedOption =
options?.find?.((opt) => opt.value === value[1]) || {};
const targetList = [...targets];
@@ -100,10 +88,10 @@ const TargetsForm = forwardRef((props, ref) => {
const selectedOption =
options?.find?.((opt) => opt.value === value[1]) || {};
- console.log('fallback selected option data:', value);
form.setFieldValue('fallback_target', {
...selectedOption?.data
});
+ console.log('handleFallbackChange:', value, dataList);
setFallbackValues({
value: value
});
@@ -127,6 +115,44 @@ const TargetsForm = forwardRef((props, ref) => {
setDataList(newDataList);
};
+ const buildKey = (path?: any[]) =>
+ Array.isArray(path) ? path.join('/') : '';
+
+ const filterOptions = (currentValue: any[]) => {
+ const currKey = buildKey(currentValue);
+
+ const selectedDataList = [...dataList, { value: fallbackValues.value }];
+
+ const selectedKeys = selectedDataList
+ .filter((item) => item.value)
+ .map((item) => buildKey(item.value));
+
+ return sourceModels
+ .map((model) => {
+ const children = model.children?.filter((child) => {
+ const key = buildKey([child.data?.parentId, child.value]);
+
+ return !selectedKeys.includes(key) || key === currKey;
+ });
+
+ return {
+ ...model,
+ children
+ };
+ })
+ .filter((model) => model.children && model.children.length > 0);
+ };
+
+ const displayRender = (labels: any[]) => {
+ return (
+
+ {labels[0]}
+ /
+ {labels[1]}
+
+ );
+ };
+
useEffect(() => {
fetchSourceModels();
}, []);
@@ -188,13 +214,21 @@ const TargetsForm = forwardRef((props, ref) => {
root: 'cascader-popup-wrapper gpu-selector'
}
}}
+ styles={{
+ popup: {
+ listItem: {
+ padding: '5px 10px'
+ }
+ }
+ }}
maxTagCount={1}
placeholder={intl.formatMessage({
id: 'providers.form.target.placeholder'
})}
value={item.value}
- options={sourceModels}
+ options={filterOptions(item.value)}
showCheckedStrategy="SHOW_CHILD"
+ displayRender={displayRender}
getPopupContainer={(triggerNode) => triggerNode.parentNode}
>
:
@@ -223,6 +257,13 @@ const TargetsForm = forwardRef((props, ref) => {
root: 'cascader-popup-wrapper gpu-selector'
}
}}
+ styles={{
+ popup: {
+ listItem: {
+ padding: '5px 10px'
+ }
+ }
+ }}
label={intl.formatMessage({
id: 'routes.form.target.fallback'
})}
@@ -231,9 +272,10 @@ const TargetsForm = forwardRef((props, ref) => {
})}
maxTagCount={1}
value={fallbackValues.value}
- options={sourceModels}
+ options={filterOptions(fallbackValues.value)}
onChange={(value, options) => handleFallbackChange(value, options)}
showCheckedStrategy="SHOW_CHILD"
+ displayRender={displayRender}
getPopupContainer={(triggerNode) => triggerNode.parentNode}
>
diff --git a/src/pages/model-routes/hooks/use-target-source-models.tsx b/src/pages/model-routes/hooks/use-target-source-models.tsx
index caf37d38..eaf83696 100644
--- a/src/pages/model-routes/hooks/use-target-source-models.tsx
+++ b/src/pages/model-routes/hooks/use-target-source-models.tsx
@@ -1,17 +1,30 @@
+import GPUStackLogo from '@/assets/images/small-logo-200x200.png';
import { queryModelsList } from '@/pages/llmodels/apis';
import { ListItem as ModelListItem } from '@/pages/llmodels/config/types';
import { queryMaasProviders } from '@/pages/maas-provider/apis';
+import ProviderLogo from '@/pages/maas-provider/components/provider-logo';
import { MaasProviderItem } from '@/pages/maas-provider/config/types';
import { useIntl } from '@umijs/max';
-import { useState } from 'react';
+import React, { useState } from 'react';
+import styled from 'styled-components';
+
+const OptionWrapper = styled.span`
+ display: flex;
+ align-items: center;
+ gap: 8px;
+`;
type EmptyObject = Record;
type CascaderOption = {
- label: string;
+ label: React.ReactNode;
value: string | number;
parent?: boolean;
disabled?: boolean;
index?: number;
+ data?: {
+ [key: string]: any;
+ parentId?: string | number;
+ };
children?: CascaderOption[];
} & Partial;
@@ -31,17 +44,10 @@ const useTargetSourceModels = () => {
const modelsList = [
{
label: (
-
+
+
{intl.formatMessage({ id: 'menu.models.deployment' })}
-
- [GPUStack]
-
-
+
),
value: 'deployments',
parent: true,
@@ -49,7 +55,8 @@ const useTargetSourceModels = () => {
label: model.name,
value: model.id,
data: {
- model_id: model.id
+ model_id: model.id,
+ parentId: 'deployments'
},
source: 'deployment'
}))
@@ -58,7 +65,12 @@ const useTargetSourceModels = () => {
const providerOptions: CascaderOption[] = providers.items
?.map?.((provider: MaasProviderItem) => ({
- label: provider.name,
+ label: (
+
+
+ {provider.name}
+
+ ),
value: provider.id,
parent: true,
children: provider.models?.map?.((model) => ({
@@ -66,7 +78,8 @@ const useTargetSourceModels = () => {
value: model.name,
data: {
provider_model_name: model.name,
- provider_id: provider.id
+ provider_id: provider.id,
+ parentId: provider.id
},
source: 'providerModel'
}))