Browse Source

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)
tags/v0.20.0
chanx 3 months ago
parent
commit
03e39ca9be
No account linked to committer's email address

+ 0
- 8
web/src/components/entity-types-form-field.tsx View File

@@ -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 ">

+ 2
- 8
web/src/components/knowledge-base-item.tsx View File

@@ -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} />
),
}));


+ 15
- 9
web/src/components/parse-configuration/raptor-form-fields.tsx View File

@@ -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}

+ 10
- 6
web/src/hooks/llm-hooks.tsx View File

@@ -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'));
}

+ 1
- 0
web/src/locales/en.ts View File

@@ -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',

+ 1
- 0
web/src/locales/zh.ts View File

@@ -1248,6 +1248,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于
agent: 'Agent',
agentDescription: '构建具备推理、工具调用和多智能体协同的智能体组件。',
maxRecords: '最大记录数',
createAgent: 'Create Agent',
stringTransform: '文本处理',
userFillUp: '等待输入',
codeExec: '代码',

+ 7
- 6
web/src/pages/agent/canvas/node/retrieval-node.tsx View File

@@ -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}

+ 13
- 2
web/src/pages/agents/agent-templates.tsx View File

@@ -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>

+ 38
- 26
web/src/pages/agents/template-card.tsx View File

@@ -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
- 0
web/src/pages/agents/template-sidebar.tsx View 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>
);
}

+ 17
- 6
web/src/pages/dataset/dataset/parsing-status-cell.tsx View File

@@ -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>
)}

+ 10
- 3
web/src/pages/dataset/setting/hooks.ts View File

@@ -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]);

+ 0
- 4
web/src/pages/dataset/setting/index.tsx View File

@@ -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,

+ 6
- 5
web/src/pages/datasets/dataset-card.tsx View File

@@ -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}

+ 11
- 4
web/src/pages/user-setting/setting-model/hooks.ts View File

@@ -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),

+ 25
- 8
web/src/pages/user-setting/setting-model/index.tsx View File

@@ -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>
)}
/>
),

+ 9
- 8
web/src/pages/user-setting/setting-model/ollama-modal/index.tsx View File

@@ -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')}

Loading…
Cancel
Save