feat: fetch file thumbnails
This commit is contained in:
parent
eb517f3106
commit
afeb7fddc3
10 changed files with 128 additions and 56 deletions
|
|
@ -150,3 +150,34 @@ export const useFetchKnowledgeList = (
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useSelectFileThumbnails = () => {
|
||||||
|
const fileThumbnails: Record<string, string> = useSelector(
|
||||||
|
(state: any) => state.kFModel.fileThumbnails,
|
||||||
|
);
|
||||||
|
|
||||||
|
return fileThumbnails;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useFetchFileThumbnails = (docIds?: Array<string>) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const fileThumbnails = useSelectFileThumbnails();
|
||||||
|
|
||||||
|
const fetchFileThumbnails = useCallback(
|
||||||
|
(docIds: Array<string>) => {
|
||||||
|
dispatch({
|
||||||
|
type: 'kFModel/fetch_document_thumbnails',
|
||||||
|
payload: { doc_ids: docIds.join(',') },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[dispatch],
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (docIds) {
|
||||||
|
fetchFileThumbnails(docIds);
|
||||||
|
}
|
||||||
|
}, [docIds, fetchFileThumbnails]);
|
||||||
|
|
||||||
|
return { fileThumbnails, fetchFileThumbnails };
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.img {
|
.img {
|
||||||
height: 16px;
|
height: 24px;
|
||||||
width: 16px;
|
width: 24px;
|
||||||
margin-right: 6px;
|
margin-right: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.column {
|
.column {
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import {
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import type { ColumnsType } from 'antd/es/table';
|
import type { ColumnsType } from 'antd/es/table';
|
||||||
import { PaginationProps } from 'antd/lib';
|
import { PaginationProps } from 'antd/lib';
|
||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { Link, useDispatch, useNavigate, useSelector } from 'umi';
|
import { Link, useDispatch, useNavigate, useSelector } from 'umi';
|
||||||
import CreateEPModal from './createEFileModal';
|
import CreateEPModal from './createEFileModal';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
@ -46,7 +46,7 @@ const KnowledgeFile = () => {
|
||||||
const [parser_id, setParserId] = useState('0');
|
const [parser_id, setParserId] = useState('0');
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
|
|
||||||
const getKfList = () => {
|
const getKfList = useCallback(() => {
|
||||||
const payload = {
|
const payload = {
|
||||||
kb_id: knowledgeBaseId,
|
kb_id: knowledgeBaseId,
|
||||||
};
|
};
|
||||||
|
|
@ -55,7 +55,7 @@ const KnowledgeFile = () => {
|
||||||
type: 'kFModel/getKfList',
|
type: 'kFModel/getKfList',
|
||||||
payload,
|
payload,
|
||||||
});
|
});
|
||||||
};
|
}, [dispatch, knowledgeBaseId]);
|
||||||
|
|
||||||
const throttledGetDocumentList = () => {
|
const throttledGetDocumentList = () => {
|
||||||
dispatch({
|
dispatch({
|
||||||
|
|
@ -64,23 +64,29 @@ const KnowledgeFile = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const setPagination = (pageNumber = 1, pageSize?: number) => {
|
const setPagination = useCallback(
|
||||||
const pagination: Pagination = {
|
(pageNumber = 1, pageSize?: number) => {
|
||||||
current: pageNumber,
|
const pagination: Pagination = {
|
||||||
} as Pagination;
|
current: pageNumber,
|
||||||
if (pageSize) {
|
} as Pagination;
|
||||||
pagination.pageSize = pageSize;
|
if (pageSize) {
|
||||||
}
|
pagination.pageSize = pageSize;
|
||||||
dispatch({
|
}
|
||||||
type: 'kFModel/setPagination',
|
dispatch({
|
||||||
payload: pagination,
|
type: 'kFModel/setPagination',
|
||||||
});
|
payload: pagination,
|
||||||
};
|
});
|
||||||
|
},
|
||||||
|
[dispatch],
|
||||||
|
);
|
||||||
|
|
||||||
const onPageChange: PaginationProps['onChange'] = (pageNumber, pageSize) => {
|
const onPageChange: PaginationProps['onChange'] = useCallback(
|
||||||
setPagination(pageNumber, pageSize);
|
(pageNumber: number, pageSize: number) => {
|
||||||
getKfList();
|
setPagination(pageNumber, pageSize);
|
||||||
};
|
getKfList();
|
||||||
|
},
|
||||||
|
[getKfList, setPagination],
|
||||||
|
);
|
||||||
|
|
||||||
const pagination: PaginationProps = useMemo(() => {
|
const pagination: PaginationProps = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
|
|
@ -92,7 +98,7 @@ const KnowledgeFile = () => {
|
||||||
pageSizeOptions: [1, 2, 10, 20, 50, 100],
|
pageSizeOptions: [1, 2, 10, 20, 50, 100],
|
||||||
onChange: onPageChange,
|
onChange: onPageChange,
|
||||||
};
|
};
|
||||||
}, [total, kFModel.pagination]);
|
}, [total, kFModel.pagination, onPageChange]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (knowledgeBaseId) {
|
if (knowledgeBaseId) {
|
||||||
|
|
@ -107,7 +113,7 @@ const KnowledgeFile = () => {
|
||||||
type: 'kFModel/pollGetDocumentList-stop',
|
type: 'kFModel/pollGetDocumentList-stop',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}, [knowledgeBaseId]);
|
}, [knowledgeBaseId, dispatch, getKfList]);
|
||||||
|
|
||||||
const handleInputChange = (
|
const handleInputChange = (
|
||||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||||
|
|
@ -129,14 +135,14 @@ const KnowledgeFile = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const showCEFModal = () => {
|
const showCEFModal = useCallback(() => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'kFModel/updateState',
|
type: 'kFModel/updateState',
|
||||||
payload: {
|
payload: {
|
||||||
isShowCEFwModal: true,
|
isShowCEFwModal: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}, [dispatch]);
|
||||||
|
|
||||||
const actionItems: MenuProps['items'] = useMemo(() => {
|
const actionItems: MenuProps['items'] = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
|
|
@ -169,7 +175,7 @@ const KnowledgeFile = () => {
|
||||||
// disabled: true,
|
// disabled: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}, []);
|
}, [knowledgeBaseId, showCEFModal]);
|
||||||
|
|
||||||
const toChunk = (id: string) => {
|
const toChunk = (id: string) => {
|
||||||
navigate(
|
navigate(
|
||||||
|
|
@ -187,13 +193,9 @@ const KnowledgeFile = () => {
|
||||||
title: 'Name',
|
title: 'Name',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
render: (text: any, { id }) => (
|
render: (text: any, { id, thumbnail }) => (
|
||||||
<div className={styles.tochunks} onClick={() => toChunk(id)}>
|
<div className={styles.tochunks} onClick={() => toChunk(id)}>
|
||||||
<img
|
<img className={styles.img} src={thumbnail} alt="" />
|
||||||
className={styles.img}
|
|
||||||
src="https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg"
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
{text}
|
{text}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ export interface KFModelState extends BaseState {
|
||||||
data: IKnowledgeFile[];
|
data: IKnowledgeFile[];
|
||||||
total: number;
|
total: number;
|
||||||
currentRecord: Nullable<IKnowledgeFile>;
|
currentRecord: Nullable<IKnowledgeFile>;
|
||||||
|
fileThumbnails: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const model: DvaModel<KFModelState> = {
|
const model: DvaModel<KFModelState> = {
|
||||||
|
|
@ -34,6 +35,7 @@ const model: DvaModel<KFModelState> = {
|
||||||
current: 1,
|
current: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
},
|
},
|
||||||
|
fileThumbnails: {} as Record<string, string>,
|
||||||
},
|
},
|
||||||
reducers: {
|
reducers: {
|
||||||
updateState(state, { payload }) {
|
updateState(state, { payload }) {
|
||||||
|
|
@ -54,6 +56,9 @@ const model: DvaModel<KFModelState> = {
|
||||||
setPagination(state, { payload }) {
|
setPagination(state, { payload }) {
|
||||||
return { ...state, pagination: { ...state.pagination, ...payload } };
|
return { ...state, pagination: { ...state.pagination, ...payload } };
|
||||||
},
|
},
|
||||||
|
setFileThumbnails(state, { payload }) {
|
||||||
|
return { ...state, fileThumbnails: payload };
|
||||||
|
},
|
||||||
},
|
},
|
||||||
effects: {
|
effects: {
|
||||||
*createKf({ payload = {} }, { call }) {
|
*createKf({ payload = {} }, { call }) {
|
||||||
|
|
@ -201,6 +206,12 @@ const model: DvaModel<KFModelState> = {
|
||||||
}
|
}
|
||||||
return retcode;
|
return retcode;
|
||||||
},
|
},
|
||||||
|
*fetch_document_thumbnails({ payload = {} }, { call, put }) {
|
||||||
|
const { data } = yield call(kbService.document_thumbnails, payload);
|
||||||
|
if (data.retcode === 0) {
|
||||||
|
yield put({ type: 'setFileThumbnails', payload: data.data });
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
export default model;
|
export default model;
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,7 @@ import { MessageType } from '@/constants/chat';
|
||||||
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
|
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
|
||||||
import { useSelectUserInfo } from '@/hooks/userSettingHook';
|
import { useSelectUserInfo } from '@/hooks/userSettingHook';
|
||||||
import { IReference, Message } from '@/interfaces/database/chat';
|
import { IReference, Message } from '@/interfaces/database/chat';
|
||||||
import {
|
import { Avatar, Button, Flex, Input, List, Popover, Space } from 'antd';
|
||||||
Avatar,
|
|
||||||
Button,
|
|
||||||
Flex,
|
|
||||||
Input,
|
|
||||||
List,
|
|
||||||
Popover,
|
|
||||||
Space,
|
|
||||||
Typography,
|
|
||||||
} from 'antd';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { ChangeEventHandler, useCallback, useMemo, useState } from 'react';
|
import { ChangeEventHandler, useCallback, useMemo, useState } from 'react';
|
||||||
import reactStringReplace from 'react-string-replace';
|
import reactStringReplace from 'react-string-replace';
|
||||||
|
|
@ -26,6 +17,7 @@ import { IClientConversation } from '../interface';
|
||||||
|
|
||||||
import Image from '@/components/image';
|
import Image from '@/components/image';
|
||||||
import NewDocumentLink from '@/components/new-document-link';
|
import NewDocumentLink from '@/components/new-document-link';
|
||||||
|
import { useSelectFileThumbnails } from '@/hooks/knowledgeHook';
|
||||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||||
import Markdown from 'react-markdown';
|
import Markdown from 'react-markdown';
|
||||||
import { visitParents } from 'unist-util-visit-parents';
|
import { visitParents } from 'unist-util-visit-parents';
|
||||||
|
|
@ -56,11 +48,10 @@ const MessageItem = ({
|
||||||
reference: IReference;
|
reference: IReference;
|
||||||
}) => {
|
}) => {
|
||||||
const userInfo = useSelectUserInfo();
|
const userInfo = useSelectUserInfo();
|
||||||
|
const fileThumbnails = useSelectFileThumbnails();
|
||||||
|
|
||||||
const isAssistant = item.role === MessageType.Assistant;
|
const isAssistant = item.role === MessageType.Assistant;
|
||||||
|
|
||||||
const getFileIcon = useGetFileIcon();
|
|
||||||
|
|
||||||
const getPopoverContent = useCallback(
|
const getPopoverContent = useCallback(
|
||||||
(chunkIndex: number) => {
|
(chunkIndex: number) => {
|
||||||
const chunks = reference?.chunks ?? [];
|
const chunks = reference?.chunks ?? [];
|
||||||
|
|
@ -82,15 +73,18 @@ const MessageItem = ({
|
||||||
<Space direction={'vertical'}>
|
<Space direction={'vertical'}>
|
||||||
<div>{chunkItem?.content_with_weight}</div>
|
<div>{chunkItem?.content_with_weight}</div>
|
||||||
{documentId && (
|
{documentId && (
|
||||||
<NewDocumentLink documentId={documentId}>
|
<Flex gap={'middle'}>
|
||||||
{document?.doc_name}
|
<img src={fileThumbnails[documentId]} alt="" />
|
||||||
</NewDocumentLink>
|
<NewDocumentLink documentId={documentId}>
|
||||||
|
{document?.doc_name}
|
||||||
|
</NewDocumentLink>
|
||||||
|
</Flex>
|
||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[reference],
|
[reference, fileThumbnails],
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderReference = useCallback(
|
const renderReference = useCallback(
|
||||||
|
|
@ -163,12 +157,13 @@ const MessageItem = ({
|
||||||
dataSource={referenceDocumentList}
|
dataSource={referenceDocumentList}
|
||||||
renderItem={(item) => (
|
renderItem={(item) => (
|
||||||
<List.Item>
|
<List.Item>
|
||||||
<Typography.Text mark>
|
{/* <SvgIcon name={getFileIcon(item.doc_name)}></SvgIcon> */}
|
||||||
{/* <SvgIcon name={getFileIcon(item.doc_name)}></SvgIcon> */}
|
<Flex gap={'middle'}>
|
||||||
</Typography.Text>
|
<img src={fileThumbnails[item.doc_id]}></img>
|
||||||
<NewDocumentLink documentId={item.doc_id}>
|
<NewDocumentLink documentId={item.doc_id}>
|
||||||
{item.doc_name}
|
{item.doc_name}
|
||||||
</NewDocumentLink>
|
</NewDocumentLink>
|
||||||
|
</Flex>
|
||||||
</List.Item>
|
</List.Item>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -384,7 +384,7 @@ export const useFetchConversation = () => {
|
||||||
|
|
||||||
const fetchConversation = useCallback(() => {
|
const fetchConversation = useCallback(() => {
|
||||||
if (isConversationIdNotExist(conversationId)) {
|
if (isConversationIdNotExist(conversationId)) {
|
||||||
dispatch<any>({
|
dispatch({
|
||||||
type: 'chatModel/getConversation',
|
type: 'chatModel/getConversation',
|
||||||
payload: {
|
payload: {
|
||||||
conversation_id: conversationId,
|
conversation_id: conversationId,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { message } from 'antd';
|
||||||
import { DvaModel } from 'umi';
|
import { DvaModel } from 'umi';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { IClientConversation, IMessage } from './interface';
|
import { IClientConversation, IMessage } from './interface';
|
||||||
|
import { getDocumentIdsFromConversionReference } from './utils';
|
||||||
|
|
||||||
export interface ChatModelState {
|
export interface ChatModelState {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
@ -111,6 +112,12 @@ const model: DvaModel<ChatModelState> = {
|
||||||
*getConversation({ payload }, { call, put }) {
|
*getConversation({ payload }, { call, put }) {
|
||||||
const { data } = yield call(chatService.getConversation, payload);
|
const { data } = yield call(chatService.getConversation, payload);
|
||||||
if (data.retcode === 0) {
|
if (data.retcode === 0) {
|
||||||
|
yield put({
|
||||||
|
type: 'kFModel/fetch_document_thumbnails',
|
||||||
|
payload: {
|
||||||
|
doc_ids: getDocumentIdsFromConversionReference(data.data),
|
||||||
|
},
|
||||||
|
});
|
||||||
yield put({ type: 'setCurrentConversation', payload: data.data });
|
yield put({ type: 'setCurrentConversation', payload: data.data });
|
||||||
}
|
}
|
||||||
return data.retcode;
|
return data.retcode;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { IConversation, IReference } from '@/interfaces/database/chat';
|
||||||
import { EmptyConversationId, variableEnabledFieldMap } from './constants';
|
import { EmptyConversationId, variableEnabledFieldMap } from './constants';
|
||||||
|
|
||||||
export const excludeUnEnabledVariables = (values: any) => {
|
export const excludeUnEnabledVariables = (values: any) => {
|
||||||
|
|
@ -14,3 +15,20 @@ export const excludeUnEnabledVariables = (values: any) => {
|
||||||
export const isConversationIdNotExist = (conversationId: string) => {
|
export const isConversationIdNotExist = (conversationId: string) => {
|
||||||
return conversationId !== EmptyConversationId && conversationId !== '';
|
return conversationId !== EmptyConversationId && conversationId !== '';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getDocumentIdsFromConversionReference = (data: IConversation) => {
|
||||||
|
const documentIds = data.reference.reduce(
|
||||||
|
(pre: Array<string>, cur: IReference) => {
|
||||||
|
cur.doc_aggs
|
||||||
|
.map((x) => x.doc_id)
|
||||||
|
.forEach((x) => {
|
||||||
|
if (pre.every((y) => y !== x)) {
|
||||||
|
pre.push(x);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return pre;
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
return documentIds.join(',');
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ const {
|
||||||
document_rm,
|
document_rm,
|
||||||
document_create,
|
document_create,
|
||||||
document_change_parser,
|
document_change_parser,
|
||||||
|
document_thumbnails,
|
||||||
chunk_list,
|
chunk_list,
|
||||||
create_chunk,
|
create_chunk,
|
||||||
set_chunk,
|
set_chunk,
|
||||||
|
|
@ -75,6 +76,10 @@ const methods = {
|
||||||
url: document_change_parser,
|
url: document_change_parser,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
},
|
},
|
||||||
|
document_thumbnails: {
|
||||||
|
url: document_thumbnails,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
// chunk管理
|
// chunk管理
|
||||||
chunk_list: {
|
chunk_list: {
|
||||||
url: chunk_list,
|
url: chunk_list,
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ export default {
|
||||||
document_create: `${api_host}/document/create`,
|
document_create: `${api_host}/document/create`,
|
||||||
document_run: `${api_host}/document/run`,
|
document_run: `${api_host}/document/run`,
|
||||||
document_change_parser: `${api_host}/document/change_parser`,
|
document_change_parser: `${api_host}/document/change_parser`,
|
||||||
|
document_thumbnails: `${api_host}/document/thumbnails`,
|
||||||
|
|
||||||
setDialog: `${api_host}/dialog/set`,
|
setDialog: `${api_host}/dialog/set`,
|
||||||
getDialog: `${api_host}/dialog/get`,
|
getDialog: `${api_host}/dialog/get`,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue