mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Create a conversation #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -1,12 +1,12 @@
|
|||||||
import message from '@/components/ui/message';
|
import message from '@/components/ui/message';
|
||||||
import { ChatSearchParams } from '@/constants/chat';
|
import { ChatSearchParams } from '@/constants/chat';
|
||||||
import { IDialog } from '@/interfaces/database/chat';
|
import { IDialog } from '@/interfaces/database/chat';
|
||||||
import chatService from '@/services/chat-service';
|
import chatService from '@/services/next-chat-service ';
|
||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
import { useDebounce } from 'ahooks';
|
import { useDebounce } from 'ahooks';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { history, useSearchParams } from 'umi';
|
import { useParams, useSearchParams } from 'umi';
|
||||||
import {
|
import {
|
||||||
useGetPaginationWithRouter,
|
useGetPaginationWithRouter,
|
||||||
useHandleSearchChange,
|
useHandleSearchChange,
|
||||||
@ -16,6 +16,7 @@ export const enum ChatApiAction {
|
|||||||
FetchDialogList = 'fetchDialogList',
|
FetchDialogList = 'fetchDialogList',
|
||||||
RemoveDialog = 'removeDialog',
|
RemoveDialog = 'removeDialog',
|
||||||
SetDialog = 'setDialog',
|
SetDialog = 'setDialog',
|
||||||
|
FetchDialog = 'fetchDialog',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useGetChatSearchParams = () => {
|
export const useGetChatSearchParams = () => {
|
||||||
@ -52,9 +53,7 @@ export const useClickDialogCard = () => {
|
|||||||
return { handleClickDialog };
|
return { handleClickDialog };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useFetchDialogList = (pureFetch = false) => {
|
export const useFetchDialogList = () => {
|
||||||
const { handleClickDialog } = useClickDialogCard();
|
|
||||||
const { dialogId } = useGetChatSearchParams();
|
|
||||||
const { searchString, handleInputChange } = useHandleSearchChange();
|
const { searchString, handleInputChange } = useHandleSearchChange();
|
||||||
const { pagination, setPagination } = useGetPaginationWithRouter();
|
const { pagination, setPagination } = useGetPaginationWithRouter();
|
||||||
const debouncedSearchString = useDebounce(searchString, { wait: 500 });
|
const debouncedSearchString = useDebounce(searchString, { wait: 500 });
|
||||||
@ -63,7 +62,7 @@ export const useFetchDialogList = (pureFetch = false) => {
|
|||||||
data,
|
data,
|
||||||
isFetching: loading,
|
isFetching: loading,
|
||||||
refetch,
|
refetch,
|
||||||
} = useQuery<IDialog[]>({
|
} = useQuery<{ dialogs: IDialog[]; total: number }>({
|
||||||
queryKey: [
|
queryKey: [
|
||||||
ChatApiAction.FetchDialogList,
|
ChatApiAction.FetchDialogList,
|
||||||
{
|
{
|
||||||
@ -71,27 +70,17 @@ export const useFetchDialogList = (pureFetch = false) => {
|
|||||||
...pagination,
|
...pagination,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
initialData: [],
|
initialData: { dialogs: [], total: 0 },
|
||||||
gcTime: 0,
|
gcTime: 0,
|
||||||
refetchOnWindowFocus: false,
|
refetchOnWindowFocus: false,
|
||||||
queryFn: async (...params) => {
|
queryFn: async () => {
|
||||||
console.log('🚀 ~ queryFn: ~ params:', params);
|
const { data } = await chatService.listDialog({
|
||||||
const { data } = await chatService.listDialog();
|
keywords: debouncedSearchString,
|
||||||
|
page_size: pagination.pageSize,
|
||||||
|
page: pagination.current,
|
||||||
|
});
|
||||||
|
|
||||||
if (data.code === 0) {
|
return data?.data ?? { dialogs: [], total: 0 };
|
||||||
const list: IDialog[] = data.data;
|
|
||||||
if (!pureFetch) {
|
|
||||||
if (list.length > 0) {
|
|
||||||
if (list.every((x) => x.id !== dialogId)) {
|
|
||||||
handleClickDialog(data.data[0].id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
history.push('/chat');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data?.data ?? [];
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -147,17 +136,14 @@ export const useSetDialog = () => {
|
|||||||
mutateAsync,
|
mutateAsync,
|
||||||
} = useMutation({
|
} = useMutation({
|
||||||
mutationKey: [ChatApiAction.SetDialog],
|
mutationKey: [ChatApiAction.SetDialog],
|
||||||
mutationFn: async (params: IDialog) => {
|
mutationFn: async (params: Partial<IDialog>) => {
|
||||||
const { data } = await chatService.setDialog(params);
|
const { data } = await chatService.setDialog(params);
|
||||||
if (data.code === 0) {
|
if (data.code === 0) {
|
||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
exact: false,
|
exact: false,
|
||||||
queryKey: ['fetchDialogList'],
|
queryKey: [ChatApiAction.FetchDialogList],
|
||||||
});
|
});
|
||||||
|
|
||||||
queryClient.invalidateQueries({
|
|
||||||
queryKey: ['fetchDialog'],
|
|
||||||
});
|
|
||||||
message.success(
|
message.success(
|
||||||
t(`message.${params.dialog_id ? 'modified' : 'created'}`),
|
t(`message.${params.dialog_id ? 'modified' : 'created'}`),
|
||||||
);
|
);
|
||||||
@ -168,3 +154,29 @@ export const useSetDialog = () => {
|
|||||||
|
|
||||||
return { data, loading, setDialog: mutateAsync };
|
return { data, loading, setDialog: mutateAsync };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useFetchDialog = () => {
|
||||||
|
const { id } = useParams();
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isFetching: loading,
|
||||||
|
refetch,
|
||||||
|
} = useQuery<IDialog>({
|
||||||
|
queryKey: [ChatApiAction.FetchDialog, id],
|
||||||
|
gcTime: 0,
|
||||||
|
initialData: {} as IDialog,
|
||||||
|
enabled: !!id,
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
queryFn: async () => {
|
||||||
|
const { data } = await chatService.getDialog(
|
||||||
|
{ params: { dialogId: id } },
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
return data?.data ?? ({} as IDialog);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading, refetch };
|
||||||
|
};
|
||||||
|
|||||||
@ -2,9 +2,9 @@ import { useFetchDialogList } from '@/hooks/use-chat-request';
|
|||||||
import { ApplicationCard } from './application-card';
|
import { ApplicationCard } from './application-card';
|
||||||
|
|
||||||
export function ChatList() {
|
export function ChatList() {
|
||||||
const { data } = useFetchDialogList(true);
|
const { data } = useFetchDialogList();
|
||||||
|
|
||||||
return data
|
return data.dialogs
|
||||||
.slice(0, 10)
|
.slice(0, 10)
|
||||||
.map((x) => (
|
.map((x) => (
|
||||||
<ApplicationCard
|
<ApplicationCard
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { PageHeader } from '@/components/page-header';
|
import { PageHeader } from '@/components/page-header';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||||
|
import { useFetchDialog } from '@/hooks/use-chat-request';
|
||||||
import { EllipsisVertical } from 'lucide-react';
|
import { EllipsisVertical } from 'lucide-react';
|
||||||
import { AppSettings } from './app-settings';
|
import { AppSettings } from './app-settings';
|
||||||
import { ChatBox } from './chat-box';
|
import { ChatBox } from './chat-box';
|
||||||
@ -8,10 +9,11 @@ import { Sessions } from './sessions';
|
|||||||
|
|
||||||
export default function Chat() {
|
export default function Chat() {
|
||||||
const { navigateToChatList } = useNavigatePage();
|
const { navigateToChatList } = useNavigatePage();
|
||||||
|
useFetchDialog();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="h-full flex flex-col">
|
<section className="h-full flex flex-col">
|
||||||
<PageHeader back={navigateToChatList} title="Chat app 01">
|
<PageHeader>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Button variant={'icon'} size={'icon'}>
|
<Button variant={'icon'} size={'icon'}>
|
||||||
<EllipsisVertical />
|
<EllipsisVertical />
|
||||||
|
|||||||
@ -1,8 +1,33 @@
|
|||||||
import { useSetModalState } from '@/hooks/common-hooks';
|
import { useSetModalState } from '@/hooks/common-hooks';
|
||||||
import { useSetDialog } from '@/hooks/use-chat-request';
|
import { useSetDialog } from '@/hooks/use-chat-request';
|
||||||
import { IDialog } from '@/interfaces/database/chat';
|
import { IDialog } from '@/interfaces/database/chat';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
|
const InitialData = {
|
||||||
|
name: '',
|
||||||
|
icon: '',
|
||||||
|
language: 'English',
|
||||||
|
prompt_config: {
|
||||||
|
empty_response: '',
|
||||||
|
prologue: '你好! 我是你的助理,有什么可以帮到你的吗?',
|
||||||
|
quote: true,
|
||||||
|
keyword: false,
|
||||||
|
tts: false,
|
||||||
|
system:
|
||||||
|
'你是一个智能助手,请总结知识库的内容来回答问题,请列举知识库中的数据详细回答。当所有知识库内容都与问题无关时,你的回答必须包括“知识库中未找到您要的答案!”这句话。回答需要考虑聊天历史。\n 以下是知识库:\n {knowledge}\n 以上是知识库。',
|
||||||
|
refine_multiturn: false,
|
||||||
|
use_kg: false,
|
||||||
|
reasoning: false,
|
||||||
|
parameters: [{ key: 'knowledge', optional: false }],
|
||||||
|
},
|
||||||
|
llm_id: '',
|
||||||
|
llm_setting: {},
|
||||||
|
similarity_threshold: 0.2,
|
||||||
|
vector_similarity_weight: 0.30000000000000004,
|
||||||
|
top_n: 8,
|
||||||
|
};
|
||||||
|
|
||||||
export const useRenameChat = () => {
|
export const useRenameChat = () => {
|
||||||
const [chat, setChat] = useState<IDialog>({} as IDialog);
|
const [chat, setChat] = useState<IDialog>({} as IDialog);
|
||||||
const {
|
const {
|
||||||
@ -14,10 +39,11 @@ export const useRenameChat = () => {
|
|||||||
|
|
||||||
const onChatRenameOk = useCallback(
|
const onChatRenameOk = useCallback(
|
||||||
async (name: string) => {
|
async (name: string) => {
|
||||||
const ret = await setDialog({
|
const nextChat = {
|
||||||
...chat,
|
...(isEmpty(chat) ? InitialData : chat),
|
||||||
name,
|
name,
|
||||||
});
|
};
|
||||||
|
const ret = await setDialog(nextChat);
|
||||||
|
|
||||||
if (ret === 0) {
|
if (ret === 0) {
|
||||||
hideChatRenameModal();
|
hideChatRenameModal();
|
||||||
@ -27,19 +53,26 @@ export const useRenameChat = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleShowChatRenameModal = useCallback(
|
const handleShowChatRenameModal = useCallback(
|
||||||
async (record: IDialog) => {
|
(record?: IDialog) => {
|
||||||
setChat(record);
|
if (record) {
|
||||||
|
setChat(record);
|
||||||
|
}
|
||||||
showChatRenameModal();
|
showChatRenameModal();
|
||||||
},
|
},
|
||||||
[showChatRenameModal],
|
[showChatRenameModal],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleHideModal = useCallback(() => {
|
||||||
|
hideChatRenameModal();
|
||||||
|
setChat({} as IDialog);
|
||||||
|
}, [hideChatRenameModal]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chatRenameLoading: loading,
|
chatRenameLoading: loading,
|
||||||
initialChatName: chat?.name,
|
initialChatName: chat?.name,
|
||||||
onChatRenameOk,
|
onChatRenameOk,
|
||||||
chatRenameVisible,
|
chatRenameVisible,
|
||||||
hideChatRenameModal,
|
hideChatRenameModal: handleHideModal,
|
||||||
showChatRenameModal: handleShowChatRenameModal,
|
showChatRenameModal: handleShowChatRenameModal,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import { ChatCard } from './chat-card';
|
|||||||
import { useRenameChat } from './hooks/use-rename-chat';
|
import { useRenameChat } from './hooks/use-rename-chat';
|
||||||
|
|
||||||
export default function ChatList() {
|
export default function ChatList() {
|
||||||
const { data: chatList, setPagination, pagination } = useFetchDialogList();
|
const { data, setPagination, pagination } = useFetchDialogList();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const {
|
const {
|
||||||
initialChatName,
|
initialChatName,
|
||||||
@ -29,11 +29,15 @@ export default function ChatList() {
|
|||||||
[setPagination],
|
[setPagination],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleShowCreateModal = useCallback(() => {
|
||||||
|
showChatRenameModal();
|
||||||
|
}, [showChatRenameModal]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="flex flex-col w-full flex-1">
|
<section className="flex flex-col w-full flex-1">
|
||||||
<div className="px-8 pt-8">
|
<div className="px-8 pt-8">
|
||||||
<ListFilterBar title="Chat apps">
|
<ListFilterBar title="Chat apps">
|
||||||
<Button>
|
<Button onClick={handleShowCreateModal}>
|
||||||
<Plus className="size-2.5" />
|
<Plus className="size-2.5" />
|
||||||
{t('chat.createChat')}
|
{t('chat.createChat')}
|
||||||
</Button>
|
</Button>
|
||||||
@ -41,7 +45,7 @@ export default function ChatList() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex-1 overflow-auto">
|
<div className="flex-1 overflow-auto">
|
||||||
<div className="flex flex-wrap gap-4 px-8">
|
<div className="flex flex-wrap gap-4 px-8">
|
||||||
{chatList.map((x) => {
|
{data.dialogs.map((x) => {
|
||||||
return (
|
return (
|
||||||
<ChatCard
|
<ChatCard
|
||||||
key={x.id}
|
key={x.id}
|
||||||
@ -65,6 +69,7 @@ export default function ChatList() {
|
|||||||
onOk={onChatRenameOk}
|
onOk={onChatRenameOk}
|
||||||
initialName={initialChatName}
|
initialName={initialChatName}
|
||||||
loading={chatRenameLoading}
|
loading={chatRenameLoading}
|
||||||
|
title={initialChatName || t('chat.createChat')}
|
||||||
></RenameDialog>
|
></RenameDialog>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
133
web/src/services/next-chat-service .ts
Normal file
133
web/src/services/next-chat-service .ts
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import api from '@/utils/api';
|
||||||
|
import { registerNextServer } from '@/utils/register-server';
|
||||||
|
|
||||||
|
const {
|
||||||
|
getDialog,
|
||||||
|
setDialog,
|
||||||
|
listDialog,
|
||||||
|
removeDialog,
|
||||||
|
getConversation,
|
||||||
|
getConversationSSE,
|
||||||
|
setConversation,
|
||||||
|
completeConversation,
|
||||||
|
listConversation,
|
||||||
|
removeConversation,
|
||||||
|
createToken,
|
||||||
|
listToken,
|
||||||
|
removeToken,
|
||||||
|
getStats,
|
||||||
|
createExternalConversation,
|
||||||
|
getExternalConversation,
|
||||||
|
completeExternalConversation,
|
||||||
|
uploadAndParseExternal,
|
||||||
|
deleteMessage,
|
||||||
|
thumbup,
|
||||||
|
tts,
|
||||||
|
ask,
|
||||||
|
mindmap,
|
||||||
|
getRelatedQuestions,
|
||||||
|
listNextDialog,
|
||||||
|
} = api;
|
||||||
|
|
||||||
|
const methods = {
|
||||||
|
getDialog: {
|
||||||
|
url: getDialog,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
setDialog: {
|
||||||
|
url: setDialog,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
removeDialog: {
|
||||||
|
url: removeDialog,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
listDialog: {
|
||||||
|
url: listNextDialog,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
listConversation: {
|
||||||
|
url: listConversation,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
getConversation: {
|
||||||
|
url: getConversation,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
getConversationSSE: {
|
||||||
|
url: getConversationSSE,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
setConversation: {
|
||||||
|
url: setConversation,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
completeConversation: {
|
||||||
|
url: completeConversation,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
removeConversation: {
|
||||||
|
url: removeConversation,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
createToken: {
|
||||||
|
url: createToken,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
listToken: {
|
||||||
|
url: listToken,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
removeToken: {
|
||||||
|
url: removeToken,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
getStats: {
|
||||||
|
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,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
ask: {
|
||||||
|
url: ask,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
getMindMap: {
|
||||||
|
url: mindmap,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
getRelatedQuestions: {
|
||||||
|
url: getRelatedQuestions,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const chatService = registerNextServer<keyof typeof methods>(methods);
|
||||||
|
|
||||||
|
export default chatService;
|
||||||
@ -108,6 +108,9 @@ export default {
|
|||||||
completeExternalConversation: `${api_host}/api/completion`,
|
completeExternalConversation: `${api_host}/api/completion`,
|
||||||
uploadAndParseExternal: `${api_host}/api/document/upload_and_parse`,
|
uploadAndParseExternal: `${api_host}/api/document/upload_and_parse`,
|
||||||
|
|
||||||
|
// next chat
|
||||||
|
listNextDialog: `${api_host}/dialog/next`,
|
||||||
|
|
||||||
// file manager
|
// file manager
|
||||||
listFile: `${api_host}/file/list`,
|
listFile: `${api_host}/file/list`,
|
||||||
uploadFile: `${api_host}/file/upload`,
|
uploadFile: `${api_host}/file/upload`,
|
||||||
|
|||||||
Reference in New Issue
Block a user