mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Search conversation by name #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -1,9 +1,15 @@
|
|||||||
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 { IConversation, IDialog } from '@/interfaces/database/chat';
|
||||||
|
import { IAskRequestBody } from '@/interfaces/request/chat';
|
||||||
|
import { IClientConversation } from '@/pages/next-chats/chat/interface';
|
||||||
|
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 chatService from '@/services/next-chat-service ';
|
||||||
|
import { buildMessageListWithUuid, getConversationId } from '@/utils/chat';
|
||||||
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 { has } from 'lodash';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useParams, useSearchParams } from 'umi';
|
import { useParams, useSearchParams } from 'umi';
|
||||||
@ -17,6 +23,13 @@ export const enum ChatApiAction {
|
|||||||
RemoveDialog = 'removeDialog',
|
RemoveDialog = 'removeDialog',
|
||||||
SetDialog = 'setDialog',
|
SetDialog = 'setDialog',
|
||||||
FetchDialog = 'fetchDialog',
|
FetchDialog = 'fetchDialog',
|
||||||
|
FetchConversationList = 'fetchConversationList',
|
||||||
|
FetchConversation = 'fetchConversation',
|
||||||
|
UpdateConversation = 'updateConversation',
|
||||||
|
RemoveConversation = 'removeConversation',
|
||||||
|
DeleteMessage = 'deleteMessage',
|
||||||
|
FetchMindMap = 'fetchMindMap',
|
||||||
|
FetchRelatedQuestions = 'fetchRelatedQuestions',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useGetChatSearchParams = () => {
|
export const useGetChatSearchParams = () => {
|
||||||
@ -74,11 +87,17 @@ export const useFetchDialogList = () => {
|
|||||||
gcTime: 0,
|
gcTime: 0,
|
||||||
refetchOnWindowFocus: false,
|
refetchOnWindowFocus: false,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await chatService.listDialog({
|
const { data } = await chatService.listDialog(
|
||||||
|
{
|
||||||
|
params: {
|
||||||
keywords: debouncedSearchString,
|
keywords: debouncedSearchString,
|
||||||
page_size: pagination.pageSize,
|
page_size: pagination.pageSize,
|
||||||
page: pagination.current,
|
page: pagination.current,
|
||||||
});
|
},
|
||||||
|
data: {},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
return data?.data ?? { dialogs: [], total: 0 };
|
return data?.data ?? { dialogs: [], total: 0 };
|
||||||
},
|
},
|
||||||
@ -180,3 +199,222 @@ export const useFetchDialog = () => {
|
|||||||
|
|
||||||
return { data, loading, refetch };
|
return { data, loading, refetch };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//#region Conversation
|
||||||
|
|
||||||
|
export const useClickConversationCard = () => {
|
||||||
|
const [currentQueryParameters, setSearchParams] = useSearchParams();
|
||||||
|
const newQueryParameters: URLSearchParams = useMemo(
|
||||||
|
() => new URLSearchParams(currentQueryParameters.toString()),
|
||||||
|
[currentQueryParameters],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleClickConversation = useCallback(
|
||||||
|
(conversationId: string, isNew: string) => {
|
||||||
|
newQueryParameters.set(ChatSearchParams.ConversationId, conversationId);
|
||||||
|
newQueryParameters.set(ChatSearchParams.isNew, isNew);
|
||||||
|
setSearchParams(newQueryParameters);
|
||||||
|
},
|
||||||
|
[setSearchParams, newQueryParameters],
|
||||||
|
);
|
||||||
|
|
||||||
|
return { handleClickConversation };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useFetchConversationList = () => {
|
||||||
|
const { id } = useParams();
|
||||||
|
const { handleClickConversation } = useClickConversationCard();
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isFetching: loading,
|
||||||
|
refetch,
|
||||||
|
} = useQuery<IConversation[]>({
|
||||||
|
queryKey: [ChatApiAction.FetchConversationList, id],
|
||||||
|
initialData: [],
|
||||||
|
gcTime: 0,
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
enabled: !!id,
|
||||||
|
queryFn: async () => {
|
||||||
|
const { data } = await chatService.listConversation(
|
||||||
|
{ params: { dialog_id: id } },
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
if (data.code === 0) {
|
||||||
|
if (data.data.length > 0) {
|
||||||
|
handleClickConversation(data.data[0].id, '');
|
||||||
|
} else {
|
||||||
|
handleClickConversation('', '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data?.data;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading, refetch };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useFetchConversation = () => {
|
||||||
|
const { isNew, conversationId } = useGetChatSearchParams();
|
||||||
|
const { sharedId } = useGetSharedChatSearchParams();
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isFetching: loading,
|
||||||
|
refetch,
|
||||||
|
} = useQuery<IClientConversation>({
|
||||||
|
queryKey: [ChatApiAction.FetchConversation, conversationId],
|
||||||
|
initialData: {} as IClientConversation,
|
||||||
|
// enabled: isConversationIdExist(conversationId),
|
||||||
|
gcTime: 0,
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
queryFn: async () => {
|
||||||
|
if (
|
||||||
|
isNew !== 'true' &&
|
||||||
|
isConversationIdExist(sharedId || conversationId)
|
||||||
|
) {
|
||||||
|
const { data } = await chatService.getConversation({
|
||||||
|
conversationId: conversationId || sharedId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const conversation = data?.data ?? {};
|
||||||
|
|
||||||
|
const messageList = buildMessageListWithUuid(conversation?.message);
|
||||||
|
|
||||||
|
return { ...conversation, message: messageList };
|
||||||
|
}
|
||||||
|
return { message: [] };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading, refetch };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdateConversation = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
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
|
||||||
|
: getConversationId(),
|
||||||
|
});
|
||||||
|
if (data.code === 0) {
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: [ChatApiAction.FetchConversationList],
|
||||||
|
});
|
||||||
|
message.success(t(`message.modified`));
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading, updateConversation: mutateAsync };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useRemoveConversation = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const { dialogId } = useGetChatSearchParams();
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isPending: loading,
|
||||||
|
mutateAsync,
|
||||||
|
} = useMutation({
|
||||||
|
mutationKey: [ChatApiAction.RemoveConversation],
|
||||||
|
mutationFn: async (conversationIds: string[]) => {
|
||||||
|
const { data } = await chatService.removeConversation({
|
||||||
|
conversationIds,
|
||||||
|
dialogId,
|
||||||
|
});
|
||||||
|
if (data.code === 0) {
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: [ChatApiAction.FetchConversationList],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return data.code;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading, removeConversation: mutateAsync };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDeleteMessage = () => {
|
||||||
|
const { conversationId } = useGetChatSearchParams();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isPending: loading,
|
||||||
|
mutateAsync,
|
||||||
|
} = useMutation({
|
||||||
|
mutationKey: [ChatApiAction.DeleteMessage],
|
||||||
|
mutationFn: async (messageId: string) => {
|
||||||
|
const { data } = await chatService.deleteMessage({
|
||||||
|
messageId,
|
||||||
|
conversationId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (data.code === 0) {
|
||||||
|
message.success(t(`message.deleted`));
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.code;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading, deleteMessage: mutateAsync };
|
||||||
|
};
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region search page
|
||||||
|
|
||||||
|
export const useFetchMindMap = () => {
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isPending: loading,
|
||||||
|
mutateAsync,
|
||||||
|
} = useMutation({
|
||||||
|
mutationKey: [ChatApiAction.FetchMindMap],
|
||||||
|
gcTime: 0,
|
||||||
|
mutationFn: async (params: IAskRequestBody) => {
|
||||||
|
try {
|
||||||
|
const ret = await chatService.getMindMap(params);
|
||||||
|
return ret?.data?.data ?? {};
|
||||||
|
} catch (error: any) {
|
||||||
|
if (has(error, 'message')) {
|
||||||
|
message.error(error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading, fetchMindMap: mutateAsync };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useFetchRelatedQuestions = () => {
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isPending: loading,
|
||||||
|
mutateAsync,
|
||||||
|
} = useMutation({
|
||||||
|
mutationKey: [ChatApiAction.FetchRelatedQuestions],
|
||||||
|
gcTime: 0,
|
||||||
|
mutationFn: async (question: string): Promise<string[]> => {
|
||||||
|
const { data } = await chatService.getRelatedQuestions({ question });
|
||||||
|
|
||||||
|
return data?.data ?? [];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading, fetchRelatedQuestions: mutateAsync };
|
||||||
|
};
|
||||||
|
//#endregion
|
||||||
|
|||||||
@ -1,27 +1,40 @@
|
|||||||
import { PageHeader } from '@/components/page-header';
|
import { PageHeader } from '@/components/page-header';
|
||||||
import { Button } from '@/components/ui/button';
|
import {
|
||||||
|
Breadcrumb,
|
||||||
|
BreadcrumbItem,
|
||||||
|
BreadcrumbLink,
|
||||||
|
BreadcrumbList,
|
||||||
|
BreadcrumbPage,
|
||||||
|
BreadcrumbSeparator,
|
||||||
|
} from '@/components/ui/breadcrumb';
|
||||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||||
import { useFetchDialog } from '@/hooks/use-chat-request';
|
import { useFetchDialog } from '@/hooks/use-chat-request';
|
||||||
import { EllipsisVertical } from 'lucide-react';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { AppSettings } from './app-settings';
|
import { AppSettings } from './app-settings';
|
||||||
import { ChatBox } from './chat-box';
|
import { ChatBox } from './chat-box';
|
||||||
import { Sessions } from './sessions';
|
import { Sessions } from './sessions';
|
||||||
|
|
||||||
export default function Chat() {
|
export default function Chat() {
|
||||||
const { navigateToChatList } = useNavigatePage();
|
const { navigateToChatList } = useNavigatePage();
|
||||||
useFetchDialog();
|
const { data } = useFetchDialog();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="h-full flex flex-col">
|
<section className="h-full flex flex-col">
|
||||||
<PageHeader>
|
<PageHeader>
|
||||||
<div className="flex items-center gap-2">
|
<Breadcrumb>
|
||||||
<Button variant={'icon'} size={'icon'}>
|
<BreadcrumbList>
|
||||||
<EllipsisVertical />
|
<BreadcrumbItem>
|
||||||
</Button>
|
<BreadcrumbLink onClick={navigateToChatList}>
|
||||||
<Button variant={'tertiary'} size={'sm'}>
|
{t('chat.chat')}
|
||||||
Publish
|
</BreadcrumbLink>
|
||||||
</Button>
|
</BreadcrumbItem>
|
||||||
</div>
|
<BreadcrumbSeparator />
|
||||||
|
<BreadcrumbItem>
|
||||||
|
<BreadcrumbPage>{data.name}</BreadcrumbPage>
|
||||||
|
</BreadcrumbItem>
|
||||||
|
</BreadcrumbList>
|
||||||
|
</Breadcrumb>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<div className="flex flex-1">
|
<div className="flex flex-1">
|
||||||
<Sessions></Sessions>
|
<Sessions></Sessions>
|
||||||
|
|||||||
33
web/src/pages/next-chats/chat/interface.ts
Normal file
33
web/src/pages/next-chats/chat/interface.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { IConversation, IReference, Message } from '@/interfaces/database/chat';
|
||||||
|
import { FormInstance } from 'antd';
|
||||||
|
|
||||||
|
export interface ISegmentedContentProps {
|
||||||
|
show: boolean;
|
||||||
|
form: FormInstance;
|
||||||
|
setHasError: (hasError: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IVariable {
|
||||||
|
temperature: number;
|
||||||
|
top_p: number;
|
||||||
|
frequency_penalty: number;
|
||||||
|
presence_penalty: number;
|
||||||
|
max_tokens: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VariableTableDataType {
|
||||||
|
key: string;
|
||||||
|
variable: string;
|
||||||
|
optional: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IPromptConfigParameters = Omit<VariableTableDataType, 'variable'>;
|
||||||
|
|
||||||
|
export interface IMessage extends Message {
|
||||||
|
id: string;
|
||||||
|
reference?: IReference; // the latest news has reference
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IClientConversation extends IConversation {
|
||||||
|
message: IMessage[];
|
||||||
|
}
|
||||||
@ -1,15 +1,15 @@
|
|||||||
|
import { MoreButton } from '@/components/more-button';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Card, CardContent } from '@/components/ui/card';
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
import { EllipsisVertical, Plus } from 'lucide-react';
|
import { useFetchConversationList } from '@/hooks/use-chat-request';
|
||||||
|
import { Plus } from 'lucide-react';
|
||||||
|
|
||||||
function SessionCard() {
|
function SessionCard() {
|
||||||
return (
|
return (
|
||||||
<Card className="bg-colors-background-inverse-weak border-colors-outline-neutral-standard">
|
<Card>
|
||||||
<CardContent className="px-3 py-2 flex justify-between items-center">
|
<CardContent className="px-3 py-2 flex justify-between items-center group">
|
||||||
xxx
|
xxx
|
||||||
<Button variant={'icon'} size={'icon'}>
|
<MoreButton></MoreButton>
|
||||||
<EllipsisVertical />
|
|
||||||
</Button>
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
@ -17,20 +17,19 @@ function SessionCard() {
|
|||||||
|
|
||||||
export function Sessions() {
|
export function Sessions() {
|
||||||
const sessionList = new Array(10).fill(1);
|
const sessionList = new Array(10).fill(1);
|
||||||
|
const {} = useFetchConversationList();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="p-6 w-[400px] max-w-[20%]">
|
<section className="p-6 w-[400px] max-w-[20%]">
|
||||||
<div className="flex justify-between items-center mb-4">
|
<div className="flex justify-between items-center mb-4">
|
||||||
<span className="text-colors-text-neutral-strong text-2xl font-bold">
|
<span className="text-xl font-bold">Conversations</span>
|
||||||
Sessions
|
<Button variant={'ghost'}>
|
||||||
</span>
|
|
||||||
<Button variant={'icon'} size={'icon'}>
|
|
||||||
<Plus></Plus>
|
<Plus></Plus>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{sessionList.map((x) => (
|
{sessionList.map((x) => (
|
||||||
<SessionCard key={x.id}></SessionCard>
|
<SessionCard key={x}></SessionCard>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -11,7 +11,8 @@ 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, setPagination, pagination } = useFetchDialogList();
|
const { data, setPagination, pagination, handleInputChange, searchString } =
|
||||||
|
useFetchDialogList();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const {
|
const {
|
||||||
initialChatName,
|
initialChatName,
|
||||||
@ -36,7 +37,11 @@ export default function ChatList() {
|
|||||||
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"
|
||||||
|
onSearchChange={handleInputChange}
|
||||||
|
searchString={searchString}
|
||||||
|
>
|
||||||
<Button onClick={handleShowCreateModal}>
|
<Button onClick={handleShowCreateModal}>
|
||||||
<Plus className="size-2.5" />
|
<Plus className="size-2.5" />
|
||||||
{t('chat.createChat')}
|
{t('chat.createChat')}
|
||||||
|
|||||||
Reference in New Issue
Block a user