fix(styles): providers access token
This commit is contained in:
@@ -77,7 +77,10 @@ const OptionNodes = (props: {
|
|||||||
|
|
||||||
const SealCascader: React.FC<
|
const SealCascader: React.FC<
|
||||||
CascaderAutoProps &
|
CascaderAutoProps &
|
||||||
SealFormItemProps & { optionNode?: React.FC<{ data: any }> }
|
SealFormItemProps & {
|
||||||
|
alwaysFocus?: boolean;
|
||||||
|
optionNode?: React.FC<{ data: any }>;
|
||||||
|
}
|
||||||
> = (props) => {
|
> = (props) => {
|
||||||
const {
|
const {
|
||||||
label,
|
label,
|
||||||
@@ -88,6 +91,7 @@ const SealCascader: React.FC<
|
|||||||
options,
|
options,
|
||||||
allowNull,
|
allowNull,
|
||||||
isInFormItems = true,
|
isInFormItems = true,
|
||||||
|
alwaysFocus = false,
|
||||||
optionNode,
|
optionNode,
|
||||||
notFoundContent,
|
notFoundContent,
|
||||||
tagRender,
|
tagRender,
|
||||||
@@ -167,7 +171,7 @@ const SealCascader: React.FC<
|
|||||||
classList={visible ? 'dropdown-visible' : ''}
|
classList={visible ? 'dropdown-visible' : ''}
|
||||||
status={status}
|
status={status}
|
||||||
label={label}
|
label={label}
|
||||||
isFocus={isFocus}
|
isFocus={alwaysFocus || isFocus}
|
||||||
required={required}
|
required={required}
|
||||||
description={description}
|
description={description}
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
|
|||||||
@@ -255,6 +255,8 @@ export default {
|
|||||||
'models.catalog.precision': 'Precision',
|
'models.catalog.precision': 'Precision',
|
||||||
'models.form.gpuPerReplica.tips': 'Enter a custom number',
|
'models.form.gpuPerReplica.tips': 'Enter a custom number',
|
||||||
'models.form.generic_proxy': 'Enable Generic Proxy',
|
'models.form.generic_proxy': 'Enable Generic Proxy',
|
||||||
|
'models.form.enable_model_access': 'Enable Model Access',
|
||||||
|
'models.form.enable_model_access.tips': 'Enable Model Access',
|
||||||
'models.form.generic_proxy.tips':
|
'models.form.generic_proxy.tips':
|
||||||
'After enabling the generic proxy, you can access URI paths that do not follow the OpenAI API standard.',
|
'After enabling the generic proxy, you can access URI paths that do not follow the OpenAI API standard.',
|
||||||
'models.form.generic_proxy.button': 'Generic Proxy',
|
'models.form.generic_proxy.button': 'Generic Proxy',
|
||||||
|
|||||||
@@ -4,13 +4,15 @@ export default {
|
|||||||
'providers.table.providerName': 'Provider',
|
'providers.table.providerName': 'Provider',
|
||||||
'providers.table.models': 'Models',
|
'providers.table.models': 'Models',
|
||||||
'providers.table.proxy': 'Proxy',
|
'providers.table.proxy': 'Proxy',
|
||||||
'providers.form.tokens.title': ' API Tokens',
|
'providers.form.tokens.title': ' API Key',
|
||||||
'providers.form.tokens.add': 'Add API Token',
|
'providers.form.tokens.add': 'Add API Key',
|
||||||
'providers.form.models.add': 'Add Model',
|
'providers.form.models.add': 'Add Model',
|
||||||
'providers.form.proxy.enable': 'Enable Proxy',
|
'providers.form.proxy.enable': 'Enable Proxy',
|
||||||
'providers.form.proxy.url': 'Proxy URL',
|
'providers.form.proxy.url': 'Proxy URL',
|
||||||
'providers.form.proxy.timeout': 'Proxy Timeout (seconds)',
|
'providers.form.proxy.timeout': 'Proxy Timeout (seconds)',
|
||||||
'providers.form.customConfig': 'Custom Configuration',
|
'providers.form.customConfig': 'Custom Configuration',
|
||||||
'providers.form.model.test': 'Test',
|
'providers.form.model.test': 'Test',
|
||||||
'providers.form.model.test.tips': 'Test Connection'
|
'providers.form.model.test.tips': 'Test Connection',
|
||||||
|
'providers.form.endpoint.placeholder': 'provider/models',
|
||||||
|
'providers.form.fallback.token': 'Fallback API Keys'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -255,6 +255,8 @@ export default {
|
|||||||
'models.catalog.precision': 'Precision',
|
'models.catalog.precision': 'Precision',
|
||||||
'models.form.gpuPerReplica.tips': 'Enter a custom number',
|
'models.form.gpuPerReplica.tips': 'Enter a custom number',
|
||||||
'models.form.generic_proxy': 'Enable Generic Proxy',
|
'models.form.generic_proxy': 'Enable Generic Proxy',
|
||||||
|
'models.form.enable_model_access': 'Enable Model Access',
|
||||||
|
'models.form.enable_model_access.tips': 'Enable Model Access',
|
||||||
'models.form.generic_proxy.tips':
|
'models.form.generic_proxy.tips':
|
||||||
'After enabling the generic proxy, you can access URI paths that do not follow the OpenAI API standard.',
|
'After enabling the generic proxy, you can access URI paths that do not follow the OpenAI API standard.',
|
||||||
'models.form.generic_proxy.button': 'Generic Proxy',
|
'models.form.generic_proxy.button': 'Generic Proxy',
|
||||||
@@ -375,4 +377,6 @@ export default {
|
|||||||
// 76. 'models.form.maxContextLength': 'Maximum Context Length',
|
// 76. 'models.form.maxContextLength': 'Maximum Context Length',
|
||||||
// 77. 'models.form.backend.helperText': 'Not enabled yet. Will be enabled after deployment. ',
|
// 77. 'models.form.backend.helperText': 'Not enabled yet. Will be enabled after deployment. ',
|
||||||
// 78. 'models.table.instance.benchmark': 'Run Benchmark'
|
// 78. 'models.table.instance.benchmark': 'Run Benchmark'
|
||||||
|
// 77. 'models.form.enable_model_access': 'Enable Model Access',
|
||||||
|
// 78. 'models.form.enable_model_access.tips': 'Enable Model Access',
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -4,13 +4,15 @@ export default {
|
|||||||
'providers.table.providerName': 'Provider',
|
'providers.table.providerName': 'Provider',
|
||||||
'providers.table.models': 'Models',
|
'providers.table.models': 'Models',
|
||||||
'providers.table.proxy': 'Proxy',
|
'providers.table.proxy': 'Proxy',
|
||||||
'providers.form.tokens.title': ' API Tokens',
|
'providers.form.tokens.title': ' API Key',
|
||||||
'providers.form.tokens.add': 'Add API Token',
|
'providers.form.tokens.add': 'Add API Key',
|
||||||
'providers.form.models.add': 'Add Model',
|
'providers.form.models.add': 'Add Model',
|
||||||
'providers.form.proxy.enable': 'Enable Proxy',
|
'providers.form.proxy.enable': 'Enable Proxy',
|
||||||
'providers.form.proxy.url': 'Proxy URL',
|
'providers.form.proxy.url': 'Proxy URL',
|
||||||
'providers.form.proxy.timeout': 'Proxy Timeout (seconds)',
|
'providers.form.proxy.timeout': 'Proxy Timeout (seconds)',
|
||||||
'providers.form.customConfig': 'Custom Configuration',
|
'providers.form.customConfig': 'Custom Configuration',
|
||||||
'providers.form.model.test': 'Test',
|
'providers.form.model.test': 'Test',
|
||||||
'providers.form.model.test.tips': 'Test Connection'
|
'providers.form.model.test.tips': 'Test Connection',
|
||||||
|
'providers.form.endpoint.placeholder': 'provider/models',
|
||||||
|
'providers.form.fallback.token': 'Fallback API Keys'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -260,6 +260,8 @@ export default {
|
|||||||
'models.catalog.precision': 'Точность',
|
'models.catalog.precision': 'Точность',
|
||||||
'models.form.gpuPerReplica.tips': 'Введите произвольное число',
|
'models.form.gpuPerReplica.tips': 'Введите произвольное число',
|
||||||
'models.form.generic_proxy': 'Включить универсальный прокси',
|
'models.form.generic_proxy': 'Включить универсальный прокси',
|
||||||
|
'models.form.enable_model_access': 'Enable Model Access',
|
||||||
|
'models.form.enable_model_access.tips': 'Enable Model Access',
|
||||||
'models.form.generic_proxy.tips':
|
'models.form.generic_proxy.tips':
|
||||||
'После включения универсального прокси вы можете получать доступ к URI-путям, которые не следуют стандарту OpenAI API.',
|
'После включения универсального прокси вы можете получать доступ к URI-путям, которые не следуют стандарту OpenAI API.',
|
||||||
'models.form.generic_proxy.button': 'Универсальный прокси',
|
'models.form.generic_proxy.button': 'Универсальный прокси',
|
||||||
@@ -287,4 +289,6 @@ export default {
|
|||||||
// 1. 'models.form.maxContextLength': 'Maximum Context Length',
|
// 1. 'models.form.maxContextLength': 'Maximum Context Length',
|
||||||
// 2. 'models.form.backend.helperText': 'Not enabled yet. Will be enabled after deployment. ',
|
// 2. 'models.form.backend.helperText': 'Not enabled yet. Will be enabled after deployment. ',
|
||||||
// 3. 'models.table.instance.benchmark': 'Run Benchmark'
|
// 3. 'models.table.instance.benchmark': 'Run Benchmark'
|
||||||
|
// 2. 'models.form.enable_model_access': 'Enable Model Access',
|
||||||
|
// 3. 'models.form.enable_model_access.tips': 'Enable Model Access',
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -4,13 +4,15 @@ export default {
|
|||||||
'providers.table.providerName': 'Provider',
|
'providers.table.providerName': 'Provider',
|
||||||
'providers.table.models': 'Models',
|
'providers.table.models': 'Models',
|
||||||
'providers.table.proxy': 'Proxy',
|
'providers.table.proxy': 'Proxy',
|
||||||
'providers.form.tokens.title': ' API Tokens',
|
'providers.form.tokens.title': ' API Key',
|
||||||
'providers.form.tokens.add': 'Add API Token',
|
'providers.form.tokens.add': 'Add API Key',
|
||||||
'providers.form.models.add': 'Add Model',
|
'providers.form.models.add': 'Add Model',
|
||||||
'providers.form.proxy.enable': 'Enable Proxy',
|
'providers.form.proxy.enable': 'Enable Proxy',
|
||||||
'providers.form.proxy.url': 'Proxy URL',
|
'providers.form.proxy.url': 'Proxy URL',
|
||||||
'providers.form.proxy.timeout': 'Proxy Timeout (seconds)',
|
'providers.form.proxy.timeout': 'Proxy Timeout (seconds)',
|
||||||
'providers.form.customConfig': 'Custom Configuration',
|
'providers.form.customConfig': 'Custom Configuration',
|
||||||
'providers.form.model.test': 'Test',
|
'providers.form.model.test': 'Test',
|
||||||
'providers.form.model.test.tips': 'Test Connection'
|
'providers.form.model.test.tips': 'Test Connection',
|
||||||
|
'providers.form.endpoint.placeholder': 'provider/models',
|
||||||
|
'providers.form.fallback.token': 'Fallback API Keys'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -242,6 +242,8 @@ export default {
|
|||||||
'models.catalog.precision': '精度',
|
'models.catalog.precision': '精度',
|
||||||
'models.form.gpuPerReplica.tips': '输入自定义数值',
|
'models.form.gpuPerReplica.tips': '输入自定义数值',
|
||||||
'models.form.generic_proxy': '启用通用代理',
|
'models.form.generic_proxy': '启用通用代理',
|
||||||
|
'models.form.enable_model_access': '启用模型接入',
|
||||||
|
'models.form.enable_model_access.tips': '启用模型接入',
|
||||||
'models.form.generic_proxy.tips':
|
'models.form.generic_proxy.tips':
|
||||||
'启用通用代理后可支持访问非 OpenAI-API 标准的 URI 路径。',
|
'启用通用代理后可支持访问非 OpenAI-API 标准的 URI 路径。',
|
||||||
'models.form.generic_proxy.button': '通用代理',
|
'models.form.generic_proxy.button': '通用代理',
|
||||||
|
|||||||
@@ -4,13 +4,15 @@ export default {
|
|||||||
'providers.table.providerName': '提供商',
|
'providers.table.providerName': '提供商',
|
||||||
'providers.table.models': '模型',
|
'providers.table.models': '模型',
|
||||||
'providers.table.proxy': '代理',
|
'providers.table.proxy': '代理',
|
||||||
'providers.form.tokens.title': 'API 令牌',
|
'providers.form.tokens.title': 'API Key',
|
||||||
'providers.form.tokens.add': '添加 API 令牌',
|
'providers.form.tokens.add': '添加 API Key',
|
||||||
'providers.form.models.add': '添加模型',
|
'providers.form.models.add': '添加模型',
|
||||||
'providers.form.proxy.enable': '启用代理',
|
'providers.form.proxy.enable': '启用代理',
|
||||||
'providers.form.proxy.url': '代理地址',
|
'providers.form.proxy.url': '代理地址',
|
||||||
'providers.form.proxy.timeout': '代理超时(秒)',
|
'providers.form.proxy.timeout': '代理超时(秒)',
|
||||||
'providers.form.customConfig': '自定义配置',
|
'providers.form.customConfig': '自定义配置',
|
||||||
'providers.form.model.test': '测试',
|
'providers.form.model.test': '测试',
|
||||||
'providers.form.model.test.tips': '测试连接'
|
'providers.form.model.test.tips': '测试连接',
|
||||||
|
'providers.form.endpoint.placeholder': '提供商/模型',
|
||||||
|
'providers.form.fallback.token': '备用 API Key'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import SealSelect from '@/components/seal-form/seal-select';
|
||||||
|
import React from 'react';
|
||||||
|
import { categoryConfig } from './model-tag';
|
||||||
|
|
||||||
|
const CategorySelect = (props: any) => {
|
||||||
|
const { options, ...rest } = props;
|
||||||
|
|
||||||
|
const optionRenderer = (option: any) => {
|
||||||
|
const config = categoryConfig[option.value] || {};
|
||||||
|
console.log('option:', option, 'config:', config);
|
||||||
|
return (
|
||||||
|
<span className="flex-center">
|
||||||
|
<span style={{ color: config.color }}>
|
||||||
|
{React.cloneElement(config.icon)}
|
||||||
|
</span>
|
||||||
|
<span style={{ marginLeft: 8 }}>{option.label}</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<SealSelect
|
||||||
|
options={options}
|
||||||
|
optionRenderer={optionRenderer}
|
||||||
|
labelRender={optionRenderer}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CategorySelect;
|
||||||
@@ -3,6 +3,7 @@ import { downloadFile, listFiles, listModels } from '@huggingface/hub';
|
|||||||
import { PipelineType } from '@huggingface/tasks';
|
import { PipelineType } from '@huggingface/tasks';
|
||||||
import { request } from '@umijs/max';
|
import { request } from '@umijs/max';
|
||||||
import qs from 'query-string';
|
import qs from 'query-string';
|
||||||
|
import { ACCESS_API } from '../../model-access/apis';
|
||||||
import {
|
import {
|
||||||
AccessControlFormData,
|
AccessControlFormData,
|
||||||
BackendItem,
|
BackendItem,
|
||||||
@@ -418,7 +419,7 @@ export async function queryBackendList(params?: { cluster_id: number }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function queryModelAccessUserList(id: number) {
|
export async function queryModelAccessUserList(id: number) {
|
||||||
return request<{ items: UserListItem[] }>(`${MODELS_API}/${id}/access`, {
|
return request<{ items: UserListItem[] }>(`${ACCESS_API}/${id}/access`, {
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -427,7 +428,7 @@ export async function updateModelAccessUser(params: {
|
|||||||
id: number;
|
id: number;
|
||||||
data: AccessControlFormData;
|
data: AccessControlFormData;
|
||||||
}) {
|
}) {
|
||||||
return request(`${MODELS_API}/${params.id}/access`, {
|
return request(`${ACCESS_API}/${params.id}/access`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: params.data
|
data: params.data
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import AlertBlockInfo from '@/components/alert-info/block';
|
import AlertBlockInfo from '@/components/alert-info/block';
|
||||||
import ModalFooter from '@/components/modal-footer';
|
import ModalFooter from '@/components/modal-footer';
|
||||||
import ScrollerModal from '@/components/scroller-modal';
|
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
|
import FormDrawer from '@/pages/_components/form-drawer';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
@@ -75,19 +75,13 @@ const AccessControlModal: React.FC<
|
|||||||
}, [open, currentData]);
|
}, [open, currentData]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollerModal
|
<FormDrawer
|
||||||
title={title}
|
title={title}
|
||||||
open={open}
|
open={open}
|
||||||
centered={true}
|
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
destroyOnHidden={true}
|
|
||||||
closeIcon={true}
|
|
||||||
maskClosable={false}
|
|
||||||
keyboard={false}
|
|
||||||
width={700}
|
width={700}
|
||||||
height={660}
|
|
||||||
footer={
|
footer={
|
||||||
<>
|
<div style={{ paddingInline: 24, paddingBottom: 8 }}>
|
||||||
{isChanged && (
|
{isChanged && (
|
||||||
<AlertBlockInfo
|
<AlertBlockInfo
|
||||||
type="warning"
|
type="warning"
|
||||||
@@ -99,7 +93,7 @@ const AccessControlModal: React.FC<
|
|||||||
></AlertBlockInfo>
|
></AlertBlockInfo>
|
||||||
)}
|
)}
|
||||||
<ModalFooter onOk={handleSumit} onCancel={onCancel}></ModalFooter>
|
<ModalFooter onOk={handleSumit} onCancel={onCancel}></ModalFooter>
|
||||||
</>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<AccessControlForm
|
<AccessControlForm
|
||||||
@@ -109,7 +103,7 @@ const AccessControlModal: React.FC<
|
|||||||
onFinish={handleOnFinish}
|
onFinish={handleOnFinish}
|
||||||
onValuesChange={handleOnValuesChange}
|
onValuesChange={handleOnValuesChange}
|
||||||
/>
|
/>
|
||||||
</ScrollerModal>
|
</FormDrawer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
import IconFont from '@/components/icon-font';
|
|
||||||
import { StatusMaps } from '@/config';
|
import { StatusMaps } from '@/config';
|
||||||
import {
|
import { EditOutlined } from '@ant-design/icons';
|
||||||
AudioOutlined,
|
|
||||||
EditOutlined,
|
|
||||||
PictureOutlined,
|
|
||||||
WechatWorkOutlined
|
|
||||||
} from '@ant-design/icons';
|
|
||||||
import React from 'react';
|
|
||||||
import { backendOptionsMap } from './backend-parameters';
|
import { backendOptionsMap } from './backend-parameters';
|
||||||
|
|
||||||
export const backendTipsList = [
|
export const backendTipsList = [
|
||||||
@@ -299,42 +292,27 @@ export const modelCategoriesMap = {
|
|||||||
export const categoryOptions = [
|
export const categoryOptions = [
|
||||||
{
|
{
|
||||||
label: 'LLM',
|
label: 'LLM',
|
||||||
value: modelCategoriesMap.llm,
|
value: modelCategoriesMap.llm
|
||||||
icon: React.createElement(WechatWorkOutlined, { style: { color: 'green' } })
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Embedding',
|
label: 'Embedding',
|
||||||
value: modelCategoriesMap.embedding,
|
value: modelCategoriesMap.embedding
|
||||||
icon: React.createElement(IconFont, {
|
|
||||||
type: 'icon-cube',
|
|
||||||
style: { color: 'magenta' }
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Reranker',
|
label: 'Reranker',
|
||||||
value: modelCategoriesMap.reranker,
|
value: modelCategoriesMap.reranker
|
||||||
icon: React.createElement(IconFont, {
|
|
||||||
type: 'icon-rank1',
|
|
||||||
style: { color: 'cyan' }
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Image',
|
label: 'Image',
|
||||||
value: modelCategoriesMap.image,
|
value: modelCategoriesMap.image
|
||||||
icon: React.createElement(PictureOutlined, { style: { color: 'orange' } })
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Text-to-Speech',
|
label: 'Text-to-Speech',
|
||||||
value: modelCategoriesMap.text_to_speech,
|
value: modelCategoriesMap.text_to_speech
|
||||||
icon: React.createElement(IconFont, {
|
|
||||||
type: 'icon-sound-wave',
|
|
||||||
style: { color: 'geekblue' }
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Speech-to-Text',
|
label: 'Speech-to-Text',
|
||||||
value: modelCategoriesMap.speech_to_text,
|
value: modelCategoriesMap.speech_to_text
|
||||||
icon: React.createElement(AudioOutlined, { style: { color: 'processing' } })
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ export type SourceType =
|
|||||||
export interface FormData {
|
export interface FormData {
|
||||||
image_name?: string;
|
image_name?: string;
|
||||||
run_command?: string;
|
run_command?: string;
|
||||||
|
enable_model_access?: boolean;
|
||||||
backend: string;
|
backend: string;
|
||||||
restart_on_error?: boolean;
|
restart_on_error?: boolean;
|
||||||
env?: Record<string, any>;
|
env?: Record<string, any>;
|
||||||
|
|||||||
@@ -16,8 +16,14 @@ const AdvanceConfig = () => {
|
|||||||
const form = Form.useFormInstance();
|
const form = Form.useFormInstance();
|
||||||
const EnviromentVars = Form.useWatch('env', form);
|
const EnviromentVars = Form.useWatch('env', form);
|
||||||
const backend = Form.useWatch('backend', form);
|
const backend = Form.useWatch('backend', form);
|
||||||
const { onValuesChange, isGGUF, modelContextData, flatBackendOptions } =
|
const modelAccessEnable = Form.useWatch('enable_model_access', form);
|
||||||
useFormContext();
|
const {
|
||||||
|
onValuesChange,
|
||||||
|
backendOptions,
|
||||||
|
flatBackendOptions,
|
||||||
|
isGGUF,
|
||||||
|
modelContextData
|
||||||
|
} = useFormContext();
|
||||||
|
|
||||||
const currentBackendOptions = useMemo(() => {
|
const currentBackendOptions = useMemo(() => {
|
||||||
return flatBackendOptions?.find((item) => item.value === backend);
|
return flatBackendOptions?.find((item) => item.value === backend);
|
||||||
@@ -128,19 +134,35 @@ const AdvanceConfig = () => {
|
|||||||
></CheckboxField>
|
></CheckboxField>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
name="generic_proxy"
|
name="enable_model_access"
|
||||||
valuePropName="checked"
|
valuePropName="checked"
|
||||||
style={{ marginBottom: 8 }}
|
style={{ marginBottom: 8 }}
|
||||||
>
|
>
|
||||||
<CheckboxField
|
<CheckboxField
|
||||||
description={intl.formatMessage({
|
description={intl.formatMessage({
|
||||||
id: 'models.form.generic_proxy.tips'
|
id: 'models.form.enable_model_access.tips'
|
||||||
})}
|
})}
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
id: 'models.form.generic_proxy'
|
id: 'models.form.enable_model_access'
|
||||||
})}
|
})}
|
||||||
></CheckboxField>
|
></CheckboxField>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
{modelAccessEnable && (
|
||||||
|
<Form.Item<FormData>
|
||||||
|
name="generic_proxy"
|
||||||
|
valuePropName="checked"
|
||||||
|
style={{ marginBottom: 8 }}
|
||||||
|
>
|
||||||
|
<CheckboxField
|
||||||
|
description={intl.formatMessage({
|
||||||
|
id: 'models.form.generic_proxy.tips'
|
||||||
|
})}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'models.form.generic_proxy'
|
||||||
|
})}
|
||||||
|
></CheckboxField>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export interface FormData {
|
|||||||
description: string;
|
description: string;
|
||||||
api_tokens: string[];
|
api_tokens: string[];
|
||||||
models: ProviderModel[];
|
models: ProviderModel[];
|
||||||
|
api_key: string;
|
||||||
config: {
|
config: {
|
||||||
type: maasProviderType;
|
type: maasProviderType;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import ListInput from '@/components/list-input';
|
import MetadataList from '@/components/metadata-list';
|
||||||
|
import SealInput from '@/components/seal-form/seal-input';
|
||||||
import useAppUtils from '@/hooks/use-app-utils';
|
import useAppUtils from '@/hooks/use-app-utils';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
@@ -10,17 +11,37 @@ const AccessToken = () => {
|
|||||||
const form = Form.useFormInstance<FormData>();
|
const form = Form.useFormInstance<FormData>();
|
||||||
const tokenList = Form.useWatch('api_tokens', form) || [];
|
const tokenList = Form.useWatch('api_tokens', form) || [];
|
||||||
|
|
||||||
const handleOnChange = (values: string[]) => {
|
const onAdd = () => {
|
||||||
form.setFieldValue('api_tokens', values);
|
const newList = [...tokenList];
|
||||||
|
newList.push('');
|
||||||
|
form.setFieldValue('api_tokens', newList);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDelete = (index: number) => {
|
||||||
|
const newList = [...tokenList];
|
||||||
|
newList.splice(index, 1);
|
||||||
|
form.setFieldValue('api_tokens', newList);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputChange = (
|
||||||
|
index: number,
|
||||||
|
e: React.ChangeEvent<HTMLInputElement>
|
||||||
|
) => {
|
||||||
|
const newList = [...tokenList];
|
||||||
|
newList[index] = e.target.value;
|
||||||
|
form.setFieldValue('api_tokens', newList);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="api_tokens"
|
name="api_tokens"
|
||||||
|
style={{
|
||||||
|
marginBottom: 8
|
||||||
|
}}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: false,
|
||||||
message: getRuleMessage(
|
message: getRuleMessage(
|
||||||
'input',
|
'input',
|
||||||
intl.formatMessage({ id: 'providers.form.tokens.title' })
|
intl.formatMessage({ id: 'providers.form.tokens.title' })
|
||||||
@@ -28,13 +49,22 @@ const AccessToken = () => {
|
|||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<ListInput
|
<MetadataList
|
||||||
required={true}
|
|
||||||
btnText={intl.formatMessage({ id: 'providers.form.tokens.add' })}
|
|
||||||
label={intl.formatMessage({ id: 'providers.form.tokens.title' })}
|
|
||||||
dataList={tokenList}
|
dataList={tokenList}
|
||||||
onChange={handleOnChange}
|
btnText={intl.formatMessage({ id: 'providers.form.tokens.add' })}
|
||||||
></ListInput>
|
label={intl.formatMessage({ id: 'providers.form.fallback.token' })}
|
||||||
|
onAdd={onAdd}
|
||||||
|
onDelete={onDelete}
|
||||||
|
>
|
||||||
|
{(item, index) => (
|
||||||
|
<div style={{ width: '100%' }} key={index}>
|
||||||
|
<SealInput.Password
|
||||||
|
value={item}
|
||||||
|
onChange={(e) => handleInputChange(index, e)}
|
||||||
|
></SealInput.Password>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</MetadataList>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import YamlEditor from '@/pages/_components/yaml-editor';
|
|||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import React, { forwardRef, useImperativeHandle } from 'react';
|
import React, { forwardRef, useImperativeHandle } from 'react';
|
||||||
|
import AccessToken from './access-token';
|
||||||
import ProxyConfig from './proxy-config';
|
import ProxyConfig from './proxy-config';
|
||||||
|
|
||||||
const AdvanceConfig: React.FC<{
|
const AdvanceConfig: React.FC<{
|
||||||
@@ -28,6 +29,7 @@ const AdvanceConfig: React.FC<{
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div data-field="advanceConfig"></div>
|
<div data-field="advanceConfig"></div>
|
||||||
|
<AccessToken></AccessToken>
|
||||||
<ProxyConfig></ProxyConfig>
|
<ProxyConfig></ProxyConfig>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
hidden
|
hidden
|
||||||
|
|||||||
@@ -54,6 +54,22 @@ const Basic = () => {
|
|||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item<FormData>
|
||||||
|
name="api_key"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: getRuleMessage('input', 'providers.form.tokens.title')
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<SealInput.Password
|
||||||
|
required
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'providers.form.tokens.title'
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
<Form.Item<FormData> name="description">
|
<Form.Item<FormData> name="description">
|
||||||
<SealInput.TextArea
|
<SealInput.TextArea
|
||||||
scaleSize={true}
|
scaleSize={true}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { useWrapperContext } from '@/pages/_components/column-wrapper/use-wrappe
|
|||||||
import ScrollSpyTabs from '@/pages/_components/scroll-spy-tabs';
|
import ScrollSpyTabs from '@/pages/_components/scroll-spy-tabs';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
|
import _ from 'lodash';
|
||||||
import {
|
import {
|
||||||
forwardRef,
|
forwardRef,
|
||||||
useEffect,
|
useEffect,
|
||||||
@@ -15,7 +16,6 @@ import {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import FormContext from '../config/form-context';
|
import FormContext from '../config/form-context';
|
||||||
import { FormData, MaasProviderItem as ListItem } from '../config/types';
|
import { FormData, MaasProviderItem as ListItem } from '../config/types';
|
||||||
import AccessToken from './access-token';
|
|
||||||
import AdvanceConfig from './advance-config';
|
import AdvanceConfig from './advance-config';
|
||||||
import Basic from './basic';
|
import Basic from './basic';
|
||||||
import SupportedModels from './supported-models';
|
import SupportedModels from './supported-models';
|
||||||
@@ -63,6 +63,17 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const handleOnFinish = (values: FormData) => {
|
||||||
|
const apiTokens = values.api_tokens?.filter?.(
|
||||||
|
(item) => item && item.trim() !== ''
|
||||||
|
);
|
||||||
|
const data = {
|
||||||
|
..._.omit(values, ['api_key']),
|
||||||
|
api_tokens: _.concat([], values.api_key, apiTokens || [])
|
||||||
|
};
|
||||||
|
onFinish(data);
|
||||||
|
};
|
||||||
|
|
||||||
const handleActiveChange = (key: string[]) => {
|
const handleActiveChange = (key: string[]) => {
|
||||||
setActiveKey(key);
|
setActiveKey(key);
|
||||||
};
|
};
|
||||||
@@ -87,6 +98,8 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
) {
|
) {
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
...currentData,
|
...currentData,
|
||||||
|
api_key: currentData.api_tokens?.[0] || '',
|
||||||
|
api_tokens: currentData.api_tokens?.slice(1) || [],
|
||||||
proxy_enabled: !!currentData.proxy_url
|
proxy_enabled: !!currentData.proxy_url
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -108,7 +121,7 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
<FormContext.Provider value={{ action }}>
|
<FormContext.Provider value={{ action }}>
|
||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
onFinish={onFinish}
|
onFinish={handleOnFinish}
|
||||||
initialValues={{
|
initialValues={{
|
||||||
proxy_enabled: false,
|
proxy_enabled: false,
|
||||||
proxy_url: '',
|
proxy_url: '',
|
||||||
@@ -116,7 +129,6 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Basic />
|
<Basic />
|
||||||
<AccessToken />
|
|
||||||
<CollapsePanel
|
<CollapsePanel
|
||||||
activeKey={activeKey}
|
activeKey={activeKey}
|
||||||
accordion={false}
|
accordion={false}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ const ModelItem: React.FC<ModelItemProps> = ({
|
|||||||
const res = await runTestModel({
|
const res = await runTestModel({
|
||||||
data: {
|
data: {
|
||||||
model_name: item.name,
|
model_name: item.name,
|
||||||
api_token: form.getFieldValue('api_tokens')?.[0] || '',
|
api_token: form.getFieldValue('api_key') || '',
|
||||||
config: {
|
config: {
|
||||||
type: form.getFieldValue(['config', 'type']) || ''
|
type: form.getFieldValue(['config', 'type']) || ''
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ const SupportedModels = () => {
|
|||||||
|
|
||||||
const handleOpenChange = async (open: boolean) => {
|
const handleOpenChange = async (open: boolean) => {
|
||||||
try {
|
try {
|
||||||
await form.validateFields(['api_tokens', ['config', 'type']]);
|
await form.validateFields(['api_key']);
|
||||||
|
|
||||||
if (open && providerModelList.length === 0) {
|
if (open && providerModelList.length === 0) {
|
||||||
fetchProviderModels({
|
fetchProviderModels({
|
||||||
data: {
|
data: {
|
||||||
api_token: form.getFieldValue('api_tokens')?.[0] || '',
|
api_token: form.getFieldValue('api_key') || '',
|
||||||
config: {
|
config: {
|
||||||
type: form.getFieldValue(['config', 'type']) || ''
|
type: form.getFieldValue(['config', 'type']) || ''
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,13 @@ const CellContent = styled.div`
|
|||||||
interface ProviderModelProps {
|
interface ProviderModelProps {
|
||||||
dataList: AccessPointItem[];
|
dataList: AccessPointItem[];
|
||||||
onSelect: (val: any, record: any) => void;
|
onSelect: (val: any, record: any) => void;
|
||||||
|
sourceModels: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AccessItemProps {
|
interface AccessItemProps {
|
||||||
onSelect: (val: any, record: any) => void;
|
onSelect: (val: any, record: any) => void;
|
||||||
data: any;
|
data: any;
|
||||||
|
sourceModels: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const childActionList = [
|
export const childActionList = [
|
||||||
@@ -48,13 +50,24 @@ export const childActionList = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const AccessItem: React.FC<AccessItemProps> = ({ onSelect, data }) => {
|
const AccessItem: React.FC<AccessItemProps> = ({
|
||||||
|
onSelect,
|
||||||
|
data,
|
||||||
|
sourceModels
|
||||||
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const renderProviderSource = () => {
|
||||||
|
const model = sourceModels.find(
|
||||||
|
(item: any) => item.value === data.provider_id || item.id === data.model
|
||||||
|
);
|
||||||
|
return model.label || '-';
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div style={{ borderRadius: 'var(--ant-table-header-border-radius)' }}>
|
<div style={{ borderRadius: 'var(--ant-table-header-border-radius)' }}>
|
||||||
<RowChildren>
|
<RowChildren>
|
||||||
<Row gutter={16} style={{ width: '100%' }}>
|
<Row gutter={16} style={{ width: '100%' }}>
|
||||||
<Col span={6}>
|
<Col span={4}>
|
||||||
<CellContent
|
<CellContent
|
||||||
style={{
|
style={{
|
||||||
paddingInline: 'var(--ant-table-cell-padding-inline)'
|
paddingInline: 'var(--ant-table-cell-padding-inline)'
|
||||||
@@ -64,7 +77,7 @@ const AccessItem: React.FC<AccessItemProps> = ({ onSelect, data }) => {
|
|||||||
</CellContent>
|
</CellContent>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={3}>
|
<Col span={3}>
|
||||||
<CellContent>-</CellContent>
|
<CellContent>{renderProviderSource()}</CellContent>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={4}>
|
<Col span={4}>
|
||||||
<CellContent>
|
<CellContent>
|
||||||
@@ -88,7 +101,7 @@ const AccessItem: React.FC<AccessItemProps> = ({ onSelect, data }) => {
|
|||||||
)}
|
)}
|
||||||
</CellContent>
|
</CellContent>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={3}>
|
<Col span={4}>
|
||||||
<CellContent>
|
<CellContent>
|
||||||
<AutoTooltip ghost>
|
<AutoTooltip ghost>
|
||||||
<StatusTag
|
<StatusTag
|
||||||
@@ -102,16 +115,16 @@ const AccessItem: React.FC<AccessItemProps> = ({ onSelect, data }) => {
|
|||||||
</CellContent>
|
</CellContent>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={5}>
|
<Col span={5}>
|
||||||
<CellContent style={{ marginLeft: -6 }}>
|
<CellContent style={{ paddingLeft: 45 }}>
|
||||||
<AutoTooltip ghost minWidth={20}>
|
<AutoTooltip ghost minWidth={20}>
|
||||||
{dayjs(data.created_at).format('YYYY-MM-DD HH:mm:ss')}
|
{dayjs(data.created_at).format('YYYY-MM-DD HH:mm:ss')}
|
||||||
</AutoTooltip>
|
</AutoTooltip>
|
||||||
</CellContent>
|
</CellContent>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={3}>
|
<Col span={4}>
|
||||||
<CellContent
|
<CellContent
|
||||||
style={{
|
style={{
|
||||||
marginLeft: -12
|
paddingLeft: 38
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DropdownButtons
|
<DropdownButtons
|
||||||
@@ -126,12 +139,21 @@ const AccessItem: React.FC<AccessItemProps> = ({ onSelect, data }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const AccessPoints: React.FC<ProviderModelProps> = ({ dataList, onSelect }) => {
|
const AccessPoints: React.FC<ProviderModelProps> = ({
|
||||||
|
dataList,
|
||||||
|
onSelect,
|
||||||
|
sourceModels
|
||||||
|
}) => {
|
||||||
console.log('AccessPoints dataList:', dataList);
|
console.log('AccessPoints dataList:', dataList);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{dataList.map((item, index) => (
|
{dataList.map((item, index) => (
|
||||||
<AccessItem data={item} key={index} onSelect={onSelect}></AccessItem>
|
<AccessItem
|
||||||
|
data={item}
|
||||||
|
key={index}
|
||||||
|
onSelect={onSelect}
|
||||||
|
sourceModels={sourceModels}
|
||||||
|
></AccessItem>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ export interface FormData {
|
|||||||
description: string;
|
description: string;
|
||||||
categories: any[];
|
categories: any[];
|
||||||
meta: Record<string, any>;
|
meta: Record<string, any>;
|
||||||
|
generic_proxy: boolean;
|
||||||
fallback_endpoint: {
|
fallback_endpoint: {
|
||||||
provider_model_name?: string;
|
provider_model_name?: string;
|
||||||
model_id?: number;
|
model_id?: number;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import CheckboxField from '@/components/seal-form/checkbox-field';
|
||||||
import SealInput from '@/components/seal-form/seal-input';
|
import SealInput from '@/components/seal-form/seal-input';
|
||||||
import SealSelect from '@/components/seal-form/seal-select';
|
|
||||||
import useAppUtils from '@/hooks/use-app-utils';
|
import useAppUtils from '@/hooks/use-app-utils';
|
||||||
|
import CategorySelect from '@/pages/_components/category-select';
|
||||||
import { categoryOptions } from '@/pages/llmodels/config';
|
import { categoryOptions } from '@/pages/llmodels/config';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
@@ -31,13 +32,13 @@ const Basic = () => {
|
|||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<SealSelect
|
<CategorySelect
|
||||||
required
|
required
|
||||||
options={categoryOptions}
|
options={categoryOptions}
|
||||||
label={intl.formatMessage({ id: 'models.form.categories' })}
|
label={intl.formatMessage({ id: 'models.form.categories' })}
|
||||||
></SealSelect>
|
></CategorySelect>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="description">
|
<Form.Item name="description" style={{ marginBottom: 8 }}>
|
||||||
<SealInput.TextArea
|
<SealInput.TextArea
|
||||||
scaleSize={true}
|
scaleSize={true}
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
@@ -45,6 +46,20 @@ const Basic = () => {
|
|||||||
})}
|
})}
|
||||||
></SealInput.TextArea>
|
></SealInput.TextArea>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item<FormData>
|
||||||
|
name="generic_proxy"
|
||||||
|
valuePropName="checked"
|
||||||
|
style={{ marginBottom: 8 }}
|
||||||
|
>
|
||||||
|
<CheckboxField
|
||||||
|
description={intl.formatMessage({
|
||||||
|
id: 'models.form.generic_proxy.tips'
|
||||||
|
})}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: 'models.form.generic_proxy'
|
||||||
|
})}
|
||||||
|
></CheckboxField>
|
||||||
|
</Form.Item>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,9 +5,29 @@ import { useIntl } from '@umijs/max';
|
|||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
|
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
import { FormData } from '../config/types';
|
import { FormData } from '../config/types';
|
||||||
import useEndpointSourceModels from '../hooks/use-endpoint-source-models';
|
import useEndpointSourceModels from '../hooks/use-endpoint-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 EndpointsForm = forwardRef((props, ref) => {
|
const EndpointsForm = forwardRef((props, ref) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { sourceModels, loading, fetchSourceModels } =
|
const { sourceModels, loading, fetchSourceModels } =
|
||||||
@@ -164,6 +184,7 @@ const EndpointsForm = forwardRef((props, ref) => {
|
|||||||
showSearch
|
showSearch
|
||||||
expandTrigger="hover"
|
expandTrigger="hover"
|
||||||
multiple={false}
|
multiple={false}
|
||||||
|
alwaysFocus={true}
|
||||||
onChange={(value, options) =>
|
onChange={(value, options) =>
|
||||||
handleEndpointsChange(value, index, options)
|
handleEndpointsChange(value, index, options)
|
||||||
}
|
}
|
||||||
@@ -174,7 +195,7 @@ const EndpointsForm = forwardRef((props, ref) => {
|
|||||||
}}
|
}}
|
||||||
maxTagCount={1}
|
maxTagCount={1}
|
||||||
placeholder={intl.formatMessage({
|
placeholder={intl.formatMessage({
|
||||||
id: 'accesses.form.endpoint.model'
|
id: 'providers.form.endpoint.placeholder'
|
||||||
})}
|
})}
|
||||||
value={item.value}
|
value={item.value}
|
||||||
options={sourceModels}
|
options={sourceModels}
|
||||||
@@ -201,6 +222,7 @@ const EndpointsForm = forwardRef((props, ref) => {
|
|||||||
showSearch
|
showSearch
|
||||||
expandTrigger="hover"
|
expandTrigger="hover"
|
||||||
multiple={false}
|
multiple={false}
|
||||||
|
alwaysFocus={true}
|
||||||
classNames={{
|
classNames={{
|
||||||
popup: {
|
popup: {
|
||||||
root: 'cascader-popup-wrapper gpu-selector'
|
root: 'cascader-popup-wrapper gpu-selector'
|
||||||
@@ -209,6 +231,9 @@ const EndpointsForm = forwardRef((props, ref) => {
|
|||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
id: 'accesses.form.endpoint.fallback'
|
id: 'accesses.form.endpoint.fallback'
|
||||||
})}
|
})}
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
id: 'providers.form.endpoint.placeholder'
|
||||||
|
})}
|
||||||
maxTagCount={1}
|
maxTagCount={1}
|
||||||
value={fallbackValues.value}
|
value={fallbackValues.value}
|
||||||
options={sourceModels}
|
options={sourceModels}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import { FormData, AccessItem as ListItem } from '../config/types';
|
|||||||
import useEditEndpoints from '../hooks/use-edit-endpoints';
|
import useEditEndpoints from '../hooks/use-edit-endpoints';
|
||||||
import Basic from './basic';
|
import Basic from './basic';
|
||||||
import Endpoints from './endpoints';
|
import Endpoints from './endpoints';
|
||||||
import MetaData from './meta-data';
|
|
||||||
|
|
||||||
interface ProviderFormProps {
|
interface ProviderFormProps {
|
||||||
ref?: any;
|
ref?: any;
|
||||||
@@ -50,12 +49,6 @@ const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
icon: <IconFont type="icon-basic" />,
|
icon: <IconFont type="icon-basic" />,
|
||||||
field: 'name'
|
field: 'name'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
value: TABKeysMap.METADATA,
|
|
||||||
label: intl.formatMessage({ id: 'accesses.form.metadata.title' }),
|
|
||||||
icon: <IconFont type="icon-database" />,
|
|
||||||
field: 'metaSize'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
value: TABKeysMap.ENDPOINTS,
|
value: TABKeysMap.ENDPOINTS,
|
||||||
label: intl.formatMessage({ id: 'accesses.form.endpoint.title' }),
|
label: intl.formatMessage({ id: 'accesses.form.endpoint.title' }),
|
||||||
@@ -202,12 +195,6 @@ const AccessForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
accordion={false}
|
accordion={false}
|
||||||
onChange={handleOnCollapseChange}
|
onChange={handleOnCollapseChange}
|
||||||
items={[
|
items={[
|
||||||
{
|
|
||||||
key: TABKeysMap.METADATA,
|
|
||||||
label: intl.formatMessage({ id: 'accesses.form.metadata.title' }),
|
|
||||||
forceRender: true,
|
|
||||||
children: <MetaData></MetaData>
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: TABKeysMap.ENDPOINTS,
|
key: TABKeysMap.ENDPOINTS,
|
||||||
label: intl.formatMessage({ id: 'accesses.form.endpoint.title' }),
|
label: intl.formatMessage({ id: 'accesses.form.endpoint.title' }),
|
||||||
|
|||||||
+15
-1
@@ -2,6 +2,7 @@ import { queryModelsList } from '@/pages/llmodels/apis';
|
|||||||
import { ListItem as ModelListItem } from '@/pages/llmodels/config/types';
|
import { ListItem as ModelListItem } from '@/pages/llmodels/config/types';
|
||||||
import { queryMaasProviders } from '@/pages/maas-provider/apis';
|
import { queryMaasProviders } from '@/pages/maas-provider/apis';
|
||||||
import { MaasProviderItem } from '@/pages/maas-provider/config/types';
|
import { MaasProviderItem } from '@/pages/maas-provider/config/types';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
type EmptyObject = Record<never, never>;
|
type EmptyObject = Record<never, never>;
|
||||||
@@ -15,6 +16,7 @@ type CascaderOption<T extends object = EmptyObject> = {
|
|||||||
} & Partial<T>;
|
} & Partial<T>;
|
||||||
|
|
||||||
const useEndpointSourceModels = () => {
|
const useEndpointSourceModels = () => {
|
||||||
|
const intl = useIntl();
|
||||||
const [sourceModels, setSourceModels] = useState<CascaderOption[]>([]);
|
const [sourceModels, setSourceModels] = useState<CascaderOption[]>([]);
|
||||||
const [loading, setLoading] = useState<boolean>(false);
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
|
||||||
@@ -28,7 +30,19 @@ const useEndpointSourceModels = () => {
|
|||||||
|
|
||||||
const modelsList = [
|
const modelsList = [
|
||||||
{
|
{
|
||||||
label: 'Deployments',
|
label: (
|
||||||
|
<span>
|
||||||
|
{intl.formatMessage({ id: 'menu.models.deployment' })}
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
color: 'var(--ant-color-text-tertiary)',
|
||||||
|
marginLeft: 4
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
[GPUStack]
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
),
|
||||||
value: 'deployments',
|
value: 'deployments',
|
||||||
parent: true,
|
parent: true,
|
||||||
children: models.items?.map?.((model: ModelListItem) => ({
|
children: models.items?.map?.((model: ModelListItem) => ({
|
||||||
@@ -15,6 +15,7 @@ import { useMemoizedFn } from 'ahooks';
|
|||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import NoResult from '../_components/no-result';
|
import NoResult from '../_components/no-result';
|
||||||
import PageBox from '../_components/page-box';
|
import PageBox from '../_components/page-box';
|
||||||
import AccessControlModal from '../llmodels/components/access-control-modal';
|
import AccessControlModal from '../llmodels/components/access-control-modal';
|
||||||
@@ -35,6 +36,7 @@ import { FormData, AccessItem as ListItem } from './config/types';
|
|||||||
import useAccessColumns from './hooks/use-access-columns';
|
import useAccessColumns from './hooks/use-access-columns';
|
||||||
import useAccessControl from './hooks/use-access-control';
|
import useAccessControl from './hooks/use-access-control';
|
||||||
import useCreateAccess from './hooks/use-create-access';
|
import useCreateAccess from './hooks/use-create-access';
|
||||||
|
import useEndpointSourceModels from './hooks/use-endpoint-source-models';
|
||||||
|
|
||||||
const Accesses: React.FC = () => {
|
const Accesses: React.FC = () => {
|
||||||
const {
|
const {
|
||||||
@@ -69,6 +71,7 @@ const Accesses: React.FC = () => {
|
|||||||
closeAccessControlModal,
|
closeAccessControlModal,
|
||||||
openAccessControlModalStatus
|
openAccessControlModalStatus
|
||||||
} = useAccessControl();
|
} = useAccessControl();
|
||||||
|
const { sourceModels, fetchSourceModels } = useEndpointSourceModels();
|
||||||
|
|
||||||
const handleClickDropdown = () => {
|
const handleClickDropdown = () => {
|
||||||
openAccessModal(
|
openAccessModal(
|
||||||
@@ -188,9 +191,19 @@ const Accesses: React.FC = () => {
|
|||||||
list: any,
|
list: any,
|
||||||
options: { parent?: any; [key: string]: any }
|
options: { parent?: any; [key: string]: any }
|
||||||
) => {
|
) => {
|
||||||
return <AccessPoints dataList={list} onSelect={onChildSelect} />;
|
return (
|
||||||
|
<AccessPoints
|
||||||
|
dataList={list}
|
||||||
|
onSelect={onChildSelect}
|
||||||
|
sourceModels={sourceModels}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSourceModels();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const columns = useAccessColumns(handleSelect);
|
const columns = useAccessColumns(handleSelect);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user