知识库以及文件重命名、移动、删除

This commit is contained in:
1025859868@qq.com
2024-06-07 13:49:49 +08:00
parent 2e6312e84f
commit 8af9a4cb61
6 changed files with 228 additions and 57 deletions

View File

@@ -167,6 +167,14 @@ export async function updateFileLib(data) {
return await axios.put(`/api/v1/knowledge/update`, data);
}
/**
* 修改支持库文件
*
*/
export async function updateFile(data) {
return await axios.put(`/api/v1/knowledge/file/update`, data);
}
/**
* 删除支持库
*

View File

@@ -18,7 +18,6 @@ import folderIcon from "../../../assets/knowledge/folder-icon.png";
export default function CreateModal({ createType, parentId, datalist, open, setOpen, reload }) {
const { t } = useTranslation()
const navigate = useNavigate()
const nameRef = useRef(null)
const descRef = useRef(null)
const [type, setType] = useState(createType)
@@ -29,12 +28,13 @@ export default function CreateModal({ createType, parentId, datalist, open, setO
// Fetch model data
useEffect(() => {
setType(createType)
getEmbeddingModel().then(res => {
const models = res.models || []
setOptions(models)
setModal(models[0] || '')
})
}, [])
}, [createType])
const { setErrorData } = useContext(alertContext);
@@ -63,7 +63,6 @@ export default function CreateModal({ createType, parentId, datalist, open, setO
parent_id: parentId,
type: type
}).then(res => {
// @ts-ignore
reload()
setOpen(false)
}))
@@ -177,7 +176,7 @@ export default function CreateModal({ createType, parentId, datalist, open, setO
return (
<div>
{
type == 1? <CreateFolder /> : <CreateKnowLedge />
createType == 1? <CreateFolder /> : <CreateKnowLedge />
}
</div>
);

View File

@@ -1,7 +1,7 @@
import { useTranslation } from "react-i18next";
import {useContext, useEffect, useRef, useState} from "react";
import {useNavigate} from "react-router-dom";
import {readFileLibDatabase, updateFileLib} from "../../../controllers/API";
import {readFileLibDatabase, updateFile, updateFileLib} from "../../../controllers/API";
import {alertContext} from "../../../contexts/alertContext";
import {captureAndAlertRequestErrorHoc} from "../../../controllers/request";
import {
@@ -14,19 +14,47 @@ import {useTable} from "../../../util/hook";
import moveIcon from "../../../assets/knowledge/move-icon.png";
import folderIcon from "../../../assets/knowledge/folder-icon.png";
import noFolderIcon from "../../../assets/knowledge/no-folder-icon.png";
import knowledgeIcon from "@/assets/knowledge/knowledge-icon.png";
export default function MoveModal({ data, open, setOpen, reload }) {
if(!open) return null
const { t } = useTranslation()
const navigate = useNavigate()
const [parentId, setParentId] = useState("")
const { setErrorData } = useContext(alertContext);
const [error, setError] = useState({ name: false })
const [datalist, setDatalist] = useState([])
useEffect(() => {
readFileLibDatabase(1, 10000, "", data.nameType == "file" ? data.knowledge_id : data.parent_id, '1').then(res => {
const list = res.data || []
const array = []
list.forEach((item) => {
if(item.id != data.id){
array.push(item)
}
})
setDatalist(array)
})
}, [])
const handleMove = () => {
const errorlist = []
if (!parentId) errorlist.push(t('lib.selectFold'))
if (errorlist.length) return handleError(errorlist)
if(data.nameType == "file"){
captureAndAlertRequestErrorHoc(updateFile({
id: data.id,
file_name: data.file_name,
knowledge_id: parentId
}).then(res => {
reload()
setOpen(false)
}))
}else{
captureAndAlertRequestErrorHoc(updateFileLib({
id: data.id,
name: data.name,
@@ -36,10 +64,8 @@ export default function MoveModal({ data, open, setOpen, reload }) {
setOpen(false)
}))
}
}
const { page, pageSize, data: datalist, total, loading, setPage, search} = useTable({},(param) =>
readFileLibDatabase(param.page, 10000, param.keyword, '', '1')
)
const handleError = (list) => {
setErrorData({
@@ -57,7 +83,6 @@ export default function MoveModal({ data, open, setOpen, reload }) {
datalist.length > 0 ?
<div className={"folder-list third-list"}>
{datalist.map((el) => (
el.id != data.id ?
<div className={parentId == el.id ? "folder-item third-item folder-item-active" : "folder-item third-item"} key={el.id}>
<div className={"folder-content-item"} onClick={() =>setParentId(el.id)}>
<div className={"folder-header"}>
@@ -72,12 +97,11 @@ export default function MoveModal({ data, open, setOpen, reload }) {
<div className={"folder-type"}>{el.type == 1?t('lib.folder'):el.type == 2?t('lib.universalKnowledgeBase'):t('lib.webSite')}</div>
</div>
</div>
: ""
))}
</div>
:
<div className={"no-folder"}>
<img src={noFolderIcon}/>
<div className={"no-folder"} style={{marginBottom: '50px'}}>
<img src={noFolderIcon} style={{marginTop: '100px'}}/>
<p>{t('lib.noFold')}</p>
</div>
}

View File

@@ -1,7 +1,7 @@
import { useTranslation } from "react-i18next";
import {useContext, useEffect, useRef, useState} from "react";
import {useNavigate} from "react-router-dom";
import {updateFileLib} from "../../../controllers/API";
import {updateFileLib, updateFile} from "../../../controllers/API";
import {alertContext} from "../../../contexts/alertContext";
import {captureAndAlertRequestErrorHoc} from "../../../controllers/request";
import writeIcon from "../../../assets/knowledge/write-icon.png";
@@ -9,11 +9,12 @@ import writeIcon from "../../../assets/knowledge/write-icon.png";
export default function CreateModal({ data, open, setOpen, reload }) {
const { t } = useTranslation()
const navigate = useNavigate()
const [nameValue, setNameValue] = useState(data.name)
const name = data.nameType == "file"? data.file_name :data.name
const [nameValue, setNameValue] = useState(name)
useEffect(() => {
setNameValue(data.name);
}, [data.name]);
setNameValue(name)
}, [name]);
const nameRef = useRef(data.name)
const { setErrorData } = useContext(alertContext);
@@ -28,6 +29,16 @@ export default function CreateModal({ data, open, setOpen, reload }) {
setError({ name: !!nameErrors})
if (errorlist.length) return handleError(errorlist)
if(data.nameType == "file"){
captureAndAlertRequestErrorHoc(updateFile({
id: data.id,
file_name: name,
knowledge_id: data.knowledge_id
}).then(res => {
reload()
setOpen(false)
}))
}else{
captureAndAlertRequestErrorHoc(updateFileLib({
id: data.id,
name: name,
@@ -37,6 +48,7 @@ export default function CreateModal({ data, open, setOpen, reload }) {
setOpen(false)
}))
}
}
const handleError = (list) => {
setErrorData({

View File

@@ -34,6 +34,10 @@ export default function FileLibPage() {
readFileLibDatabase(param.page, 10000, param.keyword, parentId)
)
useEffect(() => {
reload()
}, [])
// Delete
const { delShow, idRef, close, delConfirm } = useDelete();
@@ -62,12 +66,12 @@ export default function FileLibPage() {
const backFolder = (parentId, index) => {
setParentId(parentId)
reload();
if(index != -1){
titleArray.splice(index)
if(index == -1){
setTitleArray([])
}else if(index == (titleArray.length - 1)){
return;
}else{
setTitleArray([])
titleArray.splice(index+1)
}
}
@@ -108,7 +112,7 @@ export default function FileLibPage() {
{
titleArray.map((title, index) => (
<div className={"title-item"} key={title}>
<span>{index == (titleArray.length - 1)? ">" : ""}</span>
<span>{index <= (titleArray.length - 1)? ">" : ""}</span>
<label onClick={()=>backFolder(title.id, index)}>{title.name}</label>
</div>
))

View File

@@ -25,7 +25,13 @@ import ShadTooltip from "../../components/ShadTooltipComponent";
import { Input } from "../../components/ui/input";
import { Select, SelectContent, SelectGroup, SelectIconTrigger, SelectItem } from "../../components/ui/select1";
import { locationContext } from "../../contexts/locationContext";
import { deleteFile, readFileByLibDatabase, retryKnowledgeFileApi } from "../../controllers/API";
import {
deleteFile,
deleteFileLib,
readFileByLibDatabase,
readFileLibDatabase,
retryKnowledgeFileApi
} from "../../controllers/API";
import { captureAndAlertRequestErrorHoc } from "../../controllers/request";
import UploadModal from "../../modals/UploadModal";
import { useTable } from "../../util/hook";
@@ -50,16 +56,15 @@ export default function FilesPage() {
const nameRef = useRef(null)
const [renameOpen, setRenameOpen] = useState(false);
const [moveOpen, setMoveOpen] = useState(false);
const [parentId, setParentId] = useState('0')
const [parentId, setParentId] = useState(id)
useEffect(() => {
setParentId(id)
}, [id])
const [type, setType] = useState(1)
const [data, setData] = useState({})
const { page, pageSize, data: datalist, total, loading, setPage, search, reload, filterData, refreshData } = useTable({}, (param) =>
readFileByLibDatabase({ ...param, id, name: param.keyword }).then(res => {
setHasPermission(res.writeable)
return res
})
)
const [titleArray, setTitleArray] = useState([]);
const detailData = {
img_url: ""
@@ -70,10 +75,28 @@ export default function FilesPage() {
// filter
const [filter, setFilter] = useState(999)
const { data: libList, total: libTotal, loading: libLoading, search: libSearch, reload:libReload } = useTable({},(param) =>
readFileLibDatabase(param.page, 10000, param.keyword, parentId)
)
const { page, pageSize, data: datalist, total, loading, setPage, search, reload:fileReload, filterData, refreshData } = useTable({}, (param) =>
readFileByLibDatabase({ ...param, id: parentId, pageSize: 10000, name: param.keyword }).then(res => {
setHasPermission(res.writeable)
return res
})
)
useEffect(() => {
filterData({ status: filter })
}, [filter])
const reload = () => {
fileReload()
libReload()
}
useEffect(() => {
// @ts-ignore
const libname = window.libname // 临时记忆
@@ -91,13 +114,22 @@ export default function FilesPage() {
}
// 删除
const { delShow, idRef, close, delConfim } = useDelete()
const { delShow, idRef, delType, close, delConfim } = useDelete()
const handleDelete = () => {
//知识库里面有文件和文件夹,它对应两个表
if(delType == "file"){
captureAndAlertRequestErrorHoc(deleteFile(idRef.current).then(res => {
reload()
close()
}))
}else if(delType == "folder"){
captureAndAlertRequestErrorHoc(deleteFileLib(idRef.current).then(res => {
reload();
close();
}));
}
}
const [repeatFiles, setRepeatFiles] = useState([])
@@ -141,6 +173,25 @@ export default function FilesPage() {
setFilter(Number(id))
}
const handleLibDetail = (el) => {
setParentId(el.id)
titleArray.push(el)
setTitleArray(titleArray)
reload();
}
const backFolder = (parentId, index) => {
setParentId(parentId)
reload();
if(index == -1){
setTitleArray([])
}else if(index == (titleArray.length - 1)){
return;
}else{
titleArray.splice(index+1)
}
}
return (
<div className="w-full h-screen relative">
{loading && <div className="absolute w-full h-full top-0 left-0 flex justify-center items-center z-10 bg-[rgba(255,255,255,0.6)] dark:bg-blur-shared">
@@ -158,7 +209,7 @@ export default function FilesPage() {
<img src={"/src/assets/knowledge/knowledge-icon.png"}/>
</span>
}
<label></label>
<label>{ title }</label>
</div>
<div className={"folder-type"}>{t('lib.universalKnowledgeBase')}</div>
<div className={"file-menu-active"}>
@@ -178,7 +229,23 @@ export default function FilesPage() {
<div className={"file-list p-6 overflow-y-auto"}>
<div className={'knowledge-header'}>
<div className={'knowledge-title'}>
{t("lib.file")}6
{titleArray.length > 0?
<div className={"title-list"}>
<div className={"title-item"}>
<label onClick={()=>backFolder(id, -1)}>{t("lib.rootDirectory")}</label>
</div>
{
titleArray.map((title, index) => (
<div className={"title-item"} key={title}>
<span>{index <= (titleArray.length - 1)? ">" : ""}</span>
<label onClick={()=>backFolder(title.id, index)}>{title.name}</label>
</div>
))
}
</div>
:
<div>{t("lib.file")}{libTotal + total}</div>
}
</div>
{hasPermission &&
<div className={'knowledge-create-box'}>
@@ -190,7 +257,10 @@ export default function FilesPage() {
</div>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem ><img src={"/src/assets/knowledge/folder-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.folder")}</DropdownMenuItem>
<DropdownMenuItem onClick={()=>{
setType(1)
setOpen(true)
}}><img src={"/src/assets/knowledge/folder-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.folder")}</DropdownMenuItem>
<DropdownMenuItem ><img src={"/src/assets/knowledge/write-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.manualDataset")}</DropdownMenuItem>
<DropdownMenuItem ><img src={"/src/assets/knowledge/knowledge-no-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.textDataset")}</DropdownMenuItem>
<DropdownMenuItem ><img src={"/src/assets/knowledge/table-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.tableDataset")}</DropdownMenuItem>
@@ -237,6 +307,56 @@ export default function FilesPage() {
<span className={el.status === 3 && 'text-red-500'}>{[t('lib.parseFailed'), t('lib.parsing'), t('lib.completed'), t('lib.parseFailed')][el.status]}</span>
}
</TableCell>
<TableCell>
<DropdownMenu>
<DropdownMenuTrigger>
<img src={"/src/assets/chat/duihua-gengduo.png"} className={'more-button'}/>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onClick={(event)=>{
event.stopPropagation();
// 数据集重命名
setData({ ...el, nameType: "file" })
setRenameOpen(true)
}}><img src={"/src/assets/knowledge/write-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.rename")}</DropdownMenuItem>
<DropdownMenuItem onClick={(event)=>{
event.stopPropagation();
setData({ ...el, nameType: "file" })
setMoveOpen(true)
}}><img src={"/src/assets/knowledge/move-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.move")}</DropdownMenuItem>
{hasPermission &&
<DropdownMenuItem onClick={(event) => {
event.stopPropagation();
delConfim(el.id, "file")
}}>
<img src={"/src/assets/knowledge/delete-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t('delete')}
</DropdownMenuItem>
}
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
))}
{libList.map((el,index) => (
<TableRow key={el.id} className={"file-row"}>
<TableCell>{index + 1}</TableCell>
<TableCell onClick={ () => handleLibDetail(el) }>
<img className={"img-icon"} src={"/src/assets/knowledge/folder-icon.png"}/>
{el.name}
</TableCell>
<TableCell></TableCell>
<TableCell>{el.update_time.replace('T', ' ')}</TableCell>
<TableCell>
{el.status === 3 ? <div className="flex items-center">
<div className="tooltip" data-tip={el.remark}>
<span className='text-red-500'>{t('lib.parseFailed')}</span>
</div>
<Button variant="link"><RotateCw size={16} onClick={() => handleRetry([el])} /></Button>
</div> :
<span className={el.status === 3 && 'text-red-500'}>{[t('lib.parseFailed'), t('lib.parsing'), t('lib.completed'), t('lib.parseFailed')][el.status]}</span>
}
</TableCell>
<TableCell>
<DropdownMenu>
<DropdownMenuTrigger>
@@ -256,7 +376,7 @@ export default function FilesPage() {
{hasPermission &&
<DropdownMenuItem onClick={(event) => {
event.stopPropagation();
delConfim(el.id)
delConfim(el.id, "folder")
}}>
<img src={"/src/assets/knowledge/delete-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t('delete')}
</DropdownMenuItem>
@@ -293,16 +413,20 @@ export default function FilesPage() {
const useDelete = () => {
const [delShow, setDelShow] = useState(false)
const [delType, setDelType] = useState("")
const idRef = useRef<any>(null)
return {
delShow,
idRef,
delType,
close: () => {
setDelShow(false)
},
delConfim: (id) => {
delConfim: (id, delType) => {
idRef.current = id
setDelType(delType)
console.log(delType)
setDelShow(true)
}
}