您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. import MaxTokenNumber from '@/components/max-token-number';
  2. import { IModalManagerChildrenProps } from '@/components/modal-manager';
  3. import {
  4. MinusCircleOutlined,
  5. PlusOutlined,
  6. QuestionCircleOutlined,
  7. } from '@ant-design/icons';
  8. import {
  9. Button,
  10. Divider,
  11. Form,
  12. InputNumber,
  13. Modal,
  14. Select,
  15. Space,
  16. Tooltip,
  17. } from 'antd';
  18. import omit from 'lodash/omit';
  19. import React, { useEffect, useMemo } from 'react';
  20. import { useFetchParserListOnMount, useShowAutoKeywords } from './hooks';
  21. import { DocumentParserType } from '@/constants/knowledge';
  22. import { useTranslate } from '@/hooks/common-hooks';
  23. import { IParserConfig } from '@/interfaces/database/document';
  24. import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
  25. import { AutoKeywordsItem, AutoQuestionsItem } from '../auto-keywords-item';
  26. import { DatasetConfigurationContainer } from '../dataset-configuration-container';
  27. import Delimiter from '../delimiter';
  28. import EntityTypesItem from '../entity-types-item';
  29. import ExcelToHtml from '../excel-to-html';
  30. import LayoutRecognize from '../layout-recognize';
  31. import ParseConfiguration, {
  32. showRaptorParseConfiguration,
  33. } from '../parse-configuration';
  34. import {
  35. UseGraphRagItem,
  36. showGraphRagItems,
  37. } from '../parse-configuration/graph-rag-items';
  38. import styles from './index.less';
  39. interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> {
  40. loading: boolean;
  41. onOk: (
  42. parserId: DocumentParserType | undefined,
  43. parserConfig: IChangeParserConfigRequestBody,
  44. ) => void;
  45. showModal?(): void;
  46. parserId: DocumentParserType;
  47. parserConfig: IParserConfig;
  48. documentExtension: string;
  49. documentId: string;
  50. }
  51. const hidePagesChunkMethods = [
  52. DocumentParserType.Qa,
  53. DocumentParserType.Table,
  54. DocumentParserType.Picture,
  55. DocumentParserType.Resume,
  56. DocumentParserType.One,
  57. DocumentParserType.KnowledgeGraph,
  58. ];
  59. const ChunkMethodModal: React.FC<IProps> = ({
  60. documentId,
  61. parserId,
  62. onOk,
  63. hideModal,
  64. visible,
  65. documentExtension,
  66. parserConfig,
  67. loading,
  68. }) => {
  69. const [form] = Form.useForm();
  70. const { parserList, handleChange, selectedTag } = useFetchParserListOnMount(
  71. documentId,
  72. parserId,
  73. documentExtension,
  74. form,
  75. );
  76. const { t } = useTranslate('knowledgeDetails');
  77. const handleOk = async () => {
  78. const values = await form.validateFields();
  79. const parser_config = {
  80. ...values.parser_config,
  81. pages: values.pages?.map((x: any) => [x.from, x.to]) ?? [],
  82. };
  83. onOk(selectedTag, parser_config);
  84. };
  85. const isPdf = documentExtension === 'pdf';
  86. const showPages = useMemo(() => {
  87. return isPdf && hidePagesChunkMethods.every((x) => x !== selectedTag);
  88. }, [selectedTag, isPdf]);
  89. const showOne = useMemo(() => {
  90. return (
  91. isPdf &&
  92. hidePagesChunkMethods
  93. .filter((x) => x !== DocumentParserType.One)
  94. .every((x) => x !== selectedTag)
  95. );
  96. }, [selectedTag, isPdf]);
  97. const showMaxTokenNumber =
  98. selectedTag === DocumentParserType.Naive ||
  99. selectedTag === DocumentParserType.KnowledgeGraph;
  100. const showEntityTypes = selectedTag === DocumentParserType.KnowledgeGraph;
  101. const showExcelToHtml =
  102. selectedTag === DocumentParserType.Naive && documentExtension === 'xlsx';
  103. const showAutoKeywords = useShowAutoKeywords();
  104. const afterClose = () => {
  105. form.resetFields();
  106. };
  107. useEffect(() => {
  108. if (visible) {
  109. const pages =
  110. parserConfig?.pages?.map((x) => ({ from: x[0], to: x[1] })) ?? [];
  111. form.setFieldsValue({
  112. pages: pages.length > 0 ? pages : [{ from: 1, to: 1024 }],
  113. parser_config: omit(parserConfig, 'pages'),
  114. });
  115. }
  116. }, [form, parserConfig, visible]);
  117. return (
  118. <Modal
  119. title={t('chunkMethod')}
  120. open={visible}
  121. onOk={handleOk}
  122. onCancel={hideModal}
  123. afterClose={afterClose}
  124. confirmLoading={loading}
  125. width={700}
  126. >
  127. <Space size={[0, 8]} wrap>
  128. <Form.Item label={t('chunkMethod')} className={styles.chunkMethod}>
  129. <Select
  130. style={{ width: 160 }}
  131. onChange={handleChange}
  132. value={selectedTag}
  133. options={parserList}
  134. />
  135. </Form.Item>
  136. </Space>
  137. <Divider></Divider>
  138. <Form
  139. name="dynamic_form_nest_item"
  140. autoComplete="off"
  141. form={form}
  142. className="space-y-4"
  143. >
  144. {showPages && (
  145. <>
  146. <Space>
  147. <p>{t('pageRanges')}:</p>
  148. <Tooltip title={t('pageRangesTip')}>
  149. <QuestionCircleOutlined
  150. className={styles.questionIcon}
  151. ></QuestionCircleOutlined>
  152. </Tooltip>
  153. </Space>
  154. <Form.List name="pages">
  155. {(fields, { add, remove }) => (
  156. <>
  157. {fields.map(({ key, name, ...restField }) => (
  158. <Space
  159. key={key}
  160. style={{
  161. display: 'flex',
  162. }}
  163. align="baseline"
  164. >
  165. <Form.Item
  166. {...restField}
  167. name={[name, 'from']}
  168. dependencies={name > 0 ? [name - 1, 'to'] : []}
  169. rules={[
  170. {
  171. required: true,
  172. message: t('fromMessage'),
  173. },
  174. ({ getFieldValue }) => ({
  175. validator(_, value) {
  176. if (
  177. name === 0 ||
  178. !value ||
  179. getFieldValue(['pages', name - 1, 'to']) < value
  180. ) {
  181. return Promise.resolve();
  182. }
  183. return Promise.reject(
  184. new Error(t('greaterThanPrevious')),
  185. );
  186. },
  187. }),
  188. ]}
  189. >
  190. <InputNumber
  191. placeholder={t('fromPlaceholder')}
  192. min={0}
  193. precision={0}
  194. className={styles.pageInputNumber}
  195. />
  196. </Form.Item>
  197. <Form.Item
  198. {...restField}
  199. name={[name, 'to']}
  200. dependencies={[name, 'from']}
  201. rules={[
  202. {
  203. required: true,
  204. message: t('toMessage'),
  205. },
  206. ({ getFieldValue }) => ({
  207. validator(_, value) {
  208. if (
  209. !value ||
  210. getFieldValue(['pages', name, 'from']) < value
  211. ) {
  212. return Promise.resolve();
  213. }
  214. return Promise.reject(
  215. new Error(t('greaterThan')),
  216. );
  217. },
  218. }),
  219. ]}
  220. >
  221. <InputNumber
  222. placeholder={t('toPlaceholder')}
  223. min={0}
  224. precision={0}
  225. className={styles.pageInputNumber}
  226. />
  227. </Form.Item>
  228. {name > 0 && (
  229. <MinusCircleOutlined onClick={() => remove(name)} />
  230. )}
  231. </Space>
  232. ))}
  233. <Form.Item>
  234. <Button
  235. type="dashed"
  236. onClick={() => add()}
  237. block
  238. icon={<PlusOutlined />}
  239. >
  240. {t('addPage')}
  241. </Button>
  242. </Form.Item>
  243. </>
  244. )}
  245. </Form.List>
  246. </>
  247. )}
  248. {showPages && (
  249. <Form.Item
  250. noStyle
  251. dependencies={[['parser_config', 'layout_recognize']]}
  252. >
  253. {({ getFieldValue }) =>
  254. getFieldValue(['parser_config', 'layout_recognize']) && (
  255. <Form.Item
  256. name={['parser_config', 'task_page_size']}
  257. label={t('taskPageSize')}
  258. tooltip={t('taskPageSizeTip')}
  259. initialValue={12}
  260. rules={[
  261. {
  262. required: true,
  263. message: t('taskPageSizeMessage'),
  264. },
  265. ]}
  266. >
  267. <InputNumber min={1} max={128} />
  268. </Form.Item>
  269. )
  270. }
  271. </Form.Item>
  272. )}
  273. <DatasetConfigurationContainer show={showOne || showMaxTokenNumber}>
  274. {showOne && <LayoutRecognize></LayoutRecognize>}
  275. {showMaxTokenNumber && (
  276. <>
  277. <MaxTokenNumber
  278. max={
  279. selectedTag === DocumentParserType.KnowledgeGraph
  280. ? 8192 * 2
  281. : 2048
  282. }
  283. ></MaxTokenNumber>
  284. <Delimiter></Delimiter>
  285. </>
  286. )}
  287. </DatasetConfigurationContainer>
  288. <DatasetConfigurationContainer
  289. show={showAutoKeywords(selectedTag) || showExcelToHtml}
  290. >
  291. {showAutoKeywords(selectedTag) && (
  292. <>
  293. <AutoKeywordsItem></AutoKeywordsItem>
  294. <AutoQuestionsItem></AutoQuestionsItem>
  295. </>
  296. )}
  297. {showExcelToHtml && <ExcelToHtml></ExcelToHtml>}
  298. </DatasetConfigurationContainer>
  299. {showRaptorParseConfiguration(selectedTag) && (
  300. <DatasetConfigurationContainer>
  301. <ParseConfiguration></ParseConfiguration>
  302. </DatasetConfigurationContainer>
  303. )}
  304. {showGraphRagItems(selectedTag) && <UseGraphRagItem></UseGraphRagItem>}
  305. {showEntityTypes && <EntityTypesItem></EntityTypesItem>}
  306. </Form>
  307. </Modal>
  308. );
  309. };
  310. export default ChunkMethodModal;