balibabu
commited on
Commit
·
0dad3f5
1
Parent(s):
29e6d3f
feat: The search box is displayed globally when the page is loaded for the first time #2247 (#2325)
Browse files### What problem does this PR solve?
feat: The search box is displayed globally when the page is loaded for
the first time #2247
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- web/src/pages/search/hooks.ts +12 -7
- web/src/pages/search/index.less +31 -2
- web/src/pages/search/index.tsx +100 -65
- web/src/pages/search/sidebar.tsx +2 -1
web/src/pages/search/hooks.ts
CHANGED
@@ -3,7 +3,7 @@ import { useTestChunkRetrieval } from '@/hooks/knowledge-hooks';
|
|
3 |
import { useSendMessageWithSse } from '@/hooks/logic-hooks';
|
4 |
import { IAnswer } from '@/interfaces/database/chat';
|
5 |
import api from '@/utils/api';
|
6 |
-
import { isEmpty } from 'lodash';
|
7 |
import { ChangeEventHandler, useCallback, useEffect, useState } from 'react';
|
8 |
|
9 |
export const useSendQuestion = (kbIds: string[]) => {
|
@@ -19,18 +19,22 @@ export const useSendQuestion = (kbIds: string[]) => {
|
|
19 |
loading: mindMapLoading,
|
20 |
} = useFetchMindMap();
|
21 |
const [searchStr, setSearchStr] = useState<string>('');
|
|
|
22 |
|
23 |
const sendQuestion = useCallback(
|
24 |
(question: string) => {
|
|
|
|
|
|
|
25 |
setCurrentAnswer({} as IAnswer);
|
26 |
setSendingLoading(true);
|
27 |
-
send({ kb_ids: kbIds, question });
|
28 |
-
testChunk({ kb_id: kbIds, highlight: true, question });
|
29 |
fetchMindMap({
|
30 |
-
question,
|
31 |
kb_ids: kbIds,
|
32 |
});
|
33 |
-
fetchRelatedQuestions(
|
34 |
},
|
35 |
[send, testChunk, kbIds, fetchRelatedQuestions, fetchMindMap],
|
36 |
);
|
@@ -65,14 +69,15 @@ export const useSendQuestion = (kbIds: string[]) => {
|
|
65 |
|
66 |
return {
|
67 |
sendQuestion,
|
|
|
|
|
68 |
loading,
|
69 |
sendingLoading,
|
70 |
answer: currentAnswer,
|
71 |
relatedQuestions: relatedQuestions?.slice(0, 5) ?? [],
|
72 |
mindMap,
|
73 |
mindMapLoading,
|
74 |
-
handleClickRelatedQuestion,
|
75 |
searchStr,
|
76 |
-
|
77 |
};
|
78 |
};
|
|
|
3 |
import { useSendMessageWithSse } from '@/hooks/logic-hooks';
|
4 |
import { IAnswer } from '@/interfaces/database/chat';
|
5 |
import api from '@/utils/api';
|
6 |
+
import { isEmpty, trim } from 'lodash';
|
7 |
import { ChangeEventHandler, useCallback, useEffect, useState } from 'react';
|
8 |
|
9 |
export const useSendQuestion = (kbIds: string[]) => {
|
|
|
19 |
loading: mindMapLoading,
|
20 |
} = useFetchMindMap();
|
21 |
const [searchStr, setSearchStr] = useState<string>('');
|
22 |
+
const [isFirstRender, setIsFirstRender] = useState(true);
|
23 |
|
24 |
const sendQuestion = useCallback(
|
25 |
(question: string) => {
|
26 |
+
const q = trim(question);
|
27 |
+
if (isEmpty(q)) return;
|
28 |
+
setIsFirstRender(false);
|
29 |
setCurrentAnswer({} as IAnswer);
|
30 |
setSendingLoading(true);
|
31 |
+
send({ kb_ids: kbIds, question: q });
|
32 |
+
testChunk({ kb_id: kbIds, highlight: true, question: q });
|
33 |
fetchMindMap({
|
34 |
+
question: q,
|
35 |
kb_ids: kbIds,
|
36 |
});
|
37 |
+
fetchRelatedQuestions(q);
|
38 |
},
|
39 |
[send, testChunk, kbIds, fetchRelatedQuestions, fetchMindMap],
|
40 |
);
|
|
|
69 |
|
70 |
return {
|
71 |
sendQuestion,
|
72 |
+
handleSearchStrChange,
|
73 |
+
handleClickRelatedQuestion,
|
74 |
loading,
|
75 |
sendingLoading,
|
76 |
answer: currentAnswer,
|
77 |
relatedQuestions: relatedQuestions?.slice(0, 5) ?? [],
|
78 |
mindMap,
|
79 |
mindMapLoading,
|
|
|
80 |
searchStr,
|
81 |
+
isFirstRender,
|
82 |
};
|
83 |
};
|
web/src/pages/search/index.less
CHANGED
@@ -49,18 +49,22 @@
|
|
49 |
}
|
50 |
}
|
51 |
|
|
|
|
|
|
|
|
|
52 |
.content {
|
53 |
height: 100%;
|
54 |
.main {
|
55 |
width: 60%;
|
56 |
// background-color: aqua;
|
57 |
overflow: auto;
|
58 |
-
padding: 10px;
|
59 |
}
|
60 |
|
61 |
.graph {
|
62 |
width: 40%;
|
63 |
-
padding
|
64 |
}
|
65 |
}
|
66 |
.answerWrapper {
|
@@ -72,3 +76,28 @@
|
|
72 |
margin: 0;
|
73 |
}
|
74 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
}
|
50 |
}
|
51 |
|
52 |
+
.firstRenderContent {
|
53 |
+
height: 100%;
|
54 |
+
}
|
55 |
+
|
56 |
.content {
|
57 |
height: 100%;
|
58 |
.main {
|
59 |
width: 60%;
|
60 |
// background-color: aqua;
|
61 |
overflow: auto;
|
62 |
+
padding: 20px 10px 10px;
|
63 |
}
|
64 |
|
65 |
.graph {
|
66 |
width: 40%;
|
67 |
+
padding: 20px 10px 10px;
|
68 |
}
|
69 |
}
|
70 |
.answerWrapper {
|
|
|
76 |
margin: 0;
|
77 |
}
|
78 |
}
|
79 |
+
|
80 |
+
.input() {
|
81 |
+
:global(.ant-input-affix-wrapper) {
|
82 |
+
padding: 4px 8px;
|
83 |
+
border-start-start-radius: 30px !important;
|
84 |
+
border-end-start-radius: 30px !important;
|
85 |
+
}
|
86 |
+
input {
|
87 |
+
height: 40px;
|
88 |
+
}
|
89 |
+
button {
|
90 |
+
height: 50px !important;
|
91 |
+
border-start-end-radius: 30px !important;
|
92 |
+
border-end-end-radius: 30px !important;
|
93 |
+
}
|
94 |
+
}
|
95 |
+
|
96 |
+
.globalInput {
|
97 |
+
width: 600px;
|
98 |
+
.input();
|
99 |
+
}
|
100 |
+
.partialInput {
|
101 |
+
width: 100%;
|
102 |
+
.input();
|
103 |
+
}
|
web/src/pages/search/index.tsx
CHANGED
@@ -1,14 +1,24 @@
|
|
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 {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
import { useState } from 'react';
|
7 |
import MarkdownContent from '../chat/markdown-content';
|
8 |
import { useSendQuestion } from './hooks';
|
9 |
import SearchSidebar from './sidebar';
|
10 |
|
11 |
-
import IndentedTree from '@/components/indented-tree/indented-tree';
|
12 |
import styles from './index.less';
|
13 |
|
14 |
const { Content } = Layout;
|
@@ -27,8 +37,25 @@ const SearchPage = () => {
|
|
27 |
mindMap,
|
28 |
mindMapLoading,
|
29 |
searchStr,
|
|
|
|
|
30 |
} = useSendQuestion(checkedList);
|
31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
return (
|
33 |
<Layout className={styles.searchPage}>
|
34 |
<SearchSidebar
|
@@ -37,70 +64,78 @@ const SearchPage = () => {
|
|
37 |
></SearchSidebar>
|
38 |
<Layout>
|
39 |
<Content>
|
40 |
-
|
41 |
-
<
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
<
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
<List
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
)}
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
<Flex wrap="wrap" gap={'10px 0'}>
|
79 |
-
{relatedQuestions?.map((x, idx) => (
|
80 |
-
<Tag
|
81 |
-
key={idx}
|
82 |
-
className={styles.tag}
|
83 |
-
onClick={handleClickRelatedQuestion(x)}
|
84 |
-
>
|
85 |
-
{x}
|
86 |
-
</Tag>
|
87 |
-
))}
|
88 |
-
</Flex>
|
89 |
-
</Card>
|
90 |
-
)}
|
91 |
-
</section>
|
92 |
-
<section className={styles.graph}>
|
93 |
-
{mindMapLoading ? (
|
94 |
-
<Skeleton active />
|
95 |
-
) : (
|
96 |
-
<IndentedTree
|
97 |
-
data={mindMap}
|
98 |
-
show
|
99 |
-
style={{ width: '100%', height: '100%' }}
|
100 |
-
></IndentedTree>
|
101 |
-
)}
|
102 |
-
</section>
|
103 |
-
</Flex>
|
104 |
</Content>
|
105 |
</Layout>
|
106 |
</Layout>
|
|
|
1 |
import HightLightMarkdown from '@/components/highlight-markdown';
|
2 |
import { ImageWithPopover } from '@/components/image';
|
3 |
+
import IndentedTree from '@/components/indented-tree/indented-tree';
|
4 |
import { useSelectTestingResult } from '@/hooks/knowledge-hooks';
|
5 |
import { IReference } from '@/interfaces/database/chat';
|
6 |
+
import {
|
7 |
+
Card,
|
8 |
+
Divider,
|
9 |
+
Flex,
|
10 |
+
Input,
|
11 |
+
Layout,
|
12 |
+
List,
|
13 |
+
Skeleton,
|
14 |
+
Space,
|
15 |
+
Tag,
|
16 |
+
} from 'antd';
|
17 |
import { useState } from 'react';
|
18 |
import MarkdownContent from '../chat/markdown-content';
|
19 |
import { useSendQuestion } from './hooks';
|
20 |
import SearchSidebar from './sidebar';
|
21 |
|
|
|
22 |
import styles from './index.less';
|
23 |
|
24 |
const { Content } = Layout;
|
|
|
37 |
mindMap,
|
38 |
mindMapLoading,
|
39 |
searchStr,
|
40 |
+
loading,
|
41 |
+
isFirstRender,
|
42 |
} = useSendQuestion(checkedList);
|
43 |
|
44 |
+
const InputSearch = (
|
45 |
+
<Search
|
46 |
+
value={searchStr}
|
47 |
+
onChange={handleSearchStrChange}
|
48 |
+
placeholder="input search text"
|
49 |
+
allowClear
|
50 |
+
enterButton
|
51 |
+
onSearch={sendQuestion}
|
52 |
+
size="large"
|
53 |
+
loading={sendingLoading}
|
54 |
+
disabled={checkedList.length === 0}
|
55 |
+
className={isFirstRender ? styles.globalInput : styles.partialInput}
|
56 |
+
/>
|
57 |
+
);
|
58 |
+
|
59 |
return (
|
60 |
<Layout className={styles.searchPage}>
|
61 |
<SearchSidebar
|
|
|
64 |
></SearchSidebar>
|
65 |
<Layout>
|
66 |
<Content>
|
67 |
+
{isFirstRender ? (
|
68 |
+
<Flex
|
69 |
+
justify="center"
|
70 |
+
align="center"
|
71 |
+
className={styles.firstRenderContent}
|
72 |
+
>
|
73 |
+
{InputSearch}
|
74 |
+
</Flex>
|
75 |
+
) : (
|
76 |
+
<Flex className={styles.content}>
|
77 |
+
<section className={styles.main}>
|
78 |
+
{InputSearch}
|
79 |
+
{answer.answer && (
|
80 |
+
<div className={styles.answerWrapper}>
|
81 |
+
<MarkdownContent
|
82 |
+
loading={sendingLoading}
|
83 |
+
content={answer.answer}
|
84 |
+
reference={answer.reference ?? ({} as IReference)}
|
85 |
+
clickDocumentButton={() => {}}
|
86 |
+
></MarkdownContent>
|
87 |
+
</div>
|
88 |
+
)}
|
89 |
+
<Divider></Divider>
|
90 |
+
{list.chunks.length > 0 && (
|
91 |
+
<List
|
92 |
+
dataSource={list.chunks}
|
93 |
+
loading={loading}
|
94 |
+
renderItem={(item) => (
|
95 |
+
<List.Item>
|
96 |
+
<Card className={styles.card}>
|
97 |
+
<Space>
|
98 |
+
<ImageWithPopover
|
99 |
+
id={item.img_id}
|
100 |
+
></ImageWithPopover>
|
101 |
+
<HightLightMarkdown>
|
102 |
+
{item.highlight}
|
103 |
+
</HightLightMarkdown>
|
104 |
+
</Space>
|
105 |
+
</Card>
|
106 |
+
</List.Item>
|
107 |
+
)}
|
108 |
+
/>
|
109 |
+
)}
|
110 |
+
{relatedQuestions?.length > 0 && (
|
111 |
+
<Card>
|
112 |
+
<Flex wrap="wrap" gap={'10px 0'}>
|
113 |
+
{relatedQuestions?.map((x, idx) => (
|
114 |
+
<Tag
|
115 |
+
key={idx}
|
116 |
+
className={styles.tag}
|
117 |
+
onClick={handleClickRelatedQuestion(x)}
|
118 |
+
>
|
119 |
+
{x}
|
120 |
+
</Tag>
|
121 |
+
))}
|
122 |
+
</Flex>
|
123 |
+
</Card>
|
124 |
+
)}
|
125 |
+
</section>
|
126 |
+
<section className={styles.graph}>
|
127 |
+
{mindMapLoading ? (
|
128 |
+
<Skeleton active />
|
129 |
+
) : (
|
130 |
+
<IndentedTree
|
131 |
+
data={mindMap}
|
132 |
+
show
|
133 |
+
style={{ width: '100%', height: '100%' }}
|
134 |
+
></IndentedTree>
|
135 |
)}
|
136 |
+
</section>
|
137 |
+
</Flex>
|
138 |
+
)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
</Content>
|
140 |
</Layout>
|
141 |
</Layout>
|
web/src/pages/search/sidebar.tsx
CHANGED
@@ -22,7 +22,7 @@ interface IProps {
|
|
22 |
}
|
23 |
|
24 |
const SearchSidebar = ({ checkedList, setCheckedList }: IProps) => {
|
25 |
-
const { list } = useNextFetchKnowledgeList();
|
26 |
const ids = useMemo(() => list.map((x) => x.id), [list]);
|
27 |
|
28 |
const checkAll = list.length === checkedList.length;
|
@@ -67,6 +67,7 @@ const SearchSidebar = ({ checkedList, setCheckedList }: IProps) => {
|
|
67 |
bordered
|
68 |
dataSource={list}
|
69 |
className={styles.list}
|
|
|
70 |
renderItem={(item) => (
|
71 |
<List.Item>
|
72 |
<Checkbox value={item.id} className={styles.checkbox}>
|
|
|
22 |
}
|
23 |
|
24 |
const SearchSidebar = ({ checkedList, setCheckedList }: IProps) => {
|
25 |
+
const { list, loading } = useNextFetchKnowledgeList();
|
26 |
const ids = useMemo(() => list.map((x) => x.id), [list]);
|
27 |
|
28 |
const checkAll = list.length === checkedList.length;
|
|
|
67 |
bordered
|
68 |
dataSource={list}
|
69 |
className={styles.list}
|
70 |
+
loading={loading}
|
71 |
renderItem={(item) => (
|
72 |
<List.Item>
|
73 |
<Checkbox value={item.id} className={styles.checkbox}>
|