feat(model-settings): add system default model configuration dialog
This commit is contained in:
@@ -40,8 +40,7 @@ export default function AppSvgIcon(props: AppSvgIconProps) {
|
|||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const iconPath = `${svgPath}${pointPath}/${name}.svg?react`;
|
const iconPath = `${svgPath}${pointPath}/${name}.svg?react`;
|
||||||
logger.debug(`[AppSvgIcon] 加载图标: ${iconPath}`);
|
// logger.debug(`[AppSvgIcon] 加载图标: ${iconPath}`);
|
||||||
|
|
||||||
const iconModule = await import(/* @vite-ignore */ iconPath);
|
const iconModule = await import(/* @vite-ignore */ iconPath);
|
||||||
setIcon(() => iconModule.default);
|
setIcon(() => iconModule.default);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -310,6 +310,8 @@ export interface ITenantInfo {
|
|||||||
speech2text_id: string;
|
speech2text_id: string;
|
||||||
/** 文本转语音服务ID */
|
/** 文本转语音服务ID */
|
||||||
tts_id: string;
|
tts_id: string;
|
||||||
|
// rerank模型服务ID
|
||||||
|
rerank_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
@@ -16,9 +16,49 @@ import {
|
|||||||
CircularProgress,
|
CircularProgress,
|
||||||
IconButton,
|
IconButton,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
|
ListSubheader,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { Visibility, VisibilityOff } from '@mui/icons-material';
|
import { Visibility, VisibilityOff } from '@mui/icons-material';
|
||||||
import { useForm, Controller } from 'react-hook-form';
|
import { useForm, Controller } from 'react-hook-form';
|
||||||
|
import { LlmSvgIcon } from '@/components/AppSvgIcon';
|
||||||
|
import { IconMap, type LLMFactory } from '@/constants/llm';
|
||||||
|
import type { ITenantInfo } from '@/interfaces/database/knowledge';
|
||||||
|
import type { LlmModelType } from '@/constants/knowledge';
|
||||||
|
import type { IMyLlmModel, IThirdOAIModel } from '@/interfaces/database/llm';
|
||||||
|
|
||||||
|
// 基础对话框状态
|
||||||
|
interface BaseDialogState {
|
||||||
|
open: boolean;
|
||||||
|
loading: boolean;
|
||||||
|
editMode: boolean;
|
||||||
|
closeDialog: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModelDialogs 整合组件的 Props 接口
|
||||||
|
interface ModelDialogsProps {
|
||||||
|
apiKeyDialog: BaseDialogState & {
|
||||||
|
initialData: any;
|
||||||
|
factoryName: string;
|
||||||
|
submitApiKey: (data: ApiKeyFormData) => Promise<void>;
|
||||||
|
};
|
||||||
|
azureDialog: BaseDialogState & {
|
||||||
|
initialData: any;
|
||||||
|
submitAzureOpenAI: (data: AzureOpenAIFormData) => Promise<void>;
|
||||||
|
};
|
||||||
|
bedrockDialog: BaseDialogState & {
|
||||||
|
initialData: any;
|
||||||
|
submitBedrock: (data: BedrockFormData) => Promise<void>;
|
||||||
|
};
|
||||||
|
ollamaDialog: BaseDialogState & {
|
||||||
|
initialData: any;
|
||||||
|
submitOllama: (data: OllamaFormData) => Promise<void>;
|
||||||
|
};
|
||||||
|
systemDialog: BaseDialogState & {
|
||||||
|
allModelOptions: any;
|
||||||
|
initialData: Partial<ITenantInfo>;
|
||||||
|
submitSystemModelSetting: (data: Partial<ITenantInfo>) => Promise<void>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// 接口定义
|
// 接口定义
|
||||||
export interface ApiKeyFormData {
|
export interface ApiKeyFormData {
|
||||||
@@ -53,15 +93,54 @@ const BEDROCK_REGIONS = [
|
|||||||
'ap-south-1', 'ca-central-1', 'sa-east-1'
|
'ap-south-1', 'ca-central-1', 'sa-east-1'
|
||||||
];
|
];
|
||||||
|
|
||||||
// 通用 API Key 对话框
|
// 基础对话框 Props
|
||||||
interface ApiKeyDialogProps {
|
interface BaseDialogProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onSubmit: (data: ApiKeyFormData) => Promise<void>;
|
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
editMode?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通用 API Key 对话框
|
||||||
|
interface ApiKeyDialogProps extends BaseDialogProps {
|
||||||
|
onSubmit: (data: ApiKeyFormData) => Promise<void>;
|
||||||
factoryName: string;
|
factoryName: string;
|
||||||
initialData?: Partial<ApiKeyFormData>;
|
initialData?: Partial<ApiKeyFormData>;
|
||||||
editMode?: boolean;
|
}
|
||||||
|
|
||||||
|
// Azure OpenAI 对话框
|
||||||
|
interface AzureOpenAIDialogProps extends BaseDialogProps {
|
||||||
|
onSubmit: (data: AzureOpenAIFormData) => Promise<void>;
|
||||||
|
initialData?: Partial<AzureOpenAIFormData>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AWS Bedrock 对话框
|
||||||
|
interface BedrockDialogProps extends BaseDialogProps {
|
||||||
|
onSubmit: (data: BedrockFormData) => Promise<void>;
|
||||||
|
initialData?: Partial<BedrockFormData>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ollama 对话框
|
||||||
|
interface OllamaDialogProps extends BaseDialogProps {
|
||||||
|
onSubmit: (data: OllamaFormData) => Promise<void>;
|
||||||
|
initialData?: Partial<OllamaFormData>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AllModelOptionItem {
|
||||||
|
label: string;
|
||||||
|
options: {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
disabled: boolean;
|
||||||
|
model: IThirdOAIModel
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 系统默认模型设置对话框
|
||||||
|
interface SystemModelDialogProps extends BaseDialogProps {
|
||||||
|
onSubmit: (data: Partial<ITenantInfo>) => Promise<void>;
|
||||||
|
initialData?: Partial<ITenantInfo>;
|
||||||
|
allModelOptions: Record<string, AllModelOptionItem[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -192,15 +271,6 @@ export const ApiKeyDialog: React.FC<ApiKeyDialogProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Azure OpenAI 对话框
|
|
||||||
interface AzureOpenAIDialogProps {
|
|
||||||
open: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
onSubmit: (data: AzureOpenAIFormData) => Promise<void>;
|
|
||||||
loading: boolean;
|
|
||||||
initialData?: Partial<AzureOpenAIFormData>;
|
|
||||||
editMode?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Azure OpenAI 对话框
|
* Azure OpenAI 对话框
|
||||||
@@ -348,15 +418,6 @@ export const AzureOpenAIDialog: React.FC<AzureOpenAIDialogProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// AWS Bedrock 对话框
|
|
||||||
interface BedrockDialogProps {
|
|
||||||
open: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
onSubmit: (data: BedrockFormData) => Promise<void>;
|
|
||||||
loading: boolean;
|
|
||||||
initialData?: Partial<BedrockFormData>;
|
|
||||||
editMode?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AWS Bedrock 对话框
|
* AWS Bedrock 对话框
|
||||||
@@ -492,14 +553,6 @@ export const BedrockDialog: React.FC<BedrockDialogProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface OllamaDialogProps {
|
|
||||||
open: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
onSubmit: (data: OllamaFormData) => Promise<void>;
|
|
||||||
loading: boolean;
|
|
||||||
initialData?: Partial<OllamaFormData>;
|
|
||||||
editMode?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ollama 对话框
|
* Ollama 对话框
|
||||||
@@ -599,3 +652,319 @@ export const OllamaDialog: React.FC<OllamaDialogProps> = ({
|
|||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统默认模型设置对话框
|
||||||
|
*/
|
||||||
|
export const SystemModelDialog: React.FC<SystemModelDialogProps> = ({
|
||||||
|
open,
|
||||||
|
onClose,
|
||||||
|
onSubmit,
|
||||||
|
loading,
|
||||||
|
initialData,
|
||||||
|
allModelOptions
|
||||||
|
}) => {
|
||||||
|
const { control, handleSubmit, reset, formState: { errors } } = useForm<ITenantInfo>({
|
||||||
|
defaultValues: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取工厂图标名称
|
||||||
|
const getFactoryIconName = (factoryName: LLMFactory) => {
|
||||||
|
return IconMap[factoryName] || 'default';
|
||||||
|
};
|
||||||
|
|
||||||
|
// all model options 包含了全部的 options
|
||||||
|
|
||||||
|
const llmOptions = useMemo(() => allModelOptions?.llmOptions || [], [allModelOptions]);
|
||||||
|
const embdOptions = useMemo(() => allModelOptions?.embeddingOptions || [], [allModelOptions]);
|
||||||
|
const img2txtOptions = useMemo(() => allModelOptions?.image2textOptions || [], [allModelOptions]);
|
||||||
|
const asrOptions = useMemo(() => allModelOptions?.speech2textOptions || [], [allModelOptions]);
|
||||||
|
const ttsOptions = useMemo(() => allModelOptions?.ttsOptions || [], [allModelOptions]);
|
||||||
|
const rerankOptions = useMemo(() => allModelOptions?.rerankOptions || [], [allModelOptions]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (open && initialData) {
|
||||||
|
reset(initialData);
|
||||||
|
} else if (open) {
|
||||||
|
reset({
|
||||||
|
llm_id: '',
|
||||||
|
embd_id: '',
|
||||||
|
img2txt_id: '',
|
||||||
|
asr_id: '',
|
||||||
|
tts_id: '',
|
||||||
|
rerank_id: '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [open, initialData, reset]);
|
||||||
|
|
||||||
|
const handleFormSubmit = async (data: ITenantInfo) => {
|
||||||
|
try {
|
||||||
|
await onSubmit(data);
|
||||||
|
onClose();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('提交失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onClose={onClose} maxWidth="sm" fullWidth>
|
||||||
|
<DialogTitle>
|
||||||
|
设置默认模型
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<Box component="form" sx={{ mt: 2 }}>
|
||||||
|
<Controller
|
||||||
|
name="llm_id"
|
||||||
|
control={control}
|
||||||
|
rules={{ required: '聊天模型是必填项' }}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormControl fullWidth margin="normal" error={!!errors.llm_id}>
|
||||||
|
<InputLabel>聊天模型</InputLabel>
|
||||||
|
<Select {...field} label="聊天模型">
|
||||||
|
{llmOptions.map((group) => [
|
||||||
|
<ListSubheader key={group.label}>{group.label}</ListSubheader>,
|
||||||
|
...group.options.map((option) => (
|
||||||
|
<MenuItem key={option.value} value={option.value} disabled={option.disabled}>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||||
|
<LlmSvgIcon
|
||||||
|
name={getFactoryIconName(group.label as LLMFactory)}
|
||||||
|
sx={{ width: 20, height: 20, color: 'primary.main' }}
|
||||||
|
/>
|
||||||
|
{option.label}
|
||||||
|
</Box>
|
||||||
|
</MenuItem>
|
||||||
|
))
|
||||||
|
])}
|
||||||
|
</Select>
|
||||||
|
{errors.llm_id && (
|
||||||
|
<Typography variant="caption" color="error" sx={{ mt: 1, ml: 2 }}>
|
||||||
|
{errors.llm_id.message}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Controller
|
||||||
|
name="embd_id"
|
||||||
|
control={control}
|
||||||
|
rules={{ required: '嵌入模型是必填项' }}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormControl fullWidth margin="normal" error={!!errors.embd_id}>
|
||||||
|
<InputLabel>嵌入模型</InputLabel>
|
||||||
|
<Select {...field} label="嵌入模型">
|
||||||
|
{embdOptions.map((group) => [
|
||||||
|
<ListSubheader key={group.label}>{group.label}</ListSubheader>,
|
||||||
|
...group.options.map((option) => (
|
||||||
|
<MenuItem key={option.value} value={option.value} disabled={option.disabled}>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||||
|
<LlmSvgIcon
|
||||||
|
name={getFactoryIconName(group.label as LLMFactory)}
|
||||||
|
sx={{ width: 20, height: 20, color: 'primary.main' }}
|
||||||
|
/>
|
||||||
|
{option.label}
|
||||||
|
</Box>
|
||||||
|
</MenuItem>
|
||||||
|
))
|
||||||
|
])}
|
||||||
|
</Select>
|
||||||
|
{errors.embd_id && (
|
||||||
|
<Typography variant="caption" color="error" sx={{ mt: 1, ml: 2 }}>
|
||||||
|
{errors.embd_id.message}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Controller
|
||||||
|
name="img2txt_id"
|
||||||
|
control={control}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormControl fullWidth margin="normal">
|
||||||
|
<InputLabel>Img2txt模型</InputLabel>
|
||||||
|
<Select {...field} label="Img2txt模型">
|
||||||
|
{img2txtOptions.map((group) => [
|
||||||
|
<ListSubheader key={group.label}>{group.label}</ListSubheader>,
|
||||||
|
...group.options.map((option) => (
|
||||||
|
<MenuItem key={option.value} value={option.value} disabled={option.disabled}>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||||
|
<LlmSvgIcon
|
||||||
|
name={getFactoryIconName(group.label as LLMFactory)}
|
||||||
|
sx={{ width: 20, height: 20, color: 'primary.main' }}
|
||||||
|
/>
|
||||||
|
{option.label}
|
||||||
|
</Box>
|
||||||
|
</MenuItem>
|
||||||
|
))
|
||||||
|
])}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Controller
|
||||||
|
name="asr_id"
|
||||||
|
control={control}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormControl fullWidth margin="normal">
|
||||||
|
<InputLabel>Speech2txt模型</InputLabel>
|
||||||
|
<Select {...field} label="Speech2txt模型">
|
||||||
|
{asrOptions.map((group) => [
|
||||||
|
<ListSubheader key={group.label}>{group.label}</ListSubheader>,
|
||||||
|
...group.options.map((option) => (
|
||||||
|
<MenuItem key={option.value} value={option.value} disabled={option.disabled}>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||||
|
<LlmSvgIcon
|
||||||
|
name={getFactoryIconName(group.label as LLMFactory)}
|
||||||
|
sx={{ width: 20, height: 20, color: 'primary.main' }}
|
||||||
|
/>
|
||||||
|
{option.label}
|
||||||
|
</Box>
|
||||||
|
</MenuItem>
|
||||||
|
))
|
||||||
|
])}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Controller
|
||||||
|
name="rerank_id"
|
||||||
|
control={control}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormControl fullWidth margin="normal">
|
||||||
|
<InputLabel>Rerank模型</InputLabel>
|
||||||
|
<Select {...field} label="Rerank模型">
|
||||||
|
{rerankOptions.map((group) => [
|
||||||
|
<ListSubheader key={group.label}>{group.label}</ListSubheader>,
|
||||||
|
...group.options.map((option) => (
|
||||||
|
<MenuItem key={option.value} value={option.value} disabled={option.disabled}>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||||
|
<LlmSvgIcon
|
||||||
|
name={getFactoryIconName(group.label as LLMFactory)}
|
||||||
|
sx={{ width: 20, height: 20, color: 'primary.main' }}
|
||||||
|
/>
|
||||||
|
{option.label}
|
||||||
|
</Box>
|
||||||
|
</MenuItem>
|
||||||
|
))
|
||||||
|
])}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Controller
|
||||||
|
name="tts_id"
|
||||||
|
control={control}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormControl fullWidth margin="normal">
|
||||||
|
<InputLabel>TTS模型</InputLabel>
|
||||||
|
<Select {...field} label="TTS模型">
|
||||||
|
{ttsOptions.map((group) => [
|
||||||
|
<ListSubheader key={group.label}>{group.label}</ListSubheader>,
|
||||||
|
...group.options.map((option) => (
|
||||||
|
<MenuItem key={option.value} value={option.value} disabled={option.disabled}>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||||
|
<LlmSvgIcon
|
||||||
|
name={getFactoryIconName(group.label as LLMFactory)}
|
||||||
|
sx={{ width: 20, height: 20, color: 'primary.main' }}
|
||||||
|
/>
|
||||||
|
{option.label}
|
||||||
|
</Box>
|
||||||
|
</MenuItem>
|
||||||
|
))
|
||||||
|
])}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={onClose} disabled={loading}>
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={handleSubmit(handleFormSubmit)}
|
||||||
|
variant="contained"
|
||||||
|
disabled={loading}
|
||||||
|
startIcon={loading ? <CircularProgress size={20} /> : null}
|
||||||
|
>
|
||||||
|
确定
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型对话框整合组件
|
||||||
|
*/
|
||||||
|
export const ModelDialogs: React.FC<ModelDialogsProps> = ({
|
||||||
|
apiKeyDialog,
|
||||||
|
azureDialog,
|
||||||
|
bedrockDialog,
|
||||||
|
ollamaDialog,
|
||||||
|
systemDialog,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* API Key 对话框 */}
|
||||||
|
<ApiKeyDialog
|
||||||
|
open={apiKeyDialog.open}
|
||||||
|
onClose={apiKeyDialog.closeDialog}
|
||||||
|
onSubmit={apiKeyDialog.submitApiKey}
|
||||||
|
loading={apiKeyDialog.loading}
|
||||||
|
factoryName={apiKeyDialog.factoryName}
|
||||||
|
initialData={apiKeyDialog.initialData}
|
||||||
|
editMode={apiKeyDialog!.editMode}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Azure OpenAI 对话框 */}
|
||||||
|
<AzureOpenAIDialog
|
||||||
|
open={azureDialog.open}
|
||||||
|
onClose={azureDialog.closeDialog}
|
||||||
|
onSubmit={azureDialog.submitAzureOpenAI}
|
||||||
|
loading={azureDialog.loading}
|
||||||
|
initialData={azureDialog.initialData}
|
||||||
|
editMode={azureDialog.editMode}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* AWS Bedrock 对话框 */}
|
||||||
|
<BedrockDialog
|
||||||
|
open={bedrockDialog.open}
|
||||||
|
onClose={bedrockDialog.closeDialog}
|
||||||
|
onSubmit={bedrockDialog.submitBedrock}
|
||||||
|
loading={bedrockDialog.loading}
|
||||||
|
initialData={bedrockDialog.initialData}
|
||||||
|
editMode={bedrockDialog.editMode}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Ollama 对话框 */}
|
||||||
|
<OllamaDialog
|
||||||
|
open={ollamaDialog.open}
|
||||||
|
onClose={ollamaDialog.closeDialog}
|
||||||
|
onSubmit={ollamaDialog.submitOllama}
|
||||||
|
loading={ollamaDialog.loading}
|
||||||
|
initialData={ollamaDialog.initialData}
|
||||||
|
editMode={ollamaDialog.editMode}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* 系统默认模型设置对话框 */}
|
||||||
|
<SystemModelDialog
|
||||||
|
open={systemDialog.open}
|
||||||
|
onClose={systemDialog.closeDialog}
|
||||||
|
onSubmit={systemDialog.submitSystemModelSetting}
|
||||||
|
loading={systemDialog.loading}
|
||||||
|
initialData={systemDialog.initialData}
|
||||||
|
editMode={systemDialog.editMode}
|
||||||
|
allModelOptions={systemDialog.allModelOptions}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useCallback } from 'react';
|
import { useState, useCallback, useMemo } 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';
|
||||||
@@ -8,6 +8,9 @@ import type {
|
|||||||
BedrockFormData,
|
BedrockFormData,
|
||||||
OllamaFormData,
|
OllamaFormData,
|
||||||
} from '../components/ModelDialogs';
|
} from '../components/ModelDialogs';
|
||||||
|
import type { ITenantInfo } from '@/interfaces/database/knowledge';
|
||||||
|
import { useLlmList } from '@/hooks/llm-hooks';
|
||||||
|
import type { LlmModelType } from '@/constants/knowledge';
|
||||||
|
|
||||||
// 对话框状态管理 hook
|
// 对话框状态管理 hook
|
||||||
export const useDialogState = () => {
|
export const useDialogState = () => {
|
||||||
@@ -42,7 +45,7 @@ export const useDialogState = () => {
|
|||||||
// API Key 对话框管理
|
// API Key 对话框管理
|
||||||
export const useApiKeyDialog = () => {
|
export const useApiKeyDialog = () => {
|
||||||
const dialogState = useDialogState();
|
const dialogState = useDialogState();
|
||||||
const showMessage = useMessage();
|
const showMessage = useMessage();
|
||||||
const [factoryName, setFactoryName] = useState('');
|
const [factoryName, setFactoryName] = useState('');
|
||||||
|
|
||||||
const openApiKeyDialog = useCallback((factory: string, data?: Partial<ApiKeyFormData>, isEdit = false) => {
|
const openApiKeyDialog = useCallback((factory: string, data?: Partial<ApiKeyFormData>, isEdit = false) => {
|
||||||
@@ -81,7 +84,7 @@ export const useApiKeyDialog = () => {
|
|||||||
// Azure OpenAI 对话框管理
|
// Azure OpenAI 对话框管理
|
||||||
export const useAzureOpenAIDialog = () => {
|
export const useAzureOpenAIDialog = () => {
|
||||||
const dialogState = useDialogState();
|
const dialogState = useDialogState();
|
||||||
const showMessage = useMessage();
|
const showMessage = useMessage();
|
||||||
|
|
||||||
const submitAzureOpenAI = useCallback(async (data: AzureOpenAIFormData) => {
|
const submitAzureOpenAI = useCallback(async (data: AzureOpenAIFormData) => {
|
||||||
dialogState.setLoading(true);
|
dialogState.setLoading(true);
|
||||||
@@ -114,7 +117,7 @@ export const useAzureOpenAIDialog = () => {
|
|||||||
// AWS Bedrock 对话框管理
|
// AWS Bedrock 对话框管理
|
||||||
export const useBedrockDialog = () => {
|
export const useBedrockDialog = () => {
|
||||||
const dialogState = useDialogState();
|
const dialogState = useDialogState();
|
||||||
const showMessage = useMessage();
|
const showMessage = useMessage();
|
||||||
|
|
||||||
const submitBedrock = useCallback(async (data: BedrockFormData) => {
|
const submitBedrock = useCallback(async (data: BedrockFormData) => {
|
||||||
dialogState.setLoading(true);
|
dialogState.setLoading(true);
|
||||||
@@ -148,7 +151,7 @@ export const useBedrockDialog = () => {
|
|||||||
// Ollama 对话框管理
|
// Ollama 对话框管理
|
||||||
export const useOllamaDialog = () => {
|
export const useOllamaDialog = () => {
|
||||||
const dialogState = useDialogState();
|
const dialogState = useDialogState();
|
||||||
const showMessage = useMessage();
|
const showMessage = useMessage();
|
||||||
|
|
||||||
const submitOllama = useCallback(async (data: OllamaFormData) => {
|
const submitOllama = useCallback(async (data: OllamaFormData) => {
|
||||||
dialogState.setLoading(true);
|
dialogState.setLoading(true);
|
||||||
@@ -178,7 +181,7 @@ export const useOllamaDialog = () => {
|
|||||||
|
|
||||||
// 删除操作管理
|
// 删除操作管理
|
||||||
export const useDeleteOperations = () => {
|
export const useDeleteOperations = () => {
|
||||||
const showMessage = useMessage();
|
const showMessage = useMessage();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const deleteLlm = useCallback(async (factoryName: string, modelName: string) => {
|
const deleteLlm = useCallback(async (factoryName: string, modelName: string) => {
|
||||||
@@ -224,9 +227,56 @@ export const useDeleteOperations = () => {
|
|||||||
// 系统默认模型设置
|
// 系统默认模型设置
|
||||||
export const useSystemModelSetting = () => {
|
export const useSystemModelSetting = () => {
|
||||||
const dialogState = useDialogState();
|
const dialogState = useDialogState();
|
||||||
const showMessage = useMessage();
|
const showMessage = useMessage();
|
||||||
|
|
||||||
const submitSystemModelSetting = useCallback(async (data: { defaultModel: string }) => {
|
const { data: llmList } = useLlmList();
|
||||||
|
|
||||||
|
const getOptionsByModelType = useCallback((modelType: LlmModelType) => {
|
||||||
|
return Object.entries(llmList)
|
||||||
|
.filter(([, value]) =>
|
||||||
|
modelType
|
||||||
|
? value.some((x) => x.model_type.includes(modelType))
|
||||||
|
: true,
|
||||||
|
)
|
||||||
|
.map(([key, value]) => {
|
||||||
|
return {
|
||||||
|
label: key,
|
||||||
|
options: value
|
||||||
|
.filter(
|
||||||
|
(x) =>
|
||||||
|
(modelType ? x.model_type.includes(modelType) : true) &&
|
||||||
|
x.available,
|
||||||
|
)
|
||||||
|
.map((x) => ({
|
||||||
|
label: x.llm_name,
|
||||||
|
value: `${x.llm_name}@${x.fid}`,
|
||||||
|
disabled: !x.available,
|
||||||
|
model: x,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter((x) => x.options.length > 0);
|
||||||
|
}, [llmList]);
|
||||||
|
|
||||||
|
const allModelOptions = useMemo(() => {
|
||||||
|
const llmOptions = getOptionsByModelType('chat');
|
||||||
|
const image2textOptions = getOptionsByModelType('image2text');
|
||||||
|
const embeddingOptions = getOptionsByModelType('embedding');
|
||||||
|
const speech2textOptions = getOptionsByModelType('speech2text');
|
||||||
|
const rerankOptions = getOptionsByModelType('rerank');
|
||||||
|
const ttsOptions = getOptionsByModelType('tts');
|
||||||
|
|
||||||
|
return {
|
||||||
|
llmOptions,
|
||||||
|
image2textOptions,
|
||||||
|
embeddingOptions,
|
||||||
|
speech2textOptions,
|
||||||
|
rerankOptions,
|
||||||
|
ttsOptions,
|
||||||
|
}
|
||||||
|
}, [llmList, getOptionsByModelType]);
|
||||||
|
|
||||||
|
const submitSystemModelSetting = useCallback(async (data: Partial<ITenantInfo>) => {
|
||||||
dialogState.setLoading(true);
|
dialogState.setLoading(true);
|
||||||
try {
|
try {
|
||||||
// 这里需要根据实际的 API 接口调整
|
// 这里需要根据实际的 API 接口调整
|
||||||
@@ -245,6 +295,7 @@ export const useSystemModelSetting = () => {
|
|||||||
return {
|
return {
|
||||||
...dialogState,
|
...dialogState,
|
||||||
submitSystemModelSetting,
|
submitSystemModelSetting,
|
||||||
|
allModelOptions,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import AppSvgIcon, { LlmSvgIcon } from '@/components/AppSvgIcon';
|
|||||||
import { LLM_FACTORY_LIST, IconMap, type LLMFactory } from '@/constants/llm';
|
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';
|
||||||
|
|
||||||
|
|
||||||
// 主页面组件
|
// 主页面组件
|
||||||
@@ -90,13 +91,25 @@ function ModelsPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ p: 3 }}>
|
<Box sx={{ p: 3 }}>
|
||||||
<Typography variant="h4" gutterBottom>
|
<Box mb={4} sx={{
|
||||||
模型设置
|
display: 'flex',
|
||||||
</Typography>
|
flexDirection: 'row',
|
||||||
<Typography variant="body1" color="text.secondary" gutterBottom>
|
alignItems: 'center',
|
||||||
管理您的 LLM 模型工厂和个人模型配置
|
justifyContent: 'space-between',
|
||||||
</Typography>
|
}}>
|
||||||
|
<Box>
|
||||||
|
<Typography variant="h4" gutterBottom>
|
||||||
|
模型设置
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body1" color="text.secondary" gutterBottom>
|
||||||
|
管理您的 LLM 模型工厂和个人模型配置
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
{/* 设置默认模型 */}
|
||||||
|
<Button variant="contained" color="primary" onClick={() => modelDialogs.systemDialog.openDialog()}>
|
||||||
|
设置默认模型
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
{/* My LLM 部分 */}
|
{/* My LLM 部分 */}
|
||||||
<Box mb={4} mt={2}>
|
<Box mb={4} mt={2}>
|
||||||
{!myLlm || Object.keys(myLlm).length === 0 ? (
|
{!myLlm || Object.keys(myLlm).length === 0 ? (
|
||||||
@@ -197,7 +210,6 @@ function ModelsPage() {
|
|||||||
<Typography variant="h5" gutterBottom>
|
<Typography variant="h5" gutterBottom>
|
||||||
LLM 模型工厂
|
LLM 模型工厂
|
||||||
</Typography>
|
</Typography>
|
||||||
<AppSvgIcon name='arxiv' />
|
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails>
|
<AccordionDetails>
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
@@ -218,7 +230,7 @@ function ModelsPage() {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* 模型配置对话框 */}
|
{/* 模型配置对话框 */}
|
||||||
{/* <ModelDialogs {...modelDialogs} /> */}
|
<ModelDialogs {...modelDialogs} />
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user