balibabu commited on
Commit
d4bff6a
·
1 Parent(s): 5139555

feat: Search for the answers you want based on the selected knowledge base #2247 (#2287)

Browse files

### What problem does this PR solve?

feat: Search for the answers you want based on the selected knowledge
base #2247

### Type of change


- [x] New Feature (non-breaking change which adds functionality)

web/src/components/message-item/index.tsx CHANGED
@@ -1,6 +1,6 @@
1
  import { ReactComponent as AssistantIcon } from '@/assets/svg/assistant.svg';
2
  import { MessageType } from '@/constants/chat';
3
- import { useSetModalState, useTranslate } from '@/hooks/common-hooks';
4
  import { useSelectFileThumbnails } from '@/hooks/knowledge-hooks';
5
  import { IReference } from '@/interfaces/database/chat';
6
  import { IChunk } from '@/interfaces/database/knowledge';
@@ -50,7 +50,6 @@ const MessageItem = ({
50
  }: IProps) => {
51
  const isAssistant = item.role === MessageType.Assistant;
52
  const isUser = item.role === MessageType.User;
53
- const { t } = useTranslate('chat');
54
  const fileThumbnails = useSelectFileThumbnails();
55
  const { data: documentList, setDocumentIds } = useFetchDocumentInfosByIds();
56
  const { data: documentThumbnails, setDocumentIds: setIds } =
@@ -62,14 +61,6 @@ const MessageItem = ({
62
  return reference?.doc_aggs ?? [];
63
  }, [reference?.doc_aggs]);
64
 
65
- const content = useMemo(() => {
66
- let text = item.content;
67
- if (text === '') {
68
- text = t('searching');
69
- }
70
- return loading ? text?.concat('~~2$$') : text;
71
- }, [item.content, loading, t]);
72
-
73
  const handleUserDocumentClick = useCallback(
74
  (id: string) => () => {
75
  setClickedDocumentId(id);
@@ -154,7 +145,8 @@ const MessageItem = ({
154
  }
155
  >
156
  <MarkdownContent
157
- content={content}
 
158
  reference={reference}
159
  clickDocumentButton={clickDocumentButton}
160
  ></MarkdownContent>
 
1
  import { ReactComponent as AssistantIcon } from '@/assets/svg/assistant.svg';
2
  import { MessageType } from '@/constants/chat';
3
+ import { useSetModalState } from '@/hooks/common-hooks';
4
  import { useSelectFileThumbnails } from '@/hooks/knowledge-hooks';
5
  import { IReference } from '@/interfaces/database/chat';
6
  import { IChunk } from '@/interfaces/database/knowledge';
 
50
  }: IProps) => {
51
  const isAssistant = item.role === MessageType.Assistant;
52
  const isUser = item.role === MessageType.User;
 
53
  const fileThumbnails = useSelectFileThumbnails();
54
  const { data: documentList, setDocumentIds } = useFetchDocumentInfosByIds();
55
  const { data: documentThumbnails, setDocumentIds: setIds } =
 
61
  return reference?.doc_aggs ?? [];
62
  }, [reference?.doc_aggs]);
63
 
 
 
 
 
 
 
 
 
64
  const handleUserDocumentClick = useCallback(
65
  (id: string) => () => {
66
  setClickedDocumentId(id);
 
145
  }
146
  >
147
  <MarkdownContent
148
+ loading={loading}
149
+ content={item.content}
150
  reference={reference}
151
  clickDocumentButton={clickDocumentButton}
152
  ></MarkdownContent>
web/src/hooks/knowledge-hooks.ts CHANGED
@@ -206,6 +206,7 @@ export const useTestChunkRetrieval = (): ResponsePostType<ITestingResult> & {
206
  mutateAsync,
207
  } = useMutation({
208
  mutationKey: ['testChunk'], // This method is invalid
 
209
  mutationFn: async (values: any) => {
210
  const { data } = await kbService.retrieval_test({
211
  ...values,
 
206
  mutateAsync,
207
  } = useMutation({
208
  mutationKey: ['testChunk'], // This method is invalid
209
+ gcTime: 0,
210
  mutationFn: async (values: any) => {
211
  const { data } = await kbService.retrieval_test({
212
  ...values,
web/src/hooks/logic-hooks.ts CHANGED
@@ -297,69 +297,6 @@ export const useSpeechWithSse = (url: string = api.tts) => {
297
  return { read };
298
  };
299
 
300
- export const useFetchAudioWithSse = (url: string = api.tts) => {
301
- // const [answer, setAnswer] = useState<IAnswer>({} as IAnswer);
302
- const [done, setDone] = useState(true);
303
-
304
- const read = useCallback(
305
- async (
306
- body: any,
307
- ): Promise<{ response: Response; data: ResponseType } | undefined> => {
308
- try {
309
- setDone(false);
310
- const response = await fetch(url, {
311
- method: 'POST',
312
- headers: {
313
- [Authorization]: getAuthorization(),
314
- 'Content-Type': 'application/json',
315
- },
316
- body: JSON.stringify(body),
317
- });
318
-
319
- const res = response.clone().json();
320
-
321
- const reader = response?.body?.getReader();
322
-
323
- while (true) {
324
- const x = await reader?.read();
325
- if (x) {
326
- const { done, value } = x;
327
- try {
328
- // const val = JSON.parse(value || '');
329
- const val = value;
330
- // const d = val?.data;
331
- // if (typeof d !== 'boolean') {
332
- // console.info('data:', d);
333
- // setAnswer({
334
- // ...d,
335
- // conversationId: body?.conversation_id,
336
- // });
337
- // }
338
- } catch (e) {
339
- console.warn(e);
340
- }
341
- if (done) {
342
- console.info('done');
343
- break;
344
- }
345
- }
346
- }
347
- console.info('done?');
348
- setDone(true);
349
- // setAnswer({} as IAnswer);
350
- return { data: await res, response };
351
- } catch (e) {
352
- setDone(true);
353
- // setAnswer({} as IAnswer);
354
- console.warn(e);
355
- }
356
- },
357
- [url],
358
- );
359
-
360
- return { read, done, setDone };
361
- };
362
-
363
  //#region chat hooks
364
 
365
  export const useScrollToBottom = (messages?: unknown) => {
 
297
  return { read };
298
  };
299
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  //#region chat hooks
301
 
302
  export const useScrollToBottom = (messages?: unknown) => {
web/src/layouts/components/header/index.tsx CHANGED
@@ -9,7 +9,7 @@ import { useLocation } from 'umi';
9
  import Toolbar from '../right-toolbar';
10
 
11
  import { useFetchAppConf } from '@/hooks/logic-hooks';
12
- import { MessageOutlined } from '@ant-design/icons';
13
  import styles from './index.less';
14
 
15
  const { Header } = Layout;
@@ -27,7 +27,7 @@ const RagHeader = () => {
27
  () => [
28
  { path: '/knowledge', name: t('knowledgeBase'), icon: KnowledgeBaseIcon },
29
  { path: '/chat', name: t('chat'), icon: MessageOutlined },
30
- // { path: '/search', name: t('search'), icon: SearchOutlined },
31
  { path: '/flow', name: t('flow'), icon: GraphIcon },
32
  { path: '/file', name: t('fileManager'), icon: FileIcon },
33
  ],
 
9
  import Toolbar from '../right-toolbar';
10
 
11
  import { useFetchAppConf } from '@/hooks/logic-hooks';
12
+ import { MessageOutlined, SearchOutlined } from '@ant-design/icons';
13
  import styles from './index.less';
14
 
15
  const { Header } = Layout;
 
27
  () => [
28
  { path: '/knowledge', name: t('knowledgeBase'), icon: KnowledgeBaseIcon },
29
  { path: '/chat', name: t('chat'), icon: MessageOutlined },
30
+ { path: '/search', name: t('search'), icon: SearchOutlined },
31
  { path: '/flow', name: t('flow'), icon: GraphIcon },
32
  { path: '/file', name: t('fileManager'), icon: FileIcon },
33
  ],
web/src/pages/chat/markdown-content/index.tsx CHANGED
@@ -7,13 +7,14 @@ import { getExtension } from '@/utils/document-util';
7
  import { InfoCircleOutlined } from '@ant-design/icons';
8
  import { Button, Flex, Popover, Space } from 'antd';
9
  import DOMPurify from 'dompurify';
10
- import { useCallback } from 'react';
11
  import Markdown from 'react-markdown';
12
  import reactStringReplace from 'react-string-replace';
13
  import SyntaxHighlighter from 'react-syntax-highlighter';
14
  import remarkGfm from 'remark-gfm';
15
  import { visitParents } from 'unist-util-visit-parents';
16
 
 
17
  import styles from './index.less';
18
 
19
  const reg = /(#{2}\d+\${2})/g;
@@ -25,11 +26,22 @@ const MarkdownContent = ({
25
  reference,
26
  clickDocumentButton,
27
  content,
 
28
  }: {
29
  content: string;
 
30
  reference: IReference;
31
  clickDocumentButton?: (documentId: string, chunk: IChunk) => void;
32
  }) => {
 
 
 
 
 
 
 
 
 
33
  const fileThumbnails = useSelectFileThumbnails();
34
 
35
  const handleDocumentButtonClick = useCallback(
@@ -173,7 +185,7 @@ const MarkdownContent = ({
173
  } as any
174
  }
175
  >
176
- {content}
177
  </Markdown>
178
  );
179
  };
 
7
  import { InfoCircleOutlined } from '@ant-design/icons';
8
  import { Button, Flex, Popover, Space } from 'antd';
9
  import DOMPurify from 'dompurify';
10
+ import { useCallback, useMemo } from 'react';
11
  import Markdown from 'react-markdown';
12
  import reactStringReplace from 'react-string-replace';
13
  import SyntaxHighlighter from 'react-syntax-highlighter';
14
  import remarkGfm from 'remark-gfm';
15
  import { visitParents } from 'unist-util-visit-parents';
16
 
17
+ import { useTranslation } from 'react-i18next';
18
  import styles from './index.less';
19
 
20
  const reg = /(#{2}\d+\${2})/g;
 
26
  reference,
27
  clickDocumentButton,
28
  content,
29
+ loading,
30
  }: {
31
  content: string;
32
+ loading: boolean;
33
  reference: IReference;
34
  clickDocumentButton?: (documentId: string, chunk: IChunk) => void;
35
  }) => {
36
+ const { t } = useTranslation();
37
+ const contentWithCursor = useMemo(() => {
38
+ let text = content;
39
+ if (text === '') {
40
+ text = t('chat.searching');
41
+ }
42
+ return loading ? text?.concat('~~2$$') : text;
43
+ }, [content, loading, t]);
44
+
45
  const fileThumbnails = useSelectFileThumbnails();
46
 
47
  const handleDocumentButtonClick = useCallback(
 
185
  } as any
186
  }
187
  >
188
+ {contentWithCursor}
189
  </Markdown>
190
  );
191
  };
web/src/pages/search/hooks.ts CHANGED
@@ -1,26 +1,19 @@
1
- import { MessageType } from '@/constants/chat';
2
  import { useTestChunkRetrieval } from '@/hooks/knowledge-hooks';
3
  import { useSendMessageWithSse } from '@/hooks/logic-hooks';
 
4
  import api from '@/utils/api';
5
- import { useCallback, useEffect, useMemo, useState } from 'react';
6
- import { IMessage } from '../chat/interface';
7
 
8
  export const useSendQuestion = (kbIds: string[]) => {
9
  const { send, answer, done } = useSendMessageWithSse(api.ask);
10
  const { testChunk, loading } = useTestChunkRetrieval();
11
  const [sendingLoading, setSendingLoading] = useState(false);
12
-
13
- const message: IMessage = useMemo(() => {
14
- return {
15
- id: '',
16
- content: answer.answer,
17
- role: MessageType.Assistant,
18
- reference: answer.reference,
19
- };
20
- }, [answer]);
21
 
22
  const sendQuestion = useCallback(
23
  (question: string) => {
 
24
  setSendingLoading(true);
25
  send({ kb_ids: kbIds, question });
26
  testChunk({ kb_id: kbIds, highlight: true, question });
@@ -28,11 +21,17 @@ export const useSendQuestion = (kbIds: string[]) => {
28
  [send, testChunk, kbIds],
29
  );
30
 
 
 
 
 
 
 
31
  useEffect(() => {
32
  if (done) {
33
  setSendingLoading(false);
34
  }
35
  }, [done]);
36
 
37
- return { sendQuestion, message, loading, sendingLoading };
38
  };
 
 
1
  import { useTestChunkRetrieval } from '@/hooks/knowledge-hooks';
2
  import { useSendMessageWithSse } from '@/hooks/logic-hooks';
3
+ import { IAnswer } from '@/interfaces/database/chat';
4
  import api from '@/utils/api';
5
+ import { isEmpty } from 'lodash';
6
+ import { useCallback, useEffect, useState } from 'react';
7
 
8
  export const useSendQuestion = (kbIds: string[]) => {
9
  const { send, answer, done } = useSendMessageWithSse(api.ask);
10
  const { testChunk, loading } = useTestChunkRetrieval();
11
  const [sendingLoading, setSendingLoading] = useState(false);
12
+ const [currentAnswer, setCurrentAnswer] = useState({} as IAnswer);
 
 
 
 
 
 
 
 
13
 
14
  const sendQuestion = useCallback(
15
  (question: string) => {
16
+ setCurrentAnswer({} as IAnswer);
17
  setSendingLoading(true);
18
  send({ kb_ids: kbIds, question });
19
  testChunk({ kb_id: kbIds, highlight: true, question });
 
21
  [send, testChunk, kbIds],
22
  );
23
 
24
+ useEffect(() => {
25
+ if (!isEmpty(answer)) {
26
+ setCurrentAnswer(answer);
27
+ }
28
+ }, [answer]);
29
+
30
  useEffect(() => {
31
  if (done) {
32
  setSendingLoading(false);
33
  }
34
  }, [done]);
35
 
36
+ return { sendQuestion, loading, sendingLoading, answer: currentAnswer };
37
  };
web/src/pages/search/index.less CHANGED
@@ -1,5 +1,7 @@
1
  .searchPage {
2
- // height: 100%;
 
 
3
  }
4
 
5
  .searchSide {
 
1
  .searchPage {
2
+ .card {
3
+ width: 100%;
4
+ }
5
  }
6
 
7
  .searchSide {
web/src/pages/search/index.tsx CHANGED
@@ -1,10 +1,10 @@
1
  import HightLightMarkdown from '@/components/highlight-markdown';
2
  import { ImageWithPopover } from '@/components/image';
3
- import MessageItem from '@/components/message-item';
4
  import { useSelectTestingResult } from '@/hooks/knowledge-hooks';
5
  import { IReference } from '@/interfaces/database/chat';
6
  import { Card, Flex, Input, Layout, List, Space } from 'antd';
7
  import { useState } from 'react';
 
8
  import { useSendQuestion } from './hooks';
9
  import SearchSidebar from './sidebar';
10
 
@@ -16,8 +16,7 @@ const { Search } = Input;
16
  const SearchPage = () => {
17
  const [checkedList, setCheckedList] = useState<string[]>([]);
18
  const list = useSelectTestingResult();
19
- const { sendQuestion, message, sendingLoading } =
20
- useSendQuestion(checkedList);
21
 
22
  return (
23
  <Layout className={styles.searchPage}>
@@ -33,19 +32,20 @@ const SearchPage = () => {
33
  placeholder="input search text"
34
  onSearch={sendQuestion}
35
  size="large"
 
 
36
  />
37
- <MessageItem
38
- item={message}
39
- nickname="You"
40
- reference={message.reference ?? ({} as IReference)}
41
  loading={sendingLoading}
42
- index={0}
43
- ></MessageItem>
 
 
44
  <List
45
  dataSource={list.chunks}
46
  renderItem={(item) => (
47
  <List.Item>
48
- <Card>
49
  <Space>
50
  <ImageWithPopover id={item.img_id}></ImageWithPopover>
51
  <HightLightMarkdown>
 
1
  import HightLightMarkdown from '@/components/highlight-markdown';
2
  import { ImageWithPopover } from '@/components/image';
 
3
  import { useSelectTestingResult } from '@/hooks/knowledge-hooks';
4
  import { IReference } from '@/interfaces/database/chat';
5
  import { Card, Flex, Input, Layout, List, Space } from 'antd';
6
  import { useState } from 'react';
7
+ import MarkdownContent from '../chat/markdown-content';
8
  import { useSendQuestion } from './hooks';
9
  import SearchSidebar from './sidebar';
10
 
 
16
  const SearchPage = () => {
17
  const [checkedList, setCheckedList] = useState<string[]>([]);
18
  const list = useSelectTestingResult();
19
+ const { sendQuestion, answer, sendingLoading } = useSendQuestion(checkedList);
 
20
 
21
  return (
22
  <Layout className={styles.searchPage}>
 
32
  placeholder="input search text"
33
  onSearch={sendQuestion}
34
  size="large"
35
+ loading={sendingLoading}
36
+ disabled={checkedList.length === 0}
37
  />
38
+ <MarkdownContent
 
 
 
39
  loading={sendingLoading}
40
+ content={answer.answer}
41
+ reference={answer.reference ?? ({} as IReference)}
42
+ clickDocumentButton={() => {}}
43
+ ></MarkdownContent>
44
  <List
45
  dataSource={list.chunks}
46
  renderItem={(item) => (
47
  <List.Item>
48
+ <Card className={styles.card}>
49
  <Space>
50
  <ImageWithPopover id={item.img_id}></ImageWithPopover>
51
  <HightLightMarkdown>