Refa: Chat conversations /convsersation API to RESTFul (#13893)

### What problem does this PR solve?

Chat conversations /convsersation API to RESTFul.

### Type of change

- [x] Refactoring
This commit is contained in:
Yongteng Lei
2026-04-02 20:49:23 +08:00
committed by GitHub
parent bbb9b1df85
commit b7daf6285b
43 changed files with 1516 additions and 2002 deletions

View File

@@ -2,7 +2,6 @@
import { CheckIcon, ChevronDownIcon, XIcon } from 'lucide-react';
import {
Fragment,
MouseEventHandler,
ReactNode,
forwardRef,
@@ -207,40 +206,43 @@ export const SelectWithSearch = forwardRef<
<CommandEmpty>
<div dangerouslySetInnerHTML={{ __html: emptyData }}></div>
</CommandEmpty>
{options.map((group) => {
{options.map((group, groupIndex) => {
if (group.options) {
return (
<Fragment key={group.value}>
<CommandGroup heading={group.label} className="mb-1">
{group.options.map((option) => (
<CommandItem
key={option.value}
value={option.value}
disabled={option.disabled}
onSelect={handleSelect}
data-testid={
optionTestIdPrefix && option.value
? `${optionTestIdPrefix}${option.value}`
: 'combobox-option'
}
className={
value === option.value ? 'bg-bg-card' : ''
}
>
<span className="leading-none">{option.label}</span>
<CommandGroup
key={group.value || `group-${groupIndex}`}
heading={group.label}
className="mb-1"
>
{group.options.map((option, optionIndex) => (
<CommandItem
key={
option.value ||
`option-${groupIndex}-${optionIndex}`
}
value={option.value}
disabled={option.disabled}
onSelect={handleSelect}
data-testid={
optionTestIdPrefix && option.value
? `${optionTestIdPrefix}${option.value}`
: 'combobox-option'
}
className={value === option.value ? 'bg-bg-card' : ''}
>
<span className="leading-none">{option.label}</span>
{value === option.value && (
<CheckIcon size={16} className="ml-auto" />
)}
</CommandItem>
))}
</CommandGroup>
</Fragment>
{value === option.value && (
<CheckIcon size={16} className="ml-auto" />
)}
</CommandItem>
))}
</CommandGroup>
);
} else {
return (
<CommandItem
key={group.value}
key={group.value || `item-${groupIndex}`}
value={group.value}
disabled={group.disabled}
onSelect={handleSelect}

View File

@@ -256,7 +256,7 @@ export const AudioButton = ({
formData.append('file', audioFile);
formData.append('stream', 'false');
const response = await fetch(api.sequence2txt, {
const response = await fetch(api.chatsTranscriptions, {
method: 'POST',
headers: {
[Authorization]: getAuthorization(),

View File

@@ -12,7 +12,13 @@ import { forwardRef, useCallback, useEffect } from 'react';
const Select = SelectPrimitive.Root;
const SelectGroup = SelectPrimitive.Group;
const SelectGroup = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Group>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Group>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Group ref={ref} className={cn(className)} {...props} />
));
SelectGroup.displayName = SelectPrimitive.Group.displayName;
const SelectValue = SelectPrimitive.Value;

View File

@@ -201,9 +201,7 @@ function useSetDoneRecord() {
};
}
export const useSendMessageWithSse = (
url: string = api.completeConversation,
) => {
export const useSendMessageWithSse = () => {
const [answer, setAnswer] = useState<IAnswer>({} as IAnswer);
const [done, setDone] = useState(true);
const { doneRecord, clearDoneRecord, setDoneRecordById, allDone } =
@@ -238,6 +236,7 @@ export const useSendMessageWithSse = (
const send = useCallback(
async (
url: string,
body: any,
controller?: AbortController,
): Promise<{ response: Response; data: ResponseType } | undefined> => {
@@ -322,7 +321,7 @@ export const useSendMessageWithSse = (
// Swallow fetch errors silently
}
},
[initializeSseRef, setDoneValue, url, resetAnswer],
[initializeSseRef, setDoneValue, resetAnswer],
);
const stopOutputMessage = useCallback(() => {
@@ -342,7 +341,7 @@ export const useSendMessageWithSse = (
};
};
export const useSpeechWithSse = (url: string = api.tts) => {
export const useSpeechWithSse = (url: string = api.chatsTts) => {
const read = useCallback(
async (body: any) => {
const response = await fetch(url, {

View File

@@ -13,10 +13,9 @@ import {
} from '@/interfaces/request/chat';
import i18n from '@/locales/config';
import { useGetSharedChatSearchParams } from '@/pages/next-chats/hooks/use-send-shared-message';
import { isConversationIdExist } from '@/pages/next-chats/utils';
import chatService from '@/services/next-chat-service';
import api from '@/utils/api';
import { buildMessageListWithUuid, generateConversationId } from '@/utils/chat';
import { buildMessageListWithUuid } from '@/utils/chat';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useDebounce } from 'ahooks';
import { has } from 'lodash';
@@ -36,11 +35,12 @@ export const enum ChatApiAction {
UpdateChat = 'updateChat',
PatchChat = 'patchChat',
FetchChat = 'fetchChat',
FetchConversationList = 'fetchConversationList',
FetchConversation = 'fetchConversation',
FetchConversationManually = 'fetchConversationManually',
UpdateConversation = 'updateConversation',
RemoveConversation = 'removeConversation',
FetchSessionList = 'fetchSessionList',
FetchSession = 'fetchSession',
FetchSessionManually = 'fetchSessionManually',
CreateSession = 'createSession',
UpdateSession = 'updateSession',
RemoveSession = 'removeSession',
DeleteMessage = 'deleteMessage',
FetchMindMap = 'fetchMindMap',
FetchRelatedQuestions = 'fetchRelatedQuestions',
@@ -48,7 +48,6 @@ export const enum ChatApiAction {
FetchExternalChatInfo = 'fetchExternalChatInfo',
Feedback = 'feedback',
CreateSharedConversation = 'createSharedConversation',
FetchConversationSse = 'fetchConversationSSE',
}
export const useGetChatSearchParams = () => {
@@ -262,9 +261,9 @@ export const useFetchChat = () => {
return { data, loading, refetch };
};
//#region Conversation
//#region Session
export const useFetchConversationList = () => {
export const useFetchSessionList = () => {
const { id } = useParams();
const { searchString, handleInputChange } = useHandleSearchStrChange();
@@ -274,7 +273,7 @@ export const useFetchConversationList = () => {
isFetching: loading,
refetch,
} = useQuery<IConversation[]>({
queryKey: [ChatApiAction.FetchConversationList, id],
queryKey: [ChatApiAction.FetchSessionList, id],
initialData: [],
gcTime: 0,
refetchOnWindowFocus: false,
@@ -285,8 +284,8 @@ export const useFetchConversationList = () => {
: data;
},
queryFn: async () => {
const { data } = await chatService.listConversation(
{ params: { dialog_id: id } },
const { data } = await chatService.listSessions(
{ url: api.listSessions(id!) },
true,
);
return data?.data;
@@ -296,35 +295,57 @@ export const useFetchConversationList = () => {
return { data, loading, refetch, searchString, handleInputChange };
};
export function useFetchConversationManually() {
export function useFetchSessionManually() {
const { id: chatId } = useParams();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation<IClientConversation, unknown, string>({
mutationKey: [ChatApiAction.FetchConversationManually],
mutationFn: async (conversationId) => {
const { data } = await chatService.getConversation(
{
params: {
conversationId,
},
},
mutationKey: [ChatApiAction.FetchSessionManually],
mutationFn: async (sessionId) => {
const { data } = await chatService.getSession(
{ url: api.getSession(chatId!, sessionId) },
true,
);
const conversation = data?.data ?? {};
const messageList = buildMessageListWithUuid(conversation?.message);
const messageList = buildMessageListWithUuid(conversation?.messages);
return { ...conversation, message: messageList };
return { ...conversation, messages: messageList };
},
});
return { data, loading, fetchConversationManually: mutateAsync };
return { data, loading, fetchSessionManually: mutateAsync };
}
export const useUpdateConversation = () => {
export const useCreateSession = () => {
const queryClient = useQueryClient();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [ChatApiAction.CreateSession],
mutationFn: async ({ chatId, name }: { chatId: string; name: string }) => {
const { data } = await chatService.createSession(
{ url: api.createSession(chatId), data: { name } },
true,
);
if (data.code === 0) {
queryClient.invalidateQueries({
queryKey: [ChatApiAction.FetchSessionList],
});
}
return data;
},
});
return { data, loading, createSession: mutateAsync };
};
export const useUpdateSession = () => {
const { t } = useTranslation();
const queryClient = useQueryClient();
const {
@@ -332,17 +353,23 @@ export const useUpdateConversation = () => {
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [ChatApiAction.UpdateConversation],
mutationFn: async (params: Record<string, any>) => {
const { data } = await chatService.setConversation({
...params,
conversation_id: params.conversation_id
? params.conversation_id
: generateConversationId(),
});
mutationKey: [ChatApiAction.UpdateSession],
mutationFn: async ({
chatId,
sessionId,
params,
}: {
chatId: string;
sessionId: string;
params: Record<string, any>;
}) => {
const { data } = await chatService.updateSession(
{ url: api.updateSession(chatId, sessionId), data: params },
true,
);
if (data.code === 0) {
queryClient.invalidateQueries({
queryKey: [ChatApiAction.FetchConversationList],
queryKey: [ChatApiAction.FetchSessionList],
});
message.success(t(`message.modified`));
}
@@ -350,38 +377,39 @@ export const useUpdateConversation = () => {
},
});
return { data, loading, updateConversation: mutateAsync };
return { data, loading, updateSession: mutateAsync };
};
export const useRemoveConversation = () => {
export const useRemoveSessions = () => {
const queryClient = useQueryClient();
const { dialogId } = useGetChatSearchParams();
const { id: chatId } = useParams();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [ChatApiAction.RemoveConversation],
mutationFn: async (conversationIds: string[]) => {
const { data } = await chatService.removeConversation({
conversationIds,
dialogId,
});
mutationKey: [ChatApiAction.RemoveSession],
mutationFn: async (sessionIds: string[]) => {
const { data } = await chatService.removeSessions(
{ url: api.removeSessions(chatId!), data: { ids: sessionIds } },
true,
);
if (data.code === 0) {
queryClient.invalidateQueries({
queryKey: [ChatApiAction.FetchConversationList],
queryKey: [ChatApiAction.FetchSessionList],
});
}
return data.code;
},
});
return { data, loading, removeConversation: mutateAsync };
return { data, loading, removeSessions: mutateAsync };
};
export const useDeleteMessage = () => {
const { conversationId } = useGetChatSearchParams();
const { id: chatId } = useParams();
const { t } = useTranslation();
const {
@@ -391,10 +419,10 @@ export const useDeleteMessage = () => {
} = useMutation({
mutationKey: [ChatApiAction.DeleteMessage],
mutationFn: async (messageId: string) => {
const { data } = await chatService.deleteMessage({
messageId,
conversationId,
});
const { data } = await chatService.deleteMessage(
{ url: api.deleteMessage(chatId!, conversationId, messageId) },
true,
);
if (data.code === 0) {
message.success(t(`message.deleted`));
@@ -409,6 +437,7 @@ export const useDeleteMessage = () => {
export const useFeedback = () => {
const { conversationId } = useGetChatSearchParams();
const { id: chatId } = useParams();
const {
data,
@@ -417,10 +446,13 @@ export const useFeedback = () => {
} = useMutation({
mutationKey: [ChatApiAction.Feedback],
mutationFn: async (params: IFeedbackRequestBody) => {
const { data } = await chatService.thumbup({
...params,
conversationId,
});
const { data } = await chatService.thumbup(
{
url: api.thumbup(chatId!, conversationId, params.messageId!),
data: { thumbup: params.thumbup, feedback: params.feedback },
},
true,
);
if (data.code === 0) {
message.success(i18n.t(`message.operated`));
}
@@ -519,7 +551,7 @@ export const useFetchExternalChatInfo = () => {
return { data, loading, refetch };
};
//#endregion
//#endregion Session
//#region search page
@@ -533,7 +565,7 @@ export const useFetchMindMap = () => {
gcTime: 0,
mutationFn: async (params: IAskRequestBody) => {
try {
const ret = await chatService.getMindMap(params);
const ret = await chatService.chatsMindmap(params);
return ret?.data?.data ?? {};
} catch (error: any) {
if (has(error, 'message')) {
@@ -557,7 +589,7 @@ export const useFetchRelatedQuestions = () => {
mutationKey: [ChatApiAction.FetchRelatedQuestions],
gcTime: 0,
mutationFn: async (question: string): Promise<string[]> => {
const { data } = await chatService.getRelatedQuestions({ question });
const { data } = await chatService.chatsRelatedQuestions({ question });
return data?.data ?? [];
},
@@ -566,47 +598,3 @@ export const useFetchRelatedQuestions = () => {
return { data, loading, fetchRelatedQuestions: mutateAsync };
};
//#endregion
export const useCreateNextSharedConversation = () => {
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [ChatApiAction.CreateSharedConversation],
mutationFn: async (userId?: string) => {
const { data } = await chatService.createExternalConversation({ userId });
return data;
},
});
return { data, loading, createSharedConversation: mutateAsync };
};
export const useFetchNextConversationSSE = () => {
const { isNew } = useGetChatSearchParams();
const { sharedId } = useGetSharedChatSearchParams();
const {
data,
isFetching: loading,
refetch,
} = useQuery<IClientConversation>({
queryKey: [ChatApiAction.FetchConversationSse, sharedId],
initialData: {} as IClientConversation,
gcTime: 0,
refetchOnWindowFocus: false,
queryFn: async () => {
if (isNew !== 'true' && isConversationIdExist(sharedId || '')) {
if (!sharedId) return {};
const { data } = await chatService.getConversationSSE(sharedId);
const conversation = data?.data ?? {};
const messageList = buildMessageListWithUuid(conversation?.message);
return { ...conversation, message: messageList };
}
return { message: [] };
},
});
return { data, loading, refetch };
};

View File

@@ -2,7 +2,6 @@ import message from '@/components/ui/message';
import { Authorization } from '@/constants/authorization';
import { IReferenceObject } from '@/interfaces/database/chat';
import { BeginQuery } from '@/pages/agent/interface';
import api from '@/utils/api';
import { getAuthorization } from '@/utils/authorization-util';
import { EventSourceParserStream } from 'eventsource-parser/stream';
import { useCallback, useRef, useState } from 'react';
@@ -86,7 +85,7 @@ export type IChatEvent = INodeEvent | IMessageEvent | IMessageEndEvent;
export type IEventList = Array<IChatEvent>;
export const useSendMessageBySSE = (url: string = api.completeConversation) => {
export const useSendMessageBySSE = (url: string) => {
const [answerList, setAnswerList] = useState<IEventList>([]);
const [done, setDone] = useState(true);
const timer = useRef<any>();

View File

@@ -82,10 +82,10 @@ interface Manual {
export interface IConversation {
create_date: string;
create_time: number;
dialog_id: string;
chat_id: string;
id: string;
avatar: string;
message: Message[];
messages: Message[];
reference: IReference[];
name: string;
update_date: string;
@@ -197,7 +197,7 @@ export interface IMessage extends Message {
}
export interface IClientConversation extends IConversation {
message: IMessage[];
messages: IMessage[];
}
export interface UploadResponseDataType {

View File

@@ -3,10 +3,10 @@ import { IMessage, IReference } from '@/interfaces/database/chat';
import { isEmpty } from 'lodash';
export const buildAgentMessageItemReference = (
conversation: { message: IMessage[]; reference: IReference[] },
conversation: { messages: IMessage[]; reference: IReference[] },
message: IMessage,
) => {
const assistantMessages = conversation.message?.filter(
const assistantMessages = conversation.messages?.filter(
(x) => x.role === MessageType.Assistant,
);
const referenceIndex = assistantMessages.findIndex(

View File

@@ -240,7 +240,7 @@ const ChatCard = forwardRef(function ChatCard(
avatarDialog={currentDialog.icon}
reference={buildMessageItemReference(
{
message: derivedMessages,
messages: derivedMessages,
reference: conversation.reference,
},
message,

View File

@@ -56,11 +56,11 @@ export function SingleChatBox({
const showInternet = useShowInternet();
useEffect(() => {
const messages = conversation?.message;
const messages = conversation?.messages;
if (Array.isArray(messages)) {
setDerivedMessages(messages);
}
}, [conversation?.message, setDerivedMessages]);
}, [conversation?.messages, setDerivedMessages]);
useEffect(() => {
// Clear the message list after deleting the conversation.
@@ -90,7 +90,7 @@ export function SingleChatBox({
avatarDialog={currentDialog.icon}
reference={buildMessageItemReference(
{
message: derivedMessages,
messages: derivedMessages,
reference: conversation.reference,
},
message,

View File

@@ -7,7 +7,7 @@ import {
} from '@/components/ui/dropdown-menu';
import {
useGetChatSearchParams,
useRemoveConversation,
useRemoveSessions,
} from '@/hooks/use-chat-request';
import { IConversation } from '@/interfaces/database/chat';
import { Trash2 } from 'lucide-react';
@@ -25,7 +25,7 @@ export function ConversationDropdown({
}) {
const { t } = useTranslation();
const { setConversationBoth } = useChatUrlParams();
const { removeConversation } = useRemoveConversation();
const { removeSessions } = useRemoveSessions();
const { conversationId, isNew } = useGetChatSearchParams();
const handleDelete: MouseEventHandler<HTMLDivElement> =
@@ -36,7 +36,7 @@ export function ConversationDropdown({
setConversationBoth('', '');
}
} else {
const code = await removeConversation([conversation.id]);
const code = await removeSessions([conversation.id]);
if (code === 0) {
setConversationBoth('', '');
}
@@ -45,7 +45,7 @@ export function ConversationDropdown({
conversation.id,
conversationId,
isNew,
removeConversation,
removeSessions,
removeTemporaryConversation,
setConversationBoth,
]);

View File

@@ -1,8 +1,8 @@
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import {
useFetchConversationList,
useFetchConversationManually,
useFetchSessionList,
useFetchSessionManually,
useGetChatSearchParams,
} from '@/hooks/use-chat-request';
import { IClientConversation } from '@/interfaces/database/chat';
@@ -26,7 +26,7 @@ export default function Chat() {
const [currentConversation, setCurrentConversation] =
useState<IClientConversation>({} as IClientConversation);
const { fetchConversationManually } = useFetchConversationManually();
const { fetchSessionManually } = useFetchSessionManually();
const { handleConversationCardClick, controller, stopOutputMessage } =
useHandleClickConversationCard();
@@ -37,7 +37,7 @@ export default function Chat() {
const { conversationId, isNew } = useGetChatSearchParams();
const { data: dialogList } = useFetchConversationList();
const { data: dialogList } = useFetchSessionList();
const currentConversationName = useMemo(() => {
return (
@@ -49,13 +49,13 @@ export default function Chat() {
const fetchConversation: typeof handleConversationCardClick = useCallback(
async (conversationId, isNew) => {
if (conversationId && !isNew) {
const conversation = await fetchConversationManually(conversationId);
const conversation = await fetchSessionManually(conversationId);
if (!isEmpty(conversation)) {
setCurrentConversation(conversation);
}
}
},
[fetchConversationManually],
[fetchSessionManually],
);
const handleSessionClick: typeof handleConversationCardClick = useCallback(

View File

@@ -16,7 +16,7 @@ import { useSetModalState } from '@/hooks/common-hooks';
import {
useFetchChat,
useGetChatSearchParams,
useRemoveConversation,
useRemoveSessions,
} from '@/hooks/use-chat-request';
import {
LucideCopyX,
@@ -50,7 +50,7 @@ export function Sessions({ handleConversationCardClick }: SessionProps) {
} = useSelectDerivedConversationList();
const { data } = useFetchChat();
const { visible, switchVisible } = useSetModalState(true);
const { removeConversation } = useRemoveConversation();
const { removeSessions } = useRemoveSessions();
const { setConversationBoth } = useChatUrlParams();
const { conversationId } = useGetChatSearchParams();
@@ -118,7 +118,7 @@ export function Sessions({ handleConversationCardClick }: SessionProps) {
let removeCode = -1;
if (persistedIds.length > 0) {
removeCode = await removeConversation(persistedIds);
removeCode = await removeSessions(persistedIds);
}
if (currentConversationDeleted && conversationId) {
@@ -136,7 +136,7 @@ export function Sessions({ handleConversationCardClick }: SessionProps) {
conversationList,
setConversationBoth,
removeTemporaryConversation,
removeConversation,
removeSessions,
exitSelectionMode,
]);

View File

@@ -1,7 +1,6 @@
import { ChatSearchParams } from '@/constants/chat';
import { useGetChatSearchParams } from '@/hooks/use-chat-request';
import { IMessage } from '@/interfaces/database/chat';
import { generateConversationId } from '@/utils/chat';
import { useCallback, useMemo } from 'react';
import { useSearchParams } from 'react-router';
import { useSetConversation } from './use-set-conversation';
@@ -57,38 +56,32 @@ export const useChatUrlParams = () => {
export function useCreateConversationBeforeSendMessage() {
const { conversationId, isNew } = useGetChatSearchParams();
const { setConversation } = useSetConversation();
const { setIsNew, setConversationBoth } = useChatUrlParams();
const { setConversationBoth } = useChatUrlParams();
// Create conversation if it doesn't exist
const createConversationBeforeSendMessage = useCallback(
async (value: string) => {
let currentMessages: Array<IMessage> = [];
const currentConversationId = generateConversationId();
if (conversationId === '' || isNew === 'true') {
if (conversationId === '') {
setConversationBoth(currentConversationId, 'true');
}
const data = await setConversation(
value,
true,
conversationId || currentConversationId,
);
if (data.code !== 0) {
const data = await setConversation(value);
if (!data || data.code !== 0) {
return;
} else {
setIsNew('');
currentMessages = data.data.message;
}
const backendConvId = data.data.id;
setConversationBoth(backendConvId, '');
currentMessages = data.data.messages;
return {
targetConversationId: backendConvId,
currentMessages,
};
}
const targetConversationId = conversationId || currentConversationId;
return {
targetConversationId,
targetConversationId: conversationId,
currentMessages,
};
},
[conversationId, isNew, setConversation, setConversationBoth, setIsNew],
[conversationId, isNew, setConversation, setConversationBoth],
);
return {

View File

@@ -12,7 +12,7 @@ export const useCreateConversationBeforeUploadDocument = () => {
async (message: string) => {
const isNew = getIsNew();
if (isNew === 'true') {
const data = await setConversation(message, true);
const data = await setConversation(message);
return data;
}

View File

@@ -2,7 +2,7 @@ import { MessageType } from '@/constants/chat';
import { useTranslate } from '@/hooks/common-hooks';
import {
useFetchChatList,
useFetchConversationList,
useFetchSessionList,
} from '@/hooks/use-chat-request';
import { IConversation } from '@/interfaces/database/chat';
import { generateConversationId } from '@/utils/chat';
@@ -30,7 +30,7 @@ export const useSelectDerivedConversationList = () => {
loading,
handleInputChange,
searchString,
} = useFetchConversationList();
} = useFetchSessionList();
const { id: dialogId } = useParams();
const prologue = useFindPrologueFromDialogList();
@@ -45,9 +45,9 @@ export const useSelectDerivedConversationList = () => {
{
id: conversationId,
name: t('newConversation'),
dialog_id: dialogId,
chat_id: dialogId,
is_new: true,
message: [
messages: [
{
content: prologue,
role: MessageType.Assistant,

View File

@@ -70,9 +70,8 @@ export const useSendMessage = (controller: AbortController) => {
const { handleUploadFile, isUploading, removeFile, files, clearFiles } =
useUploadFile();
const { send, answer, done } = useSendMessageWithSse(
api.completeConversation,
);
const { id: chatId } = useParams();
const { send, answer, done } = useSendMessageWithSse();
const {
scrollRef,
messageContainerRef,
@@ -97,9 +96,10 @@ export const useSendMessage = (controller: AbortController) => {
currentConversationId?: string;
messages?: IMessage[];
} & NextMessageInputOnPressEnterParameter) => {
const sessionId = currentConversationId ?? conversationId;
const res = await send(
api.completionUrl(chatId!, sessionId),
{
conversation_id: currentConversationId ?? conversationId,
messages: [
...(Array.isArray(messages) && messages?.length > 0
? messages
@@ -122,6 +122,7 @@ export const useSendMessage = (controller: AbortController) => {
[
derivedMessages,
conversationId,
chatId,
removeLatestMessage,
setValue,
send,

View File

@@ -6,7 +6,6 @@ import {
useSelectDerivedMessages,
useSendMessageWithSse,
} from '@/hooks/logic-hooks';
import { useCreateNextSharedConversation } from '@/hooks/use-chat-request';
import { Message } from '@/interfaces/database/chat';
import { get } from 'lodash';
import trim from 'lodash/trim';
@@ -47,12 +46,9 @@ export const useSendSharedMessage = () => {
sharedId: conversationId,
data: data,
} = useGetSharedChatSearchParams();
const { createSharedConversation: setConversation } =
useCreateNextSharedConversation();
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
const { send, answer, done, stopOutputMessage } = useSendMessageWithSse(
`/api/v1/${from === SharedFrom.Agent ? 'agentbots' : 'chatbots'}/${conversationId}/completions`,
);
const completionUrl = `/api/v1/${from === SharedFrom.Agent ? 'agentbots' : 'chatbots'}/${conversationId}/completions`;
const { send, answer, done, stopOutputMessage } = useSendMessageWithSse();
const {
derivedMessages,
removeLatestMessage,
@@ -72,7 +68,7 @@ export const useSendSharedMessage = () => {
enableThinking?: boolean,
enableInternet?: boolean,
) => {
const res = await send({
const res = await send(completionUrl, {
conversation_id: id ?? conversationId,
quote: true,
question: message.content,
@@ -87,7 +83,14 @@ export const useSendSharedMessage = () => {
removeLatestMessage();
}
},
[send, conversationId, derivedMessages, setValue, removeLatestMessage],
[
send,
completionUrl,
conversationId,
derivedMessages,
setValue,
removeLatestMessage,
],
);
const handleSendMessage = useCallback(
@@ -96,27 +99,19 @@ export const useSendSharedMessage = () => {
enableThinking?: boolean,
enableInternet?: boolean,
) => {
if (conversationId !== '') {
sendMessage(message, undefined, enableThinking, enableInternet);
} else {
const data = await setConversation('user id');
if (data.code === 0) {
const id = data.data.id;
sendMessage(message, id, enableThinking, enableInternet);
}
}
sendMessage(message, undefined, enableThinking, enableInternet);
},
[conversationId, setConversation, sendMessage],
[sendMessage],
);
const fetchSessionId = useCallback(async () => {
const payload = { question: '' };
const ret = await send({ ...payload, ...data });
const ret = await send(completionUrl, { ...payload, ...data });
if (isCompletionError(ret)) {
message.error(ret?.data.message);
setHasError(true);
}
}, [send]);
}, [send, completionUrl]);
useEffect(() => {
fetchSessionId();

View File

@@ -9,6 +9,7 @@ import { useGetChatSearchParams } from '@/hooks/use-chat-request';
import { IMessage } from '@/interfaces/database/chat';
import api from '@/utils/api';
import { useCallback, useEffect } from 'react';
import { useParams } from 'react-router';
import { v4 as uuid } from 'uuid';
import { CreateConversationBeforeSendMessageReturnType } from './use-chat-url';
import { useUploadFile } from './use-upload-file';
@@ -29,10 +30,9 @@ export function useSendSingleMessage({
} & Pick<ReturnType<typeof useHandleMessageInputChange>, 'value' | 'setValue'> &
Pick<ReturnType<typeof useUploadFile>, 'files' | 'clearFiles'>) {
const { conversationId } = useGetChatSearchParams();
const { id: chatId } = useParams();
const { send, answer, done } = useSendMessageWithSse(
api.completeConversation,
);
const { send, answer, done } = useSendMessageWithSse();
const {
scrollRef,
@@ -65,9 +65,10 @@ export function useSendSingleMessage({
currentConversationId?: string;
messages?: IMessage[];
} & NextMessageInputOnPressEnterParameter) => {
const sessionId = currentConversationId ?? conversationId;
const res = await send(
api.completionUrl(chatId!, sessionId),
{
conversation_id: currentConversationId ?? conversationId,
messages: [
...(Array.isArray(messages) && messages?.length > 0
? messages

View File

@@ -1,35 +1,17 @@
import { MessageType } from '@/constants/chat';
import { useUpdateConversation } from '@/hooks/use-chat-request';
import { useCreateSession } from '@/hooks/use-chat-request';
import { useCallback } from 'react';
import { useParams } from 'react-router';
export const useSetConversation = () => {
const { id: dialogId } = useParams();
const { updateConversation } = useUpdateConversation();
const { id: chatId } = useParams();
const { createSession } = useCreateSession();
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,
conversationId,
},
],
});
async (name: string) => {
const data = await createSession({ chatId: chatId!, name });
return data;
},
[updateConversation, dialogId],
[createSession, chatId],
);
return { setConversation };

View File

@@ -3,7 +3,6 @@ import {
useGetChatSearchParams,
useUploadAndParseFile,
} from '@/hooks/use-chat-request';
import { generateConversationId } from '@/utils/chat';
import { useCallback, useState } from 'react';
import { useChatUrlParams } from './use-chat-url';
import { useSetConversation } from './use-set-conversation';
@@ -16,7 +15,7 @@ export function useUploadFile() {
);
const { setConversation } = useSetConversation();
const { conversationId, isNew } = useGetChatSearchParams();
const { setIsNew, setConversationBoth } = useChatUrlParams();
const { setConversationBoth } = useChatUrlParams();
type FileUploadParameters = Parameters<
NonNullable<FileUploadProps['onUpload']>
@@ -58,20 +57,11 @@ export function useUploadFile() {
Array.isArray(files) &&
files.length
) {
const currentConversationId = generateConversationId();
if (conversationId === '') {
setConversationBoth(currentConversationId, 'true');
}
const data = await setConversation(
files[0].name,
true,
conversationId || currentConversationId,
);
if (data.code === 0) {
setIsNew('');
handleUploadFile(files, options, data.data?.id);
const data = await setConversation(files[0].name);
if (data?.code === 0) {
const backendConvId = data.data.id;
setConversationBoth(backendConvId, '');
handleUploadFile(files, options, backendConvId);
}
} else {
handleUploadFile(files, options);
@@ -83,7 +73,6 @@ export function useUploadFile() {
isNew,
setConversation,
setConversationBoth,
setIsNew,
],
);

View File

@@ -6,13 +6,10 @@ import { useClickDrawer } from '@/components/pdf-drawer/hooks';
import { useSyncThemeFromParams } from '@/components/theme-provider';
import { MessageType, SharedFrom } from '@/constants/chat';
import { useFetchFlowSSE } from '@/hooks/use-agent-request';
import {
useFetchExternalChatInfo,
useFetchNextConversationSSE,
} from '@/hooks/use-chat-request';
import { useFetchExternalChatInfo } from '@/hooks/use-chat-request';
import i18n, { changeLanguageAsync } from '@/locales/config';
import { buildMessageUuidWithRole } from '@/utils/chat';
import React, { forwardRef, useMemo } from 'react';
import React, { forwardRef } from 'react';
import { useSendButtonDisabled } from '../hooks/use-button-disabled';
import {
useGetSharedChatSearchParams,
@@ -47,18 +44,15 @@ const ChatContainer = () => {
const sendDisabled = useSendButtonDisabled(value);
const { data: chatInfo } = useFetchExternalChatInfo();
const useFetchAvatar = useMemo(() => {
return from === SharedFrom.Agent
? useFetchFlowSSE
: useFetchNextConversationSSE;
}, [from]);
const { data: flowData } = useFetchFlowSSE();
React.useEffect(() => {
if (locale && i18n.language !== locale) {
changeLanguageAsync(locale);
}
}, [locale, visibleAvatar]);
const { data: avatarData } = useFetchAvatar();
const avatarDialogSrc =
from === SharedFrom.Agent ? flowData?.avatar : chatInfo.avatar;
if (!conversationId) {
return <div>empty</div>;
@@ -84,12 +78,12 @@ const ChatContainer = () => {
<MessageItem
visibleAvatar={visibleAvatar}
key={buildMessageUuidWithRole(message)}
avatarDialog={avatarData?.avatar}
avatarDialog={avatarDialogSrc}
item={message}
nickname="You"
reference={buildMessageItemReference(
{
message: derivedMessages,
messages: derivedMessages,
reference: [],
},
message,

View File

@@ -28,10 +28,10 @@ export const getDocumentIdsFromConversionReference = (data: IConversation) => {
};
export const buildMessageItemReference = (
conversation: { message: IMessage[]; reference: IReference[] },
conversation: { messages: IMessage[]; reference: IReference[] },
message: IMessage,
) => {
const assistantMessages = conversation.message
const assistantMessages = conversation.messages
?.filter(
(x) =>
x.role === MessageType.Assistant && !x.content.startsWith('**ERROR**:'), // Exclude error messages

View File

@@ -68,7 +68,7 @@ export const useSearchFetchMindMap = () => {
const sharedId = searchParams.get('shared_id');
const fetchMindMapFunc = sharedId
? searchService.mindmapShare
: chatService.getMindMap;
: chatService.chatsMindmap;
const {
data,
isPending: loading,
@@ -280,7 +280,7 @@ export const useFetchRelatedQuestions = (
const shared_id = searchParams.get('shared_id');
const retrievalTestFunc = shared_id
? searchService.getRelatedQuestionsShare
: chatService.getRelatedQuestions;
: chatService.chatsRelatedQuestions;
const {
data,
isPending: loading,
@@ -309,9 +309,8 @@ export const useSendQuestion = (
related_search: boolean = false,
) => {
const { sharedId } = useGetSharedSearchParams();
const { send, answer, done, stopOutputMessage } = useSendMessageWithSse(
sharedId ? api.askShare : api.ask,
);
const askUrl = sharedId ? api.askShare : api.ask;
const { send, answer, done, stopOutputMessage } = useSendMessageWithSse();
const { testChunk, loading } = useTestChunkRetrieval(tenantId);
const { testChunkAll } = useTestChunkAllRetrieval(tenantId);
@@ -334,7 +333,12 @@ export const useSendQuestion = (
setCurrentAnswer({} as IAnswer);
if (enableAI) {
setSendingLoading(true);
send({ kb_ids: kbIds, question: q, tenantId, search_id: searchId });
send(askUrl, {
kb_ids: kbIds,
question: q,
tenantId,
search_id: searchId,
});
}
testChunk({
kb_id: kbIds,

View File

@@ -9,26 +9,21 @@ const {
patchChat,
deleteChat,
bulkDeleteChats,
getConversation,
getConversationSSE,
setConversation,
completeConversation,
listConversation,
removeConversation,
createSession,
listSessions,
getSession,
updateSession,
removeSessions,
deleteMessage,
thumbup,
createToken,
listToken,
removeToken,
getStats,
createExternalConversation,
getExternalConversation,
completeExternalConversation,
uploadAndParseExternal,
deleteMessage,
thumbup,
tts,
chatsTts,
ask,
mindmap,
getRelatedQuestions,
chatsMindmap,
chatsRelatedQuestions,
upload_and_parse,
fetchExternalChatInfo,
} = api;
@@ -62,29 +57,33 @@ const methods = {
url: bulkDeleteChats,
method: 'delete',
},
listConversation: {
url: listConversation,
method: 'get',
},
getConversation: {
url: getConversation,
method: 'get',
},
getConversationSSE: {
url: getConversationSSE,
method: 'get',
},
setConversation: {
url: setConversation,
createSession: {
url: createSession,
method: 'post',
},
completeConversation: {
url: completeConversation,
method: 'post',
listSessions: {
url: listSessions,
method: 'get',
},
removeConversation: {
url: removeConversation,
method: 'post',
getSession: {
url: getSession,
method: 'get',
},
updateSession: {
url: updateSession,
method: 'put',
},
removeSessions: {
url: removeSessions,
method: 'delete',
},
deleteMessage: {
url: deleteMessage,
method: 'delete',
},
thumbup: {
url: thumbup,
method: 'put',
},
createToken: {
url: createToken,
@@ -102,44 +101,20 @@ const methods = {
url: getStats,
method: 'get',
},
createExternalConversation: {
url: createExternalConversation,
method: 'get',
},
getExternalConversation: {
url: getExternalConversation,
method: 'get',
},
completeExternalConversation: {
url: completeExternalConversation,
method: 'post',
},
uploadAndParseExternal: {
url: uploadAndParseExternal,
method: 'post',
},
deleteMessage: {
url: deleteMessage,
method: 'post',
},
thumbup: {
url: thumbup,
method: 'post',
},
tts: {
url: tts,
chatsTts: {
url: chatsTts,
method: 'post',
},
ask: {
url: ask,
method: 'post',
},
getMindMap: {
url: mindmap,
chatsMindmap: {
url: chatsMindmap,
method: 'post',
},
getRelatedQuestions: {
url: getRelatedQuestions,
chatsRelatedQuestions: {
url: chatsRelatedQuestions,
method: 'post',
},
uploadAndParse: {

View File

@@ -52,7 +52,7 @@ export default {
// plugin
llm_tools: `${api_host}/plugin/llm_tools`,
sequence2txt: `${api_host}/conversation/sequence2txt`,
chatsTranscriptions: `${ExternalApi}${api_host}/chats/transcriptions`,
// knowledge base
@@ -135,28 +135,31 @@ export default {
patchChat: (chatId: string) => `${ExternalApi}${api_host}/chats/${chatId}`,
deleteChat: (chatId: string) => `${ExternalApi}${api_host}/chats/${chatId}`,
bulkDeleteChats: `${ExternalApi}${api_host}/chats`,
setConversation: `${api_host}/conversation/set`,
getConversation: `${api_host}/conversation/get`,
getConversationSSE: (dialogId: string) =>
`${api_host}/conversation/getsse/${dialogId}`,
listConversation: `${api_host}/conversation/list`,
removeConversation: `${api_host}/conversation/rm`,
completeConversation: `${api_host}/conversation/completion`,
deleteMessage: `${api_host}/conversation/delete_msg`,
thumbup: `${api_host}/conversation/thumbup`,
tts: `${api_host}/conversation/tts`,
ask: `${api_host}/conversation/ask`,
mindmap: `${api_host}/conversation/mindmap`,
getRelatedQuestions: `${api_host}/conversation/related_questions`,
createSession: (chatId: string) =>
`${ExternalApi}${api_host}/chats/${chatId}/sessions`,
listSessions: (chatId: string) =>
`${ExternalApi}${api_host}/chats/${chatId}/sessions`,
getSession: (chatId: string, sessionId: string) =>
`${ExternalApi}${api_host}/chats/${chatId}/sessions/${sessionId}`,
updateSession: (chatId: string, sessionId: string) =>
`${ExternalApi}${api_host}/chats/${chatId}/sessions/${sessionId}`,
removeSessions: (chatId: string) =>
`${ExternalApi}${api_host}/chats/${chatId}/sessions`,
deleteMessage: (chatId: string, sessionId: string, msgId: string) =>
`${ExternalApi}${api_host}/chats/${chatId}/sessions/${sessionId}/messages/${msgId}`,
thumbup: (chatId: string, sessionId: string, msgId: string) =>
`${ExternalApi}${api_host}/chats/${chatId}/sessions/${sessionId}/messages/${msgId}/feedback`,
completionUrl: (chatId: string, sessionId: string) =>
`${ExternalApi}${api_host}/chats/${chatId}/sessions/${sessionId}/completions`,
chatsTts: `${ExternalApi}${api_host}/chats/tts`,
ask: `${ExternalApi}${api_host}/chats/ask`,
chatsMindmap: `${ExternalApi}${api_host}/chats/mindmap`,
chatsRelatedQuestions: `${ExternalApi}${api_host}/chats/related_questions`,
// chat for external
createToken: `${api_host}/api/new_token`,
listToken: `${api_host}/api/token_list`,
removeToken: `${api_host}/api/rm`,
getStats: `${api_host}/api/stats`,
createExternalConversation: `${api_host}/api/new_conversation`,
getExternalConversation: `${api_host}/api/conversation`,
completeExternalConversation: `${api_host}/api/completion`,
uploadAndParseExternal: `${api_host}/api/document/upload_and_parse`,
// next chat
fetchExternalChatInfo: (id: string) =>