balibabu
feat: The same query conditions on the search page should not request the interface every time the mind map drawer is opened. #2759 (#2760)
ab13701
import { useFetchMindMap, useFetchRelatedQuestions } from '@/hooks/chat-hooks'; | |
import { useSetModalState } from '@/hooks/common-hooks'; | |
import { useTestChunkRetrieval } from '@/hooks/knowledge-hooks'; | |
import { | |
useGetPaginationWithRouter, | |
useSendMessageWithSse, | |
} from '@/hooks/logic-hooks'; | |
import { IAnswer } from '@/interfaces/database/chat'; | |
import api from '@/utils/api'; | |
import { get, isEmpty, isEqual, trim } from 'lodash'; | |
import { | |
ChangeEventHandler, | |
useCallback, | |
useEffect, | |
useRef, | |
useState, | |
} from 'react'; | |
export const useSendQuestion = (kbIds: string[]) => { | |
const { send, answer, done } = useSendMessageWithSse(api.ask); | |
const { testChunk, loading } = useTestChunkRetrieval(); | |
const [sendingLoading, setSendingLoading] = useState(false); | |
const [currentAnswer, setCurrentAnswer] = useState({} as IAnswer); | |
const { fetchRelatedQuestions, data: relatedQuestions } = | |
useFetchRelatedQuestions(); | |
const [searchStr, setSearchStr] = useState<string>(''); | |
const [isFirstRender, setIsFirstRender] = useState(true); | |
const [selectedDocumentIds, setSelectedDocumentIds] = useState<string[]>([]); | |
const { pagination, setPagination } = useGetPaginationWithRouter(); | |
const sendQuestion = useCallback( | |
(question: string) => { | |
const q = trim(question); | |
if (isEmpty(q)) return; | |
setPagination({ page: 1 }); | |
setIsFirstRender(false); | |
setCurrentAnswer({} as IAnswer); | |
setSendingLoading(true); | |
send({ kb_ids: kbIds, question: q }); | |
testChunk({ | |
kb_id: kbIds, | |
highlight: true, | |
question: q, | |
page: 1, | |
size: pagination.pageSize, | |
}); | |
fetchRelatedQuestions(q); | |
}, | |
[ | |
send, | |
testChunk, | |
kbIds, | |
fetchRelatedQuestions, | |
setPagination, | |
pagination.pageSize, | |
], | |
); | |
const handleSearchStrChange: ChangeEventHandler<HTMLInputElement> = | |
useCallback((e) => { | |
setSearchStr(e.target.value); | |
}, []); | |
const handleClickRelatedQuestion = useCallback( | |
(question: string) => () => { | |
if (sendingLoading) return; | |
setSearchStr(question); | |
sendQuestion(question); | |
}, | |
[sendQuestion, sendingLoading], | |
); | |
const handleTestChunk = useCallback( | |
(documentIds: string[], page: number = 1, size: number = 10) => { | |
const q = trim(searchStr); | |
if (sendingLoading || isEmpty(q)) return; | |
testChunk({ | |
kb_id: kbIds, | |
highlight: true, | |
question: q, | |
doc_ids: documentIds ?? selectedDocumentIds, | |
page, | |
size, | |
}); | |
}, | |
[sendingLoading, searchStr, kbIds, testChunk, selectedDocumentIds], | |
); | |
useEffect(() => { | |
if (!isEmpty(answer)) { | |
setCurrentAnswer(answer); | |
} | |
}, [answer]); | |
useEffect(() => { | |
if (done) { | |
setSendingLoading(false); | |
} | |
}, [done]); | |
return { | |
sendQuestion, | |
handleSearchStrChange, | |
handleClickRelatedQuestion, | |
handleTestChunk, | |
setSelectedDocumentIds, | |
loading, | |
sendingLoading, | |
answer: currentAnswer, | |
relatedQuestions: relatedQuestions?.slice(0, 5) ?? [], | |
searchStr, | |
isFirstRender, | |
selectedDocumentIds, | |
isSearchStrEmpty: isEmpty(trim(searchStr)), | |
}; | |
}; | |
export const useFetchBackgroundImage = () => { | |
const [imgUrl, setImgUrl] = useState<string>(''); | |
const fetchImage = useCallback(async () => { | |
try { | |
const res = await fetch( | |
'/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=zh-CN', | |
); | |
const ret = await res.json(); | |
const url = get(ret, 'images.0.url'); | |
if (url) { | |
setImgUrl(url); | |
} | |
} catch (error) { | |
console.log('🚀 ~ fetchImage ~ error:', error); | |
} | |
}, []); | |
useEffect(() => { | |
fetchImage(); | |
}, [fetchImage]); | |
return `https://cn.bing.com${imgUrl}`; | |
}; | |
export const useTestRetrieval = ( | |
kbIds: string[], | |
searchStr: string, | |
sendingLoading: boolean, | |
) => { | |
const { testChunk, loading } = useTestChunkRetrieval(); | |
const { pagination } = useGetPaginationWithRouter(); | |
const [selectedDocumentIds, setSelectedDocumentIds] = useState<string[]>([]); | |
const handleTestChunk = useCallback(() => { | |
const q = trim(searchStr); | |
if (sendingLoading || isEmpty(q)) return; | |
testChunk({ | |
kb_id: kbIds, | |
highlight: true, | |
question: q, | |
doc_ids: Array.isArray(selectedDocumentIds) ? selectedDocumentIds : [], | |
page: pagination.current, | |
size: pagination.pageSize, | |
}); | |
}, [ | |
sendingLoading, | |
searchStr, | |
kbIds, | |
testChunk, | |
selectedDocumentIds, | |
pagination, | |
]); | |
useEffect(() => { | |
handleTestChunk(); | |
}, [handleTestChunk]); | |
return { | |
loading, | |
selectedDocumentIds, | |
setSelectedDocumentIds, | |
}; | |
}; | |
export const useShowMindMapDrawer = (kbIds: string[], question: string) => { | |
const { visible, showModal, hideModal } = useSetModalState(); | |
const ref = useRef<any>(); | |
const { | |
fetchMindMap, | |
data: mindMap, | |
loading: mindMapLoading, | |
} = useFetchMindMap(); | |
const handleShowModal = useCallback(() => { | |
const searchParams = { question: trim(question), kb_ids: kbIds }; | |
if ( | |
!isEmpty(searchParams.question) && | |
!isEqual(searchParams, ref.current) | |
) { | |
ref.current = searchParams; | |
fetchMindMap(searchParams); | |
} | |
showModal(); | |
}, [fetchMindMap, showModal, question, kbIds]); | |
return { | |
mindMap, | |
mindMapVisible: visible, | |
mindMapLoading, | |
showMindMapModal: handleShowModal, | |
hideMindMapModal: hideModal, | |
}; | |
}; | |
export const usePendingMindMap = () => { | |
const [count, setCount] = useState<number>(0); | |
const ref = useRef<NodeJS.Timeout>(); | |
const setCountInterval = useCallback(() => { | |
ref.current = setInterval(() => { | |
setCount((pre) => { | |
if (pre > 40) { | |
clearInterval(ref?.current); | |
} | |
return pre + 1; | |
}); | |
}, 1000); | |
}, []); | |
useEffect(() => { | |
setCountInterval(); | |
return () => { | |
clearInterval(ref?.current); | |
}; | |
}, [setCountInterval]); | |
return Number(((count / 43) * 100).toFixed(0)); | |
}; | |