Feat: Replace antd with shadcn and delete the template node. #10427 (#11693)

### What problem does this PR solve?

Feat: Replace antd with shadcn and delete the template node. #10427
### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-12-03 14:37:58 +08:00
committed by GitHub
parent e3f40db963
commit b44e65a12e
82 changed files with 181 additions and 4770 deletions

View File

@ -1,48 +0,0 @@
import { useTranslate } from '@/hooks/common-hooks';
import { Flex, Form, InputNumber, Slider } from 'antd';
export const AutoKeywordsItem = () => {
const { t } = useTranslate('knowledgeDetails');
return (
<Form.Item label={t('autoKeywords')} tooltip={t('autoKeywordsTip')}>
<Flex gap={20} align="center">
<Flex flex={1}>
<Form.Item
name={['parser_config', 'auto_keywords']}
noStyle
initialValue={0}
>
<Slider max={30} style={{ width: '100%' }} />
</Form.Item>
</Flex>
<Form.Item name={['parser_config', 'auto_keywords']} noStyle>
<InputNumber max={30} min={0} />
</Form.Item>
</Flex>
</Form.Item>
);
};
export const AutoQuestionsItem = () => {
const { t } = useTranslate('knowledgeDetails');
return (
<Form.Item label={t('autoQuestions')} tooltip={t('autoQuestionsTip')}>
<Flex gap={20} align="center">
<Flex flex={1}>
<Form.Item
name={['parser_config', 'auto_questions']}
noStyle
initialValue={0}
>
<Slider max={10} style={{ width: '100%' }} />
</Form.Item>
</Flex>
<Form.Item name={['parser_config', 'auto_questions']} noStyle>
<InputNumber max={10} min={0} />
</Form.Item>
</Flex>
</Form.Item>
);
};

View File

@ -1,161 +0,0 @@
import { DocumentParserType } from '@/constants/knowledge';
import { useHandleChunkMethodSelectChange } from '@/hooks/logic-hooks';
import { useSelectParserList } from '@/hooks/use-user-setting-request';
import { FormInstance } from 'antd';
import { useCallback, useEffect, useMemo, useState } from 'react';
const ParserListMap = new Map([
[
['pdf'],
[
DocumentParserType.Naive,
DocumentParserType.Resume,
DocumentParserType.Manual,
DocumentParserType.Paper,
DocumentParserType.Book,
DocumentParserType.Laws,
DocumentParserType.Presentation,
DocumentParserType.One,
DocumentParserType.Qa,
DocumentParserType.KnowledgeGraph,
],
],
[
['doc', 'docx'],
[
DocumentParserType.Naive,
DocumentParserType.Resume,
DocumentParserType.Book,
DocumentParserType.Laws,
DocumentParserType.One,
DocumentParserType.Qa,
DocumentParserType.Manual,
DocumentParserType.KnowledgeGraph,
],
],
[
['xlsx', 'xls'],
[
DocumentParserType.Naive,
DocumentParserType.Qa,
DocumentParserType.Table,
DocumentParserType.One,
DocumentParserType.KnowledgeGraph,
],
],
[['ppt', 'pptx'], [DocumentParserType.Presentation]],
[
['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tif', 'tiff', 'webp', 'svg', 'ico'],
[DocumentParserType.Picture],
],
[
['txt'],
[
DocumentParserType.Naive,
DocumentParserType.Resume,
DocumentParserType.Book,
DocumentParserType.Laws,
DocumentParserType.One,
DocumentParserType.Qa,
DocumentParserType.Table,
DocumentParserType.KnowledgeGraph,
],
],
[
['csv'],
[
DocumentParserType.Naive,
DocumentParserType.Resume,
DocumentParserType.Book,
DocumentParserType.Laws,
DocumentParserType.One,
DocumentParserType.Qa,
DocumentParserType.Table,
DocumentParserType.KnowledgeGraph,
],
],
[
['md'],
[
DocumentParserType.Naive,
DocumentParserType.Qa,
DocumentParserType.KnowledgeGraph,
],
],
[['json'], [DocumentParserType.Naive, DocumentParserType.KnowledgeGraph]],
[['eml'], [DocumentParserType.Email]],
]);
const getParserList = (
values: string[],
parserList: Array<{
value: string;
label: string;
}>,
) => {
return parserList.filter((x) => values?.some((y) => y === x.value));
};
export const useFetchParserListOnMount = (
documentId: string,
parserId: DocumentParserType,
documentExtension: string,
form: FormInstance,
) => {
const [selectedTag, setSelectedTag] = useState<DocumentParserType>();
const parserList = useSelectParserList();
const handleChunkMethodSelectChange = useHandleChunkMethodSelectChange(form);
const nextParserList = useMemo(() => {
const key = [...ParserListMap.keys()].find((x) =>
x.some((y) => y === documentExtension),
);
if (key) {
const values = ParserListMap.get(key);
return getParserList(values ?? [], parserList);
}
return getParserList(
[
DocumentParserType.Naive,
DocumentParserType.Resume,
DocumentParserType.Book,
DocumentParserType.Laws,
DocumentParserType.One,
DocumentParserType.Qa,
DocumentParserType.Table,
],
parserList,
);
}, [parserList, documentExtension]);
useEffect(() => {
setSelectedTag(parserId);
}, [parserId, documentId]);
const handleChange = (tag: string) => {
handleChunkMethodSelectChange(tag);
setSelectedTag(tag as DocumentParserType);
};
return { parserList: nextParserList, handleChange, selectedTag };
};
const hideAutoKeywords = [
DocumentParserType.Qa,
DocumentParserType.Table,
DocumentParserType.Resume,
DocumentParserType.KnowledgeGraph,
DocumentParserType.Tag,
];
export const useShowAutoKeywords = () => {
const showAutoKeywords = useCallback(
(selectedTag: DocumentParserType | undefined) => {
return hideAutoKeywords.every((x) => selectedTag !== x);
},
[],
);
return showAutoKeywords;
};

View File

@ -1,14 +0,0 @@
.pageInputNumber {
width: 220px;
}
.questionIcon {
margin-inline-start: 4px;
color: rgba(0, 0, 0, 0.45);
cursor: help;
writing-mode: horizontal-tb;
}
.chunkMethod {
margin-bottom: 0;
}

View File

@ -1,350 +0,0 @@
import MaxTokenNumber from '@/components/max-token-number';
import { IModalManagerChildrenProps } from '@/components/modal-manager';
import {
MinusCircleOutlined,
PlusOutlined,
QuestionCircleOutlined,
} from '@ant-design/icons';
import {
Button,
Divider,
Form,
InputNumber,
Modal,
Select,
Space,
Tooltip,
} from 'antd';
import omit from 'lodash/omit';
import React, { useEffect, useMemo } from 'react';
import { useFetchParserListOnMount, useShowAutoKeywords } from './hooks';
import { DocumentParserType } from '@/constants/knowledge';
import { useTranslate } from '@/hooks/common-hooks';
import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request';
import { IParserConfig } from '@/interfaces/database/document';
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
import { get } from 'lodash';
import { AutoKeywordsItem, AutoQuestionsItem } from '../auto-keywords-item';
import { DatasetConfigurationContainer } from '../dataset-configuration-container';
import Delimiter from '../delimiter';
import EntityTypesItem from '../entity-types-item';
import ExcelToHtml from '../excel-to-html';
import LayoutRecognize from '../layout-recognize';
import ParseConfiguration, {
showRaptorParseConfiguration,
} from '../parse-configuration';
import {
UseGraphRagItem,
showGraphRagItems,
} from '../parse-configuration/graph-rag-items';
import styles from './index.less';
interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> {
loading: boolean;
onOk: (
parserId: DocumentParserType | undefined,
parserConfig: IChangeParserConfigRequestBody,
) => void;
showModal?(): void;
parserId: DocumentParserType;
parserConfig: IParserConfig;
documentExtension: string;
documentId: string;
}
const hidePagesChunkMethods = [
DocumentParserType.Qa,
DocumentParserType.Table,
DocumentParserType.Picture,
DocumentParserType.Resume,
DocumentParserType.One,
DocumentParserType.KnowledgeGraph,
];
const ChunkMethodModal: React.FC<IProps> = ({
documentId,
parserId,
onOk,
hideModal,
visible,
documentExtension,
parserConfig,
loading,
}) => {
const [form] = Form.useForm();
const { parserList, handleChange, selectedTag } = useFetchParserListOnMount(
documentId,
parserId,
documentExtension,
form,
);
const { t } = useTranslate('knowledgeDetails');
const { data: knowledgeDetails } = useFetchKnowledgeBaseConfiguration();
const useGraphRag = useMemo(() => {
return knowledgeDetails.parser_config?.graphrag?.use_graphrag;
}, [knowledgeDetails.parser_config?.graphrag?.use_graphrag]);
const handleOk = async () => {
const values = await form.validateFields();
const parser_config = {
...values.parser_config,
pages: values.pages?.map((x: any) => [x.from, x.to]) ?? [],
};
onOk(selectedTag, parser_config);
};
const isPdf = documentExtension === 'pdf';
const showPages = useMemo(() => {
return isPdf && hidePagesChunkMethods.every((x) => x !== selectedTag);
}, [selectedTag, isPdf]);
const showOne = useMemo(() => {
return (
isPdf &&
hidePagesChunkMethods
.filter((x) => x !== DocumentParserType.One)
.every((x) => x !== selectedTag)
);
}, [selectedTag, isPdf]);
const showMaxTokenNumber =
selectedTag === DocumentParserType.Naive ||
selectedTag === DocumentParserType.KnowledgeGraph;
const showEntityTypes = selectedTag === DocumentParserType.KnowledgeGraph;
const showExcelToHtml =
selectedTag === DocumentParserType.Naive && documentExtension === 'xlsx';
const showAutoKeywords = useShowAutoKeywords();
const afterClose = () => {
form.resetFields();
};
useEffect(() => {
if (visible) {
const pages =
parserConfig?.pages?.map((x) => ({ from: x[0], to: x[1] })) ?? [];
form.setFieldsValue({
pages: pages.length > 0 ? pages : [{ from: 1, to: 1024 }],
parser_config: {
...omit(parserConfig, 'pages'),
graphrag: {
use_graphrag: get(
parserConfig,
'graphrag.use_graphrag',
useGraphRag,
),
},
},
});
}
}, [
form,
knowledgeDetails.parser_config,
parserConfig,
useGraphRag,
visible,
]);
return (
<Modal
title={t('chunkMethod')}
open={visible}
onOk={handleOk}
onCancel={hideModal}
afterClose={afterClose}
confirmLoading={loading}
width={700}
>
<Space size={[0, 8]} wrap>
<Form.Item label={t('chunkMethod')} className={styles.chunkMethod}>
<Select
style={{ width: 160 }}
onChange={handleChange}
value={selectedTag}
options={parserList}
/>
</Form.Item>
</Space>
<Divider></Divider>
<Form
name="dynamic_form_nest_item"
autoComplete="off"
form={form}
className="space-y-4"
>
{showPages && (
<>
<Space>
<p>{t('pageRanges')}:</p>
<Tooltip title={t('pageRangesTip')}>
<QuestionCircleOutlined
className={styles.questionIcon}
></QuestionCircleOutlined>
</Tooltip>
</Space>
<Form.List name="pages">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, ...restField }) => (
<Space
key={key}
style={{
display: 'flex',
}}
align="baseline"
>
<Form.Item
{...restField}
name={[name, 'from']}
dependencies={name > 0 ? [name - 1, 'to'] : []}
rules={[
{
required: true,
message: t('fromMessage'),
},
({ getFieldValue }) => ({
validator(_, value) {
if (
name === 0 ||
!value ||
getFieldValue(['pages', name - 1, 'to']) < value
) {
return Promise.resolve();
}
return Promise.reject(
new Error(t('greaterThanPrevious')),
);
},
}),
]}
>
<InputNumber
placeholder={t('fromPlaceholder')}
min={0}
precision={0}
className={styles.pageInputNumber}
/>
</Form.Item>
<Form.Item
{...restField}
name={[name, 'to']}
dependencies={[name, 'from']}
rules={[
{
required: true,
message: t('toMessage'),
},
({ getFieldValue }) => ({
validator(_, value) {
if (
!value ||
getFieldValue(['pages', name, 'from']) < value
) {
return Promise.resolve();
}
return Promise.reject(
new Error(t('greaterThan')),
);
},
}),
]}
>
<InputNumber
placeholder={t('toPlaceholder')}
min={0}
precision={0}
className={styles.pageInputNumber}
/>
</Form.Item>
{name > 0 && (
<MinusCircleOutlined onClick={() => remove(name)} />
)}
</Space>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => add()}
block
icon={<PlusOutlined />}
>
{t('addPage')}
</Button>
</Form.Item>
</>
)}
</Form.List>
</>
)}
{showPages && (
<Form.Item
noStyle
dependencies={[['parser_config', 'layout_recognize']]}
>
{({ getFieldValue }) =>
getFieldValue(['parser_config', 'layout_recognize']) && (
<Form.Item
name={['parser_config', 'task_page_size']}
label={t('taskPageSize')}
tooltip={t('taskPageSizeTip')}
initialValue={12}
rules={[
{
required: true,
message: t('taskPageSizeMessage'),
},
]}
>
<InputNumber min={1} max={128} />
</Form.Item>
)
}
</Form.Item>
)}
<DatasetConfigurationContainer show={showOne || showMaxTokenNumber}>
{showOne && <LayoutRecognize></LayoutRecognize>}
{showMaxTokenNumber && (
<>
<MaxTokenNumber
max={
selectedTag === DocumentParserType.KnowledgeGraph
? 8192 * 2
: 2048
}
></MaxTokenNumber>
<Delimiter></Delimiter>
</>
)}
</DatasetConfigurationContainer>
<DatasetConfigurationContainer
show={showAutoKeywords(selectedTag) || showExcelToHtml}
>
{showAutoKeywords(selectedTag) && (
<>
<AutoKeywordsItem></AutoKeywordsItem>
<AutoQuestionsItem></AutoQuestionsItem>
</>
)}
{showExcelToHtml && <ExcelToHtml></ExcelToHtml>}
</DatasetConfigurationContainer>
{showRaptorParseConfiguration(selectedTag) && (
<DatasetConfigurationContainer>
<ParseConfiguration></ParseConfiguration>
</DatasetConfigurationContainer>
)}
{showGraphRagItems(selectedTag) && useGraphRag && (
<UseGraphRagItem></UseGraphRagItem>
)}
{showEntityTypes && <EntityTypesItem></EntityTypesItem>}
</Form>
</Modal>
);
};
export default ChunkMethodModal;

View File

@ -1,40 +0,0 @@
import { Select as AntSelect, Form } from 'antd';
import { useTranslation } from 'react-i18next';
const Languages = [
'English',
'Chinese',
'Spanish',
'French',
'German',
'Japanese',
'Korean',
'Vietnamese',
];
const options = Languages.map((x) => ({ label: x, value: x }));
type CrossLanguageItemProps = {
name?: string | Array<string>;
};
export const CrossLanguageItem = ({
name = ['prompt_config', 'cross_languages'],
}: CrossLanguageItemProps) => {
const { t } = useTranslation();
return (
<Form.Item
label={t('chat.crossLanguage')}
name={name}
tooltip={t('chat.crossLanguageTip')}
>
<AntSelect
options={options}
allowClear
placeholder={t('common.languagePlaceholder')}
mode="multiple"
/>
</Form.Item>
);
};

View File

@ -1,42 +0,0 @@
import { Form, Input } from 'antd';
import { useTranslation } from 'react-i18next';
interface IProps {
value?: string | undefined;
onChange?: (val: string | undefined) => void;
maxLength?: number;
}
export const DelimiterInput = ({ value, onChange, maxLength }: IProps) => {
const nextValue = value?.replaceAll('\n', '\\n');
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const val = e.target.value;
const nextValue = val.replaceAll('\\n', '\n');
onChange?.(nextValue);
};
return (
<Input
value={nextValue}
onChange={handleInputChange}
maxLength={maxLength}
></Input>
);
};
const Delimiter = () => {
const { t } = useTranslation();
return (
<Form.Item
name={['parser_config', 'delimiter']}
label={t('knowledgeDetails.delimiter')}
initialValue={`\n`}
rules={[{ required: true }]}
tooltip={t('knowledgeDetails.delimiterTip')}
>
<DelimiterInput />
</Form.Item>
);
};
export default Delimiter;

View File

@ -1,33 +0,0 @@
import { useTranslate } from '@/hooks/common-hooks';
import { Form } from 'antd';
import EditTag from './edit-tag';
const initialEntityTypes = [
'organization',
'person',
'geo',
'event',
'category',
];
type IProps = {
field?: string[];
};
const EntityTypesItem = ({
field = ['parser_config', 'entity_types'],
}: IProps) => {
const { t } = useTranslate('knowledgeConfiguration');
return (
<Form.Item
name={field}
label={t('entityTypes')}
rules={[{ required: true }]}
initialValue={initialEntityTypes}
>
<EditTag />
</Form.Item>
);
};
export default EntityTypesItem;

View File

@ -1,19 +0,0 @@
import { useTranslate } from '@/hooks/common-hooks';
import { Form, Switch } from 'antd';
const ExcelToHtml = () => {
const { t } = useTranslate('knowledgeDetails');
return (
<Form.Item
name={['parser_config', 'html4excel']}
label={t('html4excel')}
initialValue={false}
valuePropName="checked"
tooltip={t('html4excelTip')}
>
<Switch />
</Form.Item>
);
};
export default ExcelToHtml;

View File

@ -0,0 +1,77 @@
import { IModalProps } from '@/interfaces/common';
import { IFeedbackRequestBody } from '@/interfaces/request/chat';
import { zodResolver } from '@hookform/resolvers/zod';
import { useCallback } from 'react';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { z } from 'zod';
import { RAGFlowFormItem } from './ragflow-form';
import { ButtonLoading } from './ui/button';
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
} from './ui/dialog';
import { Form } from './ui/form';
import { Textarea } from './ui/textarea';
const FormId = 'feedback-dialog';
const FeedbackDialog = ({
visible,
hideModal,
onOk,
loading,
}: IModalProps<IFeedbackRequestBody>) => {
const { t } = useTranslation();
const FormSchema = z.object({
feedback: z
.string()
.min(1, {
message: t('common.namePlaceholder'),
})
.trim(),
});
const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
defaultValues: { feedback: '' },
});
const handleOk = useCallback(
async (data: z.infer<typeof FormSchema>) => {
return onOk?.({ thumbup: false, feedback: data.feedback });
},
[onOk],
);
return (
<Dialog open={visible} onOpenChange={hideModal}>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Feedback</DialogTitle>
</DialogHeader>
<Form {...form}>
<form
onSubmit={form.handleSubmit(handleOk)}
className="space-y-6"
id={FormId}
>
<RAGFlowFormItem name="feedback">
<Textarea> </Textarea>
</RAGFlowFormItem>
</form>
</Form>
<DialogFooter>
<ButtonLoading type="submit" form={FormId} loading={loading}>
{t('common.save')}
</ButtonLoading>
</DialogFooter>
</DialogContent>
</Dialog>
);
};
export default FeedbackDialog;

View File

@ -1,13 +0,0 @@
.uploader {
:global {
.ant-upload-list {
max-height: 40vh;
overflow-y: auto;
}
}
}
.uploadLimit {
color: red;
font-size: 12px;
}

View File

@ -1,191 +0,0 @@
import { useTranslate } from '@/hooks/common-hooks';
import { IModalProps } from '@/interfaces/common';
import { InboxOutlined } from '@ant-design/icons';
import {
Checkbox,
Flex,
Modal,
Progress,
Segmented,
Tabs,
TabsProps,
Upload,
UploadFile,
UploadProps,
} from 'antd';
import { Dispatch, SetStateAction, useState } from 'react';
import styles from './index.less';
const { Dragger } = Upload;
const FileUpload = ({
directory,
fileList,
setFileList,
uploadProgress,
}: {
directory: boolean;
fileList: UploadFile[];
setFileList: Dispatch<SetStateAction<UploadFile[]>>;
uploadProgress?: number;
}) => {
const { t } = useTranslate('fileManager');
const props: UploadProps = {
multiple: true,
onRemove: (file) => {
const index = fileList.indexOf(file);
const newFileList = fileList.slice();
newFileList.splice(index, 1);
setFileList(newFileList);
},
beforeUpload: (file: UploadFile) => {
setFileList((pre) => {
return [...pre, file];
});
return false;
},
directory,
fileList,
progress: {
strokeWidth: 2,
},
};
return (
<>
<Progress percent={uploadProgress} showInfo={false} />
<Dragger {...props} className={styles.uploader}>
<p className="ant-upload-drag-icon">
<InboxOutlined />
</p>
<p className="ant-upload-text">{t('uploadTitle')}</p>
<p className="ant-upload-hint">{t('uploadDescription')}</p>
{false && <p className={styles.uploadLimit}>{t('uploadLimit')}</p>}
</Dragger>
</>
);
};
interface IFileUploadModalProps
extends IModalProps<
{ parseOnCreation: boolean; directoryFileList: UploadFile[] } | UploadFile[]
> {
uploadFileList?: UploadFile[];
setUploadFileList?: Dispatch<SetStateAction<UploadFile[]>>;
uploadProgress?: number;
setUploadProgress?: Dispatch<SetStateAction<number>>;
}
const FileUploadModal = ({
visible,
hideModal,
loading,
onOk: onFileUploadOk,
uploadFileList: fileList,
setUploadFileList: setFileList,
uploadProgress,
setUploadProgress,
}: IFileUploadModalProps) => {
const { t } = useTranslate('fileManager');
const [value, setValue] = useState<string | number>('local');
const [parseOnCreation, setParseOnCreation] = useState(false);
const [currentFileList, setCurrentFileList] = useState<UploadFile[]>([]);
const [directoryFileList, setDirectoryFileList] = useState<UploadFile[]>([]);
const clearFileList = () => {
if (setFileList) {
setFileList([]);
setUploadProgress?.(0);
} else {
setCurrentFileList([]);
}
setDirectoryFileList([]);
};
const onOk = async () => {
if (uploadProgress === 100) {
hideModal?.();
return;
}
const ret = await onFileUploadOk?.(
fileList
? { parseOnCreation, directoryFileList }
: [...currentFileList, ...directoryFileList],
);
return ret;
};
const afterClose = () => {
clearFileList();
};
const items: TabsProps['items'] = [
{
key: '1',
label: t('file'),
children: (
<FileUpload
directory={false}
fileList={fileList ? fileList : currentFileList}
setFileList={setFileList ? setFileList : setCurrentFileList}
uploadProgress={uploadProgress}
></FileUpload>
),
},
{
key: '2',
label: t('directory'),
children: (
<FileUpload
directory
fileList={directoryFileList}
setFileList={setDirectoryFileList}
uploadProgress={uploadProgress}
></FileUpload>
),
},
];
return (
<>
<Modal
title={t('uploadFile')}
open={visible}
onOk={onOk}
onCancel={hideModal}
confirmLoading={loading}
afterClose={afterClose}
>
<Flex gap={'large'} vertical>
<Segmented
options={[
{ label: t('local'), value: 'local' },
{ label: t('s3'), value: 's3' },
]}
block
value={value}
onChange={setValue}
/>
{value === 'local' ? (
<>
<Checkbox
checked={parseOnCreation}
onChange={(e) => setParseOnCreation(e.target.checked)}
>
{t('parseOnCreation')}
</Checkbox>
<Tabs defaultActiveKey="1" items={items} />
</>
) : (
t('comingSoon', { keyPrefix: 'common' })
)}
</Flex>
</Modal>
</>
);
};
export default FileUploadModal;

View File

@ -1,55 +0,0 @@
import { LlmModelType } from '@/constants/knowledge';
import { useTranslate } from '@/hooks/common-hooks';
import { useSelectLlmOptionsByModelType } from '@/hooks/use-llm-request';
import { Form, Select } from 'antd';
import { camelCase } from 'lodash';
import { useMemo } from 'react';
const enum DocumentType {
DeepDOC = 'DeepDOC',
PlainText = 'Plain Text',
}
const LayoutRecognize = () => {
const { t } = useTranslate('knowledgeDetails');
const allOptions = useSelectLlmOptionsByModelType();
const options = useMemo(() => {
const list = [DocumentType.DeepDOC, DocumentType.PlainText].map((x) => ({
label: x === DocumentType.PlainText ? t(camelCase(x)) : 'DeepDoc',
value: x,
}));
const image2TextList = allOptions[LlmModelType.Image2text].map((x) => {
return {
...x,
options: x.options.map((y) => {
return {
...y,
label: (
<div className="flex justify-between items-center gap-2">
{y.label}
<span className="text-red-500 text-sm">Experimental</span>
</div>
),
};
}),
};
});
return [...list, ...image2TextList];
}, [allOptions, t]);
return (
<Form.Item
name={['parser_config', 'layout_recognize']}
label={t('layoutRecognize')}
initialValue={DocumentType.DeepDOC}
tooltip={t('layoutRecognizeTip')}
>
<Select options={options} popupMatchSelectWidth={false} />
</Form.Item>
);
};
export default LayoutRecognize;

View File

@ -1,51 +0,0 @@
import { useTranslate } from '@/hooks/common-hooks';
import { useLlmToolsList } from '@/hooks/plugin-hooks';
import { Select, Space } from 'antd';
interface IProps {
value?: string;
onChange?: (value: string) => void;
disabled?: boolean;
}
const LLMToolsSelect = ({ value, onChange, disabled }: IProps) => {
const { t } = useTranslate("llmTools");
const tools = useLlmToolsList();
function wrapTranslation(text: string): string {
if (!text) {
return text;
}
if (text.startsWith("$t:")) {
return t(text.substring(3));
}
return text;
}
const toolOptions = tools.map(t => ({
label: wrapTranslation(t.displayName),
description: wrapTranslation(t.displayDescription),
value: t.name,
title: wrapTranslation(t.displayDescription),
}));
return (
<Select
mode="multiple"
options={toolOptions}
optionRender={option => (
<Space size="large">
{option.label}
{option.data.description}
</Space>
)}
onChange={onChange}
value={value}
disabled={disabled}
></Select>
);
};
export default LLMToolsSelect;

View File

@ -1,37 +0,0 @@
import { useTranslate } from '@/hooks/common-hooks';
import { Flex, Form, InputNumber, Slider } from 'antd';
interface IProps {
initialValue?: number;
max?: number;
}
const MaxTokenNumber = ({ initialValue = 512, max = 2048 }: IProps) => {
const { t } = useTranslate('knowledgeConfiguration');
return (
<Form.Item label={t('chunkTokenNumber')} tooltip={t('chunkTokenNumberTip')}>
<Flex gap={20} align="center">
<Flex flex={1}>
<Form.Item
name={['parser_config', 'chunk_token_num']}
noStyle
initialValue={initialValue}
rules={[{ required: true, message: t('chunkTokenNumberMessage') }]}
>
<Slider max={max} style={{ width: '100%' }} />
</Form.Item>
</Flex>
<Form.Item
name={['parser_config', 'chunk_token_num']}
noStyle
rules={[{ required: true, message: t('chunkTokenNumberMessage') }]}
>
<InputNumber max={max} min={0} />
</Form.Item>
</Flex>
</Form.Item>
);
};
export default MaxTokenNumber;

View File

@ -1,4 +1,3 @@
import { Form, InputNumber } from 'antd';
import { useFormContext } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import {
@ -10,27 +9,6 @@ import {
} from './ui/form';
import { NumberInput } from './ui/input';
const MessageHistoryWindowSizeItem = ({
initialValue,
}: {
initialValue: number;
}) => {
const { t } = useTranslation();
return (
<Form.Item
name={'message_history_window_size'}
label={t('flow.messageHistoryWindowSize')}
initialValue={initialValue}
tooltip={t('flow.messageHistoryWindowSizeTip')}
>
<InputNumber style={{ width: '100%' }} />
</Form.Item>
);
};
export default MessageHistoryWindowSizeItem;
export function MessageHistoryWindowSizeFormField() {
const form = useFormContext();
const { t } = useTranslation();

View File

@ -1,51 +0,0 @@
import { Form, Input, Modal } from 'antd';
import { IModalProps } from '@/interfaces/common';
import { IFeedbackRequestBody } from '@/interfaces/request/chat';
import { useCallback } from 'react';
type FieldType = {
feedback?: string;
};
const FeedbackModal = ({
visible,
hideModal,
onOk,
loading,
}: IModalProps<IFeedbackRequestBody>) => {
const [form] = Form.useForm();
const handleOk = useCallback(async () => {
const ret = await form.validateFields();
return onOk?.({ thumbup: false, feedback: ret.feedback });
}, [onOk, form]);
return (
<Modal
title="Feedback"
open={visible}
onOk={handleOk}
onCancel={hideModal}
confirmLoading={loading}
>
<Form
name="basic"
labelCol={{ span: 0 }}
wrapperCol={{ span: 24 }}
style={{ maxWidth: 600 }}
autoComplete="off"
form={form}
>
<Form.Item<FieldType>
name="feedback"
rules={[{ required: true, message: 'Please input your feedback!' }]}
>
<Input.TextArea rows={8} placeholder="Please input your feedback!" />
</Form.Item>
</Form>
</Modal>
);
};
export default FeedbackModal;

View File

@ -13,9 +13,9 @@ import {
import { Radio, Tooltip } from 'antd';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import FeedbackModal from './feedback-modal';
import FeedbackDialog from '../feedback-dialog';
import { PromptDialog } from '../prompt-dialog';
import { useRemoveMessage, useSendFeedback, useSpeech } from './hooks';
import PromptModal from './prompt-modal';
interface IProps {
messageId: string;
@ -79,19 +79,19 @@ export const AssistantGroupButton = ({
)}
</Radio.Group>
{visible && (
<FeedbackModal
<FeedbackDialog
visible={visible}
hideModal={hideModal}
onOk={onFeedbackOk}
loading={loading}
></FeedbackModal>
></FeedbackDialog>
)}
{promptVisible && (
<PromptModal
<PromptDialog
visible={promptVisible}
hideModal={hidePromptModal}
prompt={prompt}
></PromptModal>
></PromptDialog>
)}
</>
);

View File

@ -1,30 +0,0 @@
import { IModalProps } from '@/interfaces/common';
import { IFeedbackRequestBody } from '@/interfaces/request/chat';
import { Modal, Space } from 'antd';
import HightLightMarkdown from '../highlight-markdown';
import SvgIcon from '../svg-icon';
const PromptModal = ({
visible,
hideModal,
prompt,
}: IModalProps<IFeedbackRequestBody> & { prompt?: string }) => {
return (
<Modal
title={
<Space>
<SvgIcon name={`prompt`} width={18}></SvgIcon>
Prompt
</Space>
}
width={'80%'}
open={visible}
onCancel={hideModal}
footer={null}
>
<HightLightMarkdown>{prompt}</HightLightMarkdown>
</Modal>
);
};
export default PromptModal;

View File

@ -1,51 +0,0 @@
import { Form, Input, Modal } from 'antd';
import { IModalProps } from '@/interfaces/common';
import { IFeedbackRequestBody } from '@/interfaces/request/chat';
import { useCallback } from 'react';
type FieldType = {
feedback?: string;
};
const FeedbackModal = ({
visible,
hideModal,
onOk,
loading,
}: IModalProps<IFeedbackRequestBody>) => {
const [form] = Form.useForm();
const handleOk = useCallback(async () => {
const ret = await form.validateFields();
return onOk?.({ thumbup: false, feedback: ret.feedback });
}, [onOk, form]);
return (
<Modal
title="Feedback"
open={visible}
onOk={handleOk}
onCancel={hideModal}
confirmLoading={loading}
>
<Form
name="basic"
labelCol={{ span: 0 }}
wrapperCol={{ span: 24 }}
style={{ maxWidth: 600 }}
autoComplete="off"
form={form}
>
<Form.Item<FieldType>
name="feedback"
rules={[{ required: true, message: 'Please input your feedback!' }]}
>
<Input.TextArea rows={8} placeholder="Please input your feedback!" />
</Form.Item>
</Form>
</Modal>
);
};
export default FeedbackModal;

View File

@ -17,10 +17,10 @@ import { Radio, Tooltip } from 'antd';
import { Download, NotebookText } from 'lucide-react';
import { useCallback, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import FeedbackDialog from '../feedback-dialog';
import { PromptDialog } from '../prompt-dialog';
import { ToggleGroup, ToggleGroupItem } from '../ui/toggle-group';
import FeedbackModal from './feedback-modal';
import { useRemoveMessage, useSendFeedback, useSpeech } from './hooks';
import PromptModal from './prompt-modal';
interface IProps {
messageId: string;
@ -129,19 +129,19 @@ export const AssistantGroupButton = ({
)}
</ToggleGroup>
{visible && (
<FeedbackModal
<FeedbackDialog
visible={visible}
hideModal={hideModal}
onOk={onFeedbackOk}
loading={loading}
></FeedbackModal>
></FeedbackDialog>
)}
{promptVisible && (
<PromptModal
<PromptDialog
visible={promptVisible}
hideModal={hidePromptModal}
prompt={prompt}
></PromptModal>
></PromptDialog>
)}
</>
);

View File

@ -1,30 +0,0 @@
import { IModalProps } from '@/interfaces/common';
import { IFeedbackRequestBody } from '@/interfaces/request/chat';
import { Modal, Space } from 'antd';
import HightLightMarkdown from '../highlight-markdown';
import SvgIcon from '../svg-icon';
const PromptModal = ({
visible,
hideModal,
prompt,
}: IModalProps<IFeedbackRequestBody> & { prompt?: string }) => {
return (
<Modal
title={
<Space>
<SvgIcon name={`prompt`} width={18}></SvgIcon>
Prompt
</Space>
}
width={'80%'}
open={visible}
onCancel={hideModal}
footer={null}
>
<HightLightMarkdown>{prompt}</HightLightMarkdown>
</Modal>
);
};
export default PromptModal;

View File

@ -1,4 +0,0 @@
.delete {
// height: 24px;
display: inline-block;
}

View File

@ -1,90 +0,0 @@
import { useShowDeleteConfirm } from '@/hooks/common-hooks';
import { DeleteOutlined, MoreOutlined } from '@ant-design/icons';
import { Dropdown, MenuProps, Space } from 'antd';
import { useTranslation } from 'react-i18next';
import React, { useMemo } from 'react';
import styles from './index.less';
interface IProps {
deleteItem: () => Promise<any> | void;
iconFontSize?: number;
iconFontColor?: string;
items?: MenuProps['items'];
height?: number;
needsDeletionValidation?: boolean;
showDeleteItems?: boolean;
}
const OperateDropdown = ({
deleteItem,
children,
iconFontSize = 30,
iconFontColor = 'gray',
items: otherItems = [],
height = 24,
needsDeletionValidation = true,
showDeleteItems = true,
}: React.PropsWithChildren<IProps>) => {
const { t } = useTranslation();
const showDeleteConfirm = useShowDeleteConfirm();
const handleDelete = () => {
if (needsDeletionValidation) {
showDeleteConfirm({ onOk: deleteItem });
} else {
deleteItem();
}
};
const handleDropdownMenuClick: MenuProps['onClick'] = ({ domEvent, key }) => {
domEvent.preventDefault();
domEvent.stopPropagation();
if (key === '1') {
handleDelete();
}
};
const items: MenuProps['items'] = useMemo(() => {
const items = [];
if (showDeleteItems) {
items.push({
key: '1',
label: (
<Space>
{t('common.delete')}
<DeleteOutlined />
</Space>
),
});
}
return [...items, ...otherItems];
}, [showDeleteItems, otherItems, t]);
return (
<Dropdown
menu={{
items,
onClick: handleDropdownMenuClick,
}}
>
{children || (
<span className={styles.delete}>
<MoreOutlined
rotate={90}
style={{
fontSize: iconFontSize,
color: iconFontColor,
cursor: 'pointer',
height,
}}
/>
</span>
)}
</Dropdown>
);
};
export default OperateDropdown;

View File

@ -1,28 +0,0 @@
import { useTranslate } from '@/hooks/common-hooks';
import { Flex, Form, InputNumber, Slider } from 'antd';
const PageRank = () => {
const { t } = useTranslate('knowledgeConfiguration');
return (
<Form.Item label={t('pageRank')} tooltip={t('pageRankTip')}>
<Flex gap={20} align="center">
<Flex flex={1}>
<Form.Item
name={['pagerank']}
noStyle
initialValue={0}
rules={[{ required: true }]}
>
<Slider max={100} style={{ width: '100%' }} />
</Form.Item>
</Flex>
<Form.Item name={['pagerank']} noStyle rules={[{ required: true }]}>
<InputNumber max={100} min={0} />
</Form.Item>
</Flex>
</Form.Item>
);
};
export default PageRank;

View File

@ -1,138 +0,0 @@
import { DocumentParserType } from '@/constants/knowledge';
import { useTranslate } from '@/hooks/common-hooks';
import { cn } from '@/lib/utils';
import { Form, Select, Switch } from 'antd';
import { upperFirst } from 'lodash';
import { useCallback, useMemo } from 'react';
import { DatasetConfigurationContainer } from '../dataset-configuration-container';
import EntityTypesItem from '../entity-types-item';
const excludedTagParseMethods = [
DocumentParserType.Table,
DocumentParserType.KnowledgeGraph,
DocumentParserType.Tag,
];
export const showTagItems = (parserId: DocumentParserType) => {
return !excludedTagParseMethods.includes(parserId);
};
const enum MethodValue {
General = 'general',
Light = 'light',
}
export const excludedParseMethods = [
DocumentParserType.Table,
DocumentParserType.Resume,
DocumentParserType.Picture,
DocumentParserType.KnowledgeGraph,
DocumentParserType.Qa,
DocumentParserType.Tag,
];
export const showGraphRagItems = (parserId: DocumentParserType | undefined) => {
return !excludedParseMethods.some((x) => x === parserId);
};
type GraphRagItemsProps = {
marginBottom?: boolean;
};
export function UseGraphRagItem() {
const { t } = useTranslate('knowledgeConfiguration');
return (
<Form.Item
name={['parser_config', 'graphrag', 'use_graphrag']}
label={t('useGraphRag')}
initialValue={false}
valuePropName="checked"
tooltip={t('useGraphRagTip')}
>
<Switch />
</Form.Item>
);
}
// The three types "table", "resume" and "one" do not display this configuration.
const GraphRagItems = ({ marginBottom = false }: GraphRagItemsProps) => {
const { t } = useTranslate('knowledgeConfiguration');
const methodOptions = useMemo(() => {
return [MethodValue.Light, MethodValue.General].map((x) => ({
value: x,
label: upperFirst(x),
}));
}, []);
const renderWideTooltip = useCallback(
(title: React.ReactNode | string) => {
return {
title: typeof title === 'string' ? t(title) : title,
overlayInnerStyle: { width: '32vw' },
};
},
[t],
);
return (
<DatasetConfigurationContainer className={cn({ 'mb-4': marginBottom })}>
<UseGraphRagItem></UseGraphRagItem>
<Form.Item
shouldUpdate={(prevValues, curValues) =>
prevValues.parser_config.graphrag.use_graphrag !==
curValues.parser_config.graphrag.use_graphrag
}
>
{({ getFieldValue }) => {
const useRaptor = getFieldValue([
'parser_config',
'graphrag',
'use_graphrag',
]);
return (
useRaptor && (
<>
<EntityTypesItem
field={['parser_config', 'graphrag', 'entity_types']}
></EntityTypesItem>
<Form.Item
name={['parser_config', 'graphrag', 'method']}
label={t('graphRagMethod')}
tooltip={renderWideTooltip(
<div
dangerouslySetInnerHTML={{
__html: t('graphRagMethodTip'),
}}
></div>,
)}
initialValue={MethodValue.Light}
>
<Select options={methodOptions} />
</Form.Item>
<Form.Item
name={['parser_config', 'graphrag', 'resolution']}
label={t('resolution')}
tooltip={renderWideTooltip('resolutionTip')}
>
<Switch />
</Form.Item>
<Form.Item
name={['parser_config', 'graphrag', 'community']}
label={t('community')}
tooltip={renderWideTooltip('communityTip')}
>
<Switch />
</Form.Item>
</>
)
);
}}
</Form.Item>
</DatasetConfigurationContainer>
);
};
export default GraphRagItems;

View File

@ -0,0 +1,33 @@
import { IModalProps } from '@/interfaces/common';
import { IFeedbackRequestBody } from '@/interfaces/request/chat';
import HightLightMarkdown from './highlight-markdown';
import SvgIcon from './svg-icon';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from './ui/dialog';
type PromptDialogProps = IModalProps<IFeedbackRequestBody> & {
prompt?: string;
};
export function PromptDialog({
visible,
hideModal,
prompt,
}: PromptDialogProps) {
return (
<Dialog open={visible} onOpenChange={hideModal}>
<DialogContent className="max-w-[80vw]">
<DialogHeader>
<DialogTitle>
<div className="space-x-2">
<SvgIcon name={`prompt`} width={18}></SvgIcon>
<span> Prompt</span>
</div>
</DialogTitle>
</DialogHeader>
<section className="max-h-[80vh] overflow-auto">
<HightLightMarkdown>{prompt}</HightLightMarkdown>
</section>
</DialogContent>
</Dialog>
);
}

View File

@ -1,82 +0,0 @@
import { useTranslate } from '@/hooks/common-hooks';
import { Form, Input, Modal } from 'antd';
import { useEffect } from 'react';
import { IModalManagerChildrenProps } from '../modal-manager';
interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> {
loading: boolean;
initialName: string;
onOk: (name: string) => void;
showModal?(): void;
}
const RenameModal = ({
visible,
hideModal,
loading,
initialName,
onOk,
}: IProps) => {
const [form] = Form.useForm();
const { t } = useTranslate('common');
type FieldType = {
name?: string;
};
const handleOk = async () => {
const ret = await form.validateFields();
return onOk(ret.name);
};
const handleCancel = () => {
hideModal();
};
const onFinish = (values: any) => {
console.log('Success:', values);
};
const onFinishFailed = (errorInfo: any) => {
console.log('Failed:', errorInfo);
};
useEffect(() => {
if (visible) {
form.setFieldValue('name', initialName);
}
}, [initialName, form, visible]);
return (
<Modal
title={t('rename')}
open={visible}
onOk={handleOk}
onCancel={handleCancel}
okButtonProps={{ loading }}
confirmLoading={loading}
>
<Form
name="basic"
labelCol={{ span: 4 }}
wrapperCol={{ span: 20 }}
style={{ maxWidth: 600 }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
form={form}
>
<Form.Item<FieldType>
label={t('name')}
name="name"
rules={[{ required: true, message: t('namePlaceholder') }]}
>
<Input />
</Form.Item>
</Form>
</Modal>
);
};
export default RenameModal;

View File

@ -1,8 +1,6 @@
import { LlmModelType } from '@/constants/knowledge';
import { useTranslate } from '@/hooks/common-hooks';
import { useSelectLlmOptionsByModelType } from '@/hooks/use-llm-request';
import { Select as AntSelect, Form, message, Slider } from 'antd';
import { useCallback } from 'react';
import { useFormContext } from 'react-hook-form';
import { z } from 'zod';
import { SelectWithSearch } from './originui/select-with-search';
@ -15,47 +13,6 @@ import {
FormMessage,
} from './ui/form';
type FieldType = {
rerank_id?: string;
top_k?: number;
};
export const RerankItem = () => {
const { t } = useTranslate('knowledgeDetails');
const allOptions = useSelectLlmOptionsByModelType();
const [messageApi, contextHolder] = message.useMessage();
const handleChange = useCallback(
(val: string) => {
if (val) {
messageApi.open({
type: 'warning',
content: t('reRankModelWaring'),
});
}
},
[messageApi, t],
);
return (
<>
{contextHolder}
<Form.Item
label={t('rerankModel')}
name={'rerank_id'}
tooltip={t('rerankTip')}
>
<AntSelect
options={allOptions[LlmModelType.Rerank]}
allowClear
placeholder={t('rerankPlaceholder')}
onChange={handleChange}
/>
</Form.Item>
</>
);
};
export const topKSchema = {
top_k: z.number().optional(),
};
@ -64,35 +21,6 @@ export const initialTopKValue = {
top_k: 1024,
};
const Rerank = () => {
const { t } = useTranslate('knowledgeDetails');
return (
<>
<RerankItem></RerankItem>
<Form.Item noStyle dependencies={['rerank_id']}>
{({ getFieldValue }) => {
const rerankId = getFieldValue('rerank_id');
return (
rerankId && (
<Form.Item<FieldType>
label={t('topK')}
name={'top_k'}
initialValue={1024}
tooltip={t('topKTip')}
>
<Slider max={2048} min={1} />
</Form.Item>
)
);
}}
</Form.Item>
</>
);
};
export default Rerank;
const RerankId = 'rerank_id';
function RerankFormField() {

View File

@ -1,11 +0,0 @@
.selectFilesCollapse {
:global(.ant-collapse-header) {
padding-left: 22px;
}
margin-bottom: 32px;
overflow-y: auto;
}
.selectFilesTitle {
padding-right: 10px;
}

View File

@ -1,66 +0,0 @@
import { ReactComponent as SelectedFilesCollapseIcon } from '@/assets/svg/selected-files-collapse.svg';
import { Collapse, Flex, Space } from 'antd';
import SelectFiles from './select-files';
import {
useAllTestingResult,
useSelectTestingResult,
} from '@/hooks/use-knowledge-request';
import { useTranslation } from 'react-i18next';
import styles from './index.less';
interface IProps {
onTesting(documentIds: string[]): void;
setSelectedDocumentIds(documentIds: string[]): void;
selectedDocumentIds: string[];
}
const RetrievalDocuments = ({
onTesting,
selectedDocumentIds,
setSelectedDocumentIds,
}: IProps) => {
const { t } = useTranslation();
const { documents: documentsAll } = useAllTestingResult();
const { documents } = useSelectTestingResult();
const { documents: useDocuments } = {
documents:
documentsAll?.length > documents?.length ? documentsAll : documents,
};
return (
<Collapse
expandIcon={() => <SelectedFilesCollapseIcon></SelectedFilesCollapseIcon>}
className={styles.selectFilesCollapse}
items={[
{
key: '1',
label: (
<Flex
justify={'space-between'}
align="center"
className={styles.selectFilesTitle}
>
<Space>
<span>
{selectedDocumentIds?.length ?? 0}/{useDocuments?.length ?? 0}
</span>
{t('knowledgeDetails.filesSelected')}
</Space>
</Flex>
),
children: (
<div>
<SelectFiles
setSelectedDocumentIds={setSelectedDocumentIds}
handleTesting={onTesting}
></SelectFiles>
</div>
),
},
]}
/>
);
};
export default RetrievalDocuments;

View File

@ -1,79 +0,0 @@
import NewDocumentLink from '@/components/new-document-link';
import { useTranslate } from '@/hooks/common-hooks';
import {
useAllTestingResult,
useSelectTestingResult,
} from '@/hooks/use-knowledge-request';
import { ITestingDocument } from '@/interfaces/database/knowledge';
import { EyeOutlined } from '@ant-design/icons';
import { Button, Table, TableProps, Tooltip } from 'antd';
interface IProps {
handleTesting: (ids: string[]) => void;
setSelectedDocumentIds: (ids: string[]) => void;
}
const SelectFiles = ({ setSelectedDocumentIds, handleTesting }: IProps) => {
const { documents } = useSelectTestingResult();
const { documents: documentsAll } = useAllTestingResult();
const useDocuments =
documentsAll?.length > documents?.length ? documentsAll : documents;
const { t } = useTranslate('fileManager');
const columns: TableProps<ITestingDocument>['columns'] = [
{
title: 'Name',
dataIndex: 'doc_name',
key: 'doc_name',
render: (text) => <p>{text}</p>,
},
{
title: 'Hits',
dataIndex: 'count',
key: 'count',
width: 80,
},
{
title: 'View',
key: 'view',
width: 50,
render: (_, { doc_id, doc_name }) => (
<NewDocumentLink
documentName={doc_name}
documentId={doc_id}
prefix="document"
>
<Tooltip title={t('preview')}>
<Button type="text">
<EyeOutlined size={20} />
</Button>
</Tooltip>
</NewDocumentLink>
),
},
];
const rowSelection = {
onChange: (selectedRowKeys: React.Key[]) => {
handleTesting(selectedRowKeys as string[]);
setSelectedDocumentIds(selectedRowKeys as string[]);
},
getCheckboxProps: (record: ITestingDocument) => ({
disabled: record.doc_name === 'Disabled User', // Column configuration not to be checked
name: record.doc_name,
}),
};
return (
<Table
columns={columns}
dataSource={useDocuments}
showHeader={false}
rowSelection={rowSelection}
rowKey={'doc_id'}
/>
);
};
export default SelectFiles;

View File

@ -1,7 +1,6 @@
import { FormLayout } from '@/constants/form';
import { useTranslate } from '@/hooks/common-hooks';
import { cn } from '@/lib/utils';
import { Form, Slider } from 'antd';
import { useFormContext } from 'react-hook-form';
import { z } from 'zod';
import { SliderInputFormField } from '../slider-input-form-field';
@ -15,46 +14,6 @@ import {
} from '../ui/form';
import { NumberInput } from '../ui/input';
type FieldType = {
similarity_threshold?: number;
// vector_similarity_weight?: number;
};
interface IProps {
isTooltipShown?: boolean;
vectorSimilarityWeightName?: string;
}
const SimilaritySlider = ({
isTooltipShown = false,
vectorSimilarityWeightName = 'vector_similarity_weight',
}: IProps) => {
const { t } = useTranslate('knowledgeDetails');
return (
<>
<Form.Item<FieldType>
label={t('similarityThreshold')}
name={'similarity_threshold'}
tooltip={isTooltipShown && t('similarityThresholdTip')}
initialValue={0.2}
>
<Slider max={1} step={0.01} />
</Form.Item>
<Form.Item
label={t('vectorSimilarityWeight')}
name={vectorSimilarityWeightName}
initialValue={1 - 0.3}
tooltip={isTooltipShown && t('vectorSimilarityWeightTip')}
>
<Slider max={1} step={0.01} />
</Form.Item>
</>
);
};
export default SimilaritySlider;
interface SimilaritySliderFormFieldProps {
similarityName?: string;
vectorSimilarityWeightName?: string;

View File

@ -1,28 +0,0 @@
import { useTranslate } from '@/hooks/common-hooks';
import { Form, Input, Typography } from 'antd';
interface IProps {
name?: string | string[];
}
export function TavilyItem({
name = ['prompt_config', 'tavily_api_key'],
}: IProps) {
const { t } = useTranslate('chat');
return (
<Form.Item label={'Tavily API Key'} tooltip={t('tavilyApiKeyTip')}>
<div className="flex flex-col gap-1">
<Form.Item name={name} noStyle>
<Input.Password
placeholder={t('tavilyApiKeyMessage')}
autoComplete="new-password"
/>
</Form.Item>
<Typography.Link href="https://app.tavily.com/home" target={'_blank'}>
{t('tavilyApiKeyHelp')}
</Typography.Link>
</div>
</Form.Item>
);
}

View File

@ -1,35 +1,8 @@
import { FormLayout } from '@/constants/form';
import { useTranslate } from '@/hooks/common-hooks';
import { Form, Slider } from 'antd';
import { z } from 'zod';
import { SliderInputFormField } from './slider-input-form-field';
type FieldType = {
top_n?: number;
};
interface IProps {
initialValue?: number;
max?: number;
}
const TopNItem = ({ initialValue = 8, max = 30 }: IProps) => {
const { t } = useTranslate('chat');
return (
<Form.Item<FieldType>
label={t('topN')}
name={'top_n'}
initialValue={initialValue}
tooltip={t('topNTip')}
>
<Slider max={max} />
</Form.Item>
);
};
export default TopNItem;
interface SimilaritySliderFormFieldProps {
max?: number;
}

View File

@ -1,26 +1,6 @@
import { Form, Switch } from 'antd';
import { useTranslation } from 'react-i18next';
import { SwitchFormField } from './switch-fom-field';
type IProps = {
filedName: string[] | string;
};
export function UseKnowledgeGraphItem({ filedName }: IProps) {
const { t } = useTranslation();
return (
<Form.Item
label={t('chat.useKnowledgeGraph')}
tooltip={t('chat.useKnowledgeGraphTip')}
name={filedName}
initialValue={false}
>
<Switch></Switch>
</Form.Item>
);
}
interface UseKnowledgeGraphFormFieldProps {
name: string;
}