mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 12:32:30 +08:00
Fix:Optimize Agent template page, fix bugs in knowledge base (#9009)
### What problem does this PR solve? Replace Avatar with RAGFlowAvatar component for knowledge base and agent, optimize Agent template page, and modify bugs in knowledge base #3221 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
@ -12,13 +12,6 @@ import {
|
||||
type EntityTypesFormFieldProps = {
|
||||
name?: string;
|
||||
};
|
||||
const initialEntityTypes = [
|
||||
'organization',
|
||||
'person',
|
||||
'geo',
|
||||
'event',
|
||||
'category',
|
||||
];
|
||||
export function EntityTypesFormField({
|
||||
name = 'parser_config.entity_types',
|
||||
}: EntityTypesFormFieldProps) {
|
||||
@ -29,7 +22,6 @@ export function EntityTypesFormField({
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={name}
|
||||
defaultValue={initialEntityTypes}
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
|
||||
@ -3,9 +3,8 @@ import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { useFetchKnowledgeList } from '@/hooks/knowledge-hooks';
|
||||
import { UserOutlined } from '@ant-design/icons';
|
||||
import { Avatar as AntAvatar, Form, Select, Space } from 'antd';
|
||||
import { Book } from 'lucide-react';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar';
|
||||
import { RAGFlowAvatar } from './ragflow-avatar';
|
||||
import { FormControl, FormField, FormItem, FormLabel } from './ui/form';
|
||||
import { MultiSelect } from './ui/multi-select';
|
||||
|
||||
@ -81,12 +80,7 @@ export function KnowledgeBaseFormField() {
|
||||
label: x.name,
|
||||
value: x.id,
|
||||
icon: () => (
|
||||
<Avatar className="size-4 mr-2">
|
||||
<AvatarImage src={x.avatar} />
|
||||
<AvatarFallback>
|
||||
<Book />
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<RAGFlowAvatar className="size-4 mr-2" avatar={x.avatar} name={x.name} />
|
||||
),
|
||||
}));
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import { DocumentParserType } from '@/constants/knowledge';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import random from 'lodash/random';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { useCallback } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useFormContext, useWatch } from 'react-hook-form';
|
||||
import { SliderInputFormField } from '../slider-input-form-field';
|
||||
import { Button } from '../ui/button';
|
||||
@ -46,6 +46,10 @@ export const showTagItems = (parserId: DocumentParserType) => {
|
||||
|
||||
const UseRaptorField = 'parser_config.raptor.use_raptor';
|
||||
const RandomSeedField = 'parser_config.raptor.random_seed';
|
||||
const MaxTokenField = 'parser_config.raptor.max_token';
|
||||
const ThresholdField = 'parser_config.raptor.threshold';
|
||||
const MaxCluster = 'parser_config.raptor.max_cluster';
|
||||
const Prompt = 'parser_config.raptor.prompt';
|
||||
|
||||
// The three types "table", "resume" and "one" do not display this configuration.
|
||||
|
||||
@ -53,6 +57,15 @@ const RaptorFormFields = () => {
|
||||
const form = useFormContext();
|
||||
const { t } = useTranslate('knowledgeConfiguration');
|
||||
const useRaptor = useWatch({ name: UseRaptorField });
|
||||
useEffect(() => {
|
||||
if (useRaptor) {
|
||||
form.setValue(MaxTokenField, 256);
|
||||
form.setValue(ThresholdField, 0.1);
|
||||
form.setValue(MaxCluster, 64);
|
||||
form.setValue(RandomSeedField, 0);
|
||||
form.setValue(Prompt, t('promptText'));
|
||||
}
|
||||
}, [form, useRaptor, t]);
|
||||
|
||||
const handleGenerate = useCallback(() => {
|
||||
form.setValue(RandomSeedField, random(10000));
|
||||
@ -114,11 +127,7 @@ const RaptorFormFields = () => {
|
||||
</FormLabel>
|
||||
<div className="w-3/4">
|
||||
<FormControl>
|
||||
<Textarea
|
||||
{...field}
|
||||
rows={8}
|
||||
defaultValue={t('promptText')}
|
||||
/>
|
||||
<Textarea {...field} rows={8} />
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
@ -134,7 +143,6 @@ const RaptorFormFields = () => {
|
||||
name={'parser_config.raptor.max_token'}
|
||||
label={t('maxToken')}
|
||||
tooltip={t('maxTokenTip')}
|
||||
defaultValue={256}
|
||||
max={2048}
|
||||
min={0}
|
||||
layout={FormLayout.Horizontal}
|
||||
@ -143,7 +151,6 @@ const RaptorFormFields = () => {
|
||||
name={'parser_config.raptor.threshold'}
|
||||
label={t('threshold')}
|
||||
tooltip={t('thresholdTip')}
|
||||
defaultValue={0.1}
|
||||
step={0.01}
|
||||
max={1}
|
||||
min={0}
|
||||
@ -153,7 +160,6 @@ const RaptorFormFields = () => {
|
||||
name={'parser_config.raptor.max_cluster'}
|
||||
label={t('maxCluster')}
|
||||
tooltip={t('maxClusterTip')}
|
||||
defaultValue={64}
|
||||
max={1024}
|
||||
min={1}
|
||||
layout={FormLayout.Horizontal}
|
||||
|
||||
@ -143,7 +143,12 @@ export const useComposeLlmOptionsByModelTypes = (
|
||||
|
||||
return modelTypes.reduce<
|
||||
(DefaultOptionType & {
|
||||
options: { label: JSX.Element; value: string; disabled: boolean; is_tools: boolean }[];
|
||||
options: {
|
||||
label: JSX.Element;
|
||||
value: string;
|
||||
disabled: boolean;
|
||||
is_tools: boolean;
|
||||
}[];
|
||||
})[]
|
||||
>((pre, cur) => {
|
||||
const options = allOptions[cur];
|
||||
@ -211,7 +216,6 @@ export const useFetchMyLlmListDetailed = (): ResponseGetType<
|
||||
return { data, loading };
|
||||
};
|
||||
|
||||
|
||||
export const useSelectLlmList = () => {
|
||||
const { data: myLlmList, loading: myLlmListLoading } = useFetchMyLlmList();
|
||||
const { data: factoryList, loading: factoryListLoading } =
|
||||
@ -262,7 +266,7 @@ export const useSaveApiKey = () => {
|
||||
if (data.code === 0) {
|
||||
message.success(t('message.modified'));
|
||||
queryClient.invalidateQueries({ queryKey: ['myLlmList'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['myLlmListDetailed'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['myLlmListDetailed'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['factoryList'] });
|
||||
}
|
||||
return data.code;
|
||||
@ -314,7 +318,7 @@ export const useAddLlm = () => {
|
||||
const { data } = await userService.add_llm(params);
|
||||
if (data.code === 0) {
|
||||
queryClient.invalidateQueries({ queryKey: ['myLlmList'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['myLlmListDetailed'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['myLlmListDetailed'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['factoryList'] });
|
||||
message.success(t('message.modified'));
|
||||
}
|
||||
@ -338,7 +342,7 @@ export const useDeleteLlm = () => {
|
||||
const { data } = await userService.delete_llm(params);
|
||||
if (data.code === 0) {
|
||||
queryClient.invalidateQueries({ queryKey: ['myLlmList'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['myLlmListDetailed'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['myLlmListDetailed'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['factoryList'] });
|
||||
message.success(t('message.deleted'));
|
||||
}
|
||||
@ -362,7 +366,7 @@ export const useDeleteFactory = () => {
|
||||
const { data } = await userService.deleteFactory(params);
|
||||
if (data.code === 0) {
|
||||
queryClient.invalidateQueries({ queryKey: ['myLlmList'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['myLlmListDetailed'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['myLlmListDetailed'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['factoryList'] });
|
||||
message.success(t('message.deleted'));
|
||||
}
|
||||
|
||||
@ -1296,6 +1296,7 @@ This delimiter is used to split the input text into several text pieces echo of
|
||||
agentDescription:
|
||||
'Builds agent components equipped with reasoning, tool usage, and multi-agent collaboration. ',
|
||||
maxRecords: 'Max records',
|
||||
createAgent: 'Create Agent',
|
||||
stringTransform: 'String transform',
|
||||
userFillUp: 'Input',
|
||||
codeExec: 'Code',
|
||||
|
||||
@ -1248,6 +1248,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于
|
||||
agent: 'Agent',
|
||||
agentDescription: '构建具备推理、工具调用和多智能体协同的智能体组件。',
|
||||
maxRecords: '最大记录数',
|
||||
createAgent: 'Create Agent',
|
||||
stringTransform: '文本处理',
|
||||
userFillUp: '等待输入',
|
||||
codeExec: '代码',
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { RAGFlowAvatar } from '@/components/ragflow-avatar';
|
||||
import { useFetchKnowledgeList } from '@/hooks/knowledge-hooks';
|
||||
import { IRetrievalNode } from '@/interfaces/database/flow';
|
||||
import { UserOutlined } from '@ant-design/icons';
|
||||
import { NodeProps, Position } from '@xyflow/react';
|
||||
import { Avatar, Flex } from 'antd';
|
||||
import { Flex } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { get } from 'lodash';
|
||||
import { memo, useMemo } from 'react';
|
||||
@ -68,10 +68,11 @@ function InnerRetrievalNode({
|
||||
return (
|
||||
<div className={styles.nodeText} key={knowledge.id}>
|
||||
<Flex align={'center'} gap={6}>
|
||||
<Avatar
|
||||
size={26}
|
||||
icon={<UserOutlined />}
|
||||
src={knowledge.avatar}
|
||||
<RAGFlowAvatar
|
||||
className="size-6 rounded-lg"
|
||||
avatar={knowledge.avatar}
|
||||
name={knowledge.name || 'CN'}
|
||||
isPerson={true}
|
||||
/>
|
||||
<Flex className={styles.knowledgeNodeName} flex={1}>
|
||||
{knowledge.name}
|
||||
|
||||
@ -11,7 +11,7 @@ import { useSetModalState } from '@/hooks/common-hooks';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import { useFetchAgentTemplates, useSetAgent } from '@/hooks/use-agent-request';
|
||||
import { IFlowTemplate } from '@/interfaces/database/flow';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { CreateAgentDialog } from './create-agent-dialog';
|
||||
import { TemplateCard } from './template-card';
|
||||
@ -21,7 +21,11 @@ export default function AgentTemplates() {
|
||||
const { t } = useTranslation();
|
||||
const list = useFetchAgentTemplates();
|
||||
const { loading, setAgent } = useSetAgent();
|
||||
const [templateList, setTemplateList] = useState<IFlowTemplate[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
setTemplateList(list);
|
||||
}, [list]);
|
||||
const {
|
||||
visible: creatingVisible,
|
||||
hideModal: hideCreatingModal,
|
||||
@ -62,7 +66,14 @@ export default function AgentTemplates() {
|
||||
template?.dsl,
|
||||
],
|
||||
);
|
||||
|
||||
const handleSiderBarChange = (keyword: string) => {
|
||||
const tempList = list.filter(
|
||||
(item, index) =>
|
||||
item.title.toLocaleLowerCase().includes(keyword?.toLocaleLowerCase()) ||
|
||||
index === 0,
|
||||
);
|
||||
setTemplateList(tempList);
|
||||
};
|
||||
return (
|
||||
<section>
|
||||
<PageHeader>
|
||||
|
||||
@ -1,47 +1,59 @@
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { RAGFlowAvatar } from '@/components/ragflow-avatar';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { IFlowTemplate } from '@/interfaces/database/flow';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface IProps {
|
||||
data: IFlowTemplate;
|
||||
isCreate?: boolean;
|
||||
showModal(record: IFlowTemplate): void;
|
||||
}
|
||||
|
||||
export function TemplateCard({ data, showModal }: IProps) {
|
||||
export function TemplateCard({ data, showModal, isCreate = false }: IProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
showModal(data);
|
||||
}, [data, showModal]);
|
||||
|
||||
return (
|
||||
<Card className="bg-colors-background-inverse-weak border-colors-outline-neutral-standard group relative">
|
||||
<Card className="bg-colors-background-inverse-weak border-colors-outline-neutral-standard group relative min-h-40">
|
||||
<CardContent className="p-4 ">
|
||||
<div className="flex justify-between mb-4">
|
||||
{data.avatar ? (
|
||||
<div
|
||||
className="w-[70px] h-[70px] rounded-xl bg-cover"
|
||||
style={{ backgroundImage: `url(${data.avatar})` }}
|
||||
/>
|
||||
) : (
|
||||
<Avatar className="w-[70px] h-[70px]">
|
||||
<AvatarImage src="https://github.com/shadcn.png" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
)}
|
||||
</div>
|
||||
<h3 className="text-xl font-bold mb-2">{data.title}</h3>
|
||||
<p className="break-words">{data.description}</p>
|
||||
<Button
|
||||
variant="tertiary"
|
||||
className="absolute bottom-4 right-4 left-4 hidden justify-end group-hover:block text-center"
|
||||
onClick={handleClick}
|
||||
>
|
||||
{t('flow.useTemplate')}
|
||||
</Button>
|
||||
{isCreate && (
|
||||
<div
|
||||
className="flex flex-col justify-center items-center gap-4 mb-4 absolute top-0 right-0 left-0 bottom-0 cursor-pointer "
|
||||
onClick={handleClick}
|
||||
>
|
||||
<Plus size={50} fontWeight={700} />
|
||||
<div>{t('flow.createAgent')}</div>
|
||||
</div>
|
||||
)}
|
||||
{!isCreate && (
|
||||
<>
|
||||
<div className="flex justify-start items-center gap-4 mb-4">
|
||||
<RAGFlowAvatar
|
||||
className="w-7 h-7"
|
||||
avatar={
|
||||
data.avatar ? data.avatar : 'https://github.com/shadcn.png'
|
||||
}
|
||||
name={data?.title || 'CN'}
|
||||
></RAGFlowAvatar>
|
||||
<div className="text-[18px] font-bold ">{data.title}</div>
|
||||
</div>
|
||||
<p className="break-words">{data.description}</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"
|
||||
className="w-1/3 absolute bottom-4 right-4 left-4 justify-center text-center m-auto"
|
||||
onClick={handleClick}
|
||||
>
|
||||
{t('flow.useTemplate')}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
|
||||
57
web/src/pages/agents/template-sidebar.tsx
Normal file
57
web/src/pages/agents/template-sidebar.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useSecondPathName } from '@/hooks/route-hook';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Banknote, LayoutGrid, User } from 'lucide-react';
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
section: 'All Templates',
|
||||
items: [
|
||||
{ icon: User, label: 'Assistant', key: 'Assistant' },
|
||||
{ icon: LayoutGrid, label: 'chatbot', key: 'chatbot' },
|
||||
{ icon: Banknote, label: 'generator', key: 'generator' },
|
||||
{ icon: Banknote, label: 'Intel', key: 'Intel' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export function SideBar({ change }: { change: (keyword: string) => void }) {
|
||||
const pathName = useSecondPathName();
|
||||
const handleMenuClick = (key: string) => {
|
||||
change(key);
|
||||
};
|
||||
|
||||
return (
|
||||
<aside className="w-[303px] bg-background border-r flex flex-col">
|
||||
<div className="flex-1 overflow-auto">
|
||||
{menuItems.map((section, idx) => (
|
||||
<div key={idx}>
|
||||
<h2
|
||||
className="p-6 text-sm font-semibold hover:bg-muted/50 cursor-pointer"
|
||||
onClick={() => handleMenuClick('')}
|
||||
>
|
||||
{section.section}
|
||||
</h2>
|
||||
{section.items.map((item, itemIdx) => {
|
||||
const active = pathName === item.key;
|
||||
return (
|
||||
<Button
|
||||
key={itemIdx}
|
||||
variant={active ? 'secondary' : 'ghost'}
|
||||
className={cn('w-full justify-start gap-2.5 p-6 relative')}
|
||||
onClick={() => handleMenuClick(item.key)}
|
||||
>
|
||||
<item.icon className="w-6 h-6" />
|
||||
<span>{item.label}</span>
|
||||
{active && (
|
||||
<div className="absolute right-0 w-[5px] h-[66px] bg-primary rounded-l-xl shadow-[0_0_5.94px_#7561ff,0_0_11.88px_#7561ff,0_0_41.58px_#7561ff,0_0_83.16px_#7561ff,0_0_142.56px_#7561ff,0_0_249.48px_#7561ff]" />
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
@ -6,6 +6,11 @@ import {
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import {
|
||||
HoverCard,
|
||||
HoverCardContent,
|
||||
HoverCardTrigger,
|
||||
} from '@/components/ui/hover-card';
|
||||
import { Progress } from '@/components/ui/progress';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { IDocumentInfo } from '@/interfaces/database/document';
|
||||
@ -13,12 +18,11 @@ import { CircleX, Play, RefreshCw } from 'lucide-react';
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { RunningStatus } from './constant';
|
||||
import { ParsingCard } from './parsing-card';
|
||||
import { ParsingCard, PopoverContent } from './parsing-card';
|
||||
import { UseChangeDocumentParserShowType } from './use-change-document-parser';
|
||||
import { useHandleRunDocumentByIds } from './use-run-document';
|
||||
import { UseSaveMetaShowType } from './use-save-meta';
|
||||
import { isParserRunning } from './utils';
|
||||
|
||||
const IconMap = {
|
||||
[RunningStatus.UNSTART]: <Play />,
|
||||
[RunningStatus.RUNNING]: <CircleX />,
|
||||
@ -94,10 +98,17 @@ export function ParsingStatusCell({
|
||||
</Button>
|
||||
</ConfirmDeleteDialog>
|
||||
{isParserRunning(run) ? (
|
||||
<div className="flex items-center gap-1">
|
||||
<Progress value={p} className="h-1 flex-1 min-w-10" />
|
||||
{p}%
|
||||
</div>
|
||||
<HoverCard>
|
||||
<HoverCardTrigger asChild>
|
||||
<div className="flex items-center gap-1">
|
||||
<Progress value={p} className="h-1 flex-1 min-w-10" />
|
||||
{p}%
|
||||
</div>
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent className="w-[40vw]">
|
||||
<PopoverContent record={record}></PopoverContent>
|
||||
</HoverCardContent>
|
||||
</HoverCard>
|
||||
) : (
|
||||
<ParsingCard record={record}></ParsingCard>
|
||||
)}
|
||||
|
||||
@ -71,9 +71,13 @@ export const useFetchKnowledgeConfigurationOnMount = (
|
||||
knowledgeDetails.avatar,
|
||||
);
|
||||
|
||||
console.log('🚀 ~ useEffect ~ fileList:', fileList);
|
||||
form.reset({
|
||||
...pick(knowledgeDetails, [
|
||||
console.log('🚀 ~ useEffect ~ fileList:', fileList, knowledgeDetails);
|
||||
const parser_config = {
|
||||
...form.formState?.defaultValues?.parser_config,
|
||||
...knowledgeDetails.parser_config,
|
||||
};
|
||||
const formValues = {
|
||||
...pick({ ...knowledgeDetails, parser_config: parser_config }, [
|
||||
'description',
|
||||
'name',
|
||||
'permission',
|
||||
@ -83,6 +87,9 @@ export const useFetchKnowledgeConfigurationOnMount = (
|
||||
'parser_config',
|
||||
'pagerank',
|
||||
]),
|
||||
};
|
||||
form.reset({
|
||||
...formValues,
|
||||
avatar: fileList,
|
||||
});
|
||||
}, [form, knowledgeDetails]);
|
||||
|
||||
@ -54,10 +54,6 @@ export default function DatasetSettings() {
|
||||
topn_tags: 3,
|
||||
raptor: {
|
||||
use_raptor: false,
|
||||
max_token: 256,
|
||||
threshold: 0.1,
|
||||
max_cluster: 64,
|
||||
random_seed: 0,
|
||||
},
|
||||
graphrag: {
|
||||
use_graphrag: false,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { MoreButton } from '@/components/more-button';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { RAGFlowAvatar } from '@/components/ragflow-avatar';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
@ -32,10 +32,11 @@ export function DatasetCard({
|
||||
<CardContent className="p-2.5 pt-2 group">
|
||||
<section className="flex justify-between mb-2">
|
||||
<div className="flex gap-2 items-center">
|
||||
<Avatar className="size-6 rounded-lg">
|
||||
<AvatarImage src={dataset.avatar} />
|
||||
<AvatarFallback className="rounded-lg ">CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<RAGFlowAvatar
|
||||
className="size-6 rounded-lg"
|
||||
avatar={dataset.avatar}
|
||||
name={dataset.name || 'CN'}
|
||||
></RAGFlowAvatar>
|
||||
{owner && (
|
||||
<Badge className="h-5 rounded-sm px-1 bg-background-badge text-text-badge">
|
||||
{owner}
|
||||
|
||||
@ -111,7 +111,9 @@ export const useFetchSystemModelSettingOnMount = () => {
|
||||
export const useSubmitOllama = () => {
|
||||
const [selectedLlmFactory, setSelectedLlmFactory] = useState<string>('');
|
||||
const [editMode, setEditMode] = useState(false);
|
||||
const [initialValues, setInitialValues] = useState<Partial<IAddLlmRequestBody> | undefined>();
|
||||
const [initialValues, setInitialValues] = useState<
|
||||
Partial<IAddLlmRequestBody> | undefined
|
||||
>();
|
||||
const [originalModelName, setOriginalModelName] = useState<string>('');
|
||||
const { addLlm, loading } = useAddLlm();
|
||||
const {
|
||||
@ -126,7 +128,7 @@ export const useSubmitOllama = () => {
|
||||
if (!cleanedPayload.api_key || cleanedPayload.api_key.trim() === '') {
|
||||
delete cleanedPayload.api_key;
|
||||
}
|
||||
|
||||
|
||||
const ret = await addLlm(cleanedPayload);
|
||||
if (ret === 0) {
|
||||
hideLlmAddingModal();
|
||||
@ -137,10 +139,15 @@ export const useSubmitOllama = () => {
|
||||
[hideLlmAddingModal, addLlm],
|
||||
);
|
||||
|
||||
const handleShowLlmAddingModal = (llmFactory: string, isEdit = false, modelData?: any, detailedData?: any) => {
|
||||
const handleShowLlmAddingModal = (
|
||||
llmFactory: string,
|
||||
isEdit = false,
|
||||
modelData?: any,
|
||||
detailedData?: any,
|
||||
) => {
|
||||
setSelectedLlmFactory(llmFactory);
|
||||
setEditMode(isEdit);
|
||||
|
||||
|
||||
if (isEdit && detailedData) {
|
||||
const initialVals = {
|
||||
llm_name: getRealModelName(detailedData.name),
|
||||
|
||||
@ -3,9 +3,17 @@ 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, useSelectLlmList, useFetchMyLlmListDetailed } from '@/hooks/llm-hooks';
|
||||
import {
|
||||
LlmItem,
|
||||
useFetchMyLlmListDetailed,
|
||||
useSelectLlmList,
|
||||
} from '@/hooks/llm-hooks';
|
||||
import { getRealModelName } from '@/utils/llm-util';
|
||||
import { CloseCircleOutlined, EditOutlined, SettingOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
CloseCircleOutlined,
|
||||
EditOutlined,
|
||||
SettingOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
@ -137,7 +145,10 @@ const ModelCard = ({ item, clickApiKey, handleEditModel }: IModelCardProps) => {
|
||||
<Tag color="#b8b8b8">{model.type}</Tag>
|
||||
{isLocalLlmFactory(item.name) && (
|
||||
<Tooltip title={t('edit', { keyPrefix: 'common' })}>
|
||||
<Button type={'text'} onClick={() => handleEditModel(model, item)}>
|
||||
<Button
|
||||
type={'text'}
|
||||
onClick={() => handleEditModel(model, item)}
|
||||
>
|
||||
<EditOutlined style={{ color: '#1890ff' }} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
@ -304,14 +315,16 @@ const UserSettingModel = () => {
|
||||
(model: any, factory: LlmItem) => {
|
||||
if (factory) {
|
||||
const detailedFactory = detailedLlmList[factory.name];
|
||||
const detailedModel = detailedFactory?.llm?.find((m: any) => m.name === model.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
|
||||
model_type: model.type,
|
||||
};
|
||||
|
||||
|
||||
if (isLocalLlmFactory(factory.name)) {
|
||||
showLlmAddingModal(factory.name, true, editData, detailedModel);
|
||||
} else if (factory.name in ModalMap) {
|
||||
@ -333,7 +346,11 @@ const UserSettingModel = () => {
|
||||
grid={{ gutter: 16, column: 1 }}
|
||||
dataSource={llmList}
|
||||
renderItem={(item) => (
|
||||
<ModelCard item={item} clickApiKey={handleAddModel} handleEditModel={handleEditModel}></ModelCard>
|
||||
<ModelCard
|
||||
item={item}
|
||||
clickApiKey={handleAddModel}
|
||||
handleEditModel={handleEditModel}
|
||||
></ModelCard>
|
||||
)}
|
||||
/>
|
||||
),
|
||||
|
||||
@ -48,8 +48,8 @@ const OllamaModal = ({
|
||||
llmFactory,
|
||||
editMode = false,
|
||||
initialValues,
|
||||
}: IModalProps<IAddLlmRequestBody> & {
|
||||
llmFactory: string;
|
||||
}: IModalProps<IAddLlmRequestBody> & {
|
||||
llmFactory: string;
|
||||
editMode?: boolean;
|
||||
initialValues?: Partial<IAddLlmRequestBody>;
|
||||
}) => {
|
||||
@ -96,7 +96,7 @@ const OllamaModal = ({
|
||||
form.resetFields();
|
||||
}
|
||||
}, [visible, editMode, initialValues, form]);
|
||||
|
||||
|
||||
const url =
|
||||
llmFactoryToUrlMap[llmFactory as LlmFactory] ||
|
||||
'https://github.com/infiniflow/ragflow/blob/main/docs/guides/models/deploy_local_llm.mdx';
|
||||
@ -134,7 +134,11 @@ const OllamaModal = ({
|
||||
};
|
||||
return (
|
||||
<Modal
|
||||
title={editMode ? t('editLlmTitle', { name: llmFactory }) : t('addLlmTitle', { name: llmFactory })}
|
||||
title={
|
||||
editMode
|
||||
? t('editLlmTitle', { name: llmFactory })
|
||||
: t('addLlmTitle', { name: llmFactory })
|
||||
}
|
||||
open={visible}
|
||||
onOk={handleOk}
|
||||
onCancel={hideModal}
|
||||
@ -196,10 +200,7 @@ const OllamaModal = ({
|
||||
name="api_key"
|
||||
rules={[{ required: false, message: t('apiKeyMessage') }]}
|
||||
>
|
||||
<Input
|
||||
placeholder={t('apiKeyMessage')}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
<Input placeholder={t('apiKeyMessage')} onKeyDown={handleKeyDown} />
|
||||
</Form.Item>
|
||||
<Form.Item<FieldType>
|
||||
label={t('maxTokens')}
|
||||
|
||||
Reference in New Issue
Block a user