Spaces:
Paused
Paused
import { Authorization } from '@/constants/authorization'; | |
import { LanguageTranslationMap } from '@/constants/common'; | |
import { Pagination } from '@/interfaces/common'; | |
import { ResponseType } from '@/interfaces/database/base'; | |
import { IAnswer } from '@/interfaces/database/chat'; | |
import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | |
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | |
import api from '@/utils/api'; | |
import { getAuthorization } from '@/utils/authorization-util'; | |
import { PaginationProps } from 'antd'; | |
import axios from 'axios'; | |
import { EventSourceParserStream } from 'eventsource-parser/stream'; | |
import { | |
ChangeEventHandler, | |
useCallback, | |
useEffect, | |
useMemo, | |
useRef, | |
useState, | |
} from 'react'; | |
import { useTranslation } from 'react-i18next'; | |
import { useDispatch } from 'umi'; | |
import { useSetModalState, useTranslate } from './common-hooks'; | |
import { useSetDocumentParser } from './document-hooks'; | |
import { useSetPaginationParams } from './route-hook'; | |
import { useOneNamespaceEffectsLoading } from './store-hooks'; | |
import { useFetchTenantInfo, useSaveSetting } from './user-setting-hooks'; | |
export const useChangeDocumentParser = (documentId: string) => { | |
const setDocumentParser = useSetDocumentParser(); | |
const { | |
visible: changeParserVisible, | |
hideModal: hideChangeParserModal, | |
showModal: showChangeParserModal, | |
} = useSetModalState(); | |
const loading = useOneNamespaceEffectsLoading('kFModel', [ | |
'document_change_parser', | |
]); | |
const onChangeParserOk = useCallback( | |
async (parserId: string, parserConfig: IChangeParserConfigRequestBody) => { | |
const ret = await setDocumentParser(parserId, documentId, parserConfig); | |
if (ret === 0) { | |
hideChangeParserModal(); | |
} | |
}, | |
[hideChangeParserModal, setDocumentParser, documentId], | |
); | |
return { | |
changeParserLoading: loading, | |
onChangeParserOk, | |
changeParserVisible, | |
hideChangeParserModal, | |
showChangeParserModal, | |
}; | |
}; | |
export const useSetSelectedRecord = <T = IKnowledgeFile>() => { | |
const [currentRecord, setCurrentRecord] = useState<T>({} as T); | |
const setRecord = (record: T) => { | |
setCurrentRecord(record); | |
}; | |
return { currentRecord, setRecord }; | |
}; | |
export const useHandleSearchChange = () => { | |
const [searchString, setSearchString] = useState(''); | |
const handleInputChange = useCallback( | |
(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => { | |
const value = e.target.value; | |
setSearchString(value); | |
}, | |
[], | |
); | |
return { handleInputChange, searchString }; | |
}; | |
export const useChangeLanguage = () => { | |
const { i18n } = useTranslation(); | |
const { saveSetting } = useSaveSetting(); | |
const changeLanguage = (lng: string) => { | |
i18n.changeLanguage( | |
LanguageTranslationMap[lng as keyof typeof LanguageTranslationMap], | |
); | |
saveSetting({ language: lng }); | |
}; | |
return changeLanguage; | |
}; | |
export const useGetPaginationWithRouter = () => { | |
const { t } = useTranslate('common'); | |
const { | |
setPaginationParams, | |
page, | |
size: pageSize, | |
} = useSetPaginationParams(); | |
const onPageChange: PaginationProps['onChange'] = useCallback( | |
(pageNumber: number, pageSize: number) => { | |
setPaginationParams(pageNumber, pageSize); | |
}, | |
[setPaginationParams], | |
); | |
const setCurrentPagination = useCallback( | |
(pagination: { page: number; pageSize?: number }) => { | |
setPaginationParams(pagination.page, pagination.pageSize); | |
}, | |
[setPaginationParams], | |
); | |
const pagination: PaginationProps = useMemo(() => { | |
return { | |
showQuickJumper: true, | |
total: 0, | |
showSizeChanger: true, | |
current: page, | |
pageSize: pageSize, | |
pageSizeOptions: [1, 2, 10, 20, 50, 100], | |
onChange: onPageChange, | |
showTotal: (total) => `${t('total')} ${total}`, | |
}; | |
}, [t, onPageChange, page, pageSize]); | |
return { | |
pagination, | |
setPagination: setCurrentPagination, | |
}; | |
}; | |
export const useGetPagination = () => { | |
const [pagination, setPagination] = useState({ page: 1, pageSize: 10 }); | |
const { t } = useTranslate('common'); | |
const onPageChange: PaginationProps['onChange'] = useCallback( | |
(pageNumber: number, pageSize: number) => { | |
setPagination({ page: pageNumber, pageSize }); | |
}, | |
[], | |
); | |
const currentPagination: PaginationProps = useMemo(() => { | |
return { | |
showQuickJumper: true, | |
total: 0, | |
showSizeChanger: true, | |
current: pagination.page, | |
pageSize: pagination.pageSize, | |
pageSizeOptions: [1, 2, 10, 20, 50, 100], | |
onChange: onPageChange, | |
showTotal: (total) => `${t('total')} ${total}`, | |
}; | |
}, [t, onPageChange, pagination]); | |
return { | |
pagination: currentPagination, | |
}; | |
}; | |
export const useSetPagination = (namespace: string) => { | |
const dispatch = useDispatch(); | |
const setPagination = useCallback( | |
(pageNumber = 1, pageSize?: number) => { | |
const pagination: Pagination = { | |
current: pageNumber, | |
} as Pagination; | |
if (pageSize) { | |
pagination.pageSize = pageSize; | |
} | |
dispatch({ | |
type: `${namespace}/setPagination`, | |
payload: pagination, | |
}); | |
}, | |
[dispatch, namespace], | |
); | |
return setPagination; | |
}; | |
export interface AppConf { | |
appName: string; | |
} | |
export const useFetchAppConf = () => { | |
const [appConf, setAppConf] = useState<AppConf>({} as AppConf); | |
const fetchAppConf = useCallback(async () => { | |
const ret = await axios.get('/conf.json'); | |
setAppConf(ret.data); | |
}, []); | |
useEffect(() => { | |
fetchAppConf(); | |
}, [fetchAppConf]); | |
return appConf; | |
}; | |
export const useSendMessageWithSse = ( | |
url: string = api.completeConversation, | |
) => { | |
const [answer, setAnswer] = useState<IAnswer>({} as IAnswer); | |
const [done, setDone] = useState(true); | |
const send = useCallback( | |
async ( | |
body: any, | |
): Promise<{ response: Response; data: ResponseType } | undefined> => { | |
try { | |
setDone(false); | |
const response = await fetch(url, { | |
method: 'POST', | |
headers: { | |
[Authorization]: getAuthorization(), | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify(body), | |
}); | |
const res = response.clone().json(); | |
const reader = response?.body | |
?.pipeThrough(new TextDecoderStream()) | |
.pipeThrough(new EventSourceParserStream()) | |
.getReader(); | |
while (true) { | |
const x = await reader?.read(); | |
if (x) { | |
const { done, value } = x; | |
try { | |
const val = JSON.parse(value?.data || ''); | |
const d = val?.data; | |
if (typeof d !== 'boolean') { | |
console.info('data:', d); | |
setAnswer({ | |
...d, | |
conversationId: body?.conversation_id, | |
}); | |
} | |
} catch (e) { | |
console.warn(e); | |
} | |
if (done) { | |
console.info('done'); | |
break; | |
} | |
} | |
} | |
console.info('done?'); | |
setDone(true); | |
return { data: await res, response }; | |
} catch (e) { | |
setDone(true); | |
console.warn(e); | |
} | |
}, | |
[url], | |
); | |
return { send, answer, done, setDone }; | |
}; | |
//#region chat hooks | |
export const useScrollToBottom = (messages?: unknown) => { | |
const ref = useRef<HTMLDivElement>(null); | |
const scrollToBottom = useCallback(() => { | |
if (messages) { | |
ref.current?.scrollIntoView({ behavior: 'instant' }); | |
} | |
}, [messages]); // If the message changes, scroll to the bottom | |
useEffect(() => { | |
scrollToBottom(); | |
}, [scrollToBottom]); | |
return ref; | |
}; | |
export const useHandleMessageInputChange = () => { | |
const [value, setValue] = useState(''); | |
const handleInputChange: ChangeEventHandler<HTMLInputElement> = (e) => { | |
const value = e.target.value; | |
const nextValue = value.replaceAll('\\n', '\n').replaceAll('\\t', '\t'); | |
setValue(nextValue); | |
}; | |
return { | |
handleInputChange, | |
value, | |
setValue, | |
}; | |
}; | |
// #endregion | |
/** | |
* | |
* @param defaultId | |
* used to switch between different items, similar to radio | |
* @returns | |
*/ | |
export const useSelectItem = (defaultId?: string) => { | |
const [selectedId, setSelectedId] = useState(''); | |
const handleItemClick = useCallback( | |
(id: string) => () => { | |
setSelectedId(id); | |
}, | |
[], | |
); | |
useEffect(() => { | |
if (defaultId) { | |
setSelectedId(defaultId); | |
} | |
}, [defaultId]); | |
return { selectedId, handleItemClick }; | |
}; | |
export const useFetchModelId = () => { | |
const { data: tenantInfo } = useFetchTenantInfo(); | |
return tenantInfo?.llm_id ?? ''; | |
}; | |