mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
Refactor(setting-model): Refactor the model management interface and optimize the component structure. #10703 (#10905)
### What problem does this PR solve? Refactor(setting-model): Refactor the model management interface and optimize the component structure. #10703 ### Type of change - [x] Refactoring
This commit is contained in:
@ -31,9 +31,16 @@ export function TemplateCard({ data, showModal }: IProps) {
|
||||
avatar={data.avatar ? data.avatar : 'https://github.com/shadcn.png'}
|
||||
name={data?.title[language] || 'CN'}
|
||||
></RAGFlowAvatar>
|
||||
<div className="text-[18px] font-bold break-words hyphens-auto overflow-hidden"lang={language}>{data?.title[language]}</div>
|
||||
<div
|
||||
className="text-[18px] font-bold break-words hyphens-auto overflow-hidden"
|
||||
lang={language}
|
||||
>
|
||||
{data?.title[language]}
|
||||
</div>
|
||||
</div>
|
||||
<p className="break-words hypens-auto"lang={language}>{data?.description[language]}</p>
|
||||
<p className="break-words hypens-auto" lang={language}>
|
||||
{data?.description[language]}
|
||||
</p>
|
||||
<div className="group-hover:bg-gradient-to-t from-black/70 from-10% via-black/0 via-50% to-black/0 w-full h-full group-hover:block absolute top-0 left-0 hidden rounded-xl">
|
||||
<Button
|
||||
variant="default"
|
||||
|
||||
@ -0,0 +1,173 @@
|
||||
// src/components/ModelProviderCard.tsx
|
||||
import { LlmIcon } from '@/components/svg-icon';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useSetModalState, useTranslate } from '@/hooks/common-hooks';
|
||||
import { LlmItem } from '@/hooks/llm-hooks';
|
||||
import { getRealModelName } from '@/utils/llm-util';
|
||||
import { EditOutlined, SettingOutlined } from '@ant-design/icons';
|
||||
import { ChevronsDown, ChevronsUp, Trash2 } from 'lucide-react';
|
||||
import { FC } from 'react';
|
||||
import { isLocalLlmFactory } from '../../utils';
|
||||
import { useHandleDeleteFactory, useHandleDeleteLlm } from '../hooks';
|
||||
|
||||
interface IModelCardProps {
|
||||
item: LlmItem;
|
||||
clickApiKey: (llmFactory: string) => void;
|
||||
handleEditModel: (model: any, factory: LlmItem) => void;
|
||||
}
|
||||
|
||||
type TagType =
|
||||
| 'LLM'
|
||||
| 'TEXT EMBEDDING'
|
||||
| 'TEXT RE-RANK'
|
||||
| 'TTS'
|
||||
| 'SPEECH2TEXT'
|
||||
| 'IMAGE2TEXT'
|
||||
| 'MODERATION';
|
||||
|
||||
const sortTags = (tags: string) => {
|
||||
const orderMap: Record<TagType, number> = {
|
||||
LLM: 1,
|
||||
'TEXT EMBEDDING': 2,
|
||||
'TEXT RE-RANK': 3,
|
||||
TTS: 4,
|
||||
SPEECH2TEXT: 5,
|
||||
IMAGE2TEXT: 6,
|
||||
MODERATION: 7,
|
||||
};
|
||||
|
||||
return tags
|
||||
.split(',')
|
||||
.map((tag) => tag.trim())
|
||||
.sort(
|
||||
(a, b) =>
|
||||
(orderMap[a as TagType] || 999) - (orderMap[b as TagType] || 999),
|
||||
);
|
||||
};
|
||||
|
||||
export const ModelProviderCard: FC<IModelCardProps> = ({
|
||||
item,
|
||||
clickApiKey,
|
||||
handleEditModel,
|
||||
}) => {
|
||||
const { visible, switchVisible } = useSetModalState();
|
||||
const { t } = useTranslate('setting');
|
||||
const { handleDeleteLlm } = useHandleDeleteLlm(item.name);
|
||||
const { handleDeleteFactory } = useHandleDeleteFactory(item.name);
|
||||
|
||||
const handleApiKeyClick = () => {
|
||||
clickApiKey(item.name);
|
||||
};
|
||||
|
||||
const handleShowMoreClick = () => {
|
||||
switchVisible();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`w-full rounded-lg border border-border-default`}>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 cursor-pointer transition-colors">
|
||||
<div className="flex items-center space-x-3">
|
||||
<LlmIcon name={item.name} />
|
||||
<div>
|
||||
<h3 className="font-medium">{item.name}</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleApiKeyClick();
|
||||
}}
|
||||
className="px-3 py-1 text-sm bg-bg-input hover:bg-bg-input text-text-primary rounded-md transition-colors flex items-center space-x-1"
|
||||
>
|
||||
<SettingOutlined />
|
||||
<span>
|
||||
{isLocalLlmFactory(item.name) ? t('addTheModel') : 'API-Key'}
|
||||
</span>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleShowMoreClick();
|
||||
}}
|
||||
className="px-3 py-1 text-sm bg-bg-input hover:bg-bg-input text-text-primary rounded-md transition-colors flex items-center space-x-1"
|
||||
>
|
||||
<span>{visible ? t('hideModels') : t('showMoreModels')}</span>
|
||||
{visible ? <ChevronsDown /> : <ChevronsUp />}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant={'secondary'}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleDeleteFactory();
|
||||
}}
|
||||
className="p-1 text-text-primary hover:text-state-error transition-colors"
|
||||
>
|
||||
<Trash2 />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
{visible && (
|
||||
<div className="">
|
||||
<div className="px-4 flex flex-wrap gap-1 mt-1">
|
||||
{sortTags(item.tags).map((tag, index) => (
|
||||
<span
|
||||
key={index}
|
||||
className="px-2 py-1 text-xs bg-bg-card text-text-secondary rounded-md"
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<div className="m-4 bg-bg-card rounded-lg max-h-96 overflow-auto scrollbar-auto">
|
||||
<div className="">
|
||||
{item.llm.map((model) => (
|
||||
<div
|
||||
key={model.name}
|
||||
className="flex items-center border-b border-border-default justify-between p-3 hover:bg-bg-card transition-colors"
|
||||
>
|
||||
<div className="flex items-center space-x-3">
|
||||
<span className="font-medium">
|
||||
{getRealModelName(model.name)}
|
||||
</span>
|
||||
<span className="px-2 py-1 text-xs bg-bg-card text-text-secondary rounded-md">
|
||||
{model.type}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
{isLocalLlmFactory(item.name) && (
|
||||
<Button
|
||||
variant={'secondary'}
|
||||
onClick={() => handleEditModel(model, item)}
|
||||
className="p-1 text-text-primary transition-colors"
|
||||
>
|
||||
<EditOutlined />
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant={'secondary'}
|
||||
onClick={() => {
|
||||
handleDeleteLlm(model.name);
|
||||
console.log(handleDeleteLlm, model.name);
|
||||
}}
|
||||
className="p-1 hover:text-state-error transition-colors"
|
||||
>
|
||||
<Trash2 />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,194 @@
|
||||
import {
|
||||
SelectWithSearch,
|
||||
SelectWithSearchFlagOptionType,
|
||||
} from '@/components/originui/select-with-search';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from '@/components/ui/tooltip';
|
||||
import { LlmModelType } from '@/constants/knowledge';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import {
|
||||
ISystemModelSettingSavingParams,
|
||||
useComposeLlmOptionsByModelTypes,
|
||||
} from '@/hooks/llm-hooks';
|
||||
import { CircleQuestionMark } from 'lucide-react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useFetchSystemModelSettingOnMount } from '../hooks';
|
||||
|
||||
interface IProps {
|
||||
loading: boolean;
|
||||
onOk: (
|
||||
payload: Omit<ISystemModelSettingSavingParams, 'tenant_id' | 'name'>,
|
||||
) => void;
|
||||
}
|
||||
|
||||
const SystemSetting = ({ onOk, loading }: IProps) => {
|
||||
const { systemSetting: initialValues, allOptions } =
|
||||
useFetchSystemModelSettingOnMount();
|
||||
const { t } = useTranslate('setting');
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
llm_id: '',
|
||||
embd_id: '',
|
||||
img2txt_id: '',
|
||||
asr_id: '',
|
||||
rerank_id: '',
|
||||
tts_id: '',
|
||||
});
|
||||
|
||||
const handleFieldChange = useCallback(
|
||||
(field: string, value: string) => {
|
||||
const updatedData = { ...formData, [field]: value || '' };
|
||||
setFormData(updatedData);
|
||||
console.log('updatedData', updatedData);
|
||||
onOk(updatedData);
|
||||
},
|
||||
[formData, onOk],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setFormData({
|
||||
llm_id: initialValues.llm_id ?? '',
|
||||
embd_id: initialValues.embd_id ?? '',
|
||||
img2txt_id: initialValues.img2txt_id ?? '',
|
||||
asr_id: initialValues.asr_id ?? '',
|
||||
rerank_id: initialValues.rerank_id ?? '',
|
||||
tts_id: initialValues.tts_id ?? '',
|
||||
});
|
||||
}, [initialValues]);
|
||||
|
||||
const modelOptions = useComposeLlmOptionsByModelTypes([
|
||||
LlmModelType.Chat,
|
||||
LlmModelType.Image2text,
|
||||
]);
|
||||
|
||||
const llmList = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
id: 'llm_id',
|
||||
label: t('chatModel'),
|
||||
isRequired: true,
|
||||
value: formData.llm_id,
|
||||
options: modelOptions as SelectWithSearchFlagOptionType[],
|
||||
tooltip: t('chatModelTip'),
|
||||
},
|
||||
{
|
||||
id: 'embd_id',
|
||||
label: t('embeddingModel'),
|
||||
value: formData.embd_id,
|
||||
options: allOptions[
|
||||
LlmModelType.Embedding
|
||||
] as SelectWithSearchFlagOptionType[],
|
||||
tooltip: t('embeddingModelTip'),
|
||||
},
|
||||
{
|
||||
id: 'img2txt_id',
|
||||
label: t('img2txtModel'),
|
||||
value: formData.img2txt_id,
|
||||
options: allOptions[
|
||||
LlmModelType.Image2text
|
||||
] as SelectWithSearchFlagOptionType[],
|
||||
tooltip: t('img2txtModelTip'),
|
||||
},
|
||||
{
|
||||
id: 'asr_id',
|
||||
label: t('sequence2txtModel'),
|
||||
value: formData.asr_id,
|
||||
options: allOptions[
|
||||
LlmModelType.Speech2text
|
||||
] as SelectWithSearchFlagOptionType[],
|
||||
tooltip: t('sequence2txtModelTip'),
|
||||
},
|
||||
{
|
||||
id: 'rerank_id',
|
||||
label: t('rerankModel'),
|
||||
value: formData.rerank_id,
|
||||
options: allOptions[
|
||||
LlmModelType.Rerank
|
||||
] as SelectWithSearchFlagOptionType[],
|
||||
tooltip: t('rerankModelTip'),
|
||||
},
|
||||
{
|
||||
id: 'tts_id',
|
||||
label: t('ttsModel'),
|
||||
value: formData.tts_id,
|
||||
options: allOptions[
|
||||
LlmModelType.TTS
|
||||
] as SelectWithSearchFlagOptionType[],
|
||||
tooltip: t('ttsModelTip'),
|
||||
},
|
||||
];
|
||||
}, [formData, modelOptions, t, allOptions]);
|
||||
|
||||
const Items = ({
|
||||
label,
|
||||
value,
|
||||
options,
|
||||
tooltip,
|
||||
id,
|
||||
isRequired,
|
||||
}: {
|
||||
id: string;
|
||||
label: string;
|
||||
value: string;
|
||||
options: SelectWithSearchFlagOptionType[];
|
||||
tooltip?: string;
|
||||
isRequired?: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex gap-3">
|
||||
<label className="block text-sm font-medium text-text-primary mb-1 w-1/4">
|
||||
{isRequired && <span className="text-red-500">*</span>}
|
||||
{label}
|
||||
{tooltip && (
|
||||
<Tooltip>
|
||||
<TooltipContent>{tooltip}</TooltipContent>
|
||||
<TooltipTrigger>
|
||||
<CircleQuestionMark
|
||||
size={12}
|
||||
className="ml-1 text-text-disabled text-xs"
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
</Tooltip>
|
||||
)}
|
||||
</label>
|
||||
<SelectWithSearch
|
||||
triggerClassName="w-3/4"
|
||||
value={value}
|
||||
options={options}
|
||||
onChange={(value) => handleFieldChange(id, value)}
|
||||
placeholder={t('common:selectPlaceholder')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="rounded-lg w-full">
|
||||
<div className="flex flex-col py-4">
|
||||
<div className="text-2xl font-semibold">{t('systemModelSettings')}</div>
|
||||
<div className="text-sm text-text-secondary">
|
||||
{t('systemModelDescription')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-7 py-6 space-y-6 max-h-[70vh] overflow-y-auto border rounded-lg">
|
||||
{llmList.map((item) => (
|
||||
<Items key={item.id} {...item} />
|
||||
))}
|
||||
</div>
|
||||
{/* <div className="border-t px-6 py-4 flex justify-end">
|
||||
<Button
|
||||
onClick={hideModal}
|
||||
disabled={loading}
|
||||
className="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
|
||||
>
|
||||
{t('common:cancel')}
|
||||
</Button>
|
||||
</div> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SystemSetting;
|
||||
@ -0,0 +1,157 @@
|
||||
// src/components/AvailableModels.tsx
|
||||
import { LlmIcon } from '@/components/svg-icon';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { useSelectLlmList } from '@/hooks/llm-hooks';
|
||||
import { Plus, Search } from 'lucide-react';
|
||||
import { FC, useMemo, useState } from 'react';
|
||||
|
||||
type TagType =
|
||||
| 'LLM'
|
||||
| 'TEXT EMBEDDING'
|
||||
| 'TEXT RE-RANK'
|
||||
| 'TTS'
|
||||
| 'SPEECH2TEXT'
|
||||
| 'IMAGE2TEXT'
|
||||
| 'MODERATION';
|
||||
|
||||
const sortTags = (tags: string) => {
|
||||
const orderMap: Record<TagType, number> = {
|
||||
LLM: 1,
|
||||
'TEXT EMBEDDING': 2,
|
||||
'TEXT RE-RANK': 3,
|
||||
TTS: 4,
|
||||
SPEECH2TEXT: 5,
|
||||
IMAGE2TEXT: 6,
|
||||
MODERATION: 7,
|
||||
};
|
||||
|
||||
return tags
|
||||
.split(',')
|
||||
.map((tag) => tag.trim())
|
||||
.sort(
|
||||
(a, b) =>
|
||||
(orderMap[a as TagType] || 999) - (orderMap[b as TagType] || 999),
|
||||
);
|
||||
};
|
||||
|
||||
export const AvailableModels: FC<{
|
||||
handleAddModel: (factory: string) => void;
|
||||
}> = ({ handleAddModel }) => {
|
||||
const { t } = useTranslate('setting');
|
||||
const { factoryList } = useSelectLlmList();
|
||||
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [selectedTag, setSelectedTag] = useState<string | null>(null);
|
||||
|
||||
// 过滤模型列表
|
||||
const filteredModels = useMemo(() => {
|
||||
return factoryList.filter((model) => {
|
||||
const matchesSearch = model.name
|
||||
.toLowerCase()
|
||||
.includes(searchTerm.toLowerCase());
|
||||
const matchesTag =
|
||||
selectedTag === null ||
|
||||
model.tags.split(',').some((tag) => tag.trim() === selectedTag);
|
||||
return matchesSearch && matchesTag;
|
||||
});
|
||||
}, [factoryList, searchTerm, selectedTag]);
|
||||
|
||||
// 获取所有唯一的标签
|
||||
const allTags = useMemo(() => {
|
||||
const tagsSet = new Set<string>();
|
||||
factoryList.forEach((model) => {
|
||||
model.tags.split(',').forEach((tag) => tagsSet.add(tag.trim()));
|
||||
});
|
||||
return Array.from(tagsSet).sort();
|
||||
}, [factoryList]);
|
||||
|
||||
const handleTagClick = (tag: string) => {
|
||||
setSelectedTag(selectedTag === tag ? null : tag);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className=" text-text-primary h-full p-4">
|
||||
<div className="text-text-primary text-base mb-4">
|
||||
{t('availableModels')}
|
||||
</div>
|
||||
{/* Search Bar */}
|
||||
<div className="mb-6">
|
||||
<div className="relative">
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t('search')}
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="w-full px-4 py-3 pl-10 bg-bg-input border border-border-default rounded-lg focus:outline-none focus:ring-1 focus:ring-border-button transition-colors"
|
||||
/>
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-text-secondary" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tags Filter */}
|
||||
<div className="flex flex-wrap gap-2 mb-6">
|
||||
<Button
|
||||
variant={'secondary'}
|
||||
onClick={() => setSelectedTag(null)}
|
||||
className={`px-1 py-1 text-xs rounded-md bg-bg-card bg-bg-card h-5 transition-colors ${
|
||||
selectedTag === null
|
||||
? ' text-text-primary border border-text-primary'
|
||||
: 'text-text-secondary bg-bg-input border-none'
|
||||
}`}
|
||||
>
|
||||
All
|
||||
</Button>
|
||||
{allTags.map((tag) => (
|
||||
<Button
|
||||
variant={'secondary'}
|
||||
key={tag}
|
||||
onClick={() => handleTagClick(tag)}
|
||||
className={`px-1 py-1 text-xs rounded-md bg-bg-card h-5 transition-colors ${
|
||||
selectedTag === tag
|
||||
? ' text-text-primary border border-text-primary'
|
||||
: 'text-text-secondary border-none'
|
||||
}`}
|
||||
>
|
||||
{tag}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Models List */}
|
||||
<div className="flex flex-col gap-4 overflow-auto h-[calc(100vh-300px)] scrollbar-auto">
|
||||
{filteredModels.map((model) => (
|
||||
<div
|
||||
key={model.name}
|
||||
className=" border border-border-default rounded-lg p-3 hover:bg-bg-input transition-colors"
|
||||
>
|
||||
<div className="flex items-center space-x-3 mb-3">
|
||||
<LlmIcon name={model.name} imgClass="h-8 w-auto" />
|
||||
<div className="flex-1">
|
||||
<h3 className="font-medium truncate">{model.name}</h3>
|
||||
</div>
|
||||
<Button
|
||||
className=" px-2 flex items-center gap-0 text-xs h-6 rounded-md transition-colors"
|
||||
onClick={() => handleAddModel(model.name)}
|
||||
>
|
||||
<Plus size={12} />
|
||||
{t('addTheModel')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap gap-1 mb-3">
|
||||
{sortTags(model.tags).map((tag, index) => (
|
||||
<span
|
||||
key={index}
|
||||
className="px-1 flex items-center h-5 text-xs bg-bg-card text-text-secondary rounded-md"
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,27 @@
|
||||
import { LlmItem, useSelectLlmList } from '@/hooks/llm-hooks';
|
||||
import { ModelProviderCard } from './modal-card';
|
||||
|
||||
export const UsedModel = ({
|
||||
handleAddModel,
|
||||
handleEditModel,
|
||||
}: {
|
||||
handleAddModel: (factory: string) => void;
|
||||
handleEditModel: (model: any, factory: LlmItem) => void;
|
||||
}) => {
|
||||
const { factoryList, myLlmList: llmList, loading } = useSelectLlmList();
|
||||
return (
|
||||
<div className="flex flex-col w-full">
|
||||
<div className="text-text-primary text-2xl mb-4 mt-4">Added models</div>
|
||||
{llmList.map((llm) => {
|
||||
return (
|
||||
<ModelProviderCard
|
||||
key={llm.name}
|
||||
item={llm}
|
||||
clickApiKey={handleAddModel}
|
||||
handleEditModel={handleEditModel}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -3,8 +3,6 @@
|
||||
.factoryOperationWrapper {
|
||||
text-align: right;
|
||||
}
|
||||
.modelItem {
|
||||
}
|
||||
.llmList {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
@ -1,47 +1,16 @@
|
||||
import { ReactComponent as MoreModelIcon } from '@/assets/svg/more-model.svg';
|
||||
import { LlmIcon } from '@/components/svg-icon';
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { LLMFactory } from '@/constants/llm';
|
||||
import { useSetModalState, useTranslate } from '@/hooks/common-hooks';
|
||||
import {
|
||||
LlmItem,
|
||||
useFetchMyLlmListDetailed,
|
||||
useSelectLlmList,
|
||||
} from '@/hooks/llm-hooks';
|
||||
import { getRealModelName } from '@/utils/llm-util';
|
||||
import {
|
||||
CloseCircleOutlined,
|
||||
EditOutlined,
|
||||
SettingOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Col,
|
||||
Collapse,
|
||||
CollapseProps,
|
||||
Divider,
|
||||
Flex,
|
||||
List,
|
||||
Row,
|
||||
Space,
|
||||
Spin,
|
||||
Tag,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import { CircleHelp } from 'lucide-react';
|
||||
import { LlmItem, useFetchMyLlmListDetailed } from '@/hooks/llm-hooks';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import SettingTitle from '../components/setting-title';
|
||||
import { isLocalLlmFactory } from '../utils';
|
||||
import ApiKeyModal from './api-key-modal';
|
||||
import AzureOpenAIModal from './azure-openai-modal';
|
||||
import BedrockModal from './bedrock-modal';
|
||||
import SystemSetting from './components/system-setting';
|
||||
import { AvailableModels } from './components/un-add-model';
|
||||
import { UsedModel } from './components/used-model';
|
||||
import FishAudioModal from './fish-audio-modal';
|
||||
import GoogleModal from './google-modal';
|
||||
import {
|
||||
useHandleDeleteFactory,
|
||||
useHandleDeleteLlm,
|
||||
useSubmitApiKey,
|
||||
useSubmitAzure,
|
||||
useSubmitBedrock,
|
||||
@ -56,164 +25,15 @@ import {
|
||||
useSubmityiyan,
|
||||
} from './hooks';
|
||||
import HunyuanModal from './hunyuan-modal';
|
||||
import styles from './index.less';
|
||||
import TencentCloudModal from './next-tencent-modal';
|
||||
import OllamaModal from './ollama-modal';
|
||||
import SparkModal from './spark-modal';
|
||||
import SystemModelSettingModal from './system-model-setting-modal';
|
||||
import VolcEngineModal from './volcengine-modal';
|
||||
import YiyanModal from './yiyan-modal';
|
||||
|
||||
const { Text } = Typography;
|
||||
interface IModelCardProps {
|
||||
item: LlmItem;
|
||||
clickApiKey: (llmFactory: string) => void;
|
||||
handleEditModel: (model: any, factory: LlmItem) => void;
|
||||
}
|
||||
|
||||
type TagType =
|
||||
| 'LLM'
|
||||
| 'TEXT EMBEDDING'
|
||||
| 'TEXT RE-RANK'
|
||||
| 'TTS'
|
||||
| 'SPEECH2TEXT'
|
||||
| 'IMAGE2TEXT'
|
||||
| 'MODERATION';
|
||||
|
||||
const sortTags = (tags: string) => {
|
||||
const orderMap: Record<TagType, number> = {
|
||||
LLM: 1,
|
||||
'TEXT EMBEDDING': 2,
|
||||
'TEXT RE-RANK': 3,
|
||||
TTS: 4,
|
||||
SPEECH2TEXT: 5,
|
||||
IMAGE2TEXT: 6,
|
||||
MODERATION: 7,
|
||||
};
|
||||
|
||||
return tags
|
||||
.split(',')
|
||||
.map((tag) => tag.trim())
|
||||
.sort(
|
||||
(a, b) =>
|
||||
(orderMap[a as TagType] || 999) - (orderMap[b as TagType] || 999),
|
||||
);
|
||||
};
|
||||
|
||||
const ModelCard = ({ item, clickApiKey, handleEditModel }: IModelCardProps) => {
|
||||
const { visible, switchVisible } = useSetModalState();
|
||||
const { t } = useTranslate('setting');
|
||||
const { theme } = useTheme();
|
||||
const { handleDeleteLlm } = useHandleDeleteLlm(item.name);
|
||||
const { handleDeleteFactory } = useHandleDeleteFactory(item.name);
|
||||
|
||||
const handleApiKeyClick = () => {
|
||||
clickApiKey(item.name);
|
||||
};
|
||||
|
||||
const handleShowMoreClick = () => {
|
||||
switchVisible();
|
||||
};
|
||||
|
||||
return (
|
||||
<List.Item>
|
||||
<Card
|
||||
className={theme === 'dark' ? styles.addedCardDark : styles.addedCard}
|
||||
>
|
||||
<Row align={'middle'}>
|
||||
<Col span={12}>
|
||||
<Flex gap={'middle'} align="center">
|
||||
<LlmIcon name={item.name} />
|
||||
<Flex vertical gap={'small'}>
|
||||
<b>{item.name}</b>
|
||||
<Flex wrap="wrap">
|
||||
{sortTags(item.tags).map((tag, index) => (
|
||||
<Tag
|
||||
key={index}
|
||||
style={{
|
||||
fontSize: '12px',
|
||||
margin: '1px',
|
||||
paddingInline: '4px',
|
||||
}}
|
||||
>
|
||||
{tag}
|
||||
</Tag>
|
||||
))}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Col>
|
||||
<Col span={12} className={styles.factoryOperationWrapper}>
|
||||
<Space size={'middle'}>
|
||||
<Button onClick={handleApiKeyClick}>
|
||||
<Flex align="center" gap={4}>
|
||||
{isLocalLlmFactory(item.name) ||
|
||||
item.name === LLMFactory.VolcEngine ||
|
||||
item.name === LLMFactory.TencentHunYuan ||
|
||||
item.name === LLMFactory.XunFeiSpark ||
|
||||
item.name === LLMFactory.BaiduYiYan ||
|
||||
item.name === LLMFactory.FishAudio ||
|
||||
item.name === LLMFactory.TencentCloud ||
|
||||
item.name === LLMFactory.GoogleCloud ||
|
||||
item.name === LLMFactory.AzureOpenAI
|
||||
? t('addTheModel')
|
||||
: 'API-Key'}
|
||||
<SettingOutlined />
|
||||
</Flex>
|
||||
</Button>
|
||||
<Button onClick={handleShowMoreClick}>
|
||||
<Flex align="center" gap={4}>
|
||||
{visible ? t('hideModels') : t('showMoreModels')}
|
||||
<MoreModelIcon />
|
||||
</Flex>
|
||||
</Button>
|
||||
<Button type={'text'} onClick={handleDeleteFactory}>
|
||||
<Flex align="center">
|
||||
<CloseCircleOutlined style={{ color: '#D92D20' }} />
|
||||
</Flex>
|
||||
</Button>
|
||||
</Space>
|
||||
</Col>
|
||||
</Row>
|
||||
{visible && (
|
||||
<List
|
||||
size="small"
|
||||
dataSource={item.llm}
|
||||
className={styles.llmList}
|
||||
renderItem={(model) => (
|
||||
<List.Item>
|
||||
<Space>
|
||||
{getRealModelName(model.name)}
|
||||
<Tag color="#b8b8b8">{model.type}</Tag>
|
||||
{isLocalLlmFactory(item.name) && (
|
||||
<Tooltip title={t('edit', { keyPrefix: 'common' })}>
|
||||
<Button
|
||||
type={'text'}
|
||||
onClick={() => handleEditModel(model, item)}
|
||||
>
|
||||
<EditOutlined style={{ color: '#1890ff' }} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title={t('delete', { keyPrefix: 'common' })}>
|
||||
<Button type={'text'} onClick={handleDeleteLlm(model.name)}>
|
||||
<CloseCircleOutlined style={{ color: '#D92D20' }} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
</List.Item>
|
||||
);
|
||||
};
|
||||
|
||||
const UserSettingModel = () => {
|
||||
const { factoryList, myLlmList: llmList, loading } = useSelectLlmList();
|
||||
const ModelProviders = () => {
|
||||
const { saveSystemModelSettingLoading, onSystemSettingSavingOk } =
|
||||
useSubmitSystemModelSetting();
|
||||
const { data: detailedLlmList } = useFetchMyLlmListDetailed();
|
||||
const { theme } = useTheme();
|
||||
const {
|
||||
saveApiKeyLoading,
|
||||
initialApiKey,
|
||||
@ -224,14 +44,6 @@ const UserSettingModel = () => {
|
||||
hideApiKeyModal,
|
||||
showApiKeyModal,
|
||||
} = useSubmitApiKey();
|
||||
const {
|
||||
saveSystemModelSettingLoading,
|
||||
onSystemSettingSavingOk,
|
||||
systemSettingVisible,
|
||||
hideSystemSettingModal,
|
||||
showSystemSettingModal,
|
||||
} = useSubmitSystemModelSetting();
|
||||
const { t } = useTranslate('setting');
|
||||
const {
|
||||
llmAddingVisible,
|
||||
hideLlmAddingModal,
|
||||
@ -342,6 +154,7 @@ const UserSettingModel = () => {
|
||||
|
||||
const handleAddModel = useCallback(
|
||||
(llmFactory: string) => {
|
||||
console.log('handleAddModel', llmFactory);
|
||||
if (isLocalLlmFactory(llmFactory)) {
|
||||
showLlmAddingModal(llmFactory);
|
||||
} else if (llmFactory in ModalMap) {
|
||||
@ -378,116 +191,21 @@ const UserSettingModel = () => {
|
||||
},
|
||||
[showApiKeyModal, showLlmAddingModal, ModalMap, detailedLlmList],
|
||||
);
|
||||
|
||||
const items: CollapseProps['items'] = [
|
||||
{
|
||||
key: '1',
|
||||
label: t('addedModels'),
|
||||
children: (
|
||||
<List
|
||||
grid={{ gutter: 16, column: 1 }}
|
||||
dataSource={llmList}
|
||||
renderItem={(item) => (
|
||||
<ModelCard
|
||||
item={item}
|
||||
clickApiKey={handleAddModel}
|
||||
handleEditModel={handleEditModel}
|
||||
></ModelCard>
|
||||
)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: (
|
||||
<div className="flex items-center gap-2">
|
||||
{t('modelsToBeAdded')}
|
||||
<Tooltip title={t('modelsToBeAddedTooltip')}>
|
||||
<CircleHelp className="size-4" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
),
|
||||
children: (
|
||||
<List
|
||||
grid={{
|
||||
gutter: {
|
||||
xs: 8,
|
||||
sm: 10,
|
||||
md: 12,
|
||||
lg: 16,
|
||||
xl: 20,
|
||||
xxl: 24,
|
||||
},
|
||||
xs: 1,
|
||||
sm: 1,
|
||||
md: 2,
|
||||
lg: 3,
|
||||
xl: 4,
|
||||
xxl: 8,
|
||||
}}
|
||||
dataSource={factoryList}
|
||||
renderItem={(item) => (
|
||||
<List.Item>
|
||||
<Card
|
||||
className={
|
||||
theme === 'dark'
|
||||
? styles.toBeAddedCardDark
|
||||
: styles.toBeAddedCard
|
||||
}
|
||||
>
|
||||
<Flex vertical gap={'middle'}>
|
||||
<LlmIcon name={item.name} imgClass="h-12 w-auto" />
|
||||
<Flex vertical gap={'middle'}>
|
||||
<b>
|
||||
<Text ellipsis={{ tooltip: item.name }}>{item.name}</Text>
|
||||
</b>
|
||||
<Flex wrap="wrap" style={{ minHeight: '50px' }}>
|
||||
{sortTags(item.tags).map((tag, index) => (
|
||||
<Tag
|
||||
key={index}
|
||||
style={{
|
||||
fontSize: '8px',
|
||||
margin: '1px',
|
||||
paddingInline: '4px',
|
||||
height: '22px',
|
||||
}}
|
||||
>
|
||||
{tag}
|
||||
</Tag>
|
||||
))}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Divider className={styles.modelDivider}></Divider>
|
||||
<Button
|
||||
type="link"
|
||||
onClick={() => handleAddModel(item.name)}
|
||||
className={styles.addButton}
|
||||
>
|
||||
{t('addTheModel')}
|
||||
</Button>
|
||||
</Card>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<section id="xx" className="w-full space-y-6">
|
||||
<Spin spinning={loading}>
|
||||
<section className={styles.modelContainer}>
|
||||
<SettingTitle
|
||||
title={t('model')}
|
||||
description={t('modelDescription')}
|
||||
showRightButton
|
||||
clickButton={showSystemSettingModal}
|
||||
></SettingTitle>
|
||||
<Divider></Divider>
|
||||
<Collapse defaultActiveKey={['1', '2']} ghost items={items} />
|
||||
</section>
|
||||
</Spin>
|
||||
<div className="flex w-full">
|
||||
<section className="flex flex-col gap-4 w-3/5 px-5 border-r border-border-button overflow-auto scrollbar-auto">
|
||||
<SystemSetting
|
||||
onOk={onSystemSettingSavingOk}
|
||||
loading={saveSystemModelSettingLoading}
|
||||
/>
|
||||
<UsedModel
|
||||
handleAddModel={handleAddModel}
|
||||
handleEditModel={handleEditModel}
|
||||
/>
|
||||
</section>
|
||||
<section className="flex flex-col w-2/5 overflow-auto scrollbar-auto">
|
||||
<AvailableModels handleAddModel={handleAddModel} />
|
||||
</section>
|
||||
<ApiKeyModal
|
||||
visible={apiKeyVisible}
|
||||
hideModal={hideApiKeyModal}
|
||||
@ -497,14 +215,6 @@ const UserSettingModel = () => {
|
||||
onOk={onApiKeySavingOk}
|
||||
llmFactory={llmFactory}
|
||||
></ApiKeyModal>
|
||||
{systemSettingVisible && (
|
||||
<SystemModelSettingModal
|
||||
visible={systemSettingVisible}
|
||||
onOk={onSystemSettingSavingOk}
|
||||
hideModal={hideSystemSettingModal}
|
||||
loading={saveSystemModelSettingLoading}
|
||||
></SystemModelSettingModal>
|
||||
)}
|
||||
<OllamaModal
|
||||
visible={llmAddingVisible}
|
||||
hideModal={hideLlmAddingModal}
|
||||
@ -577,8 +287,7 @@ const UserSettingModel = () => {
|
||||
loading={AzureAddingLoading}
|
||||
llmFactory={LLMFactory.AzureOpenAI}
|
||||
></AzureOpenAIModal>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserSettingModel;
|
||||
export default ModelProviders;
|
||||
|
||||
584
web/src/pages/user-setting/setting-model/index1.tsx
Normal file
584
web/src/pages/user-setting/setting-model/index1.tsx
Normal file
@ -0,0 +1,584 @@
|
||||
import { ReactComponent as MoreModelIcon } from '@/assets/svg/more-model.svg';
|
||||
import { LlmIcon } from '@/components/svg-icon';
|
||||
import { useTheme } from '@/components/theme-provider';
|
||||
import { LLMFactory } from '@/constants/llm';
|
||||
import { useSetModalState, useTranslate } from '@/hooks/common-hooks';
|
||||
import {
|
||||
LlmItem,
|
||||
useFetchMyLlmListDetailed,
|
||||
useSelectLlmList,
|
||||
} from '@/hooks/llm-hooks';
|
||||
import { getRealModelName } from '@/utils/llm-util';
|
||||
import {
|
||||
CloseCircleOutlined,
|
||||
EditOutlined,
|
||||
SettingOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Col,
|
||||
Collapse,
|
||||
CollapseProps,
|
||||
Divider,
|
||||
Flex,
|
||||
List,
|
||||
Row,
|
||||
Space,
|
||||
Spin,
|
||||
Tag,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import { CircleHelp } from 'lucide-react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import SettingTitle from '../components/setting-title';
|
||||
import { isLocalLlmFactory } from '../utils';
|
||||
import ApiKeyModal from './api-key-modal';
|
||||
import AzureOpenAIModal from './azure-openai-modal';
|
||||
import BedrockModal from './bedrock-modal';
|
||||
import FishAudioModal from './fish-audio-modal';
|
||||
import GoogleModal from './google-modal';
|
||||
import {
|
||||
useHandleDeleteFactory,
|
||||
useHandleDeleteLlm,
|
||||
useSubmitApiKey,
|
||||
useSubmitAzure,
|
||||
useSubmitBedrock,
|
||||
useSubmitFishAudio,
|
||||
useSubmitGoogle,
|
||||
useSubmitHunyuan,
|
||||
useSubmitOllama,
|
||||
useSubmitSpark,
|
||||
useSubmitSystemModelSetting,
|
||||
useSubmitTencentCloud,
|
||||
useSubmitVolcEngine,
|
||||
useSubmityiyan,
|
||||
} from './hooks';
|
||||
import HunyuanModal from './hunyuan-modal';
|
||||
import styles from './index.less';
|
||||
import TencentCloudModal from './next-tencent-modal';
|
||||
import OllamaModal from './ollama-modal';
|
||||
import SparkModal from './spark-modal';
|
||||
import SystemModelSettingModal from './system-model-setting-modal';
|
||||
import VolcEngineModal from './volcengine-modal';
|
||||
import YiyanModal from './yiyan-modal';
|
||||
|
||||
const { Text } = Typography;
|
||||
interface IModelCardProps {
|
||||
item: LlmItem;
|
||||
clickApiKey: (llmFactory: string) => void;
|
||||
handleEditModel: (model: any, factory: LlmItem) => void;
|
||||
}
|
||||
|
||||
type TagType =
|
||||
| 'LLM'
|
||||
| 'TEXT EMBEDDING'
|
||||
| 'TEXT RE-RANK'
|
||||
| 'TTS'
|
||||
| 'SPEECH2TEXT'
|
||||
| 'IMAGE2TEXT'
|
||||
| 'MODERATION';
|
||||
|
||||
const sortTags = (tags: string) => {
|
||||
const orderMap: Record<TagType, number> = {
|
||||
LLM: 1,
|
||||
'TEXT EMBEDDING': 2,
|
||||
'TEXT RE-RANK': 3,
|
||||
TTS: 4,
|
||||
SPEECH2TEXT: 5,
|
||||
IMAGE2TEXT: 6,
|
||||
MODERATION: 7,
|
||||
};
|
||||
|
||||
return tags
|
||||
.split(',')
|
||||
.map((tag) => tag.trim())
|
||||
.sort(
|
||||
(a, b) =>
|
||||
(orderMap[a as TagType] || 999) - (orderMap[b as TagType] || 999),
|
||||
);
|
||||
};
|
||||
|
||||
const ModelCard = ({ item, clickApiKey, handleEditModel }: IModelCardProps) => {
|
||||
const { visible, switchVisible } = useSetModalState();
|
||||
const { t } = useTranslate('setting');
|
||||
const { theme } = useTheme();
|
||||
const { handleDeleteLlm } = useHandleDeleteLlm(item.name);
|
||||
const { handleDeleteFactory } = useHandleDeleteFactory(item.name);
|
||||
|
||||
const handleApiKeyClick = () => {
|
||||
clickApiKey(item.name);
|
||||
};
|
||||
|
||||
const handleShowMoreClick = () => {
|
||||
switchVisible();
|
||||
};
|
||||
|
||||
return (
|
||||
<List.Item>
|
||||
<Card
|
||||
className={theme === 'dark' ? styles.addedCardDark : styles.addedCard}
|
||||
>
|
||||
<Row align={'middle'}>
|
||||
<Col span={12}>
|
||||
<Flex gap={'middle'} align="center">
|
||||
<LlmIcon name={item.name} />
|
||||
<Flex vertical gap={'small'}>
|
||||
<b>{item.name}</b>
|
||||
<Flex wrap="wrap">
|
||||
{sortTags(item.tags).map((tag, index) => (
|
||||
<Tag
|
||||
key={index}
|
||||
style={{
|
||||
fontSize: '12px',
|
||||
margin: '1px',
|
||||
paddingInline: '4px',
|
||||
}}
|
||||
>
|
||||
{tag}
|
||||
</Tag>
|
||||
))}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Col>
|
||||
<Col span={12} className={styles.factoryOperationWrapper}>
|
||||
<Space size={'middle'}>
|
||||
<Button onClick={handleApiKeyClick}>
|
||||
<Flex align="center" gap={4}>
|
||||
{isLocalLlmFactory(item.name) ||
|
||||
item.name === LLMFactory.VolcEngine ||
|
||||
item.name === LLMFactory.TencentHunYuan ||
|
||||
item.name === LLMFactory.XunFeiSpark ||
|
||||
item.name === LLMFactory.BaiduYiYan ||
|
||||
item.name === LLMFactory.FishAudio ||
|
||||
item.name === LLMFactory.TencentCloud ||
|
||||
item.name === LLMFactory.GoogleCloud ||
|
||||
item.name === LLMFactory.AzureOpenAI
|
||||
? t('addTheModel')
|
||||
: 'API-Key'}
|
||||
<SettingOutlined />
|
||||
</Flex>
|
||||
</Button>
|
||||
<Button onClick={handleShowMoreClick}>
|
||||
<Flex align="center" gap={4}>
|
||||
{visible ? t('hideModels') : t('showMoreModels')}
|
||||
<MoreModelIcon />
|
||||
</Flex>
|
||||
</Button>
|
||||
<Button type={'text'} onClick={handleDeleteFactory}>
|
||||
<Flex align="center">
|
||||
<CloseCircleOutlined style={{ color: '#D92D20' }} />
|
||||
</Flex>
|
||||
</Button>
|
||||
</Space>
|
||||
</Col>
|
||||
</Row>
|
||||
{visible && (
|
||||
<List
|
||||
size="small"
|
||||
dataSource={item.llm}
|
||||
className={styles.llmList}
|
||||
renderItem={(model) => (
|
||||
<List.Item>
|
||||
<Space>
|
||||
{getRealModelName(model.name)}
|
||||
<Tag color="#b8b8b8">{model.type}</Tag>
|
||||
{isLocalLlmFactory(item.name) && (
|
||||
<Tooltip title={t('edit', { keyPrefix: 'common' })}>
|
||||
<Button
|
||||
type={'text'}
|
||||
onClick={() => handleEditModel(model, item)}
|
||||
>
|
||||
<EditOutlined style={{ color: '#1890ff' }} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title={t('delete', { keyPrefix: 'common' })}>
|
||||
<Button type={'text'} onClick={handleDeleteLlm(model.name)}>
|
||||
<CloseCircleOutlined style={{ color: '#D92D20' }} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
</List.Item>
|
||||
);
|
||||
};
|
||||
|
||||
const UserSettingModel = () => {
|
||||
const { factoryList, myLlmList: llmList, loading } = useSelectLlmList();
|
||||
const { data: detailedLlmList } = useFetchMyLlmListDetailed();
|
||||
const { theme } = useTheme();
|
||||
const {
|
||||
saveApiKeyLoading,
|
||||
initialApiKey,
|
||||
llmFactory,
|
||||
editMode,
|
||||
onApiKeySavingOk,
|
||||
apiKeyVisible,
|
||||
hideApiKeyModal,
|
||||
showApiKeyModal,
|
||||
} = useSubmitApiKey();
|
||||
const {
|
||||
saveSystemModelSettingLoading,
|
||||
onSystemSettingSavingOk,
|
||||
systemSettingVisible,
|
||||
hideSystemSettingModal,
|
||||
showSystemSettingModal,
|
||||
} = useSubmitSystemModelSetting();
|
||||
const { t } = useTranslate('setting');
|
||||
const {
|
||||
llmAddingVisible,
|
||||
hideLlmAddingModal,
|
||||
showLlmAddingModal,
|
||||
onLlmAddingOk,
|
||||
llmAddingLoading,
|
||||
editMode: llmEditMode,
|
||||
initialValues: llmInitialValues,
|
||||
selectedLlmFactory,
|
||||
} = useSubmitOllama();
|
||||
|
||||
const {
|
||||
volcAddingVisible,
|
||||
hideVolcAddingModal,
|
||||
showVolcAddingModal,
|
||||
onVolcAddingOk,
|
||||
volcAddingLoading,
|
||||
} = useSubmitVolcEngine();
|
||||
|
||||
const {
|
||||
HunyuanAddingVisible,
|
||||
hideHunyuanAddingModal,
|
||||
showHunyuanAddingModal,
|
||||
onHunyuanAddingOk,
|
||||
HunyuanAddingLoading,
|
||||
} = useSubmitHunyuan();
|
||||
|
||||
const {
|
||||
GoogleAddingVisible,
|
||||
hideGoogleAddingModal,
|
||||
showGoogleAddingModal,
|
||||
onGoogleAddingOk,
|
||||
GoogleAddingLoading,
|
||||
} = useSubmitGoogle();
|
||||
|
||||
const {
|
||||
TencentCloudAddingVisible,
|
||||
hideTencentCloudAddingModal,
|
||||
showTencentCloudAddingModal,
|
||||
onTencentCloudAddingOk,
|
||||
TencentCloudAddingLoading,
|
||||
} = useSubmitTencentCloud();
|
||||
|
||||
const {
|
||||
SparkAddingVisible,
|
||||
hideSparkAddingModal,
|
||||
showSparkAddingModal,
|
||||
onSparkAddingOk,
|
||||
SparkAddingLoading,
|
||||
} = useSubmitSpark();
|
||||
|
||||
const {
|
||||
yiyanAddingVisible,
|
||||
hideyiyanAddingModal,
|
||||
showyiyanAddingModal,
|
||||
onyiyanAddingOk,
|
||||
yiyanAddingLoading,
|
||||
} = useSubmityiyan();
|
||||
|
||||
const {
|
||||
FishAudioAddingVisible,
|
||||
hideFishAudioAddingModal,
|
||||
showFishAudioAddingModal,
|
||||
onFishAudioAddingOk,
|
||||
FishAudioAddingLoading,
|
||||
} = useSubmitFishAudio();
|
||||
|
||||
const {
|
||||
bedrockAddingLoading,
|
||||
onBedrockAddingOk,
|
||||
bedrockAddingVisible,
|
||||
hideBedrockAddingModal,
|
||||
showBedrockAddingModal,
|
||||
} = useSubmitBedrock();
|
||||
|
||||
const {
|
||||
AzureAddingVisible,
|
||||
hideAzureAddingModal,
|
||||
showAzureAddingModal,
|
||||
onAzureAddingOk,
|
||||
AzureAddingLoading,
|
||||
} = useSubmitAzure();
|
||||
|
||||
const ModalMap = useMemo(
|
||||
() => ({
|
||||
[LLMFactory.Bedrock]: showBedrockAddingModal,
|
||||
[LLMFactory.VolcEngine]: showVolcAddingModal,
|
||||
[LLMFactory.TencentHunYuan]: showHunyuanAddingModal,
|
||||
[LLMFactory.XunFeiSpark]: showSparkAddingModal,
|
||||
[LLMFactory.BaiduYiYan]: showyiyanAddingModal,
|
||||
[LLMFactory.FishAudio]: showFishAudioAddingModal,
|
||||
[LLMFactory.TencentCloud]: showTencentCloudAddingModal,
|
||||
[LLMFactory.GoogleCloud]: showGoogleAddingModal,
|
||||
[LLMFactory.AzureOpenAI]: showAzureAddingModal,
|
||||
}),
|
||||
[
|
||||
showBedrockAddingModal,
|
||||
showVolcAddingModal,
|
||||
showHunyuanAddingModal,
|
||||
showTencentCloudAddingModal,
|
||||
showSparkAddingModal,
|
||||
showyiyanAddingModal,
|
||||
showFishAudioAddingModal,
|
||||
showGoogleAddingModal,
|
||||
showAzureAddingModal,
|
||||
],
|
||||
);
|
||||
|
||||
const handleAddModel = useCallback(
|
||||
(llmFactory: string) => {
|
||||
if (isLocalLlmFactory(llmFactory)) {
|
||||
showLlmAddingModal(llmFactory);
|
||||
} else if (llmFactory in ModalMap) {
|
||||
ModalMap[llmFactory as keyof typeof ModalMap]();
|
||||
} else {
|
||||
showApiKeyModal({ llm_factory: llmFactory });
|
||||
}
|
||||
},
|
||||
[showApiKeyModal, showLlmAddingModal, ModalMap],
|
||||
);
|
||||
|
||||
const handleEditModel = useCallback(
|
||||
(model: any, factory: LlmItem) => {
|
||||
if (factory) {
|
||||
const detailedFactory = detailedLlmList[factory.name];
|
||||
const detailedModel = detailedFactory?.llm?.find(
|
||||
(m: any) => m.name === model.name,
|
||||
);
|
||||
|
||||
const editData = {
|
||||
llm_factory: factory.name,
|
||||
llm_name: model.name,
|
||||
model_type: model.type,
|
||||
};
|
||||
|
||||
if (isLocalLlmFactory(factory.name)) {
|
||||
showLlmAddingModal(factory.name, true, editData, detailedModel);
|
||||
} else if (factory.name in ModalMap) {
|
||||
ModalMap[factory.name as keyof typeof ModalMap]();
|
||||
} else {
|
||||
showApiKeyModal(editData, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
[showApiKeyModal, showLlmAddingModal, ModalMap, detailedLlmList],
|
||||
);
|
||||
|
||||
const items: CollapseProps['items'] = [
|
||||
{
|
||||
key: '1',
|
||||
label: t('addedModels'),
|
||||
children: (
|
||||
<List
|
||||
grid={{ gutter: 16, column: 1 }}
|
||||
dataSource={llmList}
|
||||
renderItem={(item) => (
|
||||
<ModelCard
|
||||
item={item}
|
||||
clickApiKey={handleAddModel}
|
||||
handleEditModel={handleEditModel}
|
||||
></ModelCard>
|
||||
)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: (
|
||||
<div className="flex items-center gap-2">
|
||||
{t('modelsToBeAdded')}
|
||||
<Tooltip title={t('modelsToBeAddedTooltip')}>
|
||||
<CircleHelp className="size-4" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
),
|
||||
children: (
|
||||
<List
|
||||
grid={{
|
||||
gutter: {
|
||||
xs: 8,
|
||||
sm: 10,
|
||||
md: 12,
|
||||
lg: 16,
|
||||
xl: 20,
|
||||
xxl: 24,
|
||||
},
|
||||
xs: 1,
|
||||
sm: 1,
|
||||
md: 2,
|
||||
lg: 3,
|
||||
xl: 4,
|
||||
xxl: 8,
|
||||
}}
|
||||
dataSource={factoryList}
|
||||
renderItem={(item) => (
|
||||
<List.Item>
|
||||
<Card
|
||||
className={
|
||||
theme === 'dark'
|
||||
? styles.toBeAddedCardDark
|
||||
: styles.toBeAddedCard
|
||||
}
|
||||
>
|
||||
<Flex vertical gap={'middle'}>
|
||||
<LlmIcon name={item.name} imgClass="h-12 w-auto" />
|
||||
<Flex vertical gap={'middle'}>
|
||||
<b>
|
||||
<Text ellipsis={{ tooltip: item.name }}>{item.name}</Text>
|
||||
</b>
|
||||
<Flex wrap="wrap" style={{ minHeight: '50px' }}>
|
||||
{sortTags(item.tags).map((tag, index) => (
|
||||
<Tag
|
||||
key={index}
|
||||
style={{
|
||||
fontSize: '8px',
|
||||
margin: '1px',
|
||||
paddingInline: '4px',
|
||||
height: '22px',
|
||||
}}
|
||||
>
|
||||
{tag}
|
||||
</Tag>
|
||||
))}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Divider className={styles.modelDivider}></Divider>
|
||||
<Button
|
||||
type="link"
|
||||
onClick={() => handleAddModel(item.name)}
|
||||
className={styles.addButton}
|
||||
>
|
||||
{t('addTheModel')}
|
||||
</Button>
|
||||
</Card>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<section id="xx" className="w-full space-y-6">
|
||||
<Spin spinning={loading}>
|
||||
<section className={styles.modelContainer}>
|
||||
<SettingTitle
|
||||
title={t('model')}
|
||||
description={t('modelDescription')}
|
||||
showRightButton
|
||||
clickButton={showSystemSettingModal}
|
||||
></SettingTitle>
|
||||
<Divider></Divider>
|
||||
<Collapse defaultActiveKey={['1', '2']} ghost items={items} />
|
||||
</section>
|
||||
</Spin>
|
||||
<ApiKeyModal
|
||||
visible={apiKeyVisible}
|
||||
hideModal={hideApiKeyModal}
|
||||
loading={saveApiKeyLoading}
|
||||
initialValue={initialApiKey}
|
||||
editMode={editMode}
|
||||
onOk={onApiKeySavingOk}
|
||||
llmFactory={llmFactory}
|
||||
></ApiKeyModal>
|
||||
{systemSettingVisible && (
|
||||
<SystemModelSettingModal
|
||||
visible={systemSettingVisible}
|
||||
onOk={onSystemSettingSavingOk}
|
||||
hideModal={hideSystemSettingModal}
|
||||
loading={saveSystemModelSettingLoading}
|
||||
></SystemModelSettingModal>
|
||||
)}
|
||||
<OllamaModal
|
||||
visible={llmAddingVisible}
|
||||
hideModal={hideLlmAddingModal}
|
||||
onOk={onLlmAddingOk}
|
||||
loading={llmAddingLoading}
|
||||
editMode={llmEditMode}
|
||||
initialValues={llmInitialValues}
|
||||
llmFactory={selectedLlmFactory}
|
||||
></OllamaModal>
|
||||
<VolcEngineModal
|
||||
visible={volcAddingVisible}
|
||||
hideModal={hideVolcAddingModal}
|
||||
onOk={onVolcAddingOk}
|
||||
loading={volcAddingLoading}
|
||||
llmFactory={LLMFactory.VolcEngine}
|
||||
></VolcEngineModal>
|
||||
<HunyuanModal
|
||||
visible={HunyuanAddingVisible}
|
||||
hideModal={hideHunyuanAddingModal}
|
||||
onOk={onHunyuanAddingOk}
|
||||
loading={HunyuanAddingLoading}
|
||||
llmFactory={LLMFactory.TencentHunYuan}
|
||||
></HunyuanModal>
|
||||
<GoogleModal
|
||||
visible={GoogleAddingVisible}
|
||||
hideModal={hideGoogleAddingModal}
|
||||
onOk={onGoogleAddingOk}
|
||||
loading={GoogleAddingLoading}
|
||||
llmFactory={LLMFactory.GoogleCloud}
|
||||
></GoogleModal>
|
||||
<TencentCloudModal
|
||||
visible={TencentCloudAddingVisible}
|
||||
hideModal={hideTencentCloudAddingModal}
|
||||
onOk={onTencentCloudAddingOk}
|
||||
loading={TencentCloudAddingLoading}
|
||||
llmFactory={LLMFactory.TencentCloud}
|
||||
></TencentCloudModal>
|
||||
<SparkModal
|
||||
visible={SparkAddingVisible}
|
||||
hideModal={hideSparkAddingModal}
|
||||
onOk={onSparkAddingOk}
|
||||
loading={SparkAddingLoading}
|
||||
llmFactory={LLMFactory.XunFeiSpark}
|
||||
></SparkModal>
|
||||
<YiyanModal
|
||||
visible={yiyanAddingVisible}
|
||||
hideModal={hideyiyanAddingModal}
|
||||
onOk={onyiyanAddingOk}
|
||||
loading={yiyanAddingLoading}
|
||||
llmFactory={LLMFactory.BaiduYiYan}
|
||||
></YiyanModal>
|
||||
<FishAudioModal
|
||||
visible={FishAudioAddingVisible}
|
||||
hideModal={hideFishAudioAddingModal}
|
||||
onOk={onFishAudioAddingOk}
|
||||
loading={FishAudioAddingLoading}
|
||||
llmFactory={LLMFactory.FishAudio}
|
||||
></FishAudioModal>
|
||||
<BedrockModal
|
||||
visible={bedrockAddingVisible}
|
||||
hideModal={hideBedrockAddingModal}
|
||||
onOk={onBedrockAddingOk}
|
||||
loading={bedrockAddingLoading}
|
||||
llmFactory={LLMFactory.Bedrock}
|
||||
></BedrockModal>
|
||||
<AzureOpenAIModal
|
||||
visible={AzureAddingVisible}
|
||||
hideModal={hideAzureAddingModal}
|
||||
onOk={onAzureAddingOk}
|
||||
loading={AzureAddingLoading}
|
||||
llmFactory={LLMFactory.AzureOpenAI}
|
||||
></AzureOpenAIModal>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserSettingModel;
|
||||
Reference in New Issue
Block a user