diff --git a/web/src/hooks/logic-hooks.ts b/web/src/hooks/logic-hooks.ts index a3c71fda8..e51cb9ad4 100644 --- a/web/src/hooks/logic-hooks.ts +++ b/web/src/hooks/logic-hooks.ts @@ -217,6 +217,10 @@ export const useSendMessageWithSse = ( const [answer, setAnswer] = useState({} as IAnswer); const [done, setDone] = useState(true); + const resetAnswer = useCallback(() => { + setAnswer({} as IAnswer); + }, []); + const send = useCallback( async ( body: any, @@ -251,7 +255,7 @@ export const useSendMessageWithSse = ( const val = JSON.parse(value?.data || ''); const d = val?.data; if (typeof d !== 'boolean') { - // console.info('data:', d); + console.info('data:', d); setAnswer({ ...d, conversationId: body?.conversation_id, @@ -264,18 +268,16 @@ export const useSendMessageWithSse = ( } console.info('done?'); setDone(true); - setAnswer({} as IAnswer); return { data: await res, response }; } catch (e) { setDone(true); - setAnswer({} as IAnswer); console.warn(e); } }, [url], ); - return { send, answer, done, setDone }; + return { send, answer, done, setDone, resetAnswer }; }; export const useSpeechWithSse = (url: string = api.tts) => { diff --git a/web/src/layouts/components/header/index.tsx b/web/src/layouts/components/header/index.tsx index 694840547..42370e88f 100644 --- a/web/src/layouts/components/header/index.tsx +++ b/web/src/layouts/components/header/index.tsx @@ -2,14 +2,14 @@ import { ReactComponent as FileIcon } from '@/assets/svg/file-management.svg'; import { ReactComponent as GraphIcon } from '@/assets/svg/graph.svg'; import { ReactComponent as KnowledgeBaseIcon } from '@/assets/svg/knowledge-base.svg'; import { useTranslate } from '@/hooks/common-hooks'; +import { useFetchAppConf } from '@/hooks/logic-hooks'; import { useNavigateWithFromState } from '@/hooks/route-hook'; +import { MessageOutlined, SearchOutlined } from '@ant-design/icons'; import { Flex, Layout, Radio, Space, theme } from 'antd'; import { useCallback, useMemo } from 'react'; import { useLocation } from 'umi'; import Toolbar from '../right-toolbar'; -import { useFetchAppConf } from '@/hooks/logic-hooks'; -import { MessageOutlined } from '@ant-design/icons'; import styles from './index.less'; const { Header } = Layout; @@ -27,7 +27,7 @@ const RagHeader = () => { () => [ { path: '/knowledge', name: t('knowledgeBase'), icon: KnowledgeBaseIcon }, { path: '/chat', name: t('chat'), icon: MessageOutlined }, - // { path: '/search', name: t('search'), icon: SearchOutlined }, + { path: '/search', name: t('search'), icon: SearchOutlined }, { path: '/flow', name: t('flow'), icon: GraphIcon }, { path: '/file', name: t('fileManager'), icon: FileIcon }, ], diff --git a/web/src/pages/chat/hooks.ts b/web/src/pages/chat/hooks.ts index 0f03257cc..92c6179ae 100644 --- a/web/src/pages/chat/hooks.ts +++ b/web/src/pages/chat/hooks.ts @@ -19,21 +19,12 @@ import { } from '@/hooks/common-hooks'; import { useRegenerateMessage, - useRemoveMessageById, - useRemoveMessagesAfterCurrentMessage, - useScrollToBottom, useSelectDerivedMessages, useSendMessageWithSse, } from '@/hooks/logic-hooks'; -import { - IAnswer, - IConversation, - IDialog, - Message, -} from '@/interfaces/database/chat'; +import { IConversation, IDialog, Message } from '@/interfaces/database/chat'; import { IChunk } from '@/interfaces/database/knowledge'; import { getFileExtension } from '@/utils'; -import { buildMessageUuid } from '@/utils/chat'; import { useMutationState } from '@tanstack/react-query'; import { get } from 'lodash'; import trim from 'lodash/trim'; @@ -251,118 +242,6 @@ export const useSetConversation = () => { return { setConversation }; }; -export const useSelectCurrentConversation = () => { - const [currentConversation, setCurrentConversation] = - useState({} as IClientConversation); - const { data: conversation, loading } = useFetchNextConversation(); - const { data: dialog } = useFetchNextDialog(); - const { conversationId, dialogId } = useGetChatSearchParams(); - const { removeMessageById } = useRemoveMessageById(setCurrentConversation); - const { removeMessagesAfterCurrentMessage } = - useRemoveMessagesAfterCurrentMessage(setCurrentConversation); - - // Show the entered message in the conversation immediately after sending the message - const addNewestConversation = useCallback( - (message: Message, answer: string = '') => { - setCurrentConversation((pre) => { - return { - ...pre, - message: [ - ...pre.message, - { - ...message, - id: buildMessageUuid(message), - } as IMessage, - { - role: MessageType.Assistant, - content: answer, - id: buildMessageUuid({ ...message, role: MessageType.Assistant }), - reference: {}, - } as IMessage, - ], - }; - }); - }, - [], - ); - - // Add the streaming message to the last item in the message list - const addNewestAnswer = useCallback((answer: IAnswer) => { - setCurrentConversation((pre) => { - const latestMessage = pre.message?.at(-1); - - if (latestMessage) { - return { - ...pre, - message: [ - ...pre.message.slice(0, -1), - { - ...latestMessage, - content: answer.answer, - reference: answer.reference, - id: buildMessageUuid({ - id: answer.id, - role: MessageType.Assistant, - }), - prompt: answer.prompt, - } as IMessage, - ], - }; - } - return pre; - }); - }, []); - - const removeLatestMessage = useCallback(() => { - setCurrentConversation((pre) => { - const nextMessages = pre.message?.slice(0, -2) ?? []; - return { - ...pre, - message: nextMessages, - }; - }); - }, []); - - const addPrologue = useCallback(() => { - if (dialogId !== '' && conversationId === '') { - const prologue = dialog.prompt_config?.prologue; - - const nextMessage = { - role: MessageType.Assistant, - content: prologue, - id: uuid(), - } as IMessage; - - setCurrentConversation({ - id: '', - dialog_id: dialogId, - reference: [], - message: [nextMessage], - } as any); - } - }, [conversationId, dialog, dialogId]); - - useEffect(() => { - addPrologue(); - }, [addPrologue]); - - useEffect(() => { - if (conversationId) { - setCurrentConversation(conversation); - } - }, [conversation, conversationId]); - - return { - currentConversation, - addNewestConversation, - removeLatestMessage, - addNewestAnswer, - removeMessageById, - removeMessagesAfterCurrentMessage, - loading, - }; -}; - // export const useScrollToBottom = (currentConversation: IClientConversation) => { // const ref = useRef(null); @@ -430,32 +309,6 @@ export const useSelectNextMessages = () => { }; }; -export const useFetchConversationOnMount = () => { - const { conversationId } = useGetChatSearchParams(); - const { - currentConversation, - addNewestConversation, - removeLatestMessage, - addNewestAnswer, - loading, - removeMessageById, - removeMessagesAfterCurrentMessage, - } = useSelectCurrentConversation(); - const ref = useScrollToBottom(currentConversation); - - return { - currentConversation, - addNewestConversation, - ref, - removeLatestMessage, - addNewestAnswer, - conversationId, - loading, - removeMessageById, - removeMessagesAfterCurrentMessage, - }; -}; - export const useHandleMessageInputChange = () => { const [value, setValue] = useState(''); @@ -477,7 +330,7 @@ export const useSendNextMessage = () => { const { conversationId } = useGetChatSearchParams(); const { handleInputChange, value, setValue } = useHandleMessageInputChange(); const { handleClickConversation } = useClickConversationCard(); - const { send, answer, done, setDone } = useSendMessageWithSse(); + const { send, answer, done, setDone, resetAnswer } = useSendMessageWithSse(); const { ref, derivedMessages, @@ -557,10 +410,11 @@ export const useSendNextMessage = () => { useEffect(() => { // #1289 + console.log('🚀 ~ useEffect ~ answer:', answer, done); if ( answer.answer && - !done && - (answer?.conversationId === conversationId || conversationId === '') + (answer?.conversationId === conversationId || + (!done && conversationId === '')) ) { addNewestAnswer(answer); } @@ -570,8 +424,10 @@ export const useSendNextMessage = () => { // #1289 switch to another conversion window when the last conversion answer doesn't finish. if (conversationId) { setDone(true); + } else { + resetAnswer(); } - }, [setDone, conversationId]); + }, [setDone, conversationId, resetAnswer]); const handlePressEnter = useCallback( (documentIds: string[]) => { diff --git a/web/src/pages/search/hooks.ts b/web/src/pages/search/hooks.ts index 702535536..26ebdb456 100644 --- a/web/src/pages/search/hooks.ts +++ b/web/src/pages/search/hooks.ts @@ -4,7 +4,7 @@ import { useSendMessageWithSse } from '@/hooks/logic-hooks'; import { IAnswer } from '@/interfaces/database/chat'; import api from '@/utils/api'; import { isEmpty } from 'lodash'; -import { useCallback, useEffect, useState } from 'react'; +import { ChangeEventHandler, useCallback, useEffect, useState } from 'react'; export const useSendQuestion = (kbIds: string[]) => { const { send, answer, done } = useSendMessageWithSse(api.ask); @@ -18,6 +18,7 @@ export const useSendQuestion = (kbIds: string[]) => { data: mindMap, loading: mindMapLoading, } = useFetchMindMap(); + const [searchStr, setSearchStr] = useState(''); const sendQuestion = useCallback( (question: string) => { @@ -34,10 +35,26 @@ export const useSendQuestion = (kbIds: string[]) => { [send, testChunk, kbIds, fetchRelatedQuestions, fetchMindMap], ); + const handleSearchStrChange: ChangeEventHandler = + useCallback((e) => { + setSearchStr(e.target.value); + }, []); + + const handleClickRelatedQuestion = useCallback( + (question: string) => () => { + setSearchStr(question); + sendQuestion(question); + }, + [sendQuestion], + ); + useEffect(() => { if (!isEmpty(answer)) { setCurrentAnswer(answer); } + return () => { + setCurrentAnswer({} as IAnswer); + }; }, [answer]); useEffect(() => { @@ -54,5 +71,8 @@ export const useSendQuestion = (kbIds: string[]) => { relatedQuestions: relatedQuestions?.slice(0, 5) ?? [], mindMap, mindMapLoading, + handleClickRelatedQuestion, + searchStr, + handleSearchStrChange, }; }; diff --git a/web/src/pages/search/index.less b/web/src/pages/search/index.less index dc1610c28..336901fa7 100644 --- a/web/src/pages/search/index.less +++ b/web/src/pages/search/index.less @@ -1,10 +1,17 @@ .searchPage { .card { width: 100%; + :global(.ant-card-body) { + padding: 14px; + } + p { + margin: 0; + } } .tag { padding: 4px 8px; font-size: 14px; + cursor: pointer; } } @@ -56,3 +63,12 @@ padding-right: 10px; } } +.answerWrapper { + background-color: #e6f4ff; + padding: 14px; + margin-top: 16px; + border-radius: 8px; + & > p { + margin: 0; + } +} diff --git a/web/src/pages/search/index.tsx b/web/src/pages/search/index.tsx index 48b3dd980..5cd3c2ff6 100644 --- a/web/src/pages/search/index.tsx +++ b/web/src/pages/search/index.tsx @@ -19,11 +19,14 @@ const SearchPage = () => { const list = useSelectTestingResult(); const { sendQuestion, + handleClickRelatedQuestion, + handleSearchStrChange, answer, sendingLoading, relatedQuestions, mindMap, mindMapLoading, + searchStr, } = useSendQuestion(checkedList); return ( @@ -37,18 +40,24 @@ const SearchPage = () => {
- {}} - > + {answer.answer && ( +
+ {}} + > +
+ )} ( @@ -68,7 +77,11 @@ const SearchPage = () => { {relatedQuestions?.map((x, idx) => ( - + {x} ))}