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 { 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 { buildMessageListWithUuid, getConversationId } from '@/utils/chat';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useDebounce } from 'ahooks';
|
||||
import { has } from 'lodash';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useParams, useSearchParams } from 'umi';
|
||||
@ -17,6 +23,13 @@ export const enum ChatApiAction {
|
||||
RemoveDialog = 'removeDialog',
|
||||
SetDialog = 'setDialog',
|
||||
FetchDialog = 'fetchDialog',
|
||||
FetchConversationList = 'fetchConversationList',
|
||||
FetchConversation = 'fetchConversation',
|
||||
UpdateConversation = 'updateConversation',
|
||||
RemoveConversation = 'removeConversation',
|
||||
DeleteMessage = 'deleteMessage',
|
||||
FetchMindMap = 'fetchMindMap',
|
||||
FetchRelatedQuestions = 'fetchRelatedQuestions',
|
||||
}
|
||||
|
||||
export const useGetChatSearchParams = () => {
|
||||
@ -74,11 +87,17 @@ export const useFetchDialogList = () => {
|
||||
gcTime: 0,
|
||||
refetchOnWindowFocus: false,
|
||||
queryFn: async () => {
|
||||
const { data } = await chatService.listDialog({
|
||||
const { data } = await chatService.listDialog(
|
||||
{
|
||||
params: {
|
||||
keywords: debouncedSearchString,
|
||||
page_size: pagination.pageSize,
|
||||
page: pagination.current,
|
||||
});
|
||||
},
|
||||
data: {},
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
return data?.data ?? { dialogs: [], total: 0 };
|
||||
},
|
||||
@ -180,3 +199,222 @@ export const useFetchDialog = () => {
|
||||
|
||||
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 { 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 { useFetchDialog } from '@/hooks/use-chat-request';
|
||||
import { EllipsisVertical } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { AppSettings } from './app-settings';
|
||||
import { ChatBox } from './chat-box';
|
||||
import { Sessions } from './sessions';
|
||||
|
||||
export default function Chat() {
|
||||
const { navigateToChatList } = useNavigatePage();
|
||||
useFetchDialog();
|
||||
const { data } = useFetchDialog();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<section className="h-full flex flex-col">
|
||||
<PageHeader>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant={'icon'} size={'icon'}>
|
||||
<EllipsisVertical />
|
||||
</Button>
|
||||
<Button variant={'tertiary'} size={'sm'}>
|
||||
Publish
|
||||
</Button>
|
||||
</div>
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink onClick={navigateToChatList}>
|
||||
{t('chat.chat')}
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>{data.name}</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</PageHeader>
|
||||
<div className="flex flex-1">
|
||||
<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 { 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() {
|
||||
return (
|
||||
<Card className="bg-colors-background-inverse-weak border-colors-outline-neutral-standard">
|
||||
<CardContent className="px-3 py-2 flex justify-between items-center">
|
||||
<Card>
|
||||
<CardContent className="px-3 py-2 flex justify-between items-center group">
|
||||
xxx
|
||||
<Button variant={'icon'} size={'icon'}>
|
||||
<EllipsisVertical />
|
||||
</Button>
|
||||
<MoreButton></MoreButton>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
@ -17,20 +17,19 @@ function SessionCard() {
|
||||
|
||||
export function Sessions() {
|
||||
const sessionList = new Array(10).fill(1);
|
||||
const {} = useFetchConversationList();
|
||||
|
||||
return (
|
||||
<section className="p-6 w-[400px] max-w-[20%]">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<span className="text-colors-text-neutral-strong text-2xl font-bold">
|
||||
Sessions
|
||||
</span>
|
||||
<Button variant={'icon'} size={'icon'}>
|
||||
<span className="text-xl font-bold">Conversations</span>
|
||||
<Button variant={'ghost'}>
|
||||
<Plus></Plus>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
{sessionList.map((x) => (
|
||||
<SessionCard key={x.id}></SessionCard>
|
||||
<SessionCard key={x}></SessionCard>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -11,7 +11,8 @@ import { ChatCard } from './chat-card';
|
||||
import { useRenameChat } from './hooks/use-rename-chat';
|
||||
|
||||
export default function ChatList() {
|
||||
const { data, setPagination, pagination } = useFetchDialogList();
|
||||
const { data, setPagination, pagination, handleInputChange, searchString } =
|
||||
useFetchDialogList();
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
initialChatName,
|
||||
@ -36,7 +37,11 @@ export default function ChatList() {
|
||||
return (
|
||||
<section className="flex flex-col w-full flex-1">
|
||||
<div className="px-8 pt-8">
|
||||
<ListFilterBar title="Chat apps">
|
||||
<ListFilterBar
|
||||
title="Chat apps"
|
||||
onSearchChange={handleInputChange}
|
||||
searchString={searchString}
|
||||
>
|
||||
<Button onClick={handleShowCreateModal}>
|
||||
<Plus className="size-2.5" />
|
||||
{t('chat.createChat')}
|
||||
|
||||
Reference in New Issue
Block a user