diff --git a/frontend/src/app/api/knowledge/delVectorDocs/route.ts b/frontend/src/app/api/knowledge/delVectorDocs/route.ts new file mode 100644 index 00000000..2dad6f62 --- /dev/null +++ b/frontend/src/app/api/knowledge/delVectorDocs/route.ts @@ -0,0 +1,13 @@ +import { getServerConfig } from '@/config/server'; +const { KNOWLEDGE_PROXY_URL } = getServerConfig(); +export const POST = async (request: Request) => { + const params = await request.json(); + const fetchRes = await fetch(`${KNOWLEDGE_PROXY_URL}/delete_docs`, { + body: JSON.stringify(params), + headers: { + 'Content-Type': 'application/json', + }, + method: 'POST', + }); + return fetchRes +}; diff --git a/frontend/src/app/api/knowledge/deleteDocs/route.ts b/frontend/src/app/api/knowledge/deleteDocs/route.ts new file mode 100644 index 00000000..2dad6f62 --- /dev/null +++ b/frontend/src/app/api/knowledge/deleteDocs/route.ts @@ -0,0 +1,13 @@ +import { getServerConfig } from '@/config/server'; +const { KNOWLEDGE_PROXY_URL } = getServerConfig(); +export const POST = async (request: Request) => { + const params = await request.json(); + const fetchRes = await fetch(`${KNOWLEDGE_PROXY_URL}/delete_docs`, { + body: JSON.stringify(params), + headers: { + 'Content-Type': 'application/json', + }, + method: 'POST', + }); + return fetchRes +}; diff --git a/frontend/src/app/api/knowledge/downloadDocs/route.ts b/frontend/src/app/api/knowledge/downloadDocs/route.ts new file mode 100644 index 00000000..0877da14 --- /dev/null +++ b/frontend/src/app/api/knowledge/downloadDocs/route.ts @@ -0,0 +1,13 @@ +import { getServerConfig } from '@/config/server'; +const { KNOWLEDGE_PROXY_URL } = getServerConfig(); + +export const GET = async (request: Request) => { + const searchParams = new URL(request.url).searchParams; + const knowledge_base_name = searchParams.get('knowledge_base_name') as string; + const file_name = searchParams.get('file_name') as string; + const preview = searchParams.get('preview') as string; + + const queryString = new URLSearchParams({ knowledge_base_name, file_name, preview }).toString(); + const fetchRes = await fetch(`${KNOWLEDGE_PROXY_URL}/download_doc?${queryString}`); + return fetchRes; +}; diff --git a/frontend/src/app/api/knowledge/listFiles/route.ts b/frontend/src/app/api/knowledge/listFiles/route.ts new file mode 100644 index 00000000..b625da85 --- /dev/null +++ b/frontend/src/app/api/knowledge/listFiles/route.ts @@ -0,0 +1,9 @@ +import { getServerConfig } from '@/config/server'; + +const { KNOWLEDGE_PROXY_URL } = getServerConfig(); +export const GET = async (request: Request) => { + const knowledge_base_name: string = new URL(request.url).searchParams.get('knowledge_base_name') as string; + const queryString = new URLSearchParams({ knowledge_base_name }).toString(); + const fetchRes = await fetch(`${KNOWLEDGE_PROXY_URL}/list_files?${queryString}`); + return fetchRes; +}; diff --git a/frontend/src/app/api/knowledge/reAddVectorDB/route.ts b/frontend/src/app/api/knowledge/reAddVectorDB/route.ts new file mode 100644 index 00000000..cc59e1d5 --- /dev/null +++ b/frontend/src/app/api/knowledge/reAddVectorDB/route.ts @@ -0,0 +1,14 @@ + +import { getServerConfig } from '@/config/server'; +const { KNOWLEDGE_PROXY_URL } = getServerConfig(); +export const POST = async (request: Request) => { + const params = await request.json(); + const fetchRes = await fetch(`${KNOWLEDGE_PROXY_URL}/recreate_vector_store`, { + body: JSON.stringify(params), + headers: { + 'Content-Type': 'application/json', + }, + method: 'POST', + }); + return fetchRes +}; diff --git a/frontend/src/app/api/knowledge/rebuildVectorDB/route.ts b/frontend/src/app/api/knowledge/rebuildVectorDB/route.ts new file mode 100644 index 00000000..cc59e1d5 --- /dev/null +++ b/frontend/src/app/api/knowledge/rebuildVectorDB/route.ts @@ -0,0 +1,14 @@ + +import { getServerConfig } from '@/config/server'; +const { KNOWLEDGE_PROXY_URL } = getServerConfig(); +export const POST = async (request: Request) => { + const params = await request.json(); + const fetchRes = await fetch(`${KNOWLEDGE_PROXY_URL}/recreate_vector_store`, { + body: JSON.stringify(params), + headers: { + 'Content-Type': 'application/json', + }, + method: 'POST', + }); + return fetchRes +}; diff --git a/frontend/src/app/api/knowledge/uploadDocs/route.ts b/frontend/src/app/api/knowledge/uploadDocs/route.ts new file mode 100644 index 00000000..a5902c72 --- /dev/null +++ b/frontend/src/app/api/knowledge/uploadDocs/route.ts @@ -0,0 +1,12 @@ + +import { getServerConfig } from '@/config/server'; +const { KNOWLEDGE_PROXY_URL } = getServerConfig(); + +export const POST = async (request: Request) => { + const formData = await request.formData(); + const fetchRes = await fetch(`${KNOWLEDGE_PROXY_URL}/upload_docs`, { + body: formData, + method: 'POST', + }); + return fetchRes +}; diff --git a/frontend/src/app/api/knowledge/接口存在问题.txt b/frontend/src/app/api/knowledge/接口存在问题.txt deleted file mode 100644 index 4547f0d7..00000000 --- a/frontend/src/app/api/knowledge/接口存在问题.txt +++ /dev/null @@ -1,3 +0,0 @@ - - -1. 创建接口没有简介字段 diff --git a/frontend/src/app/knowledge/(desktop)/features/KnowledgeCard.tsx b/frontend/src/app/knowledge/(desktop)/features/KnowledgeCard.tsx index 81d9bf03..506dba07 100644 --- a/frontend/src/app/knowledge/(desktop)/features/KnowledgeCard.tsx +++ b/frontend/src/app/knowledge/(desktop)/features/KnowledgeCard.tsx @@ -2,7 +2,7 @@ import { DeleteOutlined, EditOutlined, ExclamationCircleOutlined } from '@ant-de import { Card, Skeleton, message, Modal } from 'antd'; import { useRouter } from 'next/navigation'; import React, { useState } from 'react'; -import { useKnowledgeStore } from '@/store/knowledge'; +import { useKnowledgeStore } from '@/store/knowledge'; const { Meta } = Card; @@ -11,16 +11,18 @@ interface KnowLedgeCardProps { name: string; } const KnowledgeCard: React.FC = (props: KnowLedgeCardProps) => { + - const [useFetchKnowledgeDel] = useKnowledgeStore((s) => [ - s.useFetchKnowledgeDel + const [useFetchKnowledgeDel, useFetchKnowledgeList] = useKnowledgeStore((s) => [ + s.useFetchKnowledgeDel, s.useFetchKnowledgeList ]); + const { mutate } = useFetchKnowledgeList() const [loading, setLoading] = useState(false); const { name, intro } = props; const router = useRouter(); const handleCardEditClick = () => { - router.push('/knowledge/1/base'); + router.push(`/knowledge/${encodeURIComponent(name)}/base`); }; const delClick = async () => { Modal.confirm({ @@ -31,7 +33,8 @@ const KnowledgeCard: React.FC = (props: KnowLedgeCardProps) if (resCode !== 200) { message.error(resMsg) } else { - message.success(resMsg) + message.success(resMsg) + mutate() } return Promise.resolve(); }, diff --git a/frontend/src/app/knowledge/(desktop)/features/KnowledgeList.tsx b/frontend/src/app/knowledge/(desktop)/features/KnowledgeList.tsx index 3ecb7737..d65d1161 100644 --- a/frontend/src/app/knowledge/(desktop)/features/KnowledgeList.tsx +++ b/frontend/src/app/knowledge/(desktop)/features/KnowledgeList.tsx @@ -20,11 +20,6 @@ const useStyles = createStyles(({ css, token, stylish }) => ({ `, })); -// const list = [ -// { intro: '知识库简介', name: '知识库名称' }, -// { intro: '知识库简介', name: '知识库名称' }, -// ]; - const RenderList = memo(() => { const { styles } = useStyles(); const [listData, useFetchKnowledgeList] = useKnowledgeStore((s) => [ @@ -32,11 +27,15 @@ const RenderList = memo(() => { ]); const { isLoading } = useFetchKnowledgeList(); - const list = listData.map((item) => ({ - intro: '知识库简介', - // 等接口更改... - name: item as unknown as string + const list = listData.map(({ kb_info, kb_name }) => ({ + intro: kb_info, + name: kb_name })) + // const list = [ + // { intro: '知识库简介', name: '知识库名称' }, + // { intro: '知识库简介', name: '知识库名称' }, + // ]; + if (!isLoading && !listData.length) { return
diff --git a/frontend/src/app/knowledge/(desktop)/features/ModalCreateKnowledge.tsx b/frontend/src/app/knowledge/(desktop)/features/ModalCreateKnowledge.tsx index 68442543..fd2f3cfc 100644 --- a/frontend/src/app/knowledge/(desktop)/features/ModalCreateKnowledge.tsx +++ b/frontend/src/app/knowledge/(desktop)/features/ModalCreateKnowledge.tsx @@ -1,37 +1,43 @@ import { Modal, type ModalProps } from '@lobehub/ui'; import { Form, Input, Select, FormInstance, message } from 'antd'; -import { memo, useRef } from 'react'; +import { memo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; -import { useKnowledgeStore } from '@/store/knowledge'; +import { useKnowledgeStore } from '@/store/knowledge'; -const DEFAULT_FIELD_VALUE = { - vector_store_type: "faiss", - embed_model:"bge-large-zh-v1.5" +const DEFAULT_FIELD_VALUE = { + vector_store_type: "faiss", + embed_model: "bge-large-zh-v1.5" }; interface ModalCreateKnowledgeProps extends ModalProps { toggleModal: (open: boolean) => void; } const CreateKnowledgeBase = memo(({ toggleModal, open }) => { + const [confirmLoading, setConfirmLoading] = useState(false); const { t } = useTranslation('chat'); const antdFormInstance = useRef(); - const [useFetchKnowledgeAdd] = useKnowledgeStore((s) => [ - s.useFetchKnowledgeAdd + const [useFetchKnowledgeAdd, useFetchKnowledgeList] = useKnowledgeStore((s) => [ + s.useFetchKnowledgeAdd, s.useFetchKnowledgeList ]); + const { mutate } = useFetchKnowledgeList() const onSubmit = async () => { - if(!antdFormInstance.current) return; + if (!antdFormInstance.current) return; const fieldsError = await antdFormInstance.current.validateFields(); - if(fieldsError.length) return; - const values = antdFormInstance.current.getFieldsValue(true); + if (fieldsError.length) return; + const values = antdFormInstance.current.getFieldsValue(true); - const { code:resCode, data: resData, msg: resMsg } = await useFetchKnowledgeAdd({ ...values }) - if(resCode !== 200){ + setConfirmLoading(true); + const { code: resCode, data: resData, msg: resMsg } = await useFetchKnowledgeAdd({ ...values }) + setConfirmLoading(true); + + if (resCode !== 200) { message.error(resMsg) return; } - toggleModal(false); + mutate(); + toggleModal(false); } return ( @@ -43,10 +49,11 @@ const CreateKnowledgeBase = memo(({ toggleModal, open onOk={onSubmit} open={open} title="创建知识库" + confirmLoading={confirmLoading} >
- + @@ -54,7 +61,7 @@ const CreateKnowledgeBase = memo(({ toggleModal, open
- faiss milvus zilliz @@ -66,9 +73,9 @@ const CreateKnowledgeBase = memo(({ toggleModal, open
- bge-large-zh-v1.5 - text-embedding-v1 + text-embedding-v1 Bert Word2Vec FastText diff --git a/frontend/src/app/knowledge/[id]/base/features/ModalAddFile.tsx b/frontend/src/app/knowledge/[id]/base/features/ModalAddFile.tsx index 734159bc..7e03b13d 100644 --- a/frontend/src/app/knowledge/[id]/base/features/ModalAddFile.tsx +++ b/frontend/src/app/knowledge/[id]/base/features/ModalAddFile.tsx @@ -1,48 +1,154 @@ -import { InboxOutlined } from '@ant-design/icons'; -import type { UploadProps } from 'antd'; -import { Modal, Upload, message } from 'antd'; -import React, { memo } from 'react'; - -const { Dragger } = Upload; - +import { InboxOutlined } from '@ant-design/icons'; +import { Form, Modal, Upload, InputNumber, Radio, message } from 'antd'; +import React, { memo, useState } from 'react'; +import { useKnowledgeStore } from '@/store/knowledge'; +import type { GetProp, UploadFile, UploadProps } from 'antd'; + type ModalAddFileProps = { + kbName: string; open: boolean; setModalOpen: (open: boolean) => void; }; + +type FileType = Parameters>[0]; -const props: UploadProps = { - action: 'https://660d2bd96ddfa2943b33731c.mockapi.io/api/upload', - multiple: true, - name: 'file', - onChange(info) { - const { status } = info.file; - if (status !== 'uploading') { - console.log(info.file, info.fileList); - } - if (status === 'done') { - message.success(`${info.file.name} file uploaded successfully.`); - } else if (status === 'error') { - message.error(`${info.file.name} file upload failed.`); - } - }, - onDrop(e) { - console.log('Dropped files', e.dataTransfer.files); - }, -}; +const ModalAddFile = memo(({ open, setModalOpen, kbName }) => { + const [confirmLoading, setConfirmLoading] = useState(false); + const [antdFormInstance] = Form.useForm(); + const [useFetchKnowledgeUploadDocs, useFetchKnowledgeFilesList] = useKnowledgeStore((s) => [ + s.useFetchKnowledgeUploadDocs, s.useFetchKnowledgeFilesList + ]); + const { mutate } = useFetchKnowledgeFilesList(kbName) + const [fileList, setFileList] = useState([]); + + const antdUploadProps: UploadProps = { + name: "files", + onRemove: (file) => { + const index = fileList.indexOf(file); + const newFileList = fileList.slice(); + newFileList.splice(index, 1); + setFileList(newFileList); + }, + beforeUpload: (file) => { + setFileList([...fileList, file]); + return false; + }, + fileList, + }; + + const onSubmit = async () => { + if (!antdFormInstance) return; + const fieldsError = await antdFormInstance.validateFields(); + if (fieldsError.length) return; + const values = antdFormInstance.getFieldsValue(true); + if(!fileList.length){ + message.error('请选择文件') + return; + } + + const formData = new FormData(); + fileList.forEach((file) => { + formData.append('files', file as FileType); + }); + for (const key in values) { + formData.append(key, values[key]); + } + formData.append('knowledge_base_name', kbName); + + setConfirmLoading(true); + const { code: resCode, data: resData, msg: resMsg } = await useFetchKnowledgeUploadDocs(formData) + setConfirmLoading(true); + + if (resCode !== 200) { + message.error(resMsg) + return; + } + message.success(resMsg) + mutate(); + setModalOpen(false); + } + + + const layout = { + labelCol: { span: 10 }, + wrapperCol: { span: 14 }, + } -const ModalAddFile = memo(({ open, setModalOpen }) => { return ( - setModalOpen(false)} open={open} title="添加文件"> - -

- -

-

Click or drag file to this area to upload

-

- Support for a single or bulk upload. Strictly prohibited from uploading company data or - other banned files. -

-
+ setModalOpen(false)} + open={open} title="添加文件" + onOk={onSubmit} + confirmLoading={confirmLoading} + width={600} + > + + + +
+ +

+ +

+

单击或拖动文件到此区域进行上传

+

支持单个或批量上传。

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {/* + + + + */} + +
); }); diff --git a/frontend/src/app/knowledge/[id]/base/page.tsx b/frontend/src/app/knowledge/[id]/base/page.tsx index 94e1d9ea..248509df 100644 --- a/frontend/src/app/knowledge/[id]/base/page.tsx +++ b/frontend/src/app/knowledge/[id]/base/page.tsx @@ -1,37 +1,69 @@ 'use client'; -import { Button, Table } from 'antd'; +import { Button, Table, message, Spin, Modal } from 'antd'; import type { TableColumnsType } from 'antd'; import dynamic from 'next/dynamic'; import Link from 'next/link'; import React, { useState } from 'react'; import { Flexbox } from 'react-layout-kit'; +import { useKnowledgeStore } from '@/store/knowledge'; +import { useRouter } from 'next/navigation'; +import { UndoOutlined, DeleteOutlined, DownloadOutlined, PlusOutlined, ExclamationCircleOutlined } from '@ant-design/icons'; -// import ModalAddFile from './features/ModalAddFile'; const ModalAddFile = dynamic(() => import('./features/ModalAddFile')); interface DataType { - address: string; - age: number; - key: React.Key; + id: React.Key; name: string; + loader: string; + splitter: string; + source: string; + vector: string; } -const data: DataType[] = []; -for (let i = 0; i < 46; i++) { - data.push({ - address: `London, Park Lane no. ${i}`, - age: 32, - index: i, - key: i, - name: `Edward King ${i}`, - }); -} +const App: React.FC<{ params: { id: string } }> = ({ params }) => { + const router = useRouter(); + const [ + filesData, + useFetchKnowledgeFilesList, + useFetchKnowledgeDownloadDocs, + useFetcDelInknowledgeDB, + useFetcRebuildVectorDB, + useFetchKnowledgeDel -const App: React.FC<{ params }> = ({ params }) => { - const [selectedRowKeys, setSelectedRowKeys] = useState([]); + ] = useKnowledgeStore((s) => [ + s.filesData, + s.useFetchKnowledgeFilesList, + s.useFetchKnowledgeDownloadDocs, + s.useFetcDelInknowledgeDB, + s.useFetcRebuildVectorDB, + s.useFetchKnowledgeDel + ]); + const { isLoading } = useFetchKnowledgeFilesList(params.id); + + const [downloadLoading, setDownloadLoading] = useState(false); + const [delDocsLoading, setDelDocsLoading] = useState(false); + const [rebuildVectorDBLoading, setRebuildVectorDBLoading] = useState(false); + + // rebuild progress + const [rebuildProgress, setRebuildProgress] = useState("0%"); + + // const data: DataType[] = filesData.map((item, i) => ({ + // id: i, // item 应该为对象,待提交问题... + // name: item, // item 应该为对象,待提交问题... + // loader: "", + // splitter: "", + // source: "", + // vector: "" + // })); + const data = [ + { id: '1', name: 'name1', loader: "loader", splitter: "splitter", source: "source", vector: "vector" }, + { id: '2', name: 'name2', loader: "loader", splitter: "splitter", source: "source", vector: "vector" }, + ]; + + const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [loading, setLoading] = useState(false); const [isShowModal, setModal] = useState(false); - const onSelectChange = (newSelectedRowKeys: React.Key[]) => { + const onSelectChange = (newSelectedRowKeys: string[]) => { console.log('selectedRowKeys changed:', newSelectedRowKeys); setSelectedRowKeys(newSelectedRowKeys); }; @@ -42,17 +74,13 @@ const App: React.FC<{ params }> = ({ params }) => { }, { dataIndex: 'name', - render: (text) => {text}, + render: (text, rowData) => {text}, title: '文档名称', }, { dataIndex: 'loader', title: '文档加载器', }, - { - dataIndex: 'loader', - title: '文档加载器', - }, { dataIndex: 'splitter', title: '分词器', @@ -71,40 +99,126 @@ const App: React.FC<{ params }> = ({ params }) => { selectedRowKeys, }; const hasSelected = selectedRowKeys.length > 0; - console.log(params); + + const download = async () => { + setDownloadLoading(true); + for (const docName of selectedRowKeys) { + await useFetchKnowledgeDownloadDocs(params.id, docName).catch(() => { + message.error(`下载 ${docName} 失败`); + }) + } + setDownloadLoading(false); + }; + const reAddVectorDB = async () => { + console.log('reAddShapeDB: ', selectedRowKeys); + } + const rebuildVectorDB = async () => { + console.log('rebuildVectorDB '); + setRebuildVectorDBLoading(true); + try { + useFetcRebuildVectorDB({ + "knowledge_base_name": params.id, + "allow_empty_kb": true, + "vs_type": "faiss", + "embed_model": "text-embedding-v1", + "chunk_size": 250, + "chunk_overlap": 50, + "zh_title_enhance": false, + "not_refresh_vs_cache": false, + }, { + onFinish: async () => { + message.success(`重建向量库成功`); + setRebuildVectorDBLoading(false); + }, + onMessageHandle: (text) => { + setRebuildProgress(text) + } + }) + } catch (err) { + message.error(`请求错误`); + } + setRebuildVectorDBLoading(false); + } + const delInVectorDB = async () => { + console.log('delInShapeDB: ', selectedRowKeys); + + setSelectedRowKeys([]); + } + const delInknowledgeDB = async () => { + setDelDocsLoading(true); + await useFetcDelInknowledgeDB({ + "knowledge_base_name": params.id, + "file_names": [...selectedRowKeys], + "delete_content": false, + "not_refresh_vs_cache": false + }).catch(() => { + message.error(`删除失败`); + }) + setDelDocsLoading(false); + setSelectedRowKeys([]); + } + const delKnowledge = async () => { + Modal.confirm({ + title: `确认 ${params.id} 删除吗?`, + icon: , + async onOk() { + const { code: resCode, msg: resMsg } = await useFetchKnowledgeDel(params.id) + if (resCode !== 200) { + message.error(resMsg) + } else { + message.success(resMsg); + router.push('/knowledge') + } + return Promise.resolve(); + }, + }); + + } return ( <> - - - - -
- + -
+
- - - + +
+ +
} + /> + + + ); }; diff --git a/frontend/src/app/knowledge/[id]/layout.tsx b/frontend/src/app/knowledge/[id]/layout.tsx index a2806266..9cbb1cd8 100644 --- a/frontend/src/app/knowledge/[id]/layout.tsx +++ b/frontend/src/app/knowledge/[id]/layout.tsx @@ -12,7 +12,7 @@ interface LayoutProps extends PropsWithChildren { params: Record; } export default memo(({ children, params }) => { - console.log(params); + // console.log(params); return ( diff --git a/frontend/src/services/_url.ts b/frontend/src/services/_url.ts index fe826e5e..c6fde4ce 100644 --- a/frontend/src/services/_url.ts +++ b/frontend/src/services/_url.ts @@ -48,5 +48,13 @@ export const API_ENDPOINTS = mapWithBasePath({ // knowledge knowledgeList: '/api/knowledge/list', knowledgeAdd: '/api/knowledge/add', - knowledgeDel: '/api/knowledge/del' + knowledgeDel: '/api/knowledge/del', + // knowledge files + knowledgeFilesList: '/api/knowledge/listFiles', + knowledgeUploadDocs: '/api/knowledge/uploadDocs', + knowledgeDownloadDocs: '/api/knowledge/downloadDocs', + knowledgeDelInknowledgeDB: '/api/knowledge/deleteDocs', + knowledgeRebuildVectorDB: '/api/knowledge/rebuildVectorDB', + knowledgeReAddVectorDB: '/api/knowledge/reAddVectorDB', + }); diff --git a/frontend/src/services/knowledge.ts b/frontend/src/services/knowledge.ts index 23815d88..80d016e8 100644 --- a/frontend/src/services/knowledge.ts +++ b/frontend/src/services/knowledge.ts @@ -1,16 +1,21 @@ -import { KnowledgeList, KnowledgeFormFields, Reseponse } from '@/types/knowledge'; +import type { + KnowledgeList, KnowledgeFormFields, Reseponse, + KnowledgeFilesList, KnowledgeDelDocsParams, KnowledgeDelDocsRes, + KnowledgeRebuildVectorParams, KnowledgeRebuildVectorRes +} from '@/types/knowledge'; +import { fetchSSE, FetchSSEOptions } from '@/utils/fetch'; import { API_ENDPOINTS } from './_url'; - + class KnowledgeService { - getList = async (): Promise> => { + getList = async (): Promise> => { const res = await fetch(`${API_ENDPOINTS.knowledgeList}`); const data = await res.json(); return data; }; - add = async (formValues: KnowledgeFormFields) => { + add = async (formValues: KnowledgeFormFields) => { const res = await fetch(`${API_ENDPOINTS.knowledgeAdd}`, { body: JSON.stringify(formValues), headers: { @@ -21,7 +26,7 @@ class KnowledgeService { return res.json(); }; - del = async (name: string) => { + del = async (name: string) => { const res = await fetch(`${API_ENDPOINTS.knowledgeDel}`, { body: JSON.stringify(name), headers: { @@ -31,6 +36,96 @@ class KnowledgeService { }); return res.json(); }; + + getFilesList = (name: string): () => Promise> => { + const queryString = new URLSearchParams({ + knowledge_base_name: name + }).toString(); + return async () => { + const res = await fetch(`${API_ENDPOINTS.knowledgeFilesList}?${queryString}`); + const data = await res.json(); + return data; + } + }; + + uploadDocs = async (formData: FormData): Promise> => { + const res = await fetch(`${API_ENDPOINTS.knowledgeUploadDocs}`, { + body: formData, + method: 'POST', + }); + return res.json(); + }; + + delInknowledgeDB = async (params: KnowledgeDelDocsParams): Promise> => { + const res = await fetch(`${API_ENDPOINTS.knowledgeDelInknowledgeDB}`, { + body: JSON.stringify({ + ...params, + }), + headers: { + 'Content-Type': 'application/json', + }, + method: 'POST', + }); + return res.json(); + }; + + rebuildVectorDB = async (params: KnowledgeRebuildVectorParams, opts: + { onFinish: FetchSSEOptions["onFinish"]; onMessageHandle: FetchSSEOptions["onMessageHandle"] } + ) => { + const { onFinish, onMessageHandle } = opts; + fetchSSE(async ()=> await fetch(`${API_ENDPOINTS.knowledgeRebuildVectorDB}`, { + body: JSON.stringify({ + ...params, + }), + headers: { + 'Content-Type': 'application/json', + }, + method: 'POST' + }), { + onErrorHandle: (error) => { + throw new Error('请求错误:' + error); + }, + onFinish, + onMessageHandle + }) + }; + + // delVectorDocs = async (formData: FormData): Promise> => { + // // const res = await fetch(`${API_ENDPOINTS.knowledgeUploadDocs}`, { + // // body: formData, + // // // headers: { + // // // 'Content-Type': 'application/json', + // // // }, + // // method: 'POST', + // // }); + // // return res.json(); + // }; + + downloadDocs = async (kbName: string, docName: string): Promise> => { + const queryString = new URLSearchParams({ + knowledge_base_name: kbName, + file_name: docName, + preview: 'false' + }).toString(); + const res = await fetch(`${API_ENDPOINTS.knowledgeDownloadDocs}?${queryString}`); + console.log('res', res) + const data = await res.json(); + return data; + }; + + // reAddVectorDB = async (formData: FormData): Promise> => { + // // const res = await fetch(`${API_ENDPOINTS.knowledgeUploadDocs}`, { + // // body: formData, + // // // headers: { + // // // 'Content-Type': 'application/json', + // // // }, + // // method: 'POST', + // // }); + // // return res.json(); + // }; + + + } export const knowledgeService = new KnowledgeService(); diff --git a/frontend/src/store/knowledge/action.ts b/frontend/src/store/knowledge/action.ts index ca3db06a..134ed9ac 100644 --- a/frontend/src/store/knowledge/action.ts +++ b/frontend/src/store/knowledge/action.ts @@ -5,7 +5,13 @@ import type { StateCreator } from 'zustand/vanilla'; import { knowledgeService } from '@/services/knowledge'; import { globalHelpers } from '@/store/global/helpers'; -import { KnowledgeFormFields, KnowledgeList, Reseponse } from '@/types/knowledge'; +import { + KnowledgeFormFields, KnowledgeList, Reseponse, KnowledgeFilesList, + KnowledgeDelDocsParams, KnowledgeDelDocsRes, + KnowledgeRebuildVectorParams, KnowledgeRebuildVectorRes + +} from '@/types/knowledge'; +import type { FetchSSEOptions } from '@/utils/fetch'; import type { Store } from './store'; @@ -13,7 +19,19 @@ export interface StoreAction { listData: KnowledgeList; useFetchKnowledgeList: () => SWRResponse>; useFetchKnowledgeAdd: (arg: KnowledgeFormFields) => Promise>; - useFetchKnowledgeDel: (name: string)=> Promise>; + useFetchKnowledgeDel: (name: string) => Promise>; + + // files + filesData: KnowledgeFilesList; + useFetchKnowledgeFilesList: (name: string) => SWRResponse>; + useFetchKnowledgeUploadDocs: (arg: FormData) => Promise>; + useFetchKnowledgeDownloadDocs: (kbName: string, docName: string) => Promise>; + useFetcDelInknowledgeDB: (arg: KnowledgeDelDocsParams) => Promise>; + useFetcRebuildVectorDB: (arg: KnowledgeRebuildVectorParams, options: { + onFinish: FetchSSEOptions["onFinish"]; + onMessageHandle: FetchSSEOptions["onMessageHandle"] + }) => void; + } export const createKnowledgeAction: StateCreator< @@ -28,7 +46,7 @@ export const createKnowledgeAction: StateCreator< globalHelpers.getCurrentLanguage(), knowledgeService.getList, { - onSuccess: (res) => { + onSuccess: (res) => { set({ listData: res.data }) }, }, @@ -40,4 +58,31 @@ export const createKnowledgeAction: StateCreator< useFetchKnowledgeDel: async (name) => { return await knowledgeService.del(name) }, + + + filesData: [], + useFetchKnowledgeFilesList: (knowledge_base_name) => { + return useSWR>( + globalHelpers.getCurrentLanguage(), + knowledgeService.getFilesList(knowledge_base_name), + { + onSuccess: (res) => { + set({ filesData: res.data }) + }, + }, + ) + }, + useFetchKnowledgeUploadDocs: (formData) => { + return knowledgeService.uploadDocs(formData); + }, + useFetchKnowledgeDownloadDocs: (kbName: string, docName: string) => { + return knowledgeService.downloadDocs(kbName, docName); + }, + useFetcDelInknowledgeDB: (params) => { + return knowledgeService.delInknowledgeDB(params); + }, + useFetcRebuildVectorDB: (params, options) => { + return knowledgeService.rebuildVectorDB(params, options); + } + }); diff --git a/frontend/src/types/knowledge.ts b/frontend/src/types/knowledge.ts index 567c71be..1898f612 100644 --- a/frontend/src/types/knowledge.ts +++ b/frontend/src/types/knowledge.ts @@ -1,5 +1,7 @@ -export interface Reseponse { code: number; msg: string; data: T } +export interface Reseponse { code: number; msg: string; data: T } + +// create Knowledge fields export interface KnowledgeFormFields { knowledge_base_name: string; vector_store_type: string; @@ -7,6 +9,49 @@ export interface KnowledgeFormFields { embed_model: string; } -export interface KnowledgeListItemFields extends KnowledgeFormFields { } +// Knowledge base list +export interface KnowledgeListFields { + "id": number; + "kb_name": string; + "kb_info": string; + "vs_type": string; + "embed_model": string; + "file_count": number; + "create_time": string; +} +export type KnowledgeList = KnowledgeListFields[]; + +// Knowledge base file list +export type KnowledgeFilesFields = string; +export type KnowledgeFilesList = KnowledgeFilesFields[]; + +// Example Delete parameters of the knowledge base file +export interface KnowledgeDelDocsParams { + knowledge_base_name: string; + file_names: string[]; + delete_content: boolean; + not_refresh_vs_cache: boolean; +} +export interface KnowledgeDelDocsRes { + knowledge_base_name: string; + file_names: string[]; + delete_content: boolean; + not_refresh_vs_cache: boolean; +} + + + +// Rebuild the vector library +export interface KnowledgeRebuildVectorParams { + "knowledge_base_name": string; + "allow_empty_kb": boolean; + "vs_type": string; + "embed_model": string + "chunk_size": number; + "chunk_overlap": number; + "zh_title_enhance": boolean; + "not_refresh_vs_cache": boolean; +} +export interface KnowledgeRebuildVectorRes { } + -export type KnowledgeList = KnowledgeListItemFields[];