feat(models): enhance model management with improved dialogs and state handling
This commit is contained in:
@@ -11,7 +11,7 @@ import type { LLMFactory } from "@/constants/llm";
|
|||||||
* 个人中心设置
|
* 个人中心设置
|
||||||
*/
|
*/
|
||||||
export function useProfileSetting() {
|
export function useProfileSetting() {
|
||||||
const {fetchUserInfo, userInfo} = useUserData();
|
const { fetchUserInfo, userInfo } = useUserData();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchUserInfo();
|
fetchUserInfo();
|
||||||
@@ -53,36 +53,42 @@ export function useLlmModelSetting() {
|
|||||||
const [llmFactory, setLlmFactory] = useState<IFactory[]>([]);
|
const [llmFactory, setLlmFactory] = useState<IFactory[]>([]);
|
||||||
const [myLlm, setMyLlm] = useState<Record<LLMFactory, IMyLlmModel>>();
|
const [myLlm, setMyLlm] = useState<Record<LLMFactory, IMyLlmModel>>();
|
||||||
|
|
||||||
|
const fetchLlmFactory = async () => {
|
||||||
|
try {
|
||||||
|
const res = await userService.llm_factories_list();
|
||||||
|
const arr = res.data.data || [];
|
||||||
|
setLlmFactory(arr);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('获取模型工厂失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchMyLlm = async () => {
|
||||||
|
try {
|
||||||
|
const res = await userService.my_llm();
|
||||||
|
const llm_dic = res.data.data || {};
|
||||||
|
setMyLlm(llm_dic);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('获取我的模型失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchLlmFactory = async () => {
|
|
||||||
try {
|
|
||||||
const res = await userService.llm_factories_list();
|
|
||||||
const arr = res.data.data || [];
|
|
||||||
setLlmFactory(arr);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('获取模型工厂失败:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchMyLlm = async () => {
|
|
||||||
try {
|
|
||||||
const res = await userService.my_llm();
|
|
||||||
const llm_dic = res.data.data || {};
|
|
||||||
setMyLlm(llm_dic);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('获取我的模型失败:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchLlmFactory();
|
fetchLlmFactory();
|
||||||
fetchMyLlm();
|
fetchMyLlm();
|
||||||
}, []); // 空依赖数组,只在组件挂载时执行一次
|
}, []);
|
||||||
|
|
||||||
|
const refreshLlmModel = async () => {
|
||||||
|
await fetchMyLlm();
|
||||||
|
// await fetchLlmFactory();
|
||||||
|
logger.info('刷新我的模型成功');
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
llmFactory,
|
llmFactory,
|
||||||
myLlm,
|
myLlm,
|
||||||
|
refreshLlmModel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
|
export interface ISetApiKeyRequestBody {
|
||||||
|
llm_factory: string;
|
||||||
|
api_key: string;
|
||||||
|
llm_name?: string;
|
||||||
|
model_type?: string;
|
||||||
|
base_url?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IAddLlmRequestBody {
|
export interface IAddLlmRequestBody {
|
||||||
llm_factory: string; // Ollama
|
llm_factory: string; // Ollama
|
||||||
llm_name: string;
|
llm_name: string;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { IconMap, type LLMFactory } from '@/constants/llm';
|
|||||||
import type { ITenantInfo } from '@/interfaces/database/knowledge';
|
import type { ITenantInfo } from '@/interfaces/database/knowledge';
|
||||||
import type { LlmModelType } from '@/constants/knowledge';
|
import type { LlmModelType } from '@/constants/knowledge';
|
||||||
import type { IMyLlmModel, IThirdOAIModel } from '@/interfaces/database/llm';
|
import type { IMyLlmModel, IThirdOAIModel } from '@/interfaces/database/llm';
|
||||||
|
import logger from '@/utils/logger';
|
||||||
|
|
||||||
// 基础对话框状态
|
// 基础对话框状态
|
||||||
interface BaseDialogState {
|
interface BaseDialogState {
|
||||||
@@ -164,6 +165,8 @@ export const ApiKeyDialog: React.FC<ApiKeyDialogProps> = ({
|
|||||||
});
|
});
|
||||||
const [showApiKey, setShowApiKey] = React.useState(false);
|
const [showApiKey, setShowApiKey] = React.useState(false);
|
||||||
|
|
||||||
|
logger.info('ApiKeyDialog 初始化:', { open, editMode, factoryName, initialData });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open && initialData) {
|
if (open && initialData) {
|
||||||
reset(initialData);
|
reset(initialData);
|
||||||
@@ -664,6 +667,7 @@ export const SystemModelDialog: React.FC<SystemModelDialogProps> = ({
|
|||||||
onSubmit,
|
onSubmit,
|
||||||
loading,
|
loading,
|
||||||
initialData,
|
initialData,
|
||||||
|
editMode = false,
|
||||||
allModelOptions
|
allModelOptions
|
||||||
}) => {
|
}) => {
|
||||||
const { control, handleSubmit, reset, formState: { errors } } = useForm<ITenantInfo>({
|
const { control, handleSubmit, reset, formState: { errors } } = useForm<ITenantInfo>({
|
||||||
@@ -676,7 +680,6 @@ export const SystemModelDialog: React.FC<SystemModelDialogProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// all model options 包含了全部的 options
|
// all model options 包含了全部的 options
|
||||||
|
|
||||||
const llmOptions = useMemo(() => allModelOptions?.llmOptions || [], [allModelOptions]);
|
const llmOptions = useMemo(() => allModelOptions?.llmOptions || [], [allModelOptions]);
|
||||||
const embdOptions = useMemo(() => allModelOptions?.embeddingOptions || [], [allModelOptions]);
|
const embdOptions = useMemo(() => allModelOptions?.embeddingOptions || [], [allModelOptions]);
|
||||||
const img2txtOptions = useMemo(() => allModelOptions?.image2textOptions || [], [allModelOptions]);
|
const img2txtOptions = useMemo(() => allModelOptions?.image2textOptions || [], [allModelOptions]);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useCallback, useMemo } from 'react';
|
import { useState, useCallback, useMemo, useEffect } from 'react';
|
||||||
import { useMessage } from '@/hooks/useSnackbar';
|
import { useMessage } from '@/hooks/useSnackbar';
|
||||||
import userService from '@/services/user_service';
|
import userService from '@/services/user_service';
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
@@ -11,6 +11,8 @@ import type {
|
|||||||
import type { ITenantInfo } from '@/interfaces/database/knowledge';
|
import type { ITenantInfo } from '@/interfaces/database/knowledge';
|
||||||
import { useLlmList } from '@/hooks/llm-hooks';
|
import { useLlmList } from '@/hooks/llm-hooks';
|
||||||
import type { LlmModelType } from '@/constants/knowledge';
|
import type { LlmModelType } from '@/constants/knowledge';
|
||||||
|
import { useUserData } from '@/hooks/useUserData';
|
||||||
|
import type { ISetApiKeyRequestBody } from '@/interfaces/request/llm';
|
||||||
|
|
||||||
// 对话框状态管理 hook
|
// 对话框状态管理 hook
|
||||||
export const useDialogState = () => {
|
export const useDialogState = () => {
|
||||||
@@ -20,7 +22,9 @@ export const useDialogState = () => {
|
|||||||
const [initialData, setInitialData] = useState<any>(null);
|
const [initialData, setInitialData] = useState<any>(null);
|
||||||
|
|
||||||
const openDialog = useCallback((data?: any, isEdit = false) => {
|
const openDialog = useCallback((data?: any, isEdit = false) => {
|
||||||
setInitialData(data);
|
if (data != null) {
|
||||||
|
setInitialData(data);
|
||||||
|
}
|
||||||
setEditMode(isEdit);
|
setEditMode(isEdit);
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
}, []);
|
}, []);
|
||||||
@@ -55,19 +59,26 @@ export const useApiKeyDialog = () => {
|
|||||||
|
|
||||||
const submitApiKey = useCallback(async (data: ApiKeyFormData) => {
|
const submitApiKey = useCallback(async (data: ApiKeyFormData) => {
|
||||||
dialogState.setLoading(true);
|
dialogState.setLoading(true);
|
||||||
|
logger.info('提交 API Key:', data);
|
||||||
try {
|
try {
|
||||||
await userService.set_api_key({
|
const params: ISetApiKeyRequestBody = {
|
||||||
factory_name: factoryName,
|
llm_factory: factoryName,
|
||||||
model_name: '', // 根据实际需求调整
|
api_key: data.api_key,
|
||||||
// api_key: data.api_key,
|
};
|
||||||
...data
|
|
||||||
});
|
if (data.base_url && data.base_url.trim() !== '') {
|
||||||
|
params.base_url = data.base_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.group_id && data.group_id.trim() !== '') {
|
||||||
|
// params.group_id = data.group_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
await userService.set_api_key(params);
|
||||||
showMessage.success('API Key 配置成功');
|
showMessage.success('API Key 配置成功');
|
||||||
dialogState.closeDialog();
|
dialogState.closeDialog();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('API Key 配置失败:', error);
|
logger.error('API Key 配置失败:', error);
|
||||||
showMessage.error('API Key 配置失败');
|
|
||||||
throw error;
|
|
||||||
} finally {
|
} finally {
|
||||||
dialogState.setLoading(false);
|
dialogState.setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -91,8 +102,8 @@ export const useAzureOpenAIDialog = () => {
|
|||||||
try {
|
try {
|
||||||
// 调用 Azure OpenAI 特定的 API
|
// 调用 Azure OpenAI 特定的 API
|
||||||
await userService.set_api_key({
|
await userService.set_api_key({
|
||||||
factory_name: 'AzureOpenAI',
|
llm_factory: 'AzureOpenAI',
|
||||||
model_name: data.deployment_name,
|
llm_name: data.deployment_name,
|
||||||
api_key: data.api_key,
|
api_key: data.api_key,
|
||||||
// azure_endpoint: data.azure_endpoint,
|
// azure_endpoint: data.azure_endpoint,
|
||||||
// api_version: data.api_version,
|
// api_version: data.api_version,
|
||||||
@@ -124,8 +135,8 @@ export const useBedrockDialog = () => {
|
|||||||
try {
|
try {
|
||||||
// 调用 Bedrock 特定的 API
|
// 调用 Bedrock 特定的 API
|
||||||
await userService.set_api_key({
|
await userService.set_api_key({
|
||||||
factory_name: 'Bedrock',
|
llm_factory: 'Bedrock',
|
||||||
model_name: '',
|
llm_name: '',
|
||||||
api_key: '', // Bedrock 使用 access key
|
api_key: '', // Bedrock 使用 access key
|
||||||
// access_key_id: data.access_key_id,
|
// access_key_id: data.access_key_id,
|
||||||
// secret_access_key: data.secret_access_key,
|
// secret_access_key: data.secret_access_key,
|
||||||
@@ -158,8 +169,8 @@ export const useOllamaDialog = () => {
|
|||||||
try {
|
try {
|
||||||
// 调用添加 LLM 的 API
|
// 调用添加 LLM 的 API
|
||||||
await userService.add_llm({
|
await userService.add_llm({
|
||||||
factory_name: 'Ollama',
|
llm_factory: 'Ollama',
|
||||||
model_name: data.model_name,
|
llm_name: data.model_name,
|
||||||
// base_url: data.base_url,
|
// base_url: data.base_url,
|
||||||
});
|
});
|
||||||
showMessage.success('Ollama 模型添加成功');
|
showMessage.success('Ollama 模型添加成功');
|
||||||
@@ -188,14 +199,12 @@ export const useDeleteOperations = () => {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
await userService.delete_llm({
|
await userService.delete_llm({
|
||||||
factory_name: factoryName,
|
llm_factory: factoryName,
|
||||||
model_name: modelName,
|
llm_name: modelName,
|
||||||
});
|
});
|
||||||
showMessage.success('模型删除成功');
|
showMessage.success('模型删除成功');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('模型删除失败:', error);
|
logger.error('模型删除失败:', error);
|
||||||
showMessage.error('模型删除失败');
|
|
||||||
throw error;
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -205,13 +214,11 @@ export const useDeleteOperations = () => {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
await userService.deleteFactory({
|
await userService.deleteFactory({
|
||||||
factory_name: factoryName,
|
llm_factory: factoryName,
|
||||||
});
|
});
|
||||||
showMessage.success('模型工厂删除成功');
|
showMessage.success('模型工厂删除成功');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('模型工厂删除失败:', error);
|
logger.error('模型工厂删除失败:', error);
|
||||||
showMessage.error('模型工厂删除失败');
|
|
||||||
throw error;
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -231,6 +238,12 @@ export const useSystemModelSetting = () => {
|
|||||||
|
|
||||||
const { data: llmList } = useLlmList();
|
const { data: llmList } = useLlmList();
|
||||||
|
|
||||||
|
const { tenantInfo, fetchTenantInfo } = useUserData();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchTenantInfo();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const getOptionsByModelType = useCallback((modelType: LlmModelType) => {
|
const getOptionsByModelType = useCallback((modelType: LlmModelType) => {
|
||||||
return Object.entries(llmList)
|
return Object.entries(llmList)
|
||||||
.filter(([, value]) =>
|
.filter(([, value]) =>
|
||||||
@@ -278,11 +291,16 @@ export const useSystemModelSetting = () => {
|
|||||||
|
|
||||||
const submitSystemModelSetting = useCallback(async (data: Partial<ITenantInfo>) => {
|
const submitSystemModelSetting = useCallback(async (data: Partial<ITenantInfo>) => {
|
||||||
dialogState.setLoading(true);
|
dialogState.setLoading(true);
|
||||||
|
logger.debug('submitSystemModelSetting data:', data);
|
||||||
try {
|
try {
|
||||||
|
delete data.role;
|
||||||
// 这里需要根据实际的 API 接口调整
|
// 这里需要根据实际的 API 接口调整
|
||||||
// await userService.setSystemDefaultModel(data);
|
await userService.setTenantInfo({
|
||||||
|
...data,
|
||||||
|
});
|
||||||
showMessage.success('系统默认模型设置成功');
|
showMessage.success('系统默认模型设置成功');
|
||||||
dialogState.closeDialog();
|
dialogState.closeDialog();
|
||||||
|
fetchTenantInfo();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('系统默认模型设置失败:', error);
|
logger.error('系统默认模型设置失败:', error);
|
||||||
showMessage.error('系统默认模型设置失败');
|
showMessage.error('系统默认模型设置失败');
|
||||||
@@ -296,6 +314,7 @@ export const useSystemModelSetting = () => {
|
|||||||
...dialogState,
|
...dialogState,
|
||||||
submitSystemModelSetting,
|
submitSystemModelSetting,
|
||||||
allModelOptions,
|
allModelOptions,
|
||||||
|
initialData: tenantInfo,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,61 +25,82 @@ import {
|
|||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import { useLlmModelSetting } from '@/hooks/setting-hooks';
|
import { useLlmModelSetting } from '@/hooks/setting-hooks';
|
||||||
import { useModelDialogs } from './hooks/useModelDialogs';
|
import { useModelDialogs } from './hooks/useModelDialogs';
|
||||||
import AppSvgIcon, { LlmSvgIcon } from '@/components/AppSvgIcon';
|
|
||||||
import { LLM_FACTORY_LIST, IconMap, type LLMFactory } from '@/constants/llm';
|
|
||||||
import type { IFactory, IMyLlmModel, ILlmItem } from '@/interfaces/database/llm';
|
import type { IFactory, IMyLlmModel, ILlmItem } from '@/interfaces/database/llm';
|
||||||
import LLMFactoryCard, { MODEL_TYPE_COLORS } from './components/LLMFactoryCard';
|
import LLMFactoryCard, { MODEL_TYPE_COLORS } from './components/LLMFactoryCard';
|
||||||
import { ModelDialogs } from './components/ModelDialogs';
|
import { ModelDialogs } from './components/ModelDialogs';
|
||||||
|
import { useDialog } from '@/hooks/useDialog';
|
||||||
|
import logger from '@/utils/logger';
|
||||||
|
import { useMessage } from '@/hooks/useSnackbar';
|
||||||
|
|
||||||
|
function MyLlmGridItem({ model, onDelete }: { model: ILlmItem, onDelete: (model: ILlmItem) => void }) {
|
||||||
|
return (
|
||||||
|
<Grid size={{ xs: 6, sm: 4, md: 3 }} key={model.name}>
|
||||||
|
<Card variant="outlined" sx={{ p: 2 }}>
|
||||||
|
<Box display="flex" justifyContent="space-between" alignItems="flex-start" mb={1}>
|
||||||
|
<Typography variant="body2" fontWeight="bold">
|
||||||
|
{model.name}
|
||||||
|
</Typography>
|
||||||
|
<Box>
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
color="error"
|
||||||
|
onClick={() => onDelete(model)}
|
||||||
|
>
|
||||||
|
<DeleteIcon fontSize="small" />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Chip
|
||||||
|
label={model.type}
|
||||||
|
size="small"
|
||||||
|
sx={{
|
||||||
|
backgroundColor: MODEL_TYPE_COLORS[model.type.toUpperCase()] || '#757575',
|
||||||
|
color: 'white',
|
||||||
|
mb: 1,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// 主页面组件
|
// 主页面组件
|
||||||
function ModelsPage() {
|
function ModelsPage() {
|
||||||
const { llmFactory, myLlm } = useLlmModelSetting();
|
const { llmFactory, myLlm, refreshLlmModel } = useLlmModelSetting();
|
||||||
const modelDialogs = useModelDialogs();
|
const modelDialogs = useModelDialogs();
|
||||||
|
|
||||||
// 处理配置模型工厂
|
// 处理配置模型工厂
|
||||||
const handleConfigureFactory = useCallback((factory: IFactory) => {
|
const handleConfigureFactory = useCallback((factory: IFactory) => {
|
||||||
// modelDialogs.openDialog(factory.name);
|
modelDialogs.apiKeyDialog.openApiKeyDialog(factory.name);
|
||||||
}, [modelDialogs]);
|
}, [modelDialogs, refreshLlmModel]);
|
||||||
|
|
||||||
// 处理删除模型工厂
|
const dialog = useDialog();
|
||||||
const handleDeleteFactory = useCallback(async (factoryName: string) => {
|
|
||||||
try {
|
|
||||||
// await modelDialogs.deleteOperations.deleteFactory(factoryName);
|
|
||||||
// 刷新数据
|
|
||||||
window.location.reload();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('删除工厂失败:', error);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// 处理删除单个模型
|
// 处理删除单个模型
|
||||||
const handleDeleteModel = useCallback(async (factoryName: string, modelName: string) => {
|
const handleDeleteModel = useCallback(async (factoryName: string, modelName: string) => {
|
||||||
try {
|
dialog.confirm({
|
||||||
// await modelDialogs.deleteOperations.deleteLlm(factoryName, modelName);
|
title: '确认删除',
|
||||||
// 刷新数据
|
content: `是否确认删除模型 ${modelName}?`,
|
||||||
window.location.reload();
|
showCancel: true,
|
||||||
} catch (error) {
|
onConfirm: async () => {
|
||||||
console.error('删除模型失败:', error);
|
await modelDialogs.deleteOps.deleteLlm(factoryName, modelName);
|
||||||
}
|
await refreshLlmModel();
|
||||||
}, []);
|
},
|
||||||
|
});
|
||||||
|
}, [dialog, refreshLlmModel]);
|
||||||
|
|
||||||
// 处理编辑模型
|
// 处理删除模型工厂
|
||||||
const handleEditModel = useCallback((factory: IFactory, model: ILlmItem) => {
|
const handleDeleteFactory = useCallback(async (factoryName: string) => {
|
||||||
// 设置编辑模式并打开对话框
|
dialog.confirm({
|
||||||
// modelDialogs.openDialog(factory.name, {
|
title: '确认删除',
|
||||||
// model_name: model.name,
|
content: `是否确认删除模型工厂 ${factoryName}?`,
|
||||||
// api_base: model.api_base,
|
showCancel: true,
|
||||||
// max_tokens: model.max_tokens,
|
onConfirm: async () => {
|
||||||
// });
|
await modelDialogs.deleteOps.deleteFactory(factoryName);
|
||||||
}, [modelDialogs]);
|
await refreshLlmModel();
|
||||||
|
},
|
||||||
// 根据工厂名称获取对应的模型列表
|
});
|
||||||
const getModelsForFactory = (factoryName: LLMFactory): ILlmItem[] => {
|
}, [dialog, refreshLlmModel]);
|
||||||
if (!myLlm) return [];
|
|
||||||
const factoryGroup = myLlm[factoryName];
|
|
||||||
return factoryGroup?.llm || [];
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!llmFactory || !myLlm) {
|
if (!llmFactory || !myLlm) {
|
||||||
return (
|
return (
|
||||||
@@ -98,12 +119,12 @@ function ModelsPage() {
|
|||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
}}>
|
}}>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography variant="h4" gutterBottom>
|
<Typography variant="h4" gutterBottom>
|
||||||
模型设置
|
模型设置
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body1" color="text.secondary" gutterBottom>
|
<Typography variant="body1" color="text.secondary" gutterBottom>
|
||||||
管理您的 LLM 模型工厂和个人模型配置
|
管理您的 LLM 模型工厂和个人模型配置
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
{/* 设置默认模型 */}
|
{/* 设置默认模型 */}
|
||||||
<Button variant="contained" color="primary" onClick={() => modelDialogs.systemDialog.openDialog()}>
|
<Button variant="contained" color="primary" onClick={() => modelDialogs.systemDialog.openDialog()}>
|
||||||
@@ -129,68 +150,51 @@ function ModelsPage() {
|
|||||||
<Grid size={12} key={factoryName}>
|
<Grid size={12} key={factoryName}>
|
||||||
<Card variant="outlined">
|
<Card variant="outlined">
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Typography variant="h6" gutterBottom>
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
{factoryName}
|
<Box>
|
||||||
</Typography>
|
{/* 模型工厂名称 */}
|
||||||
<Box display="flex" gap={1} mb={2}>
|
<Typography variant="h6" gutterBottom>
|
||||||
{group.tags.split(',').map((tag) => (
|
{factoryName}
|
||||||
<Chip
|
</Typography>
|
||||||
key={tag}
|
{/* 模型标签 */}
|
||||||
label={tag.trim()}
|
<Box display="flex" gap={1} mb={2}>
|
||||||
size="small"
|
{group.tags.split(',').map((tag) => (
|
||||||
sx={{
|
|
||||||
backgroundColor: MODEL_TYPE_COLORS[tag.trim()] || '#757575',
|
|
||||||
color: 'white',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Box>
|
|
||||||
<Grid container spacing={2}>
|
|
||||||
{group.llm.map((model) => (
|
|
||||||
<Grid size={{ xs: 12, sm: 6, md: 4 }} key={model.name}>
|
|
||||||
<Card variant="outlined" sx={{ p: 2 }}>
|
|
||||||
<Box display="flex" justifyContent="space-between" alignItems="flex-start" mb={1}>
|
|
||||||
<Typography variant="body2" fontWeight="bold">
|
|
||||||
{model.name}
|
|
||||||
</Typography>
|
|
||||||
<Box>
|
|
||||||
<IconButton
|
|
||||||
size="small"
|
|
||||||
onClick={() => handleEditModel({ name: factoryName } as IFactory, model)}
|
|
||||||
>
|
|
||||||
<EditIcon fontSize="small" />
|
|
||||||
</IconButton>
|
|
||||||
<IconButton
|
|
||||||
size="small"
|
|
||||||
color="error"
|
|
||||||
onClick={() => handleDeleteModel(factoryName, model.name)}
|
|
||||||
>
|
|
||||||
<DeleteIcon fontSize="small" />
|
|
||||||
</IconButton>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
<Chip
|
<Chip
|
||||||
label={model.type}
|
key={tag}
|
||||||
|
label={tag.trim()}
|
||||||
size="small"
|
size="small"
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: MODEL_TYPE_COLORS[model.type.toUpperCase()] || '#757575',
|
backgroundColor: MODEL_TYPE_COLORS[tag.trim()] || '#757575',
|
||||||
color: 'white',
|
color: 'white',
|
||||||
mb: 1,
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Typography variant="caption" display="block" color="text.secondary">
|
))}
|
||||||
Max Tokens: {model.max_tokens}
|
</Box>
|
||||||
</Typography>
|
</Box>
|
||||||
<Typography variant="caption" display="block" color="text.secondary">
|
{/* edit and delete factory button */}
|
||||||
Used: {model.used_token}
|
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||||
</Typography>
|
<Button
|
||||||
{model.api_base && (
|
variant='contained' color='primary' startIcon={<EditIcon />}
|
||||||
<Typography variant="caption" display="block" color="text.secondary">
|
onClick={() => modelDialogs.apiKeyDialog.openApiKeyDialog(factoryName)}
|
||||||
Base URL: {model.api_base}
|
>
|
||||||
</Typography>
|
编辑
|
||||||
)}
|
</Button>
|
||||||
</Card>
|
<Button
|
||||||
</Grid>
|
variant='outlined' color='primary' startIcon={<DeleteIcon />}
|
||||||
|
onClick={() => handleDeleteFactory(factoryName)}
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
{/* 模型列表 */}
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
{group.llm.map((model) => (
|
||||||
|
<MyLlmGridItem
|
||||||
|
key={model.name}
|
||||||
|
model={model}
|
||||||
|
onDelete={() => handleDeleteModel(factoryName, model.name)}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
@@ -230,6 +234,7 @@ function ModelsPage() {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* 模型配置对话框 */}
|
{/* 模型配置对话框 */}
|
||||||
|
{/* @ts-ignore */}
|
||||||
<ModelDialogs {...modelDialogs} />
|
<ModelDialogs {...modelDialogs} />
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import request, { post } from '@/utils/request';
|
|||||||
import type { ITenantInfo } from '@/interfaces/database/knowledge';
|
import type { ITenantInfo } from '@/interfaces/database/knowledge';
|
||||||
import type { IUserInfo, ITenant } from '@/interfaces/database/user-setting';
|
import type { IUserInfo, ITenant } from '@/interfaces/database/user-setting';
|
||||||
import type { LlmModelType } from '@/constants/knowledge';
|
import type { LlmModelType } from '@/constants/knowledge';
|
||||||
|
import type { IAddLlmRequestBody, IDeleteLlmRequestBody, ISetApiKeyRequestBody } from '@/interfaces/request/llm';
|
||||||
|
|
||||||
// 用户相关API服务
|
// 用户相关API服务
|
||||||
const userService = {
|
const userService = {
|
||||||
@@ -53,7 +54,7 @@ const userService = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 设置租户信息
|
// 设置租户信息
|
||||||
setTenantInfo: (data: ITenantInfo) => {
|
setTenantInfo: (data: Partial<Omit<ITenantInfo, 'role'>>) => {
|
||||||
return post(api.set_tenant_info, data);
|
return post(api.set_tenant_info, data);
|
||||||
},
|
},
|
||||||
// 租户用户管理
|
// 租户用户管理
|
||||||
@@ -95,22 +96,22 @@ const userService = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// add llm
|
// add llm
|
||||||
add_llm: (data: { factory_name: string; model_name: string }) => {
|
add_llm: (data: Partial<IAddLlmRequestBody>) => {
|
||||||
return request.post(api.add_llm, data);
|
return request.post(api.add_llm, data);
|
||||||
},
|
},
|
||||||
|
|
||||||
// delete llm
|
// delete llm
|
||||||
delete_llm: (data: { factory_name: string; model_name: string }) => {
|
delete_llm: (data: IDeleteLlmRequestBody) => {
|
||||||
return request.post(api.delete_llm, data);
|
return request.post(api.delete_llm, data);
|
||||||
},
|
},
|
||||||
|
|
||||||
// delete factory
|
// delete factory
|
||||||
deleteFactory: (data: { factory_name: string }) => {
|
deleteFactory: (data: IDeleteLlmRequestBody) => {
|
||||||
return request.post(api.deleteFactory, data);
|
return request.post(api.deleteFactory, data);
|
||||||
},
|
},
|
||||||
|
|
||||||
// set api key
|
// set api key
|
||||||
set_api_key: (data: { factory_name: string; model_name: string; api_key: string }) => {
|
set_api_key: (data: ISetApiKeyRequestBody) => {
|
||||||
return request.post(api.set_api_key, data);
|
return request.post(api.set_api_key, data);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user