diff --git a/web/src/components/file-icon/index.less b/web/src/components/file-icon/index.less index a549a0615..47718cd03 100644 --- a/web/src/components/file-icon/index.less +++ b/web/src/components/file-icon/index.less @@ -1,3 +1,4 @@ .thumbnailImg { + display: inline-block; max-width: 20px; } diff --git a/web/src/constants/chat.ts b/web/src/constants/chat.ts index f0181e29c..882c8e915 100644 --- a/web/src/constants/chat.ts +++ b/web/src/constants/chat.ts @@ -15,3 +15,10 @@ export enum SharedFrom { Agent = 'agent', Chat = 'chat', } + +export enum ChatSearchParams { + DialogId = 'dialogId', + ConversationId = 'conversationId', +} + +export const EmptyConversationId = 'empty'; diff --git a/web/src/hooks/chat-hooks.ts b/web/src/hooks/chat-hooks.ts index ed933678e..477c8125c 100644 --- a/web/src/hooks/chat-hooks.ts +++ b/web/src/hooks/chat-hooks.ts @@ -1,131 +1,255 @@ +import { ChatSearchParams } from '@/constants/chat'; import { IConversation, IDialog, IStats, IToken, + Message, } from '@/interfaces/database/chat'; +import i18n from '@/locales/config'; +import { IClientConversation, IMessage } from '@/pages/chat/interface'; import chatService from '@/services/chat-service'; +import { isConversationIdExist } from '@/utils/chat'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { message } from 'antd'; import dayjs, { Dayjs } from 'dayjs'; -import { useCallback, useState } from 'react'; -import { useDispatch, useSelector } from 'umi'; +import { useCallback, useMemo, useState } from 'react'; +import { useSearchParams } from 'umi'; +import { v4 as uuid } from 'uuid'; -export const useFetchDialogList = () => { - const dispatch = useDispatch(); +//#region logic - const fetchDialogList = useCallback(() => { - return dispatch({ type: 'chatModel/listDialog' }); - }, [dispatch]); +export const useClickDialogCard = () => { + const [, setSearchParams] = useSearchParams(); - return fetchDialogList; -}; + const newQueryParameters: URLSearchParams = useMemo(() => { + return new URLSearchParams(); + }, []); -export const useSelectDialogList = () => { - const dialogList: IDialog[] = useSelector( - (state: any) => state.chatModel.dialogList, + const handleClickDialog = useCallback( + (dialogId: string) => { + newQueryParameters.set(ChatSearchParams.DialogId, dialogId); + // newQueryParameters.set( + // ChatSearchParams.ConversationId, + // EmptyConversationId, + // ); + setSearchParams(newQueryParameters); + }, + [newQueryParameters, setSearchParams], ); - return dialogList; + return { handleClickDialog }; }; -export const useFetchConversationList = () => { - const dispatch = useDispatch(); +export const useGetChatSearchParams = () => { + const [currentQueryParameters] = useSearchParams(); - const fetchConversationList = useCallback( - async (dialogId: string) => { - if (dialogId) { - dispatch({ - type: 'chatModel/listConversation', - payload: { dialog_id: dialogId }, - }); + return { + dialogId: currentQueryParameters.get(ChatSearchParams.DialogId) || '', + conversationId: + currentQueryParameters.get(ChatSearchParams.ConversationId) || '', + }; +}; + +//#endregion + +//#region dialog + +export const useFetchNextDialogList = () => { + const { handleClickDialog } = useClickDialogCard(); + + const { + data, + isFetching: loading, + refetch, + } = useQuery({ + queryKey: ['fetchDialogList'], + initialData: [], + gcTime: 0, + refetchOnWindowFocus: false, + queryFn: async () => { + const { data } = await chatService.listDialog(); + + if (data.retcode === 0 && data.data.length > 0) { + handleClickDialog(data.data[0].id); } + + return data?.data ?? []; }, - [dispatch], - ); + }); - return fetchConversationList; + return { data, loading, refetch }; }; -export const useSelectConversationList = () => { - const conversationList: IConversation[] = useSelector( - (state: any) => state.chatModel.conversationList, - ); - - return conversationList; -}; - -export const useFetchConversation = () => { - const dispatch = useDispatch(); - - const fetchConversation = useCallback( - (conversationId: string, needToBeSaved = true) => { - return dispatch({ - type: 'chatModel/getConversation', - payload: { - needToBeSaved, - conversation_id: conversationId, - }, - }); - }, - [dispatch], - ); - - return fetchConversation; -}; - -export const useFetchDialog = () => { - const dispatch = useDispatch(); - - const fetchDialog = useCallback( - (dialogId: string, needToBeSaved = true) => { - if (dialogId) { - return dispatch({ - type: 'chatModel/getDialog', - payload: { dialog_id: dialogId, needToBeSaved }, - }); +export const useSetNextDialog = () => { + const queryClient = useQueryClient(); + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['setDialog'], + mutationFn: async (params: IDialog) => { + const { data } = await chatService.setDialog(params); + if (data.retcode === 0) { + queryClient.invalidateQueries({ queryKey: ['fetchDialogList'] }); + message.success( + i18n.t(`message.${params.id ? 'modified' : 'created'}`), + ); } + return data?.retcode; }, - [dispatch], - ); + }); - return fetchDialog; + return { data, loading, setDialog: mutateAsync }; }; -export const useRemoveDialog = () => { - const dispatch = useDispatch(); +export const useFetchNextDialog = () => { + const { dialogId } = useGetChatSearchParams(); - const removeDocument = useCallback( - (dialogIds: Array) => { - return dispatch({ - type: 'chatModel/removeDialog', - payload: { - dialog_ids: dialogIds, - }, - }); + const { data, isFetching: loading } = useQuery({ + queryKey: ['fetchDialog', dialogId], + gcTime: 0, + initialData: {} as IDialog, + enabled: !!dialogId, + refetchOnWindowFocus: false, + queryFn: async () => { + const { data } = await chatService.getDialog({ dialogId }); + + return data?.data ?? ({} as IDialog); }, - [dispatch], - ); + }); - return removeDocument; + return { data, loading }; }; -export const useUpdateConversation = () => { - const dispatch = useDispatch(); +export const useFetchManualDialog = () => { + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['fetchManualDialog'], + gcTime: 0, + mutationFn: async (dialogId: string) => { + const { data } = await chatService.getDialog({ dialogId }); - const updateConversation = useCallback( - (payload: any) => { - return dispatch({ - type: 'chatModel/setConversation', - payload, - }); + return data; }, - [dispatch], - ); + }); - return updateConversation; + return { data, loading, fetchDialog: mutateAsync }; +}; + +export const useRemoveNextDialog = () => { + const queryClient = useQueryClient(); + + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['removeDialog'], + mutationFn: async (dialogIds: string[]) => { + const { data } = await chatService.removeDialog({ dialogIds }); + if (data.retcode === 0) { + queryClient.invalidateQueries({ queryKey: ['fetchDialogList'] }); + message.success(i18n.t('message.deleted')); + } + return data.retcode; + }, + }); + + return { data, loading, removeDialog: mutateAsync }; +}; + +//#endregion + +//#region conversation + +export const useFetchNextConversationList = () => { + const { dialogId } = useGetChatSearchParams(); + const { + data, + isFetching: loading, + refetch, + } = useQuery({ + queryKey: ['fetchConversationList', dialogId], + initialData: [], + gcTime: 0, + refetchOnWindowFocus: false, + enabled: !!dialogId, + queryFn: async () => { + const { data } = await chatService.listConversation({ dialogId }); + + return data?.data; + }, + }); + + return { data, loading, refetch }; +}; + +export const useFetchNextConversation = () => { + const { conversationId } = useGetChatSearchParams(); + const { + data, + isFetching: loading, + refetch, + } = useQuery({ + queryKey: ['fetchConversation', conversationId], + initialData: {} as IClientConversation, + // enabled: isConversationIdExist(conversationId), + gcTime: 0, + refetchOnWindowFocus: false, + queryFn: async () => { + if (isConversationIdExist(conversationId)) { + const { data } = await chatService.getConversation({ conversationId }); + // if (data.retcode === 0 && needToBeSaved) { + // yield put({ + // type: 'kFModel/fetch_document_thumbnails', + // payload: { + // doc_ids: getDocumentIdsFromConversionReference(data.data), + // }, + // }); + // yield put({ type: 'setCurrentConversation', payload: data.data }); + // } + const conversation = data?.data ?? {}; + + const messageList = + conversation?.message?.map((x: Message | IMessage) => ({ + ...x, + id: 'id' in x && x.id ? x.id : uuid(), + })) ?? []; + + return { ...conversation, message: messageList }; + } + return { message: [] }; + }, + }); + + return { data, loading, refetch }; +}; + +export const useFetchManualConversation = () => { + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['fetchManualConversation'], + gcTime: 0, + mutationFn: async (conversationId: string) => { + const { data } = await chatService.getConversation({ conversationId }); + + return data; + }, + }); + + return { data, loading, fetchConversation: mutateAsync }; }; export const useUpdateNextConversation = () => { + const queryClient = useQueryClient(); const { data, isPending: loading, @@ -134,7 +258,9 @@ export const useUpdateNextConversation = () => { mutationKey: ['updateConversation'], mutationFn: async (params: Record) => { const { data } = await chatService.setConversation(params); - + if (data.retcode === 0) { + queryClient.invalidateQueries({ queryKey: ['fetchConversationList'] }); + } return data; }, }); @@ -142,72 +268,34 @@ export const useUpdateNextConversation = () => { return { data, loading, updateConversation: mutateAsync }; }; -export const useSetDialog = () => { - const dispatch = useDispatch(); +export const useRemoveNextConversation = () => { + const queryClient = useQueryClient(); + const { dialogId } = useGetChatSearchParams(); - const setDialog = useCallback( - (payload: IDialog) => { - return dispatch({ type: 'chatModel/setDialog', payload }); - }, - [dispatch], - ); - - return setDialog; -}; - -export const useRemoveConversation = () => { - const dispatch = useDispatch(); - - const removeConversation = useCallback( - (conversationIds: Array, dialogId: string) => { - return dispatch({ - type: 'chatModel/removeConversation', - payload: { - dialog_id: dialogId, - conversation_ids: conversationIds, - }, + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['removeConversation'], + mutationFn: async (conversationIds: string[]) => { + const { data } = await chatService.removeConversation({ + conversationIds, + dialogId, }); + if (data.retcode === 0) { + queryClient.invalidateQueries({ queryKey: ['fetchConversationList'] }); + } + return data.retcode; }, - [dispatch], - ); + }); - return removeConversation; -}; - -/* -@deprecated - */ -export const useCompleteConversation = () => { - const dispatch = useDispatch(); - - const completeConversation = useCallback( - (payload: any) => { - return dispatch({ - type: 'chatModel/completeConversation', - payload, - }); - }, - [dispatch], - ); - - return completeConversation; + return { data, loading, removeConversation: mutateAsync }; }; +//#endregion // #region API provided for external calls -export const useCreateToken = (params: Record) => { - const dispatch = useDispatch(); - - const createToken = useCallback(() => { - return dispatch({ - type: 'chatModel/createToken', - payload: params, - }); - }, [dispatch, params]); - - return createToken; -}; - export const useCreateNextToken = () => { const queryClient = useQueryClient(); const { @@ -303,36 +391,41 @@ export const useFetchNextStats = () => { //#region shared chat -export const useCreateSharedConversation = () => { - const dispatch = useDispatch(); +export const useCreateNextSharedConversation = () => { + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['createSharedConversation'], + mutationFn: async (userId?: string) => { + const { data } = await chatService.createExternalConversation({ userId }); - const createSharedConversation = useCallback( - (userId?: string) => { - return dispatch({ - type: 'chatModel/createExternalConversation', - payload: { userId }, - }); + return data; }, - [dispatch], - ); + }); - return createSharedConversation; + return { data, loading, createSharedConversation: mutateAsync }; }; -export const useFetchSharedConversation = () => { - const dispatch = useDispatch(); +export const useFetchNextSharedConversation = () => { + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['fetchSharedConversation'], + mutationFn: async (conversationId: string) => { + const { data } = await chatService.getExternalConversation( + null, + conversationId, + ); - const fetchSharedConversation = useCallback( - (conversationId: string) => { - return dispatch({ - type: 'chatModel/getExternalConversation', - payload: conversationId, - }); + return data; }, - [dispatch], - ); + }); - return fetchSharedConversation; + return { data, loading, fetchConversation: mutateAsync }; }; //#endregion diff --git a/web/src/interfaces/database/user-setting.ts b/web/src/interfaces/database/user-setting.ts index e98b117b2..75bf563b9 100644 --- a/web/src/interfaces/database/user-setting.ts +++ b/web/src/interfaces/database/user-setting.ts @@ -28,8 +28,9 @@ export interface ISystemStatus { mysql: Minio; redis: Redis; task_executor: { + error?: string; status: string; - elapsed: TaskExecutorElapsed; + elapsed?: TaskExecutorElapsed; }; } diff --git a/web/src/pages/chat/chat-container/index.tsx b/web/src/pages/chat/chat-container/index.tsx index e50669aed..06388e55c 100644 --- a/web/src/pages/chat/chat-container/index.tsx +++ b/web/src/pages/chat/chat-container/index.tsx @@ -8,7 +8,6 @@ import { useFetchConversationOnMount, useGetFileIcon, useGetSendButtonDisabled, - useSelectConversationLoading, useSendButtonDisabled, useSendMessage, } from '../hooks'; @@ -16,6 +15,7 @@ import { buildMessageItemReference } from '../utils'; import MessageInput from '@/components/message-input'; import { useFetchUserInfo } from '@/hooks/user-setting-hooks'; +import { memo } from 'react'; import styles from './index.less'; const ChatContainer = () => { @@ -26,6 +26,7 @@ const ChatContainer = () => { removeLatestMessage, addNewestAnswer, conversationId, + loading, } = useFetchConversationOnMount(); const { handleInputChange, @@ -43,7 +44,6 @@ const ChatContainer = () => { const disabled = useGetSendButtonDisabled(); const sendDisabled = useSendButtonDisabled(value); useGetFileIcon(); - const loading = useSelectConversationLoading(); const { data: userInfo } = useFetchUserInfo(); const { createConversationBeforeUploadDocument } = useCreateConversationBeforeUploadDocument(); @@ -104,4 +104,4 @@ const ChatContainer = () => { ); }; -export default ChatContainer; +export default memo(ChatContainer); diff --git a/web/src/pages/chat/hooks.ts b/web/src/pages/chat/hooks.ts index f1e3cc15e..7e4fe9361 100644 --- a/web/src/pages/chat/hooks.ts +++ b/web/src/pages/chat/hooks.ts @@ -1,16 +1,16 @@ import { MessageType } from '@/constants/chat'; import { fileIconMap } from '@/constants/common'; import { - useFetchConversation, - useFetchConversationList, - useFetchDialog, - useFetchDialogList, - useRemoveConversation, - useRemoveDialog, - useSelectConversationList, - useSelectDialogList, - useSetDialog, - useUpdateConversation, + useFetchManualConversation, + useFetchManualDialog, + useFetchNextConversation, + useFetchNextConversationList, + useFetchNextDialog, + useGetChatSearchParams, + useRemoveNextConversation, + useRemoveNextDialog, + useSetNextDialog, + useUpdateNextConversation, } from '@/hooks/chat-hooks'; import { useSetModalState, @@ -18,7 +18,6 @@ import { useTranslate, } from '@/hooks/common-hooks'; import { useSendMessageWithSse } from '@/hooks/logic-hooks'; -import { useOneNamespaceEffectsLoading } from '@/hooks/store-hooks'; import { IAnswer, IConversation, @@ -27,6 +26,8 @@ import { } from '@/interfaces/database/chat'; import { IChunk } from '@/interfaces/database/knowledge'; import { getFileExtension } from '@/utils'; +import { useMutationState } from '@tanstack/react-query'; +import { get } from 'lodash'; import omit from 'lodash/omit'; import trim from 'lodash/trim'; import { @@ -37,7 +38,7 @@ import { useRef, useState, } from 'react'; -import { useDispatch, useSearchParams, useSelector } from 'umi'; +import { useSearchParams } from 'umi'; import { v4 as uuid } from 'uuid'; import { ChatSearchParams } from './constants'; import { @@ -45,70 +46,20 @@ import { IMessage, VariableTableDataType, } from './interface'; -import { ChatModelState } from './model'; -import { isConversationIdExist } from './utils'; export const useSelectCurrentDialog = () => { - const currentDialog: IDialog = useSelector( - (state: any) => state.chatModel.currentDialog, - ); - - return currentDialog; -}; - -export const useFetchDialogOnMount = ( - dialogId: string, - visible: boolean, -): IDialog => { - const currentDialog: IDialog = useSelectCurrentDialog(); - const fetchDialog = useFetchDialog(); - - useEffect(() => { - if (dialogId && visible) { - fetchDialog(dialogId); - } - }, [dialogId, fetchDialog, visible]); - - return currentDialog; -}; - -export const useSetCurrentDialog = () => { - const dispatch = useDispatch(); - - const currentDialog: IDialog = useSelector( - (state: any) => state.chatModel.currentDialog, - ); - - const setCurrentDialog = useCallback( - (dialogId: string) => { - dispatch({ - type: 'chatModel/setCurrentDialog', - payload: { id: dialogId }, - }); + const data = useMutationState({ + filters: { mutationKey: ['fetchDialog'] }, + select: (mutation) => { + return get(mutation, 'state.data.data', {}); }, - [dispatch], - ); + }); - return { currentDialog, setCurrentDialog }; -}; - -export const useResetCurrentDialog = () => { - const dispatch = useDispatch(); - - const resetCurrentDialog = useCallback(() => { - dispatch({ - type: 'chatModel/setCurrentDialog', - payload: {}, - }); - }, [dispatch]); - - return { resetCurrentDialog }; + return (data.at(-1) ?? {}) as IDialog; }; export const useSelectPromptConfigParameters = (): VariableTableDataType[] => { - const currentDialog: IDialog = useSelector( - (state: any) => state.chatModel.currentDialog, - ); + const { data: currentDialog } = useFetchNextDialog(); const finalParameters: VariableTableDataType[] = useMemo(() => { const parameters = currentDialog?.prompt_config?.parameters ?? []; @@ -129,83 +80,15 @@ export const useSelectPromptConfigParameters = (): VariableTableDataType[] => { export const useDeleteDialog = () => { const showDeleteConfirm = useShowDeleteConfirm(); - const removeDocument = useRemoveDialog(); + const { removeDialog } = useRemoveNextDialog(); const onRemoveDialog = (dialogIds: Array) => { - showDeleteConfirm({ onOk: () => removeDocument(dialogIds) }); + showDeleteConfirm({ onOk: () => removeDialog(dialogIds) }); }; return { onRemoveDialog }; }; -export const useGetChatSearchParams = () => { - const [currentQueryParameters] = useSearchParams(); - - return { - dialogId: currentQueryParameters.get(ChatSearchParams.DialogId) || '', - conversationId: - currentQueryParameters.get(ChatSearchParams.ConversationId) || '', - }; -}; - -export const useSetCurrentConversation = () => { - const dispatch = useDispatch(); - - const setCurrentConversation = useCallback( - (currentConversation: IClientConversation) => { - dispatch({ - type: 'chatModel/setCurrentConversation', - payload: currentConversation, - }); - }, - [dispatch], - ); - - return setCurrentConversation; -}; - -export const useClickDialogCard = () => { - const [currentQueryParameters, setSearchParams] = useSearchParams(); - - const newQueryParameters: URLSearchParams = useMemo(() => { - return new URLSearchParams(); - }, []); - - const handleClickDialog = useCallback( - (dialogId: string) => { - newQueryParameters.set(ChatSearchParams.DialogId, dialogId); - // newQueryParameters.set( - // ChatSearchParams.ConversationId, - // EmptyConversationId, - // ); - setSearchParams(newQueryParameters); - }, - [newQueryParameters, setSearchParams], - ); - - return { handleClickDialog }; -}; - -export const useSelectFirstDialogOnMount = () => { - const fetchDialogList = useFetchDialogList(); - const dialogList = useSelectDialogList(); - - const { handleClickDialog } = useClickDialogCard(); - - const fetchList = useCallback(async () => { - const data = await fetchDialogList(); - if (data.retcode === 0 && data.data.length > 0) { - handleClickDialog(data.data[0].id); - } - }, [fetchDialogList, handleClickDialog]); - - useEffect(() => { - fetchList(); - }, [fetchList]); - - return dialogList; -}; - export const useHandleItemHover = () => { const [activated, setActivated] = useState(''); @@ -226,9 +109,8 @@ export const useHandleItemHover = () => { export const useEditDialog = () => { const [dialog, setDialog] = useState({} as IDialog); - const fetchDialog = useFetchDialog(); - const submitDialog = useSetDialog(); - const loading = useOneNamespaceEffectsLoading('chatModel', ['setDialog']); + const { fetchDialog } = useFetchManualDialog(); + const { setDialog: submitDialog, loading } = useSetNextDialog(); const { visible: dialogEditVisible, @@ -255,7 +137,7 @@ export const useEditDialog = () => { const handleShowDialogEditModal = useCallback( async (dialogId?: string) => { if (dialogId) { - const ret = await fetchDialog(dialogId, false); + const ret = await fetchDialog(dialogId); if (ret.retcode === 0) { setDialog(ret.data); } @@ -282,25 +164,15 @@ export const useEditDialog = () => { //#region conversation -export const useFetchConversationListOnMount = () => { - const conversationList = useSelectConversationList(); - const { dialogId } = useGetChatSearchParams(); - const fetchConversationList = useFetchConversationList(); - - useEffect(() => { - fetchConversationList(dialogId); - }, [fetchConversationList, dialogId]); - - return conversationList; -}; - export const useSelectDerivedConversationList = () => { + const { t } = useTranslate('chat'); + const [list, setList] = useState>([]); - let chatModel: ChatModelState = useSelector((state: any) => state.chatModel); - const { conversationList, currentDialog } = chatModel; + const { data: currentDialog } = useFetchNextDialog(); + const { data: conversationList, loading } = useFetchNextConversationList(); const { dialogId } = useGetChatSearchParams(); const prologue = currentDialog?.prompt_config?.prologue ?? ''; - const { t } = useTranslate('chat'); + const addTemporaryConversation = useCallback(() => { setList((pre) => { if (dialogId) { @@ -329,7 +201,7 @@ export const useSelectDerivedConversationList = () => { addTemporaryConversation(); }, [addTemporaryConversation]); - return { list, addTemporaryConversation }; + return { list, addTemporaryConversation, loading }; }; export const useClickConversationCard = () => { @@ -352,7 +224,7 @@ export const useClickConversationCard = () => { export const useSetConversation = () => { const { dialogId } = useGetChatSearchParams(); - const updateConversation = useUpdateConversation(); + const { updateConversation } = useUpdateNextConversation(); const setConversation = useCallback( (message: string) => { @@ -376,11 +248,8 @@ export const useSetConversation = () => { export const useSelectCurrentConversation = () => { const [currentConversation, setCurrentConversation] = useState({} as IClientConversation); - - const conversation: IClientConversation = useSelector( - (state: any) => state.chatModel.currentConversation, - ); - const dialog = useSelectCurrentDialog(); + const { data: conversation, loading } = useFetchNextConversation(); + const { data: dialog } = useFetchNextDialog(); const { conversationId, dialogId } = useGetChatSearchParams(); const addNewestConversation = useCallback( @@ -474,6 +343,7 @@ export const useSelectCurrentConversation = () => { addNewestConversation, removeLatestMessage, addNewestAnswer, + loading, }; }; @@ -495,25 +365,15 @@ export const useScrollToBottom = (currentConversation: IClientConversation) => { export const useFetchConversationOnMount = () => { const { conversationId } = useGetChatSearchParams(); - const fetchConversation = useFetchConversation(); const { currentConversation, addNewestConversation, removeLatestMessage, addNewestAnswer, + loading, } = useSelectCurrentConversation(); const ref = useScrollToBottom(currentConversation); - const fetchConversationOnMount = useCallback(() => { - if (isConversationIdExist(conversationId)) { - fetchConversation(conversationId); - } - }, [fetchConversation, conversationId]); - - useEffect(() => { - fetchConversationOnMount(); - }, [fetchConversationOnMount]); - return { currentConversation, addNewestConversation, @@ -521,6 +381,7 @@ export const useFetchConversationOnMount = () => { removeLatestMessage, addNewestAnswer, conversationId, + loading, }; }; @@ -655,13 +516,12 @@ export const useGetFileIcon = () => { }; export const useDeleteConversation = () => { - const { dialogId } = useGetChatSearchParams(); const { handleClickConversation } = useClickConversationCard(); const showDeleteConfirm = useShowDeleteConfirm(); - const removeConversation = useRemoveConversation(); + const { removeConversation } = useRemoveNextConversation(); const deleteConversation = (conversationIds: Array) => async () => { - const ret = await removeConversation(conversationIds, dialogId); + const ret = await removeConversation(conversationIds); if (ret === 0) { handleClickConversation(''); } @@ -679,13 +539,13 @@ export const useRenameConversation = () => { const [conversation, setConversation] = useState( {} as IClientConversation, ); - const fetchConversation = useFetchConversation(); + const { fetchConversation } = useFetchManualConversation(); const { visible: conversationRenameVisible, hideModal: hideConversationRenameModal, showModal: showConversationRenameModal, } = useSetModalState(); - const updateConversation = useUpdateConversation(); + const { updateConversation, loading } = useUpdateNextConversation(); const onConversationRenameOk = useCallback( async (name: string) => { @@ -702,13 +562,9 @@ export const useRenameConversation = () => { [updateConversation, conversation, hideConversationRenameModal], ); - const loading = useOneNamespaceEffectsLoading('chatModel', [ - 'setConversation', - ]); - const handleShowConversationRenameModal = useCallback( async (conversationId: string) => { - const ret = await fetchConversation(conversationId, false); + const ret = await fetchConversation(conversationId); if (ret.retcode === 0) { setConversation(ret.data); } @@ -751,16 +607,6 @@ export const useClickDrawer = () => { }; }; -export const useSelectDialogListLoading = () => { - return useOneNamespaceEffectsLoading('chatModel', ['listDialog']); -}; -export const useSelectConversationListLoading = () => { - return useOneNamespaceEffectsLoading('chatModel', ['listConversation']); -}; -export const useSelectConversationLoading = () => { - return useOneNamespaceEffectsLoading('chatModel', ['getConversation']); -}; - export const useGetSendButtonDisabled = () => { const { dialogId, conversationId } = useGetChatSearchParams(); diff --git a/web/src/pages/chat/index.tsx b/web/src/pages/chat/index.tsx index ac6f66e9a..3201b82fe 100644 --- a/web/src/pages/chat/index.tsx +++ b/web/src/pages/chat/index.tsx @@ -26,22 +26,20 @@ import ChatConfigurationModal from './chat-configuration-modal'; import ChatContainer from './chat-container'; import { useClickConversationCard, - useClickDialogCard, useDeleteConversation, useDeleteDialog, useEditDialog, - useFetchConversationListOnMount, - useFetchDialogOnMount, - useGetChatSearchParams, useHandleItemHover, useRenameConversation, - useSelectConversationListLoading, useSelectDerivedConversationList, - useSelectDialogListLoading, - useSelectFirstDialogOnMount, } from './hooks'; import ChatOverviewModal from '@/components/api-service/chat-overview-modal'; +import { + useClickDialogCard, + useFetchNextDialogList, + useGetChatSearchParams, +} from '@/hooks/chat-hooks'; import { useSetModalState, useTranslate } from '@/hooks/common-hooks'; import { useSetSelectedRecord } from '@/hooks/logic-hooks'; import { IDialog } from '@/interfaces/database/chat'; @@ -50,14 +48,17 @@ import styles from './index.less'; const { Text } = Typography; const Chat = () => { - const dialogList = useSelectFirstDialogOnMount(); + const { data: dialogList, loading: dialogLoading } = useFetchNextDialogList(); const { onRemoveDialog } = useDeleteDialog(); const { onRemoveConversation } = useDeleteConversation(); const { handleClickDialog } = useClickDialogCard(); const { handleClickConversation } = useClickConversationCard(); const { dialogId, conversationId } = useGetChatSearchParams(); - const { list: conversationList, addTemporaryConversation } = - useSelectDerivedConversationList(); + const { + list: conversationList, + addTemporaryConversation, + loading: conversationLoading, + } = useSelectDerivedConversationList(); const { activated, handleItemEnter, handleItemLeave } = useHandleItemHover(); const { activated: conversationActivated, @@ -81,8 +82,6 @@ const Chat = () => { hideDialogEditModal, showDialogEditModal, } = useEditDialog(); - const dialogLoading = useSelectDialogListLoading(); - const conversationLoading = useSelectConversationListLoading(); const { t } = useTranslate('chat'); const { visible: overviewVisible, @@ -91,8 +90,6 @@ const Chat = () => { } = useSetModalState(); const { currentRecord, setRecord } = useSetSelectedRecord(); - useFetchDialogOnMount(dialogId, true); - const handleAppCardEnter = (id: string) => () => { handleItemEnter(id); }; @@ -236,8 +233,6 @@ const Chat = () => { return appItems; }; - useFetchConversationListOnMount(); - return ( diff --git a/web/src/pages/chat/shared-hooks.ts b/web/src/pages/chat/shared-hooks.ts index 4ad43a4ee..219728818 100644 --- a/web/src/pages/chat/shared-hooks.ts +++ b/web/src/pages/chat/shared-hooks.ts @@ -1,10 +1,9 @@ import { MessageType, SharedFrom } from '@/constants/chat'; import { - useCreateSharedConversation, - useFetchSharedConversation, + useCreateNextSharedConversation, + useFetchNextSharedConversation, } from '@/hooks/chat-hooks'; import { useSendMessageWithSse } from '@/hooks/logic-hooks'; -import { useOneNamespaceEffectsLoading } from '@/hooks/store-hooks'; import { IAnswer, Message } from '@/interfaces/database/chat'; import api from '@/utils/api'; import omit from 'lodash/omit'; @@ -25,12 +24,12 @@ export const useCreateSharedConversationOnMount = () => { const [currentQueryParameters] = useSearchParams(); const [conversationId, setConversationId] = useState(''); - const createConversation = useCreateSharedConversation(); + const { createSharedConversation: createConversation } = + useCreateNextSharedConversation(); const sharedId = currentQueryParameters.get('shared_id'); const userId = currentQueryParameters.get('user_id'); const setConversation = useCallback(async () => { - console.info(sharedId); if (sharedId) { const data = await createConversation(userId ?? undefined); const id = data.data?.id; @@ -50,10 +49,7 @@ export const useCreateSharedConversationOnMount = () => { export const useSelectCurrentSharedConversation = (conversationId: string) => { const [currentConversation, setCurrentConversation] = useState({} as IClientConversation); - const fetchConversation = useFetchSharedConversation(); - const loading = useOneNamespaceEffectsLoading('chatModel', [ - 'getExternalConversation', - ]); + const { fetchConversation, loading } = useFetchNextSharedConversation(); const ref = useScrollToBottom(currentConversation); @@ -147,7 +143,8 @@ export const useSendSharedMessage = ( addNewestAnswer: (answer: IAnswer) => void, ) => { const conversationId = conversation.id; - const setConversation = useCreateSharedConversation(); + const { createSharedConversation: setConversation } = + useCreateNextSharedConversation(); const { handleInputChange, value, setValue } = useHandleMessageInputChange(); const { send, answer, done } = useSendMessageWithSse( diff --git a/web/src/pages/force-graph/input-upload.tsx b/web/src/pages/force-graph/input-upload.tsx index a4b203d5a..3d6064cf4 100644 --- a/web/src/pages/force-graph/input-upload.tsx +++ b/web/src/pages/force-graph/input-upload.tsx @@ -1,72 +1,14 @@ import { Authorization } from '@/constants/authorization'; import { getAuthorization } from '@/utils/authorization-util'; import { PlusOutlined } from '@ant-design/icons'; -import type { GetProp, UploadFile, UploadProps } from 'antd'; +import type { UploadFile, UploadProps } from 'antd'; import { Image, Input, Upload } from 'antd'; import { useState } from 'react'; -import { useGetChatSearchParams } from '../chat/hooks'; - -type FileType = Parameters>[0]; - -const getBase64 = (file: FileType): Promise => - new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.readAsDataURL(file); - reader.onload = () => resolve(reader.result as string); - reader.onerror = (error) => reject(error); - }); const InputWithUpload = () => { const [previewOpen, setPreviewOpen] = useState(false); const [previewImage, setPreviewImage] = useState(''); - const { conversationId } = useGetChatSearchParams(); - const [fileList, setFileList] = useState([ - { - uid: '-1', - name: 'image.png', - status: 'done', - url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', - }, - { - uid: '-2', - name: 'image.png', - status: 'done', - url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', - }, - { - uid: '-3', - name: 'image.png', - status: 'done', - url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', - }, - { - uid: '-4', - name: 'image.png', - status: 'done', - url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', - }, - { - uid: '-xxx', - percent: 50, - name: 'image.png', - status: 'uploading', - url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', - }, - { - uid: '-5', - name: 'image.png', - status: 'error', - }, - ]); - - const handlePreview = async (file: UploadFile) => { - if (!file.url && !file.preview) { - file.preview = await getBase64(file.originFileObj as FileType); - } - - setPreviewImage(file.url || (file.preview as string)); - setPreviewOpen(true); - }; + const [fileList, setFileList] = useState([]); const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) => setFileList(newFileList); @@ -84,7 +26,6 @@ const InputWithUpload = () => { action="/v1/document/upload_and_parse" listType="picture-card" fileList={fileList} - onPreview={handlePreview} onChange={handleChange} multiple headers={{ [Authorization]: getAuthorization() }} diff --git a/web/src/pages/user-setting/setting-system/index.tsx b/web/src/pages/user-setting/setting-system/index.tsx index d24833cf7..5ca8d791a 100644 --- a/web/src/pages/user-setting/setting-system/index.tsx +++ b/web/src/pages/user-setting/setting-system/index.tsx @@ -70,9 +70,13 @@ const SystemInfo = () => { key={key} > {key === 'task_executor' ? ( - + info?.elapsed ? ( + + ) : ( + {info.error} + ) ) : ( Object.keys(info) .filter((x) => x !== 'status') diff --git a/web/src/utils/chat.ts b/web/src/utils/chat.ts new file mode 100644 index 000000000..1ab0da2c1 --- /dev/null +++ b/web/src/utils/chat.ts @@ -0,0 +1,5 @@ +import { EmptyConversationId } from '@/constants/chat'; + +export const isConversationIdExist = (conversationId: string) => { + return conversationId !== EmptyConversationId && conversationId !== ''; +};