* feat: create chunk and edit chunk * feat: delete chunk * feat: search chunks * feat: delete chunks in batches * feat: set whether chunks are available in batchestags/v0.1.0
| "jsencrypt": "^3.3.2", | "jsencrypt": "^3.3.2", | ||||
| "lodash": "^4.17.21", | "lodash": "^4.17.21", | ||||
| "moment": "^2.30.1", | "moment": "^2.30.1", | ||||
| "rc-tween-one": "^3.0.6", | |||||
| "react-i18next": "^14.0.0", | "react-i18next": "^14.0.0", | ||||
| "react-infinite-scroll-component": "^6.1.0", | "react-infinite-scroll-component": "^6.1.0", | ||||
| "umi": "^4.0.90", | "umi": "^4.0.90", | ||||
| "type": "^1.0.1" | "type": "^1.0.1" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/d3-array": { | |||||
| "version": "1.2.4", | |||||
| "resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-1.2.4.tgz", | |||||
| "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" | |||||
| }, | |||||
| "node_modules/d3-polygon": { | |||||
| "version": "1.0.6", | |||||
| "resolved": "https://registry.npmmirror.com/d3-polygon/-/d3-polygon-1.0.6.tgz", | |||||
| "integrity": "sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ==" | |||||
| }, | |||||
| "node_modules/data-uri-to-buffer": { | "node_modules/data-uri-to-buffer": { | ||||
| "version": "4.0.1", | "version": "4.0.1", | ||||
| "resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", | "resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", | ||||
| "dva-core": "^1.1.0 || ^1.5.0-0 || ^1.6.0-0" | "dva-core": "^1.1.0 || ^1.5.0-0 || ^1.6.0-0" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/earcut": { | |||||
| "version": "2.2.4", | |||||
| "resolved": "https://registry.npmmirror.com/earcut/-/earcut-2.2.4.tgz", | |||||
| "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" | |||||
| }, | |||||
| "node_modules/easy-icons": { | "node_modules/easy-icons": { | ||||
| "version": "1.1.5", | "version": "1.1.5", | ||||
| "resolved": "https://registry.npmmirror.com/easy-icons/-/easy-icons-1.1.5.tgz", | "resolved": "https://registry.npmmirror.com/easy-icons/-/easy-icons-1.1.5.tgz", | ||||
| "deprecated": "flatten is deprecated in favor of utility frameworks such as lodash.", | "deprecated": "flatten is deprecated in favor of utility frameworks such as lodash.", | ||||
| "dev": true | "dev": true | ||||
| }, | }, | ||||
| "node_modules/flubber": { | |||||
| "version": "0.4.2", | |||||
| "resolved": "https://registry.npmmirror.com/flubber/-/flubber-0.4.2.tgz", | |||||
| "integrity": "sha512-79RkJe3rA4nvRCVc2uXjj7U/BAUq84TS3KHn6c0Hr9K64vhj83ZNLUziNx4pJoBumSPhOl5VjH+Z0uhi+eE8Uw==", | |||||
| "dependencies": { | |||||
| "d3-array": "^1.2.0", | |||||
| "d3-polygon": "^1.0.3", | |||||
| "earcut": "^2.1.1", | |||||
| "svg-path-properties": "^0.2.1", | |||||
| "svgpath": "^2.2.1", | |||||
| "topojson-client": "^3.0.0" | |||||
| } | |||||
| }, | |||||
| "node_modules/flubber/node_modules/svg-path-properties": { | |||||
| "version": "0.2.2", | |||||
| "resolved": "https://registry.npmmirror.com/svg-path-properties/-/svg-path-properties-0.2.2.tgz", | |||||
| "integrity": "sha512-GmrB+b6woz6CCdQe6w1GHs/1lt25l7SR5hmhF8jRdarpv/OgjLyuQygLu1makJapixeb1aQhP/Oa1iKi93o/aQ==" | |||||
| }, | |||||
| "node_modules/follow-redirects": { | "node_modules/follow-redirects": { | ||||
| "version": "1.15.4", | "version": "1.15.4", | ||||
| "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.4.tgz", | "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.4.tgz", | ||||
| "node": ">=0.12" | "node": ">=0.12" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/performance-now": { | |||||
| "version": "2.1.0", | |||||
| "resolved": "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz", | |||||
| "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" | |||||
| }, | |||||
| "node_modules/picocolors": { | "node_modules/picocolors": { | ||||
| "version": "1.0.0", | "version": "1.0.0", | ||||
| "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz", | "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz", | ||||
| "node": ">=8" | "node": ">=8" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/raf": { | |||||
| "version": "3.4.1", | |||||
| "resolved": "https://registry.npmmirror.com/raf/-/raf-3.4.1.tgz", | |||||
| "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", | |||||
| "dependencies": { | |||||
| "performance-now": "^2.1.0" | |||||
| } | |||||
| }, | |||||
| "node_modules/ramda": { | "node_modules/ramda": { | ||||
| "version": "0.27.2", | "version": "0.27.2", | ||||
| "resolved": "https://registry.npmmirror.com/ramda/-/ramda-0.27.2.tgz", | "resolved": "https://registry.npmmirror.com/ramda/-/ramda-0.27.2.tgz", | ||||
| "react-dom": "*" | "react-dom": "*" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/rc-tween-one": { | |||||
| "version": "3.0.6", | |||||
| "resolved": "https://registry.npmmirror.com/rc-tween-one/-/rc-tween-one-3.0.6.tgz", | |||||
| "integrity": "sha512-5zTSXyyv7bahDBQ/kJw/kNxxoBqTouttoelw8FOVOyWqmTMndizJEpvaj1N+yES5Xjss6Y2iVw+9vSJQZE8Z6g==", | |||||
| "dependencies": { | |||||
| "@babel/runtime": "^7.11.1", | |||||
| "style-utils": "^0.3.4", | |||||
| "tween-one": "^1.0.50" | |||||
| }, | |||||
| "engines": { | |||||
| "node": ">=8.x" | |||||
| }, | |||||
| "peerDependencies": { | |||||
| "react": ">=16.9.0", | |||||
| "react-dom": ">=16.9.0" | |||||
| } | |||||
| }, | |||||
| "node_modules/rc-upload": { | "node_modules/rc-upload": { | ||||
| "version": "4.5.2", | "version": "4.5.2", | ||||
| "resolved": "https://registry.npmmirror.com/rc-upload/-/rc-upload-4.5.2.tgz", | "resolved": "https://registry.npmmirror.com/rc-upload/-/rc-upload-4.5.2.tgz", | ||||
| "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==", | "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==", | ||||
| "peer": true | "peer": true | ||||
| }, | }, | ||||
| "node_modules/style-utils": { | |||||
| "version": "0.3.8", | |||||
| "resolved": "https://registry.npmmirror.com/style-utils/-/style-utils-0.3.8.tgz", | |||||
| "integrity": "sha512-RmGftIhY4tqtD1ERwKsVEDlt/M6UyxN/rcr95UmlooWmhtL0RwVUYJkpo1kSx3ppd9/JZzbknhy742zbMAawjQ==" | |||||
| }, | |||||
| "node_modules/stylelint": { | "node_modules/stylelint": { | ||||
| "version": "14.16.1", | "version": "14.16.1", | ||||
| "resolved": "https://registry.npmmirror.com/stylelint/-/stylelint-14.16.1.tgz", | "resolved": "https://registry.npmmirror.com/stylelint/-/stylelint-14.16.1.tgz", | ||||
| "resolved": "https://registry.npmmirror.com/svg-parser/-/svg-parser-2.0.4.tgz", | "resolved": "https://registry.npmmirror.com/svg-parser/-/svg-parser-2.0.4.tgz", | ||||
| "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" | "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" | ||||
| }, | }, | ||||
| "node_modules/svg-path-properties": { | |||||
| "version": "1.3.0", | |||||
| "resolved": "https://registry.npmmirror.com/svg-path-properties/-/svg-path-properties-1.3.0.tgz", | |||||
| "integrity": "sha512-R1+z37FrqyS3UXDhajNfvMxKI0smuVdedqOo4YbAQUfGqA86B9mGvr2IEXrwjjvGzCtdIKy/ad9N8m6YclaKAw==" | |||||
| }, | |||||
| "node_modules/svg-tags": { | "node_modules/svg-tags": { | ||||
| "version": "1.0.0", | "version": "1.0.0", | ||||
| "resolved": "https://registry.npmmirror.com/svg-tags/-/svg-tags-1.0.0.tgz", | "resolved": "https://registry.npmmirror.com/svg-tags/-/svg-tags-1.0.0.tgz", | ||||
| "node": ">= 10" | "node": ">= 10" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/svgpath": { | |||||
| "version": "2.6.0", | |||||
| "resolved": "https://registry.npmmirror.com/svgpath/-/svgpath-2.6.0.tgz", | |||||
| "integrity": "sha512-OIWR6bKzXvdXYyO4DK/UWa1VA1JeKq8E+0ug2DG98Y/vOmMpfZNj+TIG988HjfYSqtcy/hFOtZq/n/j5GSESNg==" | |||||
| }, | |||||
| "node_modules/swr": { | "node_modules/swr": { | ||||
| "version": "2.2.4", | "version": "2.2.4", | ||||
| "resolved": "https://registry.npmmirror.com/swr/-/swr-2.2.4.tgz", | "resolved": "https://registry.npmmirror.com/swr/-/swr-2.2.4.tgz", | ||||
| "resolved": "https://registry.npmmirror.com/toggle-selection/-/toggle-selection-1.0.6.tgz", | "resolved": "https://registry.npmmirror.com/toggle-selection/-/toggle-selection-1.0.6.tgz", | ||||
| "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" | "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" | ||||
| }, | }, | ||||
| "node_modules/topojson-client": { | |||||
| "version": "3.1.0", | |||||
| "resolved": "https://registry.npmmirror.com/topojson-client/-/topojson-client-3.1.0.tgz", | |||||
| "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==", | |||||
| "dependencies": { | |||||
| "commander": "2" | |||||
| }, | |||||
| "bin": { | |||||
| "topo2geo": "bin/topo2geo", | |||||
| "topomerge": "bin/topomerge", | |||||
| "topoquantize": "bin/topoquantize" | |||||
| } | |||||
| }, | |||||
| "node_modules/topojson-client/node_modules/commander": { | |||||
| "version": "2.20.3", | |||||
| "resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz", | |||||
| "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" | |||||
| }, | |||||
| "node_modules/trim-newlines": { | "node_modules/trim-newlines": { | ||||
| "version": "3.0.1", | "version": "3.0.1", | ||||
| "resolved": "https://registry.npmmirror.com/trim-newlines/-/trim-newlines-3.0.1.tgz", | "resolved": "https://registry.npmmirror.com/trim-newlines/-/trim-newlines-3.0.1.tgz", | ||||
| "resolved": "https://registry.npmmirror.com/tty-browserify/-/tty-browserify-0.0.0.tgz", | "resolved": "https://registry.npmmirror.com/tty-browserify/-/tty-browserify-0.0.0.tgz", | ||||
| "integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==" | "integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==" | ||||
| }, | }, | ||||
| "node_modules/tween-functions": { | |||||
| "version": "1.2.0", | |||||
| "resolved": "https://registry.npmmirror.com/tween-functions/-/tween-functions-1.2.0.tgz", | |||||
| "integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==" | |||||
| }, | |||||
| "node_modules/tween-one": { | |||||
| "version": "1.2.7", | |||||
| "resolved": "https://registry.npmmirror.com/tween-one/-/tween-one-1.2.7.tgz", | |||||
| "integrity": "sha512-F+Z9LO9GsYqf0j5bgNhAF98RDrAZ7QjQrujJ2lVYSHl4+dBPW/atHluL2bwclZf8Vo0Yo96f6pw2uq1OGzpC/Q==", | |||||
| "dependencies": { | |||||
| "@babel/runtime": "^7.11.1", | |||||
| "flubber": "^0.4.2", | |||||
| "raf": "^3.4.1", | |||||
| "style-utils": "^0.3.6", | |||||
| "svg-path-properties": "^1.0.4", | |||||
| "tween-functions": "^1.2.0" | |||||
| } | |||||
| }, | |||||
| "node_modules/type": { | "node_modules/type": { | ||||
| "version": "1.2.0", | "version": "1.2.0", | ||||
| "resolved": "https://registry.npmmirror.com/type/-/type-1.2.0.tgz", | "resolved": "https://registry.npmmirror.com/type/-/type-1.2.0.tgz", |
| "jsencrypt": "^3.3.2", | "jsencrypt": "^3.3.2", | ||||
| "lodash": "^4.17.21", | "lodash": "^4.17.21", | ||||
| "moment": "^2.30.1", | "moment": "^2.30.1", | ||||
| "rc-tween-one": "^3.0.6", | |||||
| "react-i18next": "^14.0.0", | "react-i18next": "^14.0.0", | ||||
| "react-infinite-scroll-component": "^6.1.0", | "react-infinite-scroll-component": "^6.1.0", | ||||
| "umi": "^4.0.90", | "umi": "^4.0.90", |
| import showDeleteConfirm from '@/components/deleting-confirm'; | import showDeleteConfirm from '@/components/deleting-confirm'; | ||||
| import { IKnowledge } from '@/interfaces/database/knowledge'; | import { IKnowledge } from '@/interfaces/database/knowledge'; | ||||
| import { useCallback } from 'react'; | |||||
| import { useDispatch, useSearchParams, useSelector } from 'umi'; | import { useDispatch, useSearchParams, useSelector } from 'umi'; | ||||
| export const useKnowledgeBaseId = (): string => { | export const useKnowledgeBaseId = (): string => { | ||||
| parserConfig: item?.parser_config ?? '', | parserConfig: item?.parser_config ?? '', | ||||
| }; | }; | ||||
| }; | }; | ||||
| export const useDeleteChunkByIds = (): { | |||||
| removeChunk: (chunkIds: string[], documentId: string) => Promise<number>; | |||||
| } => { | |||||
| const dispatch = useDispatch(); | |||||
| const removeChunk = useCallback( | |||||
| (chunkIds: string[], documentId: string) => () => { | |||||
| return dispatch({ | |||||
| type: 'chunkModel/rm_chunk', | |||||
| payload: { | |||||
| chunk_ids: chunkIds, | |||||
| doc_id: documentId, | |||||
| }, | |||||
| }); | |||||
| }, | |||||
| [dispatch], | |||||
| ); | |||||
| const onRemoveChunk = useCallback( | |||||
| (chunkIds: string[], documentId: string): Promise<number> => { | |||||
| return showDeleteConfirm({ onOk: removeChunk(chunkIds, documentId) }); | |||||
| }, | |||||
| [removeChunk], | |||||
| ); | |||||
| return { | |||||
| removeChunk: onRemoveChunk, | |||||
| }; | |||||
| }; |
| .imagePreview { | .imagePreview { | ||||
| width: 600px; | width: 600px; | ||||
| } | } | ||||
| .content { | |||||
| flex: 1; | |||||
| em { | |||||
| color: red; | |||||
| font-style: normal; | |||||
| } | |||||
| } |
| import { IChunk } from '@/interfaces/database/knowledge'; | import { IChunk } from '@/interfaces/database/knowledge'; | ||||
| import { api_host } from '@/utils/api'; | import { api_host } from '@/utils/api'; | ||||
| import { Card, Checkbox, CheckboxProps, Flex, Popover, Switch } from 'antd'; | import { Card, Checkbox, CheckboxProps, Flex, Popover, Switch } from 'antd'; | ||||
| import { useDispatch } from 'umi'; | |||||
| import { useState } from 'react'; | import { useState } from 'react'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| interface IProps { | interface IProps { | ||||
| item: IChunk; | item: IChunk; | ||||
| checked: boolean; | checked: boolean; | ||||
| switchChunk: (available?: number, chunkIds?: string[]) => void; | |||||
| editChunk: (chunkId: string) => void; | |||||
| handleCheckboxClick: (chunkId: string, checked: boolean) => void; | handleCheckboxClick: (chunkId: string, checked: boolean) => void; | ||||
| } | } | ||||
| ); | ); | ||||
| }; | }; | ||||
| const ChunkCard = ({ item, checked, handleCheckboxClick }: IProps) => { | |||||
| const dispatch = useDispatch(); | |||||
| const ChunkCard = ({ | |||||
| item, | |||||
| checked, | |||||
| handleCheckboxClick, | |||||
| editChunk, | |||||
| switchChunk, | |||||
| }: IProps) => { | |||||
| const available = Number(item.available_int); | const available = Number(item.available_int); | ||||
| const [enabled, setEnabled] = useState(available === 1); | const [enabled, setEnabled] = useState(available === 1); | ||||
| const switchChunk = () => { | |||||
| dispatch({ | |||||
| type: 'chunkModel/switch_chunk', | |||||
| payload: { | |||||
| chunk_ids: [item.chunk_id], | |||||
| available_int: available === 0 ? 1 : 0, | |||||
| doc_id: item.doc_id, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| const onChange = (checked: boolean) => { | const onChange = (checked: boolean) => { | ||||
| setEnabled(checked); | setEnabled(checked); | ||||
| switchChunk(); | |||||
| switchChunk(available === 0 ? 1 : 0, [item.chunk_id]); | |||||
| }; | }; | ||||
| const handleCheck: CheckboxProps['onChange'] = (e) => { | const handleCheck: CheckboxProps['onChange'] = (e) => { | ||||
| handleCheckboxClick(item.chunk_id, e.target.checked); | handleCheckboxClick(item.chunk_id, e.target.checked); | ||||
| }; | }; | ||||
| const handleContentClick = () => { | |||||
| editChunk(item.chunk_id); | |||||
| }; | |||||
| return ( | return ( | ||||
| <div> | <div> | ||||
| <Card> | <Card> | ||||
| </Popover> | </Popover> | ||||
| )} | )} | ||||
| <section>{item.content_with_weight}</section> | |||||
| <section | |||||
| onDoubleClick={handleContentClick} | |||||
| className={styles.content} | |||||
| dangerouslySetInnerHTML={{ __html: item.content_with_weight }} | |||||
| > | |||||
| {/* {item.content_with_weight} */} | |||||
| </section> | |||||
| <div> | <div> | ||||
| <Switch checked={enabled} onChange={onChange} /> | <Switch checked={enabled} onChange={onChange} /> | ||||
| </div> | </div> |
| import { useDeleteChunkByIds } from '@/hooks/knowledgeHook'; | |||||
| import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; | |||||
| import { DeleteOutlined } from '@ant-design/icons'; | |||||
| import { Checkbox, Form, Input, Modal, Space } from 'antd'; | |||||
| import React, { useCallback, useEffect, useState } from 'react'; | |||||
| import { useDispatch, useSelector } from 'umi'; | |||||
| import EditTag from '../edit-tag'; | |||||
| type FieldType = { | |||||
| content?: string; | |||||
| }; | |||||
| interface kFProps { | |||||
| doc_id: string; | |||||
| chunkId: string | undefined; | |||||
| } | |||||
| const ChunkCreatingModal: React.FC<kFProps> = ({ doc_id, chunkId }) => { | |||||
| const dispatch = useDispatch(); | |||||
| const [form] = Form.useForm(); | |||||
| const isShowCreateModal: boolean = useSelector( | |||||
| (state: any) => state.chunkModel.isShowCreateModal, | |||||
| ); | |||||
| const [checked, setChecked] = useState(false); | |||||
| const [keywords, setKeywords] = useState<string[]>([]); | |||||
| const loading = useOneNamespaceEffectsLoading('chunkModel', ['create_chunk']); | |||||
| const { removeChunk } = useDeleteChunkByIds(); | |||||
| const handleCancel = () => { | |||||
| dispatch({ | |||||
| type: 'chunkModel/setIsShowCreateModal', | |||||
| payload: false, | |||||
| }); | |||||
| }; | |||||
| const getChunk = useCallback(async () => { | |||||
| console.info(chunkId); | |||||
| if (chunkId && isShowCreateModal) { | |||||
| const data = await dispatch<any>({ | |||||
| type: 'chunkModel/get_chunk', | |||||
| payload: { | |||||
| chunk_id: chunkId, | |||||
| }, | |||||
| }); | |||||
| if (data?.retcode === 0) { | |||||
| const { content_with_weight, important_kwd = [] } = data.data; | |||||
| form.setFieldsValue({ content: content_with_weight }); | |||||
| setKeywords(important_kwd); | |||||
| } | |||||
| } | |||||
| if (!chunkId) { | |||||
| setKeywords([]); | |||||
| form.setFieldsValue({ content: undefined }); | |||||
| } | |||||
| }, [chunkId, isShowCreateModal, dispatch, form]); | |||||
| useEffect(() => { | |||||
| getChunk(); | |||||
| }, [getChunk]); | |||||
| const handleOk = async () => { | |||||
| try { | |||||
| const values = await form.validateFields(); | |||||
| dispatch({ | |||||
| type: 'chunkModel/create_chunk', | |||||
| payload: { | |||||
| content_with_weight: values.content, | |||||
| doc_id, | |||||
| chunk_id: chunkId, | |||||
| important_kwd: keywords, // keywords | |||||
| }, | |||||
| }); | |||||
| } catch (errorInfo) { | |||||
| console.log('Failed:', errorInfo); | |||||
| } | |||||
| }; | |||||
| const handleRemove = () => { | |||||
| if (chunkId) { | |||||
| return removeChunk([chunkId], doc_id); | |||||
| } | |||||
| }; | |||||
| const handleCheck = () => { | |||||
| setChecked(!checked); | |||||
| }; | |||||
| return ( | |||||
| <Modal | |||||
| title={`${chunkId ? 'Edit' : 'Create'} Chunk`} | |||||
| open={isShowCreateModal} | |||||
| onOk={handleOk} | |||||
| onCancel={handleCancel} | |||||
| okButtonProps={{ loading }} | |||||
| > | |||||
| <Form | |||||
| form={form} | |||||
| // name="validateOnly" | |||||
| autoComplete="off" | |||||
| layout={'vertical'} | |||||
| > | |||||
| <Form.Item<FieldType> | |||||
| label="Chunk" | |||||
| name="content" | |||||
| rules={[{ required: true, message: 'Please input value!' }]} | |||||
| > | |||||
| <Input.TextArea autoSize={{ minRows: 4, maxRows: 10 }} /> | |||||
| </Form.Item> | |||||
| </Form> | |||||
| <section> | |||||
| <p>Keyword*</p> | |||||
| <EditTag tags={keywords} setTags={setKeywords} /> | |||||
| </section> | |||||
| {chunkId && ( | |||||
| <section> | |||||
| <p>Function*</p> | |||||
| <Space size={'large'}> | |||||
| <Checkbox onChange={handleCheck} checked={checked}> | |||||
| Enabled | |||||
| </Checkbox> | |||||
| <span onClick={handleRemove}> | |||||
| <DeleteOutlined /> Delete | |||||
| </span> | |||||
| </Space> | |||||
| </section> | |||||
| )} | |||||
| </Modal> | |||||
| ); | |||||
| }; | |||||
| export default ChunkCreatingModal; |
| Button, | Button, | ||||
| Checkbox, | Checkbox, | ||||
| Flex, | Flex, | ||||
| Input, | |||||
| Menu, | Menu, | ||||
| MenuProps, | MenuProps, | ||||
| Popover, | Popover, | ||||
| RadioChangeEvent, | RadioChangeEvent, | ||||
| Space, | Space, | ||||
| } from 'antd'; | } from 'antd'; | ||||
| import { useCallback, useMemo } from 'react'; | |||||
| import { ChangeEventHandler, useCallback, useMemo, useState } from 'react'; | |||||
| import { Link, useDispatch, useSelector } from 'umi'; | import { Link, useDispatch, useSelector } from 'umi'; | ||||
| import { ChunkModelState } from '../../model'; | import { ChunkModelState } from '../../model'; | ||||
| checked: boolean; | checked: boolean; | ||||
| getChunkList: () => void; | getChunkList: () => void; | ||||
| selectAllChunk: (checked: boolean) => void; | selectAllChunk: (checked: boolean) => void; | ||||
| createChunk: () => void; | |||||
| removeChunk: () => void; | |||||
| switchChunk: (available: number) => void; | |||||
| } | } | ||||
| const ChunkToolBar = ({ getChunkList, selectAllChunk, checked }: IProps) => { | |||||
| const { documentInfo, available }: ChunkModelState = useSelector( | |||||
| (state: any) => state.chunkModel, | |||||
| ); | |||||
| const ChunkToolBar = ({ | |||||
| getChunkList, | |||||
| selectAllChunk, | |||||
| checked, | |||||
| createChunk, | |||||
| removeChunk, | |||||
| switchChunk, | |||||
| }: IProps) => { | |||||
| const { documentInfo, available, searchString }: ChunkModelState = | |||||
| useSelector((state: any) => state.chunkModel); | |||||
| const dispatch = useDispatch(); | const dispatch = useDispatch(); | ||||
| const knowledgeBaseId = useKnowledgeBaseId(); | const knowledgeBaseId = useKnowledgeBaseId(); | ||||
| const [isShowSearchBox, setIsShowSearchBox] = useState(false); | |||||
| const handleSelectAllCheck = useCallback( | const handleSelectAllCheck = useCallback( | ||||
| (e: any) => { | (e: any) => { | ||||
| // console.info(e.target.checked); | |||||
| selectAllChunk(e.target.checked); | selectAllChunk(e.target.checked); | ||||
| }, | }, | ||||
| [selectAllChunk], | [selectAllChunk], | ||||
| ); | ); | ||||
| const handleSearchIconClick = () => { | |||||
| setIsShowSearchBox(true); | |||||
| }; | |||||
| const handleSearchChange: ChangeEventHandler<HTMLInputElement> = (e) => { | |||||
| const val = e.target.value; | |||||
| dispatch({ type: 'chunkModel/setSearchString', payload: val }); | |||||
| dispatch({ | |||||
| type: 'chunkModel/throttledGetChunkList', | |||||
| payload: documentInfo.id, | |||||
| }); | |||||
| }; | |||||
| const handleSearchBlur = () => { | |||||
| if (!searchString.trim()) { | |||||
| setIsShowSearchBox(false); | |||||
| } | |||||
| }; | |||||
| const handleDelete = useCallback(() => { | |||||
| removeChunk(); | |||||
| }, [removeChunk]); | |||||
| const handleEnabledClick = () => { | |||||
| switchChunk(1); | |||||
| }; | |||||
| const handleDisabledClick = () => { | |||||
| switchChunk(0); | |||||
| }; | |||||
| const items: MenuProps['items'] = useMemo(() => { | const items: MenuProps['items'] = useMemo(() => { | ||||
| return [ | return [ | ||||
| { | { | ||||
| { | { | ||||
| key: '2', | key: '2', | ||||
| label: ( | label: ( | ||||
| <Space> | |||||
| <Space onClick={handleEnabledClick}> | |||||
| <CheckCircleOutlined /> | <CheckCircleOutlined /> | ||||
| <b>Enabled Selected</b> | <b>Enabled Selected</b> | ||||
| </Space> | </Space> | ||||
| { | { | ||||
| key: '3', | key: '3', | ||||
| label: ( | label: ( | ||||
| <Space> | |||||
| <Space onClick={handleDisabledClick}> | |||||
| <CloseCircleOutlined /> | <CloseCircleOutlined /> | ||||
| <b>Disabled Selected</b> | <b>Disabled Selected</b> | ||||
| </Space> | </Space> | ||||
| { | { | ||||
| key: '4', | key: '4', | ||||
| label: ( | label: ( | ||||
| <Space> | |||||
| <Space onClick={handleDelete}> | |||||
| <DeleteOutlined /> | <DeleteOutlined /> | ||||
| <b>Delete Selected</b> | <b>Delete Selected</b> | ||||
| </Space> | </Space> | ||||
| ), | ), | ||||
| }, | }, | ||||
| ]; | ]; | ||||
| }, [checked, handleSelectAllCheck]); | |||||
| }, [checked, handleSelectAllCheck, handleDelete]); | |||||
| const content = ( | const content = ( | ||||
| <Menu style={{ width: 200 }} items={items} selectable={false} /> | <Menu style={{ width: 200 }} items={items} selectable={false} /> | ||||
| ); | ); | ||||
| const handleFilterChange = (e: RadioChangeEvent) => { | const handleFilterChange = (e: RadioChangeEvent) => { | ||||
| selectAllChunk(false); | |||||
| dispatch({ type: 'chunkModel/setAvailable', payload: e.target.value }); | dispatch({ type: 'chunkModel/setAvailable', payload: e.target.value }); | ||||
| getChunkList(); | getChunkList(); | ||||
| }; | }; | ||||
| <DownOutlined /> | <DownOutlined /> | ||||
| </Button> | </Button> | ||||
| </Popover> | </Popover> | ||||
| <Button icon={<SearchOutlined />} /> | |||||
| {isShowSearchBox ? ( | |||||
| <Input | |||||
| size="middle" | |||||
| placeholder="Search" | |||||
| prefix={<SearchOutlined />} | |||||
| allowClear | |||||
| onChange={handleSearchChange} | |||||
| onBlur={handleSearchBlur} | |||||
| value={searchString} | |||||
| /> | |||||
| ) : ( | |||||
| <Button icon={<SearchOutlined />} onClick={handleSearchIconClick} /> | |||||
| )} | |||||
| <Popover content={filterContent} placement="bottom" arrow={false}> | <Popover content={filterContent} placement="bottom" arrow={false}> | ||||
| <Button icon={<FilterIcon />} /> | <Button icon={<FilterIcon />} /> | ||||
| </Popover> | </Popover> | ||||
| <Button icon={<DeleteOutlined />} /> | |||||
| <Button icon={<PlusOutlined />} type="primary" /> | |||||
| <Button | |||||
| icon={<PlusOutlined />} | |||||
| type="primary" | |||||
| onClick={() => createChunk()} | |||||
| /> | |||||
| </Space> | </Space> | ||||
| </Flex> | </Flex> | ||||
| ); | ); |
| import { Form, Input, Modal } from 'antd'; | |||||
| import React, { useCallback, useEffect, useState } from 'react'; | |||||
| import { useTranslation } from 'react-i18next'; | |||||
| import { useDispatch } from 'umi'; | |||||
| import EditTag from './editTag'; | |||||
| type FieldType = { | |||||
| content_ltks?: string; | |||||
| }; | |||||
| interface kFProps { | |||||
| getChunkList: () => void; | |||||
| isShowCreateModal: boolean; | |||||
| doc_id: string; | |||||
| chunk_id: string; | |||||
| } | |||||
| const Index: React.FC<kFProps> = ({ | |||||
| getChunkList, | |||||
| doc_id, | |||||
| isShowCreateModal, | |||||
| chunk_id, | |||||
| }) => { | |||||
| const dispatch = useDispatch(); | |||||
| const [form] = Form.useForm(); | |||||
| // const { , chunkInfo } = chunkModel | |||||
| const [important_kwd, setImportantKwd] = useState([ | |||||
| 'Unremovable', | |||||
| 'Tag 2', | |||||
| 'Tag 3', | |||||
| ]); | |||||
| const { t } = useTranslation(); | |||||
| const handleCancel = () => { | |||||
| dispatch({ | |||||
| type: 'chunkModel/updateState', | |||||
| payload: { | |||||
| isShowCreateModal: false, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| const getChunk = useCallback(async () => { | |||||
| if (chunk_id && isShowCreateModal) { | |||||
| const data = await dispatch<any>({ | |||||
| type: 'chunkModel/get_chunk', | |||||
| payload: { | |||||
| chunk_id, | |||||
| }, | |||||
| }); | |||||
| if (data?.retcode === 0) { | |||||
| const { content_ltks, important_kwd = [] } = data.data; | |||||
| form.setFieldsValue({ content_ltks }); | |||||
| setImportantKwd(important_kwd); | |||||
| } | |||||
| } | |||||
| }, [chunk_id, isShowCreateModal]); | |||||
| useEffect(() => { | |||||
| getChunk(); | |||||
| }, [getChunk]); | |||||
| const handleOk = async () => { | |||||
| try { | |||||
| const values = await form.validateFields(); | |||||
| dispatch({ | |||||
| type: 'chunkModel/create_hunk', | |||||
| payload: { | |||||
| content_ltks: values.content_ltks, | |||||
| doc_id, | |||||
| chunk_id, | |||||
| important_kwd, | |||||
| }, | |||||
| // callback: () => { | |||||
| // dispatch({ | |||||
| // type: 'chunkModel/updateState', | |||||
| // payload: { | |||||
| // isShowCreateModal: false, | |||||
| // }, | |||||
| // }); | |||||
| // getChunkList && getChunkList(); | |||||
| // }, | |||||
| }); | |||||
| } catch (errorInfo) { | |||||
| console.log('Failed:', errorInfo); | |||||
| } | |||||
| }; | |||||
| return ( | |||||
| <Modal | |||||
| title="Basic Modal" | |||||
| open={isShowCreateModal} | |||||
| onOk={handleOk} | |||||
| onCancel={handleCancel} | |||||
| > | |||||
| <Form | |||||
| form={form} | |||||
| name="validateOnly" | |||||
| labelCol={{ span: 5 }} | |||||
| wrapperCol={{ span: 19 }} | |||||
| style={{ maxWidth: 600 }} | |||||
| autoComplete="off" | |||||
| > | |||||
| <Form.Item<FieldType> | |||||
| label="chunk 内容" | |||||
| name="content_ltks" | |||||
| rules={[{ required: true, message: 'Please input value!' }]} | |||||
| > | |||||
| <Input.TextArea /> | |||||
| </Form.Item> | |||||
| <EditTag tags={important_kwd} setTags={setImportantKwd} /> | |||||
| </Form> | |||||
| </Modal> | |||||
| ); | |||||
| }; | |||||
| export default Index; |
| .tweenGroup { | |||||
| display: inline-block; | |||||
| } |
| import { PlusOutlined } from '@ant-design/icons'; | |||||
| import type { InputRef } from 'antd'; | |||||
| import { Input, Tag, theme } from 'antd'; | |||||
| import { TweenOneGroup } from 'rc-tween-one'; | |||||
| import React, { useEffect, useRef, useState } from 'react'; | |||||
| import styles from './index.less'; | |||||
| interface EditTagsProps { | |||||
| tags: string[]; | |||||
| setTags: (tags: string[]) => void; | |||||
| } | |||||
| const EditTag = ({ tags, setTags }: EditTagsProps) => { | |||||
| const { token } = theme.useToken(); | |||||
| const [inputVisible, setInputVisible] = useState(false); | |||||
| const [inputValue, setInputValue] = useState(''); | |||||
| const inputRef = useRef<InputRef>(null); | |||||
| useEffect(() => { | |||||
| if (inputVisible) { | |||||
| inputRef.current?.focus(); | |||||
| } | |||||
| }, [inputVisible]); | |||||
| const handleClose = (removedTag: string) => { | |||||
| const newTags = tags.filter((tag) => tag !== removedTag); | |||||
| console.log(newTags); | |||||
| setTags(newTags); | |||||
| }; | |||||
| const showInput = () => { | |||||
| setInputVisible(true); | |||||
| }; | |||||
| const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { | |||||
| setInputValue(e.target.value); | |||||
| }; | |||||
| const handleInputConfirm = () => { | |||||
| if (inputValue && tags.indexOf(inputValue) === -1) { | |||||
| setTags([...tags, inputValue]); | |||||
| } | |||||
| setInputVisible(false); | |||||
| setInputValue(''); | |||||
| }; | |||||
| const forMap = (tag: string) => { | |||||
| const tagElem = ( | |||||
| <Tag | |||||
| closable | |||||
| onClose={(e) => { | |||||
| e.preventDefault(); | |||||
| handleClose(tag); | |||||
| }} | |||||
| > | |||||
| {tag} | |||||
| </Tag> | |||||
| ); | |||||
| return ( | |||||
| <span key={tag} style={{ display: 'inline-block' }}> | |||||
| {tagElem} | |||||
| </span> | |||||
| ); | |||||
| }; | |||||
| const tagChild = tags.map(forMap); | |||||
| const tagPlusStyle: React.CSSProperties = { | |||||
| background: token.colorBgContainer, | |||||
| borderStyle: 'dashed', | |||||
| }; | |||||
| return ( | |||||
| <> | |||||
| <span> | |||||
| <TweenOneGroup | |||||
| className={styles.tweenGroup} | |||||
| enter={{ | |||||
| scale: 0.8, | |||||
| opacity: 0, | |||||
| type: 'from', | |||||
| duration: 100, | |||||
| }} | |||||
| onEnd={(e) => { | |||||
| if (e.type === 'appear' || e.type === 'enter') { | |||||
| (e.target as any).style = 'display: inline-block'; | |||||
| } | |||||
| }} | |||||
| leave={{ opacity: 0, width: 0, scale: 0, duration: 200 }} | |||||
| appear={false} | |||||
| > | |||||
| {tagChild} | |||||
| </TweenOneGroup> | |||||
| </span> | |||||
| {inputVisible ? ( | |||||
| <Input | |||||
| ref={inputRef} | |||||
| type="text" | |||||
| size="small" | |||||
| style={{ width: 78 }} | |||||
| value={inputValue} | |||||
| onChange={handleInputChange} | |||||
| onBlur={handleInputConfirm} | |||||
| onPressEnter={handleInputConfirm} | |||||
| /> | |||||
| ) : ( | |||||
| <Tag onClick={showInput} style={tagPlusStyle}> | |||||
| <PlusOutlined /> | |||||
| </Tag> | |||||
| )} | |||||
| </> | |||||
| ); | |||||
| }; | |||||
| export default EditTag; |
| } | } | ||||
| } | } | ||||
| .chunkContainer { | |||||
| height: calc(100vh - 320px); | |||||
| overflow: auto; | |||||
| } | |||||
| .pageFooter { | .pageFooter { | ||||
| height: 32px; | height: 32px; | ||||
| } | } |
| import { getOneNamespaceEffectsLoading } from '@/utils/storeUtil'; | import { getOneNamespaceEffectsLoading } from '@/utils/storeUtil'; | ||||
| import type { PaginationProps } from 'antd'; | import type { PaginationProps } from 'antd'; | ||||
| import { Button, Input, Pagination, Space, Spin } from 'antd'; | |||||
| import { debounce } from 'lodash'; | |||||
| import React, { useCallback, useEffect, useState } from 'react'; | |||||
| import { Divider, Pagination, Space, Spin, message } from 'antd'; | |||||
| import { useCallback, useEffect, useState } from 'react'; | |||||
| import { useDispatch, useSearchParams, useSelector } from 'umi'; | import { useDispatch, useSearchParams, useSelector } from 'umi'; | ||||
| import CreateModal from './components/createModal'; | |||||
| import CreatingModal from './components/chunk-creating-modal'; | |||||
| import { useDeleteChunkByIds } from '@/hooks/knowledgeHook'; | |||||
| import ChunkCard from './components/chunk-card'; | import ChunkCard from './components/chunk-card'; | ||||
| import ChunkToolBar from './components/chunk-toolbar'; | import ChunkToolBar from './components/chunk-toolbar'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| const chunkModel: ChunkModelState = useSelector( | const chunkModel: ChunkModelState = useSelector( | ||||
| (state: any) => state.chunkModel, | (state: any) => state.chunkModel, | ||||
| ); | ); | ||||
| const [keywords, SetKeywords] = useState(''); | |||||
| const [selectedChunkIds, setSelectedChunkIds] = useState<string[]>([]); | const [selectedChunkIds, setSelectedChunkIds] = useState<string[]>([]); | ||||
| const [searchParams] = useSearchParams(); | const [searchParams] = useSearchParams(); | ||||
| const { | |||||
| data = [], | |||||
| total, | |||||
| chunk_id, | |||||
| isShowCreateModal, | |||||
| pagination, | |||||
| } = chunkModel; | |||||
| const { data = [], total, pagination } = chunkModel; | |||||
| const effects = useSelector((state: any) => state.loading.effects); | const effects = useSelector((state: any) => state.loading.effects); | ||||
| const loading = getOneNamespaceEffectsLoading('chunkModel', effects, [ | const loading = getOneNamespaceEffectsLoading('chunkModel', effects, [ | ||||
| 'create_hunk', | 'create_hunk', | ||||
| 'switch_chunk', | 'switch_chunk', | ||||
| ]); | ]); | ||||
| const documentId: string = searchParams.get('doc_id') || ''; | const documentId: string = searchParams.get('doc_id') || ''; | ||||
| const [chunkId, setChunkId] = useState<string | undefined>(); | |||||
| const { removeChunk } = useDeleteChunkByIds(); | |||||
| const getChunkList = () => { | |||||
| const getChunkList = useCallback(() => { | |||||
| const payload: PayloadType = { | const payload: PayloadType = { | ||||
| doc_id: documentId, | doc_id: documentId, | ||||
| }; | }; | ||||
| ...payload, | ...payload, | ||||
| }, | }, | ||||
| }); | }); | ||||
| }; | |||||
| const confirm = async (id: string) => { | |||||
| const retcode = await dispatch<any>({ | |||||
| type: 'chunkModel/rm_chunk', | |||||
| payload: { | |||||
| chunk_ids: [id], | |||||
| }, | |||||
| }); | |||||
| }, [dispatch, documentId]); | |||||
| retcode === 0 && getChunkList(); | |||||
| }; | |||||
| const handleEditChunk = useCallback( | |||||
| (chunk_id?: string) => { | |||||
| setChunkId(chunk_id); | |||||
| const handleEditchunk = (chunk_id?: string) => { | |||||
| dispatch({ | |||||
| type: 'chunkModel/updateState', | |||||
| payload: { | |||||
| isShowCreateModal: true, | |||||
| chunk_id, | |||||
| doc_id: documentId, | |||||
| }, | |||||
| }); | |||||
| getChunkList(); | |||||
| }; | |||||
| dispatch({ | |||||
| type: 'chunkModel/setIsShowCreateModal', | |||||
| payload: true, | |||||
| }); | |||||
| }, | |||||
| [dispatch], | |||||
| ); | |||||
| const onPaginationChange: PaginationProps['onShowSizeChange'] = ( | const onPaginationChange: PaginationProps['onShowSizeChange'] = ( | ||||
| page, | page, | ||||
| const selectAllChunk = useCallback( | const selectAllChunk = useCallback( | ||||
| (checked: boolean) => { | (checked: boolean) => { | ||||
| setSelectedChunkIds(checked ? data.map((x) => x.chunk_id) : []); | setSelectedChunkIds(checked ? data.map((x) => x.chunk_id) : []); | ||||
| // setSelectedChunkIds((previousIds) => { | |||||
| // return checked ? [...previousIds, ...data.map((x) => x.chunk_id)] : []; | |||||
| // }); | |||||
| }, | }, | ||||
| [data], | [data], | ||||
| ); | ); | ||||
| }, | }, | ||||
| [], | [], | ||||
| ); | ); | ||||
| const showSelectedChunkWarning = () => { | |||||
| message.warning('Please select chunk!'); | |||||
| }; | |||||
| const handleRemoveChunk = useCallback(async () => { | |||||
| if (selectedChunkIds.length > 0) { | |||||
| const resCode: number = await removeChunk(selectedChunkIds, documentId); | |||||
| if (resCode === 0) { | |||||
| setSelectedChunkIds([]); | |||||
| } | |||||
| } else { | |||||
| showSelectedChunkWarning(); | |||||
| } | |||||
| }, [selectedChunkIds, documentId, removeChunk]); | |||||
| const switchChunk = useCallback( | |||||
| async (available?: number, chunkIds?: string[]) => { | |||||
| let ids = chunkIds; | |||||
| if (!chunkIds) { | |||||
| ids = selectedChunkIds; | |||||
| if (selectedChunkIds.length === 0) { | |||||
| showSelectedChunkWarning(); | |||||
| return; | |||||
| } | |||||
| } | |||||
| const resCode: number = await dispatch<any>({ | |||||
| type: 'chunkModel/switch_chunk', | |||||
| payload: { | |||||
| chunk_ids: ids, | |||||
| available_int: available, | |||||
| doc_id: documentId, | |||||
| }, | |||||
| }); | |||||
| if (!chunkIds && resCode === 0) { | |||||
| getChunkList(); | |||||
| } | |||||
| }, | |||||
| [dispatch, documentId, getChunkList, selectedChunkIds], | |||||
| ); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| getChunkList(); | getChunkList(); | ||||
| type: 'chunkModel/resetFilter', // TODO: need to reset state uniformly | type: 'chunkModel/resetFilter', // TODO: need to reset state uniformly | ||||
| }); | }); | ||||
| }; | }; | ||||
| }, [documentId]); | |||||
| const debounceChange = debounce(getChunkList, 300); | |||||
| const debounceCallback = useCallback( | |||||
| (value: string) => debounceChange(value), | |||||
| [], | |||||
| ); | |||||
| const handleInputChange = ( | |||||
| e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>, | |||||
| ) => { | |||||
| setSelectedChunkIds([]); | |||||
| const value = e.target.value; | |||||
| SetKeywords(value); | |||||
| debounceCallback(value); | |||||
| }; | |||||
| }, [dispatch, getChunkList]); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <ChunkToolBar | <ChunkToolBar | ||||
| getChunkList={getChunkList} | getChunkList={getChunkList} | ||||
| selectAllChunk={selectAllChunk} | selectAllChunk={selectAllChunk} | ||||
| createChunk={handleEditChunk} | |||||
| removeChunk={handleRemoveChunk} | |||||
| checked={selectedChunkIds.length === data.length} | checked={selectedChunkIds.length === data.length} | ||||
| switchChunk={switchChunk} | |||||
| ></ChunkToolBar> | ></ChunkToolBar> | ||||
| <div className={styles.filter}> | |||||
| <div> | |||||
| <Input | |||||
| placeholder="搜索" | |||||
| style={{ width: 220 }} | |||||
| value={keywords} | |||||
| allowClear | |||||
| onChange={handleInputChange} | |||||
| /> | |||||
| </div> | |||||
| <Button | |||||
| onClick={() => { | |||||
| handleEditchunk(); | |||||
| }} | |||||
| type="link" | |||||
| > | |||||
| 添加分段 | |||||
| </Button> | |||||
| </div> | |||||
| <Divider></Divider> | |||||
| <div className={styles.pageContent}> | <div className={styles.pageContent}> | ||||
| <Spin spinning={loading} className={styles.spin} size="large"> | <Spin spinning={loading} className={styles.spin} size="large"> | ||||
| <Space direction="vertical" size={'middle'}> | |||||
| <Space | |||||
| direction="vertical" | |||||
| size={'middle'} | |||||
| className={styles.chunkContainer} | |||||
| > | |||||
| {data.map((item) => ( | {data.map((item) => ( | ||||
| <ChunkCard | <ChunkCard | ||||
| item={item} | item={item} | ||||
| key={item.chunk_id} | key={item.chunk_id} | ||||
| editChunk={handleEditChunk} | |||||
| checked={selectedChunkIds.some((x) => x === item.chunk_id)} | checked={selectedChunkIds.some((x) => x === item.chunk_id)} | ||||
| handleCheckboxClick={handleSingleCheckboxClick} | handleCheckboxClick={handleSingleCheckboxClick} | ||||
| switchChunk={switchChunk} | |||||
| ></ChunkCard> | ></ChunkCard> | ||||
| ))} | ))} | ||||
| </Space> | </Space> | ||||
| showQuickJumper | showQuickJumper | ||||
| showSizeChanger | showSizeChanger | ||||
| onChange={onPaginationChange} | onChange={onPaginationChange} | ||||
| defaultPageSize={10} | |||||
| pageSize={pagination.pageSize} | |||||
| pageSizeOptions={[10, 30, 60, 90]} | pageSizeOptions={[10, 30, 60, 90]} | ||||
| defaultCurrent={pagination.current} | |||||
| current={pagination.current} | |||||
| total={total} | total={total} | ||||
| /> | /> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <CreateModal | |||||
| doc_id={documentId} | |||||
| isShowCreateModal={isShowCreateModal} | |||||
| chunk_id={chunk_id} | |||||
| getChunkList={getChunkList} | |||||
| /> | |||||
| <CreatingModal doc_id={documentId} chunkId={chunkId} /> | |||||
| </> | </> | ||||
| ); | ); | ||||
| }; | }; |
| import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | ||||
| import kbService from '@/services/kbService'; | import kbService from '@/services/kbService'; | ||||
| import { message } from 'antd'; | import { message } from 'antd'; | ||||
| import { pick } from 'lodash'; | |||||
| // import { delay } from '@/utils/storeUtil'; | // import { delay } from '@/utils/storeUtil'; | ||||
| import { DvaModel } from 'umi'; | import { DvaModel } from 'umi'; | ||||
| ...payload, | ...payload, | ||||
| }; | }; | ||||
| }, | }, | ||||
| setIsShowCreateModal(state, { payload }) { | |||||
| return { | |||||
| ...state, | |||||
| isShowCreateModal: | |||||
| typeof payload === 'boolean' ? payload : !state.isShowCreateModal, | |||||
| }; | |||||
| }, | |||||
| setAvailable(state, { payload }) { | setAvailable(state, { payload }) { | ||||
| return { ...state, available: payload }; | return { ...state, available: payload }; | ||||
| }, | }, | ||||
| setPagination(state, { payload }) { | setPagination(state, { payload }) { | ||||
| return { ...state, pagination: { ...state.pagination, ...payload } }; | return { ...state, pagination: { ...state.pagination, ...payload } }; | ||||
| }, | }, | ||||
| resetFilter(state, { payload }) { | |||||
| resetFilter(state, {}) { | |||||
| return { | return { | ||||
| ...state, | ...state, | ||||
| pagination: { | pagination: { | ||||
| }); | }); | ||||
| } | } | ||||
| }, | }, | ||||
| *switch_chunk({ payload = {} }, { call, put }) { | |||||
| throttledGetChunkList: [ | |||||
| function* ({ payload }, { put }) { | |||||
| yield put({ type: 'chunk_list', payload: { doc_id: payload } }); | |||||
| }, | |||||
| { type: 'throttle', ms: 1000 }, // TODO: Provide type support for this effect | |||||
| ], | |||||
| *switch_chunk({ payload = {} }, { call }) { | |||||
| const { data } = yield call(kbService.switch_chunk, payload); | const { data } = yield call(kbService.switch_chunk, payload); | ||||
| const { retcode } = data; | const { retcode } = data; | ||||
| if (retcode === 0) { | if (retcode === 0) { | ||||
| return retcode; | return retcode; | ||||
| }, | }, | ||||
| *rm_chunk({ payload = {} }, { call, put }) { | *rm_chunk({ payload = {} }, { call, put }) { | ||||
| console.log('shanchu'); | |||||
| const { data, response } = yield call(kbService.rm_chunk, payload); | |||||
| const { retcode, data: res, retmsg } = data; | |||||
| const { data } = yield call(kbService.rm_chunk, payload); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | |||||
| yield put({ | |||||
| type: 'setIsShowCreateModal', | |||||
| payload: false, | |||||
| }); | |||||
| yield put({ type: 'setPagination', payload: { current: 1 } }); | |||||
| yield put({ type: 'chunk_list', payload: pick(payload, ['doc_id']) }); | |||||
| } | |||||
| return retcode; | return retcode; | ||||
| }, | }, | ||||
| *get_chunk({ payload = {} }, { call, put }) { | *get_chunk({ payload = {} }, { call, put }) { | ||||
| const { data, response } = yield call(kbService.get_chunk, payload); | |||||
| const { retcode, data: res, retmsg } = data; | |||||
| const { data } = yield call(kbService.get_chunk, payload); | |||||
| const { retcode, data: res } = data; | |||||
| if (retcode === 0) { | if (retcode === 0) { | ||||
| yield put({ | yield put({ | ||||
| type: 'updateState', | type: 'updateState', | ||||
| } | } | ||||
| return data; | return data; | ||||
| }, | }, | ||||
| *create_hunk({ payload = {} }, { call, put }) { | |||||
| *create_chunk({ payload = {} }, { call, put }) { | |||||
| let service = kbService.create_chunk; | let service = kbService.create_chunk; | ||||
| if (payload.chunk_id) { | if (payload.chunk_id) { | ||||
| service = kbService.set_chunk; | service = kbService.set_chunk; | ||||
| } | } | ||||
| const { data, response } = yield call(service, payload); | |||||
| const { retcode, data: res, retmsg } = data; | |||||
| const { data } = yield call(service, payload); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | if (retcode === 0) { | ||||
| yield put({ | yield put({ | ||||
| type: 'updateState', | |||||
| payload: { | |||||
| isShowCreateModal: false, | |||||
| }, | |||||
| type: 'setIsShowCreateModal', | |||||
| payload: false, | |||||
| }); | }); | ||||
| yield put({ type: 'chunk_list', payload: pick(payload, ['doc_id']) }); | |||||
| } | } | ||||
| }, | }, | ||||
| }, | }, |
| import { debounce } from 'lodash'; | import { debounce } from 'lodash'; | ||||
| import React, { useCallback, useEffect } from 'react'; | import React, { useCallback, useEffect } from 'react'; | ||||
| import { useDispatch, useSelector } from 'umi'; | import { useDispatch, useSelector } from 'umi'; | ||||
| import CreateModal from '../knowledge-chunk/components/createModal'; | |||||
| import CreateModal from '../knowledge-chunk/components/chunk-creating-modal'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <CreateModal | <CreateModal | ||||
| getChunkList={getChunkList} | |||||
| isShowCreateModal={isShowCreateModal} | isShowCreateModal={isShowCreateModal} | ||||
| chunk_id={chunk_id} | chunk_id={chunk_id} | ||||
| doc_id={doc_id} | doc_id={doc_id} |
| if (payload.chunk_id) { | if (payload.chunk_id) { | ||||
| service = kbService.set_chunk; | service = kbService.set_chunk; | ||||
| } | } | ||||
| const { data, response } = yield call(service, payload); | |||||
| const { retcode, data: res, retmsg } = data; | |||||
| const { data } = yield call(service, payload); | |||||
| const { retcode } = data; | |||||
| yield put({ | yield put({ | ||||
| type: 'updateState', | type: 'updateState', | ||||
| payload: { | payload: { |