You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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