mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-05-23 21:19:44 +08:00
### 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)
This commit is contained in:
parent
884dcbcb7e
commit
ceae4df889
@ -3,7 +3,7 @@ import { useTestChunkRetrieval } from '@/hooks/knowledge-hooks';
|
|||||||
import { useSendMessageWithSse } from '@/hooks/logic-hooks';
|
import { useSendMessageWithSse } from '@/hooks/logic-hooks';
|
||||||
import { IAnswer } from '@/interfaces/database/chat';
|
import { IAnswer } from '@/interfaces/database/chat';
|
||||||
import api from '@/utils/api';
|
import api from '@/utils/api';
|
||||||
import { isEmpty } from 'lodash';
|
import { isEmpty, trim } from 'lodash';
|
||||||
import { ChangeEventHandler, useCallback, useEffect, useState } from 'react';
|
import { ChangeEventHandler, useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
export const useSendQuestion = (kbIds: string[]) => {
|
export const useSendQuestion = (kbIds: string[]) => {
|
||||||
@ -19,18 +19,22 @@ export const useSendQuestion = (kbIds: string[]) => {
|
|||||||
loading: mindMapLoading,
|
loading: mindMapLoading,
|
||||||
} = useFetchMindMap();
|
} = useFetchMindMap();
|
||||||
const [searchStr, setSearchStr] = useState<string>('');
|
const [searchStr, setSearchStr] = useState<string>('');
|
||||||
|
const [isFirstRender, setIsFirstRender] = useState(true);
|
||||||
|
|
||||||
const sendQuestion = useCallback(
|
const sendQuestion = useCallback(
|
||||||
(question: string) => {
|
(question: string) => {
|
||||||
|
const q = trim(question);
|
||||||
|
if (isEmpty(q)) return;
|
||||||
|
setIsFirstRender(false);
|
||||||
setCurrentAnswer({} as IAnswer);
|
setCurrentAnswer({} as IAnswer);
|
||||||
setSendingLoading(true);
|
setSendingLoading(true);
|
||||||
send({ kb_ids: kbIds, question });
|
send({ kb_ids: kbIds, question: q });
|
||||||
testChunk({ kb_id: kbIds, highlight: true, question });
|
testChunk({ kb_id: kbIds, highlight: true, question: q });
|
||||||
fetchMindMap({
|
fetchMindMap({
|
||||||
question,
|
question: q,
|
||||||
kb_ids: kbIds,
|
kb_ids: kbIds,
|
||||||
});
|
});
|
||||||
fetchRelatedQuestions(question);
|
fetchRelatedQuestions(q);
|
||||||
},
|
},
|
||||||
[send, testChunk, kbIds, fetchRelatedQuestions, fetchMindMap],
|
[send, testChunk, kbIds, fetchRelatedQuestions, fetchMindMap],
|
||||||
);
|
);
|
||||||
@ -65,14 +69,15 @@ export const useSendQuestion = (kbIds: string[]) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
sendQuestion,
|
sendQuestion,
|
||||||
|
handleSearchStrChange,
|
||||||
|
handleClickRelatedQuestion,
|
||||||
loading,
|
loading,
|
||||||
sendingLoading,
|
sendingLoading,
|
||||||
answer: currentAnswer,
|
answer: currentAnswer,
|
||||||
relatedQuestions: relatedQuestions?.slice(0, 5) ?? [],
|
relatedQuestions: relatedQuestions?.slice(0, 5) ?? [],
|
||||||
mindMap,
|
mindMap,
|
||||||
mindMapLoading,
|
mindMapLoading,
|
||||||
handleClickRelatedQuestion,
|
|
||||||
searchStr,
|
searchStr,
|
||||||
handleSearchStrChange,
|
isFirstRender,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -49,18 +49,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.firstRenderContent {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
.main {
|
.main {
|
||||||
width: 60%;
|
width: 60%;
|
||||||
// background-color: aqua;
|
// background-color: aqua;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 10px;
|
padding: 20px 10px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.graph {
|
.graph {
|
||||||
width: 40%;
|
width: 40%;
|
||||||
padding-right: 10px;
|
padding: 20px 10px 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.answerWrapper {
|
.answerWrapper {
|
||||||
@ -72,3 +76,28 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input() {
|
||||||
|
:global(.ant-input-affix-wrapper) {
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-start-start-radius: 30px !important;
|
||||||
|
border-end-start-radius: 30px !important;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
height: 50px !important;
|
||||||
|
border-start-end-radius: 30px !important;
|
||||||
|
border-end-end-radius: 30px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.globalInput {
|
||||||
|
width: 600px;
|
||||||
|
.input();
|
||||||
|
}
|
||||||
|
.partialInput {
|
||||||
|
width: 100%;
|
||||||
|
.input();
|
||||||
|
}
|
||||||
|
@ -1,14 +1,24 @@
|
|||||||
import HightLightMarkdown from '@/components/highlight-markdown';
|
import HightLightMarkdown from '@/components/highlight-markdown';
|
||||||
import { ImageWithPopover } from '@/components/image';
|
import { ImageWithPopover } from '@/components/image';
|
||||||
|
import IndentedTree from '@/components/indented-tree/indented-tree';
|
||||||
import { useSelectTestingResult } from '@/hooks/knowledge-hooks';
|
import { useSelectTestingResult } from '@/hooks/knowledge-hooks';
|
||||||
import { IReference } from '@/interfaces/database/chat';
|
import { IReference } from '@/interfaces/database/chat';
|
||||||
import { Card, Flex, Input, Layout, List, Skeleton, Space, Tag } from 'antd';
|
import {
|
||||||
|
Card,
|
||||||
|
Divider,
|
||||||
|
Flex,
|
||||||
|
Input,
|
||||||
|
Layout,
|
||||||
|
List,
|
||||||
|
Skeleton,
|
||||||
|
Space,
|
||||||
|
Tag,
|
||||||
|
} from 'antd';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import MarkdownContent from '../chat/markdown-content';
|
import MarkdownContent from '../chat/markdown-content';
|
||||||
import { useSendQuestion } from './hooks';
|
import { useSendQuestion } from './hooks';
|
||||||
import SearchSidebar from './sidebar';
|
import SearchSidebar from './sidebar';
|
||||||
|
|
||||||
import IndentedTree from '@/components/indented-tree/indented-tree';
|
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
const { Content } = Layout;
|
const { Content } = Layout;
|
||||||
@ -27,8 +37,25 @@ const SearchPage = () => {
|
|||||||
mindMap,
|
mindMap,
|
||||||
mindMapLoading,
|
mindMapLoading,
|
||||||
searchStr,
|
searchStr,
|
||||||
|
loading,
|
||||||
|
isFirstRender,
|
||||||
} = useSendQuestion(checkedList);
|
} = useSendQuestion(checkedList);
|
||||||
|
|
||||||
|
const InputSearch = (
|
||||||
|
<Search
|
||||||
|
value={searchStr}
|
||||||
|
onChange={handleSearchStrChange}
|
||||||
|
placeholder="input search text"
|
||||||
|
allowClear
|
||||||
|
enterButton
|
||||||
|
onSearch={sendQuestion}
|
||||||
|
size="large"
|
||||||
|
loading={sendingLoading}
|
||||||
|
disabled={checkedList.length === 0}
|
||||||
|
className={isFirstRender ? styles.globalInput : styles.partialInput}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout className={styles.searchPage}>
|
<Layout className={styles.searchPage}>
|
||||||
<SearchSidebar
|
<SearchSidebar
|
||||||
@ -37,70 +64,78 @@ const SearchPage = () => {
|
|||||||
></SearchSidebar>
|
></SearchSidebar>
|
||||||
<Layout>
|
<Layout>
|
||||||
<Content>
|
<Content>
|
||||||
<Flex className={styles.content}>
|
{isFirstRender ? (
|
||||||
<section className={styles.main}>
|
<Flex
|
||||||
<Search
|
justify="center"
|
||||||
value={searchStr}
|
align="center"
|
||||||
onChange={handleSearchStrChange}
|
className={styles.firstRenderContent}
|
||||||
placeholder="input search text"
|
>
|
||||||
onSearch={sendQuestion}
|
{InputSearch}
|
||||||
size="large"
|
</Flex>
|
||||||
loading={sendingLoading}
|
) : (
|
||||||
disabled={checkedList.length === 0}
|
<Flex className={styles.content}>
|
||||||
/>
|
<section className={styles.main}>
|
||||||
{answer.answer && (
|
{InputSearch}
|
||||||
<div className={styles.answerWrapper}>
|
{answer.answer && (
|
||||||
<MarkdownContent
|
<div className={styles.answerWrapper}>
|
||||||
loading={sendingLoading}
|
<MarkdownContent
|
||||||
content={answer.answer}
|
loading={sendingLoading}
|
||||||
reference={answer.reference ?? ({} as IReference)}
|
content={answer.answer}
|
||||||
clickDocumentButton={() => {}}
|
reference={answer.reference ?? ({} as IReference)}
|
||||||
></MarkdownContent>
|
clickDocumentButton={() => {}}
|
||||||
</div>
|
></MarkdownContent>
|
||||||
)}
|
</div>
|
||||||
<List
|
|
||||||
dataSource={list.chunks}
|
|
||||||
renderItem={(item) => (
|
|
||||||
<List.Item>
|
|
||||||
<Card className={styles.card}>
|
|
||||||
<Space>
|
|
||||||
<ImageWithPopover id={item.img_id}></ImageWithPopover>
|
|
||||||
<HightLightMarkdown>
|
|
||||||
{item.highlight}
|
|
||||||
</HightLightMarkdown>
|
|
||||||
</Space>
|
|
||||||
</Card>
|
|
||||||
</List.Item>
|
|
||||||
)}
|
)}
|
||||||
/>
|
<Divider></Divider>
|
||||||
{relatedQuestions?.length > 0 && (
|
{list.chunks.length > 0 && (
|
||||||
<Card>
|
<List
|
||||||
<Flex wrap="wrap" gap={'10px 0'}>
|
dataSource={list.chunks}
|
||||||
{relatedQuestions?.map((x, idx) => (
|
loading={loading}
|
||||||
<Tag
|
renderItem={(item) => (
|
||||||
key={idx}
|
<List.Item>
|
||||||
className={styles.tag}
|
<Card className={styles.card}>
|
||||||
onClick={handleClickRelatedQuestion(x)}
|
<Space>
|
||||||
>
|
<ImageWithPopover
|
||||||
{x}
|
id={item.img_id}
|
||||||
</Tag>
|
></ImageWithPopover>
|
||||||
))}
|
<HightLightMarkdown>
|
||||||
</Flex>
|
{item.highlight}
|
||||||
</Card>
|
</HightLightMarkdown>
|
||||||
)}
|
</Space>
|
||||||
</section>
|
</Card>
|
||||||
<section className={styles.graph}>
|
</List.Item>
|
||||||
{mindMapLoading ? (
|
)}
|
||||||
<Skeleton active />
|
/>
|
||||||
) : (
|
)}
|
||||||
<IndentedTree
|
{relatedQuestions?.length > 0 && (
|
||||||
data={mindMap}
|
<Card>
|
||||||
show
|
<Flex wrap="wrap" gap={'10px 0'}>
|
||||||
style={{ width: '100%', height: '100%' }}
|
{relatedQuestions?.map((x, idx) => (
|
||||||
></IndentedTree>
|
<Tag
|
||||||
)}
|
key={idx}
|
||||||
</section>
|
className={styles.tag}
|
||||||
</Flex>
|
onClick={handleClickRelatedQuestion(x)}
|
||||||
|
>
|
||||||
|
{x}
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
<section className={styles.graph}>
|
||||||
|
{mindMapLoading ? (
|
||||||
|
<Skeleton active />
|
||||||
|
) : (
|
||||||
|
<IndentedTree
|
||||||
|
data={mindMap}
|
||||||
|
show
|
||||||
|
style={{ width: '100%', height: '100%' }}
|
||||||
|
></IndentedTree>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
</Content>
|
</Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
@ -22,7 +22,7 @@ interface IProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const SearchSidebar = ({ checkedList, setCheckedList }: IProps) => {
|
const SearchSidebar = ({ checkedList, setCheckedList }: IProps) => {
|
||||||
const { list } = useNextFetchKnowledgeList();
|
const { list, loading } = useNextFetchKnowledgeList();
|
||||||
const ids = useMemo(() => list.map((x) => x.id), [list]);
|
const ids = useMemo(() => list.map((x) => x.id), [list]);
|
||||||
|
|
||||||
const checkAll = list.length === checkedList.length;
|
const checkAll = list.length === checkedList.length;
|
||||||
@ -67,6 +67,7 @@ const SearchSidebar = ({ checkedList, setCheckedList }: IProps) => {
|
|||||||
bordered
|
bordered
|
||||||
dataSource={list}
|
dataSource={list}
|
||||||
className={styles.list}
|
className={styles.list}
|
||||||
|
loading={loading}
|
||||||
renderItem={(item) => (
|
renderItem={(item) => (
|
||||||
<List.Item>
|
<List.Item>
|
||||||
<Checkbox value={item.id} className={styles.checkbox}>
|
<Checkbox value={item.id} className={styles.checkbox}>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user