- {sessionList.map((x) => (
-
+
+ {conversationList.map((x) => (
+
+
+ {x.name}
+
+
+
))}
+
+
+
+
+
);
}
diff --git a/web/src/pages/next-chats/hooks/use-button-disabled.tsx b/web/src/pages/next-chats/hooks/use-button-disabled.tsx
new file mode 100644
index 000000000..50bad8867
--- /dev/null
+++ b/web/src/pages/next-chats/hooks/use-button-disabled.tsx
@@ -0,0 +1,14 @@
+import { useGetChatSearchParams } from '@/hooks/use-chat-request';
+import { trim } from 'lodash';
+import { useParams } from 'umi';
+
+export const useGetSendButtonDisabled = () => {
+ const { conversationId } = useGetChatSearchParams();
+ const { id: dialogId } = useParams();
+
+ return dialogId === '' || conversationId === '';
+};
+
+export const useSendButtonDisabled = (value: string) => {
+ return trim(value) === '';
+};
diff --git a/web/src/pages/next-chats/hooks/use-click-card.ts b/web/src/pages/next-chats/hooks/use-click-card.ts
new file mode 100644
index 000000000..9d7a65f7c
--- /dev/null
+++ b/web/src/pages/next-chats/hooks/use-click-card.ts
@@ -0,0 +1,20 @@
+import { useClickConversationCard } from '@/hooks/use-chat-request';
+import { useCallback, useState } from 'react';
+
+export function useHandleClickConversationCard() {
+ const [controller, setController] = useState(new AbortController());
+ const { handleClickConversation } = useClickConversationCard();
+
+ const handleConversationCardClick = useCallback(
+ (conversationId: string, isNew: boolean) => {
+ handleClickConversation(conversationId, isNew ? 'true' : '');
+ setController((pre) => {
+ pre.abort();
+ return new AbortController();
+ });
+ },
+ [handleClickConversation],
+ );
+
+ return { controller, handleConversationCardClick };
+}
diff --git a/web/src/pages/next-chats/hooks/use-create-conversation.ts b/web/src/pages/next-chats/hooks/use-create-conversation.ts
new file mode 100644
index 000000000..b27ec486d
--- /dev/null
+++ b/web/src/pages/next-chats/hooks/use-create-conversation.ts
@@ -0,0 +1,29 @@
+import { useGetChatSearchParams } from '@/hooks/use-chat-request';
+import { useCallback } from 'react';
+import {
+ useSetChatRouteParams,
+ useSetConversation,
+} from './use-send-chat-message';
+
+export const useCreateConversationBeforeUploadDocument = () => {
+ const { setConversation } = useSetConversation();
+ const { dialogId } = useGetChatSearchParams();
+ const { getConversationIsNew } = useSetChatRouteParams();
+
+ const createConversationBeforeUploadDocument = useCallback(
+ async (message: string) => {
+ const isNew = getConversationIsNew();
+ if (isNew === 'true') {
+ const data = await setConversation(message, true);
+
+ return data;
+ }
+ },
+ [setConversation, getConversationIsNew],
+ );
+
+ return {
+ createConversationBeforeUploadDocument,
+ dialogId,
+ };
+};
diff --git a/web/src/pages/next-chats/hooks/use-select-conversation-list.ts b/web/src/pages/next-chats/hooks/use-select-conversation-list.ts
new file mode 100644
index 000000000..26b165d52
--- /dev/null
+++ b/web/src/pages/next-chats/hooks/use-select-conversation-list.ts
@@ -0,0 +1,85 @@
+import { ChatSearchParams, MessageType } from '@/constants/chat';
+import { useTranslate } from '@/hooks/common-hooks';
+import {
+ useFetchConversationList,
+ useFetchDialogList,
+} from '@/hooks/use-chat-request';
+import { IConversation } from '@/interfaces/database/chat';
+import { getConversationId } from '@/utils/chat';
+import { useCallback, useEffect, useMemo, useState } from 'react';
+import { useParams, useSearchParams } from 'umi';
+
+export const useFindPrologueFromDialogList = () => {
+ const { id: dialogId } = useParams();
+ const { data } = useFetchDialogList();
+
+ const prologue = useMemo(() => {
+ return data.dialogs.find((x) => x.id === dialogId)?.prompt_config.prologue;
+ }, [dialogId, data]);
+
+ return prologue;
+};
+
+export const useSetNewConversationRouteParams = () => {
+ const [currentQueryParameters, setSearchParams] = useSearchParams();
+ const newQueryParameters: URLSearchParams = useMemo(
+ () => new URLSearchParams(currentQueryParameters.toString()),
+ [currentQueryParameters],
+ );
+
+ const setNewConversationRouteParams = useCallback(
+ (conversationId: string, isNew: string) => {
+ newQueryParameters.set(ChatSearchParams.ConversationId, conversationId);
+ newQueryParameters.set(ChatSearchParams.isNew, isNew);
+ setSearchParams(newQueryParameters);
+ },
+ [newQueryParameters, setSearchParams],
+ );
+
+ return { setNewConversationRouteParams };
+};
+
+export const useSelectDerivedConversationList = () => {
+ const { t } = useTranslate('chat');
+
+ const [list, setList] = useState
>([]);
+ const { data: conversationList, loading } = useFetchConversationList();
+ const { id: dialogId } = useParams();
+ const { setNewConversationRouteParams } = useSetNewConversationRouteParams();
+ const prologue = useFindPrologueFromDialogList();
+
+ const addTemporaryConversation = useCallback(() => {
+ const conversationId = getConversationId();
+ setList((pre) => {
+ if (dialogId) {
+ setNewConversationRouteParams(conversationId, 'true');
+ const nextList = [
+ {
+ id: conversationId,
+ name: t('newConversation'),
+ dialog_id: dialogId,
+ is_new: true,
+ message: [
+ {
+ content: prologue,
+ role: MessageType.Assistant,
+ },
+ ],
+ } as any,
+ ...conversationList,
+ ];
+ return nextList;
+ }
+
+ return pre;
+ });
+ }, [conversationList, dialogId, prologue, t, setNewConversationRouteParams]);
+
+ // When you first enter the page, select the top conversation card
+
+ useEffect(() => {
+ setList([...conversationList]);
+ }, [conversationList]);
+
+ return { list, addTemporaryConversation, loading };
+};
diff --git a/web/src/pages/next-chats/hooks/use-send-chat-message.ts b/web/src/pages/next-chats/hooks/use-send-chat-message.ts
new file mode 100644
index 000000000..534120b6d
--- /dev/null
+++ b/web/src/pages/next-chats/hooks/use-send-chat-message.ts
@@ -0,0 +1,279 @@
+import { ChatSearchParams, MessageType } from '@/constants/chat';
+import {
+ useHandleMessageInputChange,
+ useRegenerateMessage,
+ useSelectDerivedMessages,
+ useSendMessageWithSse,
+} from '@/hooks/logic-hooks';
+import {
+ useFetchConversation,
+ useGetChatSearchParams,
+ useUpdateConversation,
+} from '@/hooks/use-chat-request';
+import { Message } from '@/interfaces/database/chat';
+import api from '@/utils/api';
+import { trim } from 'lodash';
+import { useCallback, useEffect, useMemo } from 'react';
+import { useParams, useSearchParams } from 'umi';
+import { v4 as uuid } from 'uuid';
+import { IMessage } from '../chat/interface';
+import { useFindPrologueFromDialogList } from './use-select-conversation-list';
+
+export const useSetChatRouteParams = () => {
+ const [currentQueryParameters, setSearchParams] = useSearchParams();
+ const newQueryParameters: URLSearchParams = useMemo(
+ () => new URLSearchParams(currentQueryParameters.toString()),
+ [currentQueryParameters],
+ );
+
+ const setConversationIsNew = useCallback(
+ (value: string) => {
+ newQueryParameters.set(ChatSearchParams.isNew, value);
+ setSearchParams(newQueryParameters);
+ },
+ [newQueryParameters, setSearchParams],
+ );
+
+ const getConversationIsNew = useCallback(() => {
+ return newQueryParameters.get(ChatSearchParams.isNew);
+ }, [newQueryParameters]);
+
+ return { setConversationIsNew, getConversationIsNew };
+};
+
+export const useSelectNextMessages = () => {
+ const {
+ scrollRef,
+ messageContainerRef,
+ setDerivedMessages,
+ derivedMessages,
+ addNewestAnswer,
+ addNewestQuestion,
+ removeLatestMessage,
+ removeMessageById,
+ removeMessagesAfterCurrentMessage,
+ } = useSelectDerivedMessages();
+ const { data: conversation, loading } = useFetchConversation();
+ const { conversationId, isNew } = useGetChatSearchParams();
+ const { id: dialogId } = useParams();
+ const prologue = useFindPrologueFromDialogList();
+
+ const addPrologue = useCallback(() => {
+ if (dialogId !== '' && isNew === 'true') {
+ const nextMessage = {
+ role: MessageType.Assistant,
+ content: prologue,
+ id: uuid(),
+ } as IMessage;
+
+ setDerivedMessages([nextMessage]);
+ }
+ }, [dialogId, isNew, prologue, setDerivedMessages]);
+
+ useEffect(() => {
+ addPrologue();
+ }, [addPrologue]);
+
+ useEffect(() => {
+ if (
+ conversationId &&
+ isNew !== 'true' &&
+ conversation.message?.length > 0
+ ) {
+ setDerivedMessages(conversation.message);
+ }
+
+ if (!conversationId) {
+ setDerivedMessages([]);
+ }
+ }, [conversation.message, conversationId, setDerivedMessages, isNew]);
+
+ return {
+ scrollRef,
+ messageContainerRef,
+ derivedMessages,
+ loading,
+ addNewestAnswer,
+ addNewestQuestion,
+ removeLatestMessage,
+ removeMessageById,
+ removeMessagesAfterCurrentMessage,
+ };
+};
+
+export const useSetConversation = () => {
+ const { id: dialogId } = useParams();
+ const { updateConversation } = useUpdateConversation();
+
+ const setConversation = useCallback(
+ async (
+ message: string,
+ isNew: boolean = false,
+ conversationId?: string,
+ ) => {
+ const data = await updateConversation({
+ dialog_id: dialogId,
+ name: message,
+ is_new: isNew,
+ conversation_id: conversationId,
+ message: [
+ {
+ role: MessageType.Assistant,
+ content: message,
+ },
+ ],
+ });
+
+ return data;
+ },
+ [updateConversation, dialogId],
+ );
+
+ return { setConversation };
+};
+
+export const useSendMessage = (controller: AbortController) => {
+ const { setConversation } = useSetConversation();
+ const { conversationId, isNew } = useGetChatSearchParams();
+ const { handleInputChange, value, setValue } = useHandleMessageInputChange();
+
+ const { send, answer, done } = useSendMessageWithSse(
+ api.completeConversation,
+ );
+ const {
+ scrollRef,
+ messageContainerRef,
+ derivedMessages,
+ loading,
+ addNewestAnswer,
+ addNewestQuestion,
+ removeLatestMessage,
+ removeMessageById,
+ removeMessagesAfterCurrentMessage,
+ } = useSelectNextMessages();
+ const { setConversationIsNew, getConversationIsNew } =
+ useSetChatRouteParams();
+
+ const stopOutputMessage = useCallback(() => {
+ controller.abort();
+ }, [controller]);
+
+ const sendMessage = useCallback(
+ async ({
+ message,
+ currentConversationId,
+ messages,
+ }: {
+ message: Message;
+ currentConversationId?: string;
+ messages?: Message[];
+ }) => {
+ const res = await send(
+ {
+ conversation_id: currentConversationId ?? conversationId,
+ messages: [...(messages ?? derivedMessages ?? []), message],
+ },
+ controller,
+ );
+
+ if (res && (res?.response.status !== 200 || res?.data?.code !== 0)) {
+ // cancel loading
+ setValue(message.content);
+ console.info('removeLatestMessage111');
+ removeLatestMessage();
+ }
+ },
+ [
+ derivedMessages,
+ conversationId,
+ removeLatestMessage,
+ setValue,
+ send,
+ controller,
+ ],
+ );
+
+ const handleSendMessage = useCallback(
+ async (message: Message) => {
+ const isNew = getConversationIsNew();
+ if (isNew !== 'true') {
+ sendMessage({ message });
+ } else {
+ const data = await setConversation(
+ message.content,
+ true,
+ conversationId,
+ );
+ if (data.code === 0) {
+ setConversationIsNew('');
+ const id = data.data.id;
+ // currentConversationIdRef.current = id;
+ sendMessage({
+ message,
+ currentConversationId: id,
+ messages: data.data.message,
+ });
+ }
+ }
+ },
+ [
+ setConversation,
+ sendMessage,
+ setConversationIsNew,
+ getConversationIsNew,
+ conversationId,
+ ],
+ );
+
+ const { regenerateMessage } = useRegenerateMessage({
+ removeMessagesAfterCurrentMessage,
+ sendMessage,
+ messages: derivedMessages,
+ });
+
+ useEffect(() => {
+ // #1289
+ if (answer.answer && conversationId && isNew !== 'true') {
+ addNewestAnswer(answer);
+ }
+ }, [answer, addNewestAnswer, conversationId, isNew]);
+
+ const handlePressEnter = useCallback(
+ (documentIds: string[]) => {
+ if (trim(value) === '') return;
+ const id = uuid();
+
+ addNewestQuestion({
+ content: value,
+ doc_ids: documentIds,
+ id,
+ role: MessageType.User,
+ });
+ if (done) {
+ setValue('');
+ handleSendMessage({
+ id,
+ content: value.trim(),
+ role: MessageType.User,
+ doc_ids: documentIds,
+ });
+ }
+ },
+ [addNewestQuestion, handleSendMessage, done, setValue, value],
+ );
+
+ return {
+ handlePressEnter,
+ handleInputChange,
+ value,
+ setValue,
+ regenerateMessage,
+ sendLoading: !done,
+ loading,
+ scrollRef,
+ messageContainerRef,
+ derivedMessages,
+ removeMessageById,
+ stopOutputMessage,
+ };
+};