Merge pull request #87 from guanweiwang/main

feat: 模型调整
This commit is contained in:
Yoko
2025-07-15 18:30:43 +08:00
committed by GitHub
11 changed files with 545 additions and 224 deletions

View File

@@ -15,9 +15,11 @@ import {
DomainAllModelResp,
DomainCheckModelReq,
DomainCreateModelReq,
DomainGetProviderModelListResp,
DomainModel,
DomainModelTokenUsageResp,
DomainUpdateModelReq,
GetGetProviderModelListParams,
GetGetTokenUsageParams,
GetMyModelListParams,
WebResp,
@@ -169,6 +171,36 @@ export const getMyModelList = (
...params,
});
/**
* @description 获取供应商支持的模型列表
*
* @tags Model
* @name GetGetProviderModelList
* @summary 获取供应商支持的模型列表
* @request GET:/api/v1/model/provider/supported
* @response `200` `(WebResp & {
data?: DomainGetProviderModelListResp,
})` OK
*/
export const getGetProviderModelList = (
query: GetGetProviderModelListParams,
params: RequestParams = {},
) =>
request<
WebResp & {
data?: DomainGetProviderModelListResp;
}
>({
path: `/api/v1/model/provider/supported`,
method: "GET",
query: query,
type: ContentType.Json,
format: "json",
...params,
});
/**
* @description 获取模型token使用情况
*

View File

@@ -35,6 +35,19 @@ export enum ConstsModelStatus {
ModelStatusInactive = "inactive",
}
export enum ConstsModelProvider {
ModelProviderSiliconFlow = "SiliconFlow",
ModelProviderOpenAI = "OpenAI",
ModelProviderOllama = "Ollama",
ModelProviderDeepSeek = "DeepSeek",
ModelProviderMoonshot = "Moonshot",
ModelProviderAzureOpenAI = "AzureOpenAI",
ModelProviderBaiZhiCloud = "BaiZhiCloud",
ModelProviderHunyuan = "Hunyuan",
ModelProviderBaiLian = "BaiLian",
ModelProviderVolcengine = "Volcengine",
}
export enum ConstsChatRole {
ChatRoleUser = "user",
ChatRoleAssistant = "assistant",
@@ -133,12 +146,15 @@ export interface DomainChatRecord {
export interface DomainCheckModelReq {
/** 接口地址 */
api_base: string;
api_header?: string;
/** 接口密钥 */
api_key: string;
api_version?: string;
/** 模型名称 */
model_name: string;
/** 提供商 */
provider: string;
provider: ConstsModelProvider;
type: "llm" | "coder" | "embedding" | "rerank";
}
export interface DomainCompletionInfo {
@@ -174,15 +190,29 @@ export interface DomainCreateAdminReq {
export interface DomainCreateModelReq {
/** 接口地址 如https://api.qwen.com */
api_base?: string;
api_base: string;
api_header?: string;
/** 接口密钥 如sk-xxxx */
api_key?: string;
api_version?: string;
/** 模型名称 如: deepseek-v3 */
model_name?: string;
model_name: string;
/** 模型类型 llm:对话模型 coder:代码模型 */
model_type?: ConstsModelType;
/** 提供商 */
provider?: string;
provider:
| "SiliconFlow"
| "OpenAI"
| "Ollama"
| "DeepSeek"
| "Moonshot"
| "AzureOpenAI"
| "BaiZhiCloud"
| "Hunyuan"
| "BaiLian"
| "Volcengine";
/** 模型显示名称 */
show_name?: string;
}
export interface DomainCustomOAuth {
@@ -253,6 +283,10 @@ export interface DomainDingtalkOAuthReq {
enable?: boolean;
}
export interface DomainGetProviderModelListResp {
models?: DomainProviderModelListItem[];
}
export interface DomainIPInfo {
/** ASN */
asn?: string;
@@ -332,8 +366,12 @@ export interface DomainLoginResp {
export interface DomainModel {
/** 接口地址 如https://api.qwen.com */
api_base?: string;
/** 接口头 如Authorization: Bearer sk-xxxx */
api_header?: string;
/** 接口密钥 如sk-xxxx */
api_key?: string;
/** 接口版本 如2023-05-15 */
api_version?: string;
/** 创建时间 */
created_at?: number;
/** 模型ID */
@@ -349,7 +387,9 @@ export interface DomainModel {
/** 输出token数 */
output?: number;
/** 提供商 */
provider?: string;
provider?: ConstsModelProvider;
/** 模型显示名称 */
show_name?: string;
/** 状态 active:启用 inactive:禁用 */
status?: ConstsModelStatus;
/** 更新时间 */
@@ -362,7 +402,17 @@ export interface DomainModelBasic {
/** 模型名称 */
name?: string;
/** 提供商 */
provider?: string;
provider:
| "SiliconFlow"
| "OpenAI"
| "Ollama"
| "DeepSeek"
| "Moonshot"
| "AzureOpenAI"
| "BaiZhiCloud"
| "Hunyuan"
| "BaiLian"
| "Volcengine";
}
export interface DomainModelData {
@@ -411,6 +461,10 @@ export interface DomainProviderModel {
provider?: string;
}
export interface DomainProviderModelListItem {
model?: string;
}
export interface DomainRegisterReq {
/** 邀请码 */
code: string;
@@ -506,14 +560,28 @@ export interface DomainTimeStat {
export interface DomainUpdateModelReq {
/** 接口地址 如https://api.qwen.com */
api_base?: string;
api_header?: string;
/** 接口密钥 如sk-xxxx */
api_key?: string;
api_version?: string;
/** 模型ID */
id?: string;
/** 模型名称 */
model_name?: string;
/** 提供商 */
provider?: string;
provider:
| "SiliconFlow"
| "OpenAI"
| "Ollama"
| "DeepSeek"
| "Moonshot"
| "AzureOpenAI"
| "BaiZhiCloud"
| "Hunyuan"
| "BaiLian"
| "Volcengine";
/** 模型显示名称 */
show_name?: string;
/** 状态 active:启用 inactive:禁用 */
status?: ConstsModelStatus;
}
@@ -805,6 +873,24 @@ export interface GetMyModelListParams {
model_type?: "llm" | "coder" | "embedding" | "audio" | "reranker";
}
export interface GetGetProviderModelListParams {
api_header?: string;
api_key?: string;
base_url: string;
provider:
| "SiliconFlow"
| "OpenAI"
| "Ollama"
| "DeepSeek"
| "Moonshot"
| "AzureOpenAI"
| "BaiZhiCloud"
| "Hunyuan"
| "BaiLian"
| "Volcengine";
type: "llm" | "coder" | "embedding" | "audio" | "reranker";
}
export interface GetGetTokenUsageParams {
/** 模型类型 llm:对话模型 coder:代码模型 */
model_type: "llm" | "coder" | "embedding" | "audio" | "reranker";

File diff suppressed because one or more lines are too long

View File

@@ -16,7 +16,7 @@ export const FormItem = ({
children,
required,
}: {
label: string;
label: string | React.ReactNode;
children: React.ReactNode;
required?: boolean;
}) => {

View File

@@ -44,7 +44,7 @@ const Completion = () => {
const { data: userOptions = { users: [] } } = useRequest(() =>
getListUser({
page: 1,
size: 10,
size: 9999,
})
);

View File

@@ -2,7 +2,7 @@ import React, { useState } from 'react';
import Card from '@/components/card';
import { useRequest } from 'ahooks';
import { getMyModelList, putUpdateModel } from '@/api/Model';
import { DomainModel, ConstsModelStatus } from '@/api/types';
import { DomainModel, ConstsModelStatus, ConstsModelType } from '@/api/types';
import { Stack, Box, Button, Grid2 as Grid, ButtonBase } from '@mui/material';
import StyledLabel from '@/components/label';
import { Icon, Modal, message } from '@c-x/ui';
@@ -40,6 +40,7 @@ const ModelItem = ({
putUpdateModel({
id: data.id,
status: ConstsModelStatus.ModelStatusInactive,
provider: data.provider!,
}).then(() => {
message.success('停用成功');
refresh();
@@ -64,6 +65,7 @@ const ModelItem = ({
putUpdateModel({
id: data.id,
status: ConstsModelStatus.ModelStatusActive,
provider: data.provider!,
}).then(() => {
message.success('激活成功');
refresh();
@@ -110,7 +112,7 @@ const ModelItem = ({
<Stack direction='row' alignItems='center' gap={1}>
<Icon
type={
ModelProvider[data.provider as keyof typeof ModelProvider].icon
ModelProvider[data.provider as keyof typeof ModelProvider]?.icon
}
sx={{ fontSize: 24 }}
/>
@@ -202,7 +204,7 @@ const ModelItem = ({
interface IModelCardProps {
title: string;
modelType: 'llm' | 'coder';
modelType: ConstsModelType;
}
const ModelCard: React.FC<IModelCardProps> = ({ title, modelType }) => {
@@ -257,7 +259,7 @@ const ModelCard: React.FC<IModelCardProps> = ({ title, modelType }) => {
}}
refresh={refresh}
data={editData}
modelType={modelType}
type={modelType}
/>
</Card>
);

View File

@@ -1,48 +1,62 @@
import {
postCreateModel,
putUpdateModel,
getGetProviderModelList,
postCheckModel,
getListModel,
} from '@/api/Model';
putUpdateModel,
} from '@/api';
import { ConstsModelType, DomainModel } from '@/api/types';
import Card from '@/components/card';
import { ModelProvider } from '../constant';
import { Icon, message, Modal } from '@c-x/ui';
import { StyledFormLabel } from '@/components/form';
import { ModelProvider } from '@/pages/model/constant';
import {
Box,
Button,
MenuItem,
Stack,
TextField,
useTheme,
alpha,
alpha as addOpacityToColor,
} from '@mui/material';
import { useEffect, useMemo, useState } from 'react';
import { Icon, message, Modal } from '@c-x/ui';
import { useEffect, useState } from 'react';
import { Controller, useForm } from 'react-hook-form';
import {
ConstsModelType,
DomainUpdateModelReq,
DomainCreateModelReq,
DomainProviderModel,
} from '@/api/types';
type ModelItem = any;
interface AddModelProps {
open: boolean;
data?: ModelItem;
data: DomainModel | null;
type: ConstsModelType;
onClose: () => void;
refresh: () => void;
modelType: 'llm' | 'coder';
}
const ModelModal = ({
interface AddModelForm {
provider: keyof typeof ModelProvider;
model: string;
base_url: string;
api_version: string;
api_key: string;
api_header_key: string;
api_header_value: string;
type: ConstsModelType;
}
const titleMap = {
[ConstsModelType.ModelTypeLLM]: '对话模型',
[ConstsModelType.ModelTypeCoder]: '代码补全模型',
[ConstsModelType.ModelTypeEmbedding]: '向量模型',
[ConstsModelType.ModelTypeAudio]: '音频模型',
[ConstsModelType.ModelTypeReranker]: '重排序模型',
};
const ModelAdd = ({
open,
onClose,
refresh,
data,
modelType,
type = ConstsModelType.ModelTypeLLM,
}: AddModelProps) => {
const theme = useTheme();
const providers: Record<string, any> = ModelProvider;
const {
formState: { errors },
handleSubmit,
@@ -50,64 +64,134 @@ const ModelModal = ({
reset,
setValue,
watch,
} = useForm<Required<DomainCreateModelReq>>({
} = useForm<AddModelForm>({
defaultValues: {
provider: data?.provider || 'DeepSeek',
api_base: data?.api_base || ModelProvider.DeepSeek.defaultBaseUrl,
model_name: data?.model_name || '',
api_key: data?.api_key || '',
type,
provider: 'BaiZhiCloud',
base_url: providers['BaiZhiCloud'].defaultBaseUrl,
model: '',
api_version: '',
api_key: '',
api_header_key: '',
api_header_value: '',
},
});
const providerBrand = watch('provider') as keyof typeof ModelProvider;
const providerBrand = watch('provider');
const [modelUserList, setModelUserList] = useState<DomainProviderModel[]>([]);
const [modelUserList, setModelUserList] = useState<{ model: string }[]>([]);
const [loading, setLoading] = useState(false);
const [modelLoading, setModelLoading] = useState(false);
const [error, setError] = useState('');
const [success, setSuccess] = useState(false);
const onCreateModel = (value: DomainCreateModelReq) => {
return postCreateModel({
...value,
model_type: modelType as ConstsModelType,
}).then(() => {
message.success('添加成功');
reset();
onClose();
refresh();
const handleReset = () => {
onClose();
reset({
type,
provider: 'BaiZhiCloud',
model: '',
base_url: '',
api_key: '',
api_version: '',
api_header_key: '',
api_header_value: '',
});
setModelUserList([]);
setSuccess(false);
setLoading(false);
setModelLoading(false);
setError('');
refresh();
};
const onUpdateModel = (value: DomainUpdateModelReq) => {
return putUpdateModel({
...value,
}).then(() => {
message.success('修改成功');
reset();
onClose();
refresh();
});
const getModel = (value: AddModelForm) => {
let header = '';
if (value.api_header_key && value.api_header_value) {
header = value.api_header_key + '=' + value.api_header_value;
}
setModelLoading(true);
getGetProviderModelList({
type,
api_key: value.api_key,
base_url: value.base_url,
provider: value.provider as Exclude<typeof value.provider, 'Other'>,
api_header: header,
})
.then((res) => {
setModelUserList(
(res.models || [])
.filter((item): item is { model: string } => !!item.model)
.sort((a, b) => a.model!.localeCompare(b.model!))
);
if (
data &&
(res.models || []).find((it) => it.model === data.model_name)
) {
setValue('model', data.model_name!);
} else {
setValue('model', res.models?.[0]?.model || '');
}
setSuccess(true);
})
.finally(() => {
setModelLoading(false);
});
};
const onSubmit = (value: Required<DomainCreateModelReq>) => {
const onSubmit = (value: AddModelForm) => {
let header = '';
if (value.api_header_key && value.api_header_value) {
header = value.api_header_key + '=' + value.api_header_value;
}
setError('');
setLoading(true);
postCheckModel({
...value,
// @ts-ignore
type,
api_key: value.api_key,
api_base: value.base_url,
api_version: value.api_version,
// @ts-ignore
provider: value.provider,
model_name: value.model,
api_header: header,
})
.then((res) => {
if (data) {
onUpdateModel({
...value,
putUpdateModel({
api_key: value.api_key,
api_base: value.base_url,
model_name: value.model,
api_header: header,
api_version: value.api_version,
id: data.id,
}).finally(() => {
setLoading(false);
});
provider: value.provider as Exclude<typeof value.provider, 'Other'>,
})
.then(() => {
message.success('修改成功');
handleReset();
})
.finally(() => {
setLoading(false);
});
} else {
onCreateModel(value).finally(() => {
setLoading(false);
});
postCreateModel({
model_type: type,
api_key: value.api_key,
api_base: value.base_url,
model_name: value.model,
api_header: header,
provider: value.provider as Exclude<typeof value.provider, 'Other'>,
})
.then(() => {
message.success('添加成功');
handleReset();
})
.finally(() => {
setLoading(false);
});
}
})
.catch(() => {
@@ -115,72 +199,64 @@ const ModelModal = ({
});
};
const resetCurData = (value: DomainModel) => {
// @ts-ignore
if (value.provider && value.provider !== 'Other') {
getModel({
api_key: value.api_key || '',
base_url: value.api_base || '',
model: value.model_name || '',
provider: value.provider,
api_version: value.api_version || '',
api_header_key: value.api_header?.split('=')[0] || '',
api_header_value: value.api_header?.split('=')[1] || '',
type,
});
}
reset({
type,
provider: value.provider || 'Other',
model: value.model_name || '',
base_url: value.api_base || '',
api_key: value.api_key || '',
api_version: value.api_version || '',
api_header_key: value.api_header?.split('=')[0] || '',
api_header_value: value.api_header?.split('=')[1] || '',
});
};
useEffect(() => {
if (open) {
if (data) {
reset(
{
provider: data.provider || 'Other',
model_name: data.model_name || '',
api_base: data.api_base || '',
api_key: data.api_key || '',
},
{
keepDefaultValues: true,
}
);
console.log(data);
resetCurData(data);
} else {
reset();
reset({
type,
provider: 'BaiZhiCloud',
model: '',
base_url: providers['BaiZhiCloud'].defaultBaseUrl,
api_key: '',
api_version: '',
api_header_key: '',
api_header_value: '',
});
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [data, open]);
useEffect(() => {
if (open) {
getListModel().then((res) => {
setModelUserList(res.providers || []);
if (!data) {
setValue('provider', res.providers?.[0].provider || 'DeepSeek');
}
});
}
}, [open]);
const currentModelList = useMemo(() => {
return (
modelUserList.find((it) => it.provider === providerBrand)?.models || []
);
}, [modelUserList, providerBrand]);
useEffect(() => {
if (currentModelList.length > 0) {
if (data) {
setValue('api_base', data.api_base || '');
setValue('model_name', data.model_name || '');
} else {
setValue('api_base', currentModelList[0].api_base || '');
setValue('model_name', currentModelList[0].name || '');
}
}
}, [currentModelList, data]);
return (
<Modal
title={data ? '修改第三方模型' : '添加第三方模型'}
title={data ? `修改${titleMap[type]}` : `添加${titleMap[type]}`}
open={open}
width={800}
onCancel={() => {
reset();
setModelUserList([]);
setLoading(false);
setError('');
onClose();
}}
onCancel={handleReset}
okText='保存'
onOk={handleSubmit(onSubmit)}
okButtonProps={{
loading,
disabled: !success && providerBrand !== 'Other',
}}
>
<Stack direction={'row'} alignItems={'stretch'} gap={3}>
@@ -189,7 +265,7 @@ const ModelModal = ({
sx={{
width: 200,
flexShrink: 0,
bgcolor: 'rgb(248, 249, 250)',
bgcolor: 'background.paper2',
borderRadius: '10px',
p: 1,
}}
@@ -199,12 +275,12 @@ const ModelModal = ({
>
</Box>
{modelUserList.map((it) => (
{Object.values(providers).map((it) => (
<Stack
direction={'row'}
alignItems={'center'}
gap={1.5}
key={it.provider}
key={it.label}
sx={{
cursor: 'pointer',
fontSize: 14,
@@ -213,8 +289,8 @@ const ModelModal = ({
borderRadius: '10px',
fontWeight: 'bold',
fontFamily: 'Gbold',
...(providerBrand === it.provider && {
bgcolor: alpha(theme.palette.primary.main, 0.1),
...(providerBrand === it.label && {
bgcolor: addOpacityToColor(theme.palette.primary.main, 0.1),
color: 'primary.main',
}),
'&:hover': {
@@ -222,36 +298,41 @@ const ModelModal = ({
},
}}
onClick={() => {
if (data) return;
setError('');
reset(
{
provider: it.provider as keyof typeof ModelProvider,
api_base: '',
model_name: '',
if (data && data.provider === it.label) {
resetCurData(data);
} else {
setModelUserList([]);
setError('');
setModelLoading(false);
setSuccess(false);
reset({
provider: it.label as keyof typeof ModelProvider,
base_url:
it.label === 'AzureOpenAI' ? '' : it.defaultBaseUrl,
model: '',
api_version: '',
api_key: '',
},
{
keepDefaultValues: true,
}
);
api_header_key: '',
api_header_value: '',
});
}
}}
>
<Icon
type={
ModelProvider[it.provider as keyof typeof ModelProvider].icon
}
sx={{ fontSize: 18 }}
/>
{it.provider}
<Icon type={it.icon} sx={{ fontSize: 18 }} />
{it.cn || it.label || '其他'}
</Stack>
))}
</Stack>
<Box sx={{ flex: 1 }}>
<StyledFormLabel required>API </StyledFormLabel>
<Box sx={{ fontSize: 14, lineHeight: '32px' }}>
API {' '}
<Box component={'span'} sx={{ color: 'red' }}>
*
</Box>
</Box>
<Controller
control={control}
name='api_base'
name='base_url'
rules={{
required: {
value: true,
@@ -262,15 +343,16 @@ const ModelModal = ({
<TextField
{...field}
fullWidth
disabled={!ModelProvider[providerBrand].urlWrite}
disabled={!providers[providerBrand].urlWrite}
size='small'
placeholder={ModelProvider[providerBrand].defaultBaseUrl}
error={!!errors.api_base}
helperText={errors.api_base?.message}
placeholder={providers[providerBrand].defaultBaseUrl}
error={!!errors.base_url}
helperText={errors.base_url?.message}
onChange={(e) => {
field.onChange(e.target.value);
setModelUserList([]);
setValue('model_name', '');
setValue('model', '');
setSuccess(false);
}}
/>
)}
@@ -281,12 +363,16 @@ const ModelModal = ({
justifyContent={'space-between'}
sx={{ fontSize: 14, lineHeight: '32px', mt: 2 }}
>
<StyledFormLabel
required={ModelProvider[providerBrand].secretRequired}
>
<Box>
API Secret
</StyledFormLabel>
{ModelProvider[providerBrand].modelDocumentUrl && (
{providers[providerBrand].secretRequired && (
<Box component={'span'} sx={{ color: 'red' }}>
{' '}
*
</Box>
)}
</Box>
{providers[providerBrand].modelDocumentUrl && (
<Box
component={'span'}
sx={{
@@ -297,7 +383,7 @@ const ModelModal = ({
}}
onClick={() =>
window.open(
ModelProvider[providerBrand].modelDocumentUrl,
providers[providerBrand].modelDocumentUrl,
'_blank'
)
}
@@ -311,7 +397,7 @@ const ModelModal = ({
name='api_key'
rules={{
required: {
value: ModelProvider[providerBrand].secretRequired,
value: providers[providerBrand].secretRequired,
message: 'API Secret 不能为空',
},
}}
@@ -325,36 +411,148 @@ const ModelModal = ({
helperText={errors.api_key?.message}
onChange={(e) => {
field.onChange(e.target.value);
setModelUserList([]);
setValue('model', '');
setSuccess(false);
}}
/>
)}
/>
<Box sx={{ mt: 2 }}>
<StyledFormLabel required></StyledFormLabel>
</Box>
<Controller
control={control}
name='model_name'
render={({ field }) => (
<TextField
{...field}
fullWidth
select
size='small'
placeholder=''
error={!!errors.model_name}
helperText={errors.model_name?.message}
>
{currentModelList.map((it) => (
<MenuItem key={it.name} value={it.name}>
{it.name}
</MenuItem>
))}
</TextField>
)}
/>
{providerBrand === 'AzureOpenAI' && (
<>
<Box sx={{ fontSize: 14, lineHeight: '32px', mt: 2 }}>
API Version
</Box>
<Controller
control={control}
name='api_version'
render={({ field }) => (
<TextField
{...field}
fullWidth
size='small'
placeholder='2024-10-21'
error={!!errors.api_version}
helperText={errors.api_version?.message}
onChange={(e) => {
field.onChange(e.target.value);
setModelUserList([]);
setValue('model', '');
setSuccess(false);
}}
/>
)}
/>
</>
)}
{providerBrand === 'Other' ? (
<>
<Box sx={{ fontSize: 14, lineHeight: '32px', mt: 2 }}>
{' '}
<Box component={'span'} sx={{ color: 'red' }}>
*
</Box>
</Box>
<Controller
control={control}
name='model'
rules={{
required: '模型名称不能为空',
}}
render={({ field }) => (
<TextField
{...field}
fullWidth
size='small'
placeholder=''
error={!!errors.model}
helperText={errors.model?.message}
/>
)}
/>
<Box sx={{ fontSize: 12, color: 'error.main', mt: 1 }}>
便
</Box>
</>
) : modelUserList.length === 0 ? (
<Button
fullWidth
variant='outlined'
loading={modelLoading}
sx={{ mt: 4 }}
onClick={handleSubmit(getModel)}
>
</Button>
) : (
<>
<Box sx={{ fontSize: 14, lineHeight: '32px', mt: 2 }}>
{' '}
<Box component={'span'} sx={{ color: 'red' }}>
*
</Box>
</Box>
<Controller
control={control}
name='model'
render={({ field }) => (
<TextField
{...field}
fullWidth
select
size='small'
placeholder=''
error={!!errors.model}
helperText={errors.model?.message}
>
{modelUserList.map((it) => (
<MenuItem key={it.model} value={it.model}>
{it.model}
</MenuItem>
))}
</TextField>
)}
/>
{providers[providerBrand].customHeader && (
<>
<Box sx={{ fontSize: 14, lineHeight: '32px', mt: 2 }}>
Header
</Box>
<Stack direction={'row'} gap={1}>
<Controller
control={control}
name='api_header_key'
render={({ field }) => (
<TextField
{...field}
fullWidth
size='small'
placeholder='key'
error={!!errors.api_header_key}
helperText={errors.api_header_key?.message}
/>
)}
/>
<Box sx={{ fontSize: 14, lineHeight: '36px' }}>=</Box>
<Controller
control={control}
name='api_header_value'
render={({ field }) => (
<TextField
{...field}
fullWidth
size='small'
placeholder='value'
error={!!errors.api_header_value}
helperText={errors.api_header_value?.message}
/>
)}
/>
</Stack>
</>
)}
</>
)}
{error && (
<Card
sx={{
@@ -376,4 +574,4 @@ const ModelModal = ({
);
};
export default ModelModal;
export default ModelAdd;

View File

@@ -1,13 +1,13 @@
export const ModelProvider = {
: {
label: '百智云',
cn: '',
BaiZhiCloud: {
label: 'BaiZhiCloud',
cn: '百智云',
icon: 'icon-baizhiyunlogo',
urlWrite: false,
secretRequired: true,
customHeader: false,
modelDocumentUrl: 'https://platform.deepseek.com/api_keys',
defaultBaseUrl: 'https://api.deepseek.com/v1',
modelDocumentUrl: 'https://model-square.app.baizhi.cloud/token',
defaultBaseUrl: 'https://model-square.app.baizhi.cloud/v1',
},
DeepSeek: {
label: 'DeepSeek',
@@ -19,6 +19,37 @@ export const ModelProvider = {
modelDocumentUrl: 'https://platform.deepseek.com/api_keys',
defaultBaseUrl: 'https://api.deepseek.com/v1',
},
Hunyuan: {
label: 'Hunyuan',
cn: '腾讯混元',
icon: 'icon-tengxunhunyuan',
urlWrite: false,
secretRequired: true,
customHeader: false,
modelDocumentUrl: 'https://console.cloud.tencent.com/hunyuan/start',
defaultBaseUrl: 'https://api.hunyuan.cloud.tencent.com/v1',
},
BaiLian: {
label: 'BaiLian',
cn: '阿里云百炼',
icon: 'icon-aliyunbailian',
urlWrite: false,
secretRequired: true,
customHeader: false,
modelDocumentUrl: 'https://bailian.console.aliyun.com/?tab=model#/api-key',
defaultBaseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
},
Volcengine: {
label: 'Volcengine',
cn: '火山引擎',
icon: 'icon-huoshanyinqing',
urlWrite: false,
secretRequired: true,
customHeader: false,
modelDocumentUrl:
'https://console.volcengine.com/ark/region:ark+cn-beijing/apiKey',
defaultBaseUrl: 'https://ark.cn-beijing.volces.com/api/v3',
},
OpenAI: {
label: 'OpenAI',
cn: '',

View File

@@ -2,13 +2,17 @@ import React from 'react';
import TokenUsage from './components/tokenUsage';
import ModelCard from './components/modelCard';
import { Stack } from '@mui/material';
import { ConstsModelType } from '@/api/types';
const Model = () => {
return (
<Stack gap={2}>
<TokenUsage />
<ModelCard title='对话模型' modelType='llm' />
<ModelCard title='代码补全模型' modelType='coder' />
<ModelCard title='对话模型' modelType={ConstsModelType.ModelTypeLLM} />
<ModelCard
title='代码补全模型'
modelType={ConstsModelType.ModelTypeCoder}
/>
</Stack>
);
};

View File

@@ -44,7 +44,7 @@ const Completion = () => {
const { data: userOptions = { users: [] } } = useRequest(() =>
getListUser({
page: 1,
size: 10,
size: 9999,
})
);

View File

@@ -17,38 +17,6 @@ const Dashboard = () => {
const [memberData, setMemberData] = useState<DomainUser | null>(null);
const [timeRange, setTimeRange] = useState<TimeRange>('24h');
const { data: userData, refresh } = useRequest(
() =>
getListUser({
page: 1,
size: 99999,
}),
{
manual: true,
onSuccess: (res) => {
if (id) {
setMemberData(res.users?.find((item) => item.id === id) || null);
} else {
setMemberData(res.users?.[0] || null);
navigate(`/dashboard/member/${res.users?.[0]?.id}`);
}
},
}
);
const userList = useMemo(() => {
return userData?.users || [];
}, [userData]);
useEffect(() => {
if (tabValue === 'member') {
refresh();
}
}, [tabValue]);
const onMemberChange = (data: DomainUser) => {
setMemberData(data);
navigate(`/dashboard/member/${data.id}`);
};
return (
<Stack gap={2} sx={{ height: '100%' }}>
<Stack direction='row' justifyContent='space-between' alignItems='center'>