Fix: Document Previewer is not working #9606 (#9656)

### What problem does this PR solve?
Fix: Document Previewer is not working #9606
### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
balibabu
2025-08-22 12:03:51 +08:00
committed by GitHub
parent 312635cb13
commit 3e6a4b2628
7 changed files with 507 additions and 9 deletions

View File

@ -8,9 +8,13 @@ import {
} from '@/interfaces/database/llm'; } from '@/interfaces/database/llm';
import { buildLlmUuid } from '@/utils/llm-util'; import { buildLlmUuid } from '@/utils/llm-util';
export const enum LLMApiAction {
LlmList = 'llmList',
}
export const useFetchLlmList = (modelType?: LlmModelType) => { export const useFetchLlmList = (modelType?: LlmModelType) => {
const { data } = useQuery<IThirdAiModelCollection>({ const { data } = useQuery<IThirdAiModelCollection>({
queryKey: ['llmList'], queryKey: [LLMApiAction.LlmList],
initialData: {}, initialData: {},
queryFn: async () => { queryFn: async () => {
const { data } = await userService.llm_list({ model_type: modelType }); const { data } = await userService.llm_list({ model_type: modelType });

View File

@ -0,0 +1,464 @@
import message from '@/components/ui/message';
import { LanguageTranslationMap } from '@/constants/common';
import { ResponseGetType } from '@/interfaces/database/base';
import { IToken } from '@/interfaces/database/chat';
import { ITenantInfo } from '@/interfaces/database/knowledge';
import { ILangfuseConfig } from '@/interfaces/database/system';
import {
ISystemStatus,
ITenant,
ITenantUser,
IUserInfo,
} from '@/interfaces/database/user-setting';
import { ISetLangfuseConfigRequestBody } from '@/interfaces/request/system';
import userService, {
addTenantUser,
agreeTenant,
deleteTenantUser,
listTenant,
listTenantUser,
} from '@/services/user-service';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { Modal } from 'antd';
import DOMPurify from 'dompurify';
import { isEmpty } from 'lodash';
import { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { history } from 'umi';
export const enum UserSettingApiAction {
UserInfo = 'userInfo',
TenantInfo = 'tenantInfo',
SaveSetting = 'saveSetting',
FetchManualSystemTokenList = 'fetchManualSystemTokenList',
FetchSystemTokenList = 'fetchSystemTokenList',
RemoveSystemToken = 'removeSystemToken',
CreateSystemToken = 'createSystemToken',
ListTenantUser = 'listTenantUser',
AddTenantUser = 'addTenantUser',
DeleteTenantUser = 'deleteTenantUser',
ListTenant = 'listTenant',
AgreeTenant = 'agreeTenant',
SetLangfuseConfig = 'setLangfuseConfig',
DeleteLangfuseConfig = 'deleteLangfuseConfig',
FetchLangfuseConfig = 'fetchLangfuseConfig',
}
export const useFetchUserInfo = (): ResponseGetType<IUserInfo> => {
const { i18n } = useTranslation();
const { data, isFetching: loading } = useQuery({
queryKey: [UserSettingApiAction.UserInfo],
initialData: {},
gcTime: 0,
queryFn: async () => {
const { data } = await userService.user_info();
if (data.code === 0) {
i18n.changeLanguage(
LanguageTranslationMap[
data.data.language as keyof typeof LanguageTranslationMap
],
);
}
return data?.data ?? {};
},
});
return { data, loading };
};
export const useFetchTenantInfo = (
showEmptyModelWarn = false,
): ResponseGetType<ITenantInfo> => {
const { t } = useTranslation();
const { data, isFetching: loading } = useQuery({
queryKey: [UserSettingApiAction.TenantInfo],
initialData: {},
gcTime: 0,
queryFn: async () => {
const { data: res } = await userService.get_tenant_info();
if (res.code === 0) {
// llm_id is chat_id
// asr_id is speech2txt
const { data } = res;
if (
showEmptyModelWarn &&
(isEmpty(data.embd_id) || isEmpty(data.llm_id))
) {
Modal.warning({
title: t('common.warn'),
content: (
<div
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(t('setting.modelProvidersWarn')),
}}
></div>
),
onOk() {
history.push('/user-setting/model');
},
});
}
data.chat_id = data.llm_id;
data.speech2text_id = data.asr_id;
return data;
}
return res;
},
});
return { data, loading };
};
export const useSelectParserList = (): Array<{
value: string;
label: string;
}> => {
const { data: tenantInfo } = useFetchTenantInfo(true);
const parserList = useMemo(() => {
const parserArray: Array<string> = tenantInfo?.parser_ids?.split(',') ?? [];
return parserArray.map((x) => {
const arr = x.split(':');
return { value: arr[0], label: arr[1] };
});
}, [tenantInfo]);
return parserList;
};
export const useSaveSetting = () => {
const queryClient = useQueryClient();
const { t } = useTranslation();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [UserSettingApiAction.SaveSetting],
mutationFn: async (
userInfo: { new_password: string } | Partial<IUserInfo>,
) => {
const { data } = await userService.setting(userInfo);
if (data.code === 0) {
message.success(t('message.modified'));
queryClient.invalidateQueries({ queryKey: ['userInfo'] });
}
return data?.code;
},
});
return { data, loading, saveSetting: mutateAsync };
};
export const useFetchSystemVersion = () => {
const [version, setVersion] = useState('');
const [loading, setLoading] = useState(false);
const fetchSystemVersion = useCallback(async () => {
try {
setLoading(true);
const { data } = await userService.getSystemVersion();
if (data.code === 0) {
setVersion(data.data);
setLoading(false);
}
} catch (error) {
setLoading(false);
}
}, []);
return { fetchSystemVersion, version, loading };
};
export const useFetchSystemStatus = () => {
const [systemStatus, setSystemStatus] = useState<ISystemStatus>(
{} as ISystemStatus,
);
const [loading, setLoading] = useState(false);
const fetchSystemStatus = useCallback(async () => {
setLoading(true);
const { data } = await userService.getSystemStatus();
if (data.code === 0) {
setSystemStatus(data.data);
setLoading(false);
}
}, []);
return {
systemStatus,
fetchSystemStatus,
loading,
};
};
export const useFetchManualSystemTokenList = () => {
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [UserSettingApiAction.FetchManualSystemTokenList],
mutationFn: async () => {
const { data } = await userService.listToken();
return data?.data ?? [];
},
});
return { data, loading, fetchSystemTokenList: mutateAsync };
};
export const useFetchSystemTokenList = () => {
const {
data,
isFetching: loading,
refetch,
} = useQuery<IToken[]>({
queryKey: [UserSettingApiAction.FetchSystemTokenList],
initialData: [],
gcTime: 0,
queryFn: async () => {
const { data } = await userService.listToken();
return data?.data ?? [];
},
});
return { data, loading, refetch };
};
export const useRemoveSystemToken = () => {
const queryClient = useQueryClient();
const { t } = useTranslation();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [UserSettingApiAction.RemoveSystemToken],
mutationFn: async (token: string) => {
const { data } = await userService.removeToken({}, token);
if (data.code === 0) {
message.success(t('message.deleted'));
queryClient.invalidateQueries({
queryKey: [UserSettingApiAction.FetchSystemTokenList],
});
}
return data?.data ?? [];
},
});
return { data, loading, removeToken: mutateAsync };
};
export const useCreateSystemToken = () => {
const queryClient = useQueryClient();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [UserSettingApiAction.CreateSystemToken],
mutationFn: async (params: Record<string, any>) => {
const { data } = await userService.createToken(params);
if (data.code === 0) {
queryClient.invalidateQueries({
queryKey: [UserSettingApiAction.FetchSystemTokenList],
});
}
return data?.data ?? [];
},
});
return { data, loading, createToken: mutateAsync };
};
export const useListTenantUser = () => {
const { data: tenantInfo } = useFetchTenantInfo();
const tenantId = tenantInfo.tenant_id;
const {
data,
isFetching: loading,
refetch,
} = useQuery<ITenantUser[]>({
queryKey: [UserSettingApiAction.ListTenantUser, tenantId],
initialData: [],
gcTime: 0,
enabled: !!tenantId,
queryFn: async () => {
const { data } = await listTenantUser(tenantId);
return data?.data ?? [];
},
});
return { data, loading, refetch };
};
export const useAddTenantUser = () => {
const { data: tenantInfo } = useFetchTenantInfo();
const queryClient = useQueryClient();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [UserSettingApiAction.AddTenantUser],
mutationFn: async (email: string) => {
const { data } = await addTenantUser(tenantInfo.tenant_id, email);
if (data.code === 0) {
queryClient.invalidateQueries({
queryKey: [UserSettingApiAction.ListTenantUser],
});
}
return data?.code;
},
});
return { data, loading, addTenantUser: mutateAsync };
};
export const useDeleteTenantUser = () => {
const { data: tenantInfo } = useFetchTenantInfo();
const queryClient = useQueryClient();
const { t } = useTranslation();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [UserSettingApiAction.DeleteTenantUser],
mutationFn: async ({
userId,
tenantId,
}: {
userId: string;
tenantId?: string;
}) => {
const { data } = await deleteTenantUser({
tenantId: tenantId ?? tenantInfo.tenant_id,
userId,
});
if (data.code === 0) {
message.success(t('message.deleted'));
queryClient.invalidateQueries({
queryKey: [UserSettingApiAction.ListTenantUser],
});
queryClient.invalidateQueries({
queryKey: [UserSettingApiAction.ListTenant],
});
}
return data?.data ?? [];
},
});
return { data, loading, deleteTenantUser: mutateAsync };
};
export const useListTenant = () => {
const { data: tenantInfo } = useFetchTenantInfo();
const tenantId = tenantInfo.tenant_id;
const {
data,
isFetching: loading,
refetch,
} = useQuery<ITenant[]>({
queryKey: [UserSettingApiAction.ListTenant, tenantId],
initialData: [],
gcTime: 0,
enabled: !!tenantId,
queryFn: async () => {
const { data } = await listTenant();
return data?.data ?? [];
},
});
return { data, loading, refetch };
};
export const useAgreeTenant = () => {
const queryClient = useQueryClient();
const { t } = useTranslation();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [UserSettingApiAction.AgreeTenant],
mutationFn: async (tenantId: string) => {
const { data } = await agreeTenant(tenantId);
if (data.code === 0) {
message.success(t('message.operated'));
queryClient.invalidateQueries({
queryKey: [UserSettingApiAction.ListTenant],
});
}
return data?.data ?? [];
},
});
return { data, loading, agreeTenant: mutateAsync };
};
export const useSetLangfuseConfig = () => {
const { t } = useTranslation();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [UserSettingApiAction.SetLangfuseConfig],
mutationFn: async (params: ISetLangfuseConfigRequestBody) => {
const { data } = await userService.setLangfuseConfig(params);
if (data.code === 0) {
message.success(t('message.operated'));
}
return data?.code;
},
});
return { data, loading, setLangfuseConfig: mutateAsync };
};
export const useDeleteLangfuseConfig = () => {
const { t } = useTranslation();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [UserSettingApiAction.DeleteLangfuseConfig],
mutationFn: async () => {
const { data } = await userService.deleteLangfuseConfig();
if (data.code === 0) {
message.success(t('message.deleted'));
}
return data?.code;
},
});
return { data, loading, deleteLangfuseConfig: mutateAsync };
};
export const useFetchLangfuseConfig = () => {
const { data, isFetching: loading } = useQuery<ILangfuseConfig>({
queryKey: [UserSettingApiAction.FetchLangfuseConfig],
gcTime: 0,
queryFn: async () => {
const { data } = await userService.getLangfuseConfig();
return data?.data;
},
});
return { data, loading };
};

View File

@ -2,6 +2,8 @@ import { LargeModelFormFieldWithoutFilter } from '@/components/large-model-form-
import { LlmSettingSchema } from '@/components/llm-setting-items/next'; import { LlmSettingSchema } from '@/components/llm-setting-items/next';
import { NextMessageInput } from '@/components/message-input/next'; import { NextMessageInput } from '@/components/message-input/next';
import MessageItem from '@/components/message-item'; import MessageItem from '@/components/message-item';
import PdfDrawer from '@/components/pdf-drawer';
import { useClickDrawer } from '@/components/pdf-drawer/hooks';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Form } from '@/components/ui/form'; import { Form } from '@/components/ui/form';
@ -54,7 +56,8 @@ type ChatCardProps = {
} & Pick< } & Pick<
MultipleChatBoxProps, MultipleChatBoxProps,
'controller' | 'removeChatBox' | 'addChatBox' | 'chatBoxIds' 'controller' | 'removeChatBox' | 'addChatBox' | 'chatBoxIds'
>; > &
Pick<ReturnType<typeof useClickDrawer>, 'clickDocumentButton'>;
const ChatCard = forwardRef(function ChatCard( const ChatCard = forwardRef(function ChatCard(
{ {
@ -66,6 +69,7 @@ const ChatCard = forwardRef(function ChatCard(
chatBoxIds, chatBoxIds,
derivedMessages, derivedMessages,
sendLoading, sendLoading,
clickDocumentButton,
}: ChatCardProps, }: ChatCardProps,
ref, ref,
) { ) {
@ -178,6 +182,7 @@ const ChatCard = forwardRef(function ChatCard(
removeMessageById={removeMessageById} removeMessageById={removeMessageById}
regenerateMessage={regenerateMessage} regenerateMessage={regenerateMessage}
sendLoading={sendLoading} sendLoading={sendLoading}
clickDocumentButton={clickDocumentButton}
></MessageItem> ></MessageItem>
); );
})} })}
@ -211,6 +216,8 @@ export function MultipleChatBox({
const { conversationId } = useGetChatSearchParams(); const { conversationId } = useGetChatSearchParams();
const disabled = useGetSendButtonDisabled(); const disabled = useGetSendButtonDisabled();
const sendDisabled = useSendButtonDisabled(value); const sendDisabled = useSendButtonDisabled(value);
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
useClickDrawer();
return ( return (
<section className="h-full flex flex-col px-5"> <section className="h-full flex flex-col px-5">
@ -227,6 +234,7 @@ export function MultipleChatBox({
derivedMessages={messageRecord[id]} derivedMessages={messageRecord[id]}
ref={setFormRef(id)} ref={setFormRef(id)}
sendLoading={sendLoading} sendLoading={sendLoading}
clickDocumentButton={clickDocumentButton}
></ChatCard> ></ChatCard>
))} ))}
</div> </div>
@ -246,6 +254,14 @@ export function MultipleChatBox({
onUpload={handleUploadFile} onUpload={handleUploadFile}
/> />
</div> </div>
{visible && (
<PdfDrawer
visible={visible}
hideModal={hideModal}
documentId={documentId}
chunk={selectedChunk}
></PdfDrawer>
)}
</section> </section>
); );
} }

View File

@ -1,5 +1,7 @@
import { NextMessageInput } from '@/components/message-input/next'; import { NextMessageInput } from '@/components/message-input/next';
import MessageItem from '@/components/message-item'; import MessageItem from '@/components/message-item';
import PdfDrawer from '@/components/pdf-drawer';
import { useClickDrawer } from '@/components/pdf-drawer/hooks';
import { MessageType } from '@/constants/chat'; import { MessageType } from '@/constants/chat';
import { import {
useFetchConversation, useFetchConversation,
@ -43,6 +45,8 @@ export function SingleChatBox({ controller }: IProps) {
const { data: conversation } = useFetchConversation(); const { data: conversation } = useFetchConversation();
const disabled = useGetSendButtonDisabled(); const disabled = useGetSendButtonDisabled();
const sendDisabled = useSendButtonDisabled(value); const sendDisabled = useSendButtonDisabled(value);
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
useClickDrawer();
return ( return (
<section className="flex flex-col p-5 h-full"> <section className="flex flex-col p-5 h-full">
@ -68,7 +72,7 @@ export function SingleChatBox({ controller }: IProps) {
}, },
message, message,
)} )}
// clickDocumentButton={clickDocumentButton} clickDocumentButton={clickDocumentButton}
index={i} index={i}
removeMessageById={removeMessageById} removeMessageById={removeMessageById}
regenerateMessage={regenerateMessage} regenerateMessage={regenerateMessage}
@ -94,6 +98,14 @@ export function SingleChatBox({ controller }: IProps) {
onUpload={handleUploadFile} onUpload={handleUploadFile}
isUploading={isUploading} isUploading={isUploading}
/> />
{visible && (
<PdfDrawer
visible={visible}
hideModal={hideModal}
documentId={documentId}
chunk={selectedChunk}
></PdfDrawer>
)}
</section> </section>
); );
} }

View File

@ -109,13 +109,12 @@ export default function Chat() {
<Card className="flex-1 min-w-0 bg-transparent border h-full"> <Card className="flex-1 min-w-0 bg-transparent border h-full">
<CardContent className="flex p-0 h-full"> <CardContent className="flex p-0 h-full">
<Card className="flex flex-col flex-1 bg-transparent"> <Card className="flex flex-col flex-1 bg-transparent min-w-0">
<CardHeader <CardHeader
className={cn('p-5', { 'border-b': hasSingleChatBox })} className={cn('p-5', { 'border-b': hasSingleChatBox })}
> >
<CardTitle className="flex justify-between items-center text-base"> <CardTitle className="flex justify-between items-center text-base">
<div>{conversation.name}</div> <div className="truncate">{conversation.name}</div>
<Button <Button
variant={'ghost'} variant={'ghost'}
onClick={switchDebugMode} onClick={switchDebugMode}

View File

@ -1,5 +1,6 @@
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 { useFetchTenantInfo } from '@/hooks/use-user-setting-request';
import { IDialog } from '@/interfaces/database/chat'; import { IDialog } from '@/interfaces/database/chat';
import { isEmpty, omit } from 'lodash'; import { isEmpty, omit } from 'lodash';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
@ -14,6 +15,7 @@ export const useRenameChat = () => {
} = useSetModalState(); } = useSetModalState();
const { setDialog, loading } = useSetDialog(); const { setDialog, loading } = useSetDialog();
const { t } = useTranslation(); const { t } = useTranslation();
const tenantInfo = useFetchTenantInfo();
const InitialData = useMemo( const InitialData = useMemo(
() => ({ () => ({
@ -32,13 +34,13 @@ export const useRenameChat = () => {
reasoning: false, reasoning: false,
parameters: [{ key: 'knowledge', optional: false }], parameters: [{ key: 'knowledge', optional: false }],
}, },
llm_id: '', llm_id: tenantInfo.data.llm_id,
llm_setting: {}, llm_setting: {},
similarity_threshold: 0.2, similarity_threshold: 0.2,
vector_similarity_weight: 0.30000000000000004, vector_similarity_weight: 0.30000000000000004,
top_n: 8, top_n: 8,
}), }),
[t], [t, tenantInfo.data.llm_id],
); );
const onChatRenameOk = useCallback( const onChatRenameOk = useCallback(

View File

@ -1,3 +1,4 @@
import showMessage from '@/components/ui/message';
import { MessageType } from '@/constants/chat'; import { MessageType } from '@/constants/chat';
import { import {
useHandleMessageInputChange, useHandleMessageInputChange,
@ -159,7 +160,7 @@ export function useSendMultipleChatMessage(
if (res && (res?.response.status !== 200 || res?.data?.code !== 0)) { if (res && (res?.response.status !== 200 || res?.data?.code !== 0)) {
// cancel loading // cancel loading
setValue(message.content); setValue(message.content);
console.info('removeLatestMessage111'); showMessage.error(res.data.message);
removeLatestMessage(chatBoxId); removeLatestMessage(chatBoxId);
} }
}, },