mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-24 23:46:52 +08:00
### 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:
@ -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>
|
||||
);
|
||||
};
|
||||
@ -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;
|
||||
};
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
@ -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>
|
||||
);
|
||||
};
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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;
|
||||
77
web/src/components/feedback-dialog.tsx
Normal file
77
web/src/components/feedback-dialog.tsx
Normal 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;
|
||||
@ -1,13 +0,0 @@
|
||||
.uploader {
|
||||
:global {
|
||||
.ant-upload-list {
|
||||
max-height: 40vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.uploadLimit {
|
||||
color: red;
|
||||
font-size: 12px;
|
||||
}
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
@ -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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@ -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;
|
||||
@ -1,4 +0,0 @@
|
||||
.delete {
|
||||
// height: 24px;
|
||||
display: inline-block;
|
||||
}
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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;
|
||||
33
web/src/components/prompt-dialog.tsx
Normal file
33
web/src/components/prompt-dialog.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@ -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;
|
||||
@ -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() {
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
.selectFilesCollapse {
|
||||
:global(.ant-collapse-header) {
|
||||
padding-left: 22px;
|
||||
}
|
||||
margin-bottom: 32px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.selectFilesTitle {
|
||||
padding-right: 10px;
|
||||
}
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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;
|
||||
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user