diff --git a/dsRag/Dao/KbDao.py b/dsRag/Dao/KbDao.py index 68b0c2a4..fa7439f9 100644 --- a/dsRag/Dao/KbDao.py +++ b/dsRag/Dao/KbDao.py @@ -101,4 +101,11 @@ class KbDao: async with conn.cursor(DictCursor) as cur: await cur.execute( "SELECT * FROM t_ai_kb_files WHERE state = 0") + return await cur.fetchall() + + async def list_kbs(self) -> List[Dict]: + """获取所有知识库列表""" + async with self.mysql_pool.acquire() as conn: + async with conn.cursor(DictCursor) as cur: + await cur.execute("SELECT * FROM t_ai_kb") return await cur.fetchall() \ No newline at end of file diff --git a/dsRag/Dao/__pycache__/KbDao.cpython-310.pyc b/dsRag/Dao/__pycache__/KbDao.cpython-310.pyc index 575a5666..773e58a4 100644 Binary files a/dsRag/Dao/__pycache__/KbDao.cpython-310.pyc and b/dsRag/Dao/__pycache__/KbDao.cpython-310.pyc differ diff --git a/dsRag/Doc/7、启动.txt b/dsRag/Doc/7、启动.txt new file mode 100644 index 00000000..93e34ea6 --- /dev/null +++ b/dsRag/Doc/7、启动.txt @@ -0,0 +1 @@ +http://localhost:8000/static/index.html \ No newline at end of file diff --git a/dsRag/Start.py b/dsRag/Start.py index 5100a2a2..667df41f 100644 --- a/dsRag/Start.py +++ b/dsRag/Start.py @@ -9,6 +9,8 @@ from fastapi import FastAPI, UploadFile, File from Dao.KbDao import KbDao from Util.MySQLUtil import init_mysql_pool +from fastapi.staticfiles import StaticFiles + # 初始化日志 logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -43,6 +45,11 @@ async def lifespan(app: FastAPI): app = FastAPI(lifespan=lifespan) # 知识库CRUD接口 +@app.get("/kb") +async def list_kbs(): + """获取所有知识库列表""" + return await app.state.kb_dao.list_kbs() + @app.post("/kb") async def create_kb(kb: dict): """创建知识库""" @@ -90,5 +97,7 @@ async def upload_file(kb_id: int, file: UploadFile = File(...)): """文件上传接口""" return await app.state.kb_dao.handle_upload(kb_id, file) +app.mount("/static", StaticFiles(directory="Static"), name="static") + if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000) \ No newline at end of file diff --git a/dsRag/Static/css/style.css b/dsRag/Static/css/style.css new file mode 100644 index 00000000..e2d47410 --- /dev/null +++ b/dsRag/Static/css/style.css @@ -0,0 +1,30 @@ +body { + font-size: .875rem; +} + +.sidebar { + position: fixed; + top: 0; + bottom: 0; + left: 0; + z-index: 100; + padding: 48px 0 0; + box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1); +} + +.sidebar .nav-link { + font-weight: 500; + color: #adb5bd; +} + +.sidebar .nav-link.active { + color: #fff; +} + +.sidebar .nav-link:hover { + color: rgba(255, 255, 255, .75); +} + +main { + padding-top: 1.5rem; +} \ No newline at end of file diff --git a/dsRag/Static/index.html b/dsRag/Static/index.html new file mode 100644 index 00000000..3b649828 --- /dev/null +++ b/dsRag/Static/index.html @@ -0,0 +1,102 @@ + + + + + 知识库管理系统 + + + + + +
+
+ + + + +
+
+ +
+
+

知识库管理

+ +
+
+ + + + + + + + + + + +
ID名称描述创建时间操作
+
+
+ + +
+
+

文件管理

+ +
+
+ +
+
+ + + + + + + + + + + + + +
ID文件名大小类型状态上传时间操作
+
+
+
+
+
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/dsRag/Static/js/app.js b/dsRag/Static/js/app.js new file mode 100644 index 00000000..37824957 --- /dev/null +++ b/dsRag/Static/js/app.js @@ -0,0 +1,171 @@ +// API基础URL +const API_BASE_URL = 'http://localhost:8000'; + +// 初始化页面 +document.addEventListener('DOMContentLoaded', function() { + loadKbList(); + setupEventListeners(); +}); + +// 设置事件监听器 +function setupEventListeners() { + // 添加知识库按钮 + document.getElementById('add-kb-btn').addEventListener('click', showKbModal); + + // 上传文件按钮 + document.getElementById('upload-file-btn').addEventListener('click', showFileModal); + + // 知识库选择器变化 + document.getElementById('kb-selector').addEventListener('change', function() { + loadFileList(this.value); + }); +} + +// 加载知识库列表 +async function loadKbList() { + try { + const response = await axios.get(`${API_BASE_URL}/kb`); + const kbList = response.data; + + const tbody = document.getElementById('kb-table-body'); + tbody.innerHTML = ''; + + const kbSelector = document.getElementById('kb-selector'); + kbSelector.innerHTML = ''; + + kbList.forEach(kb => { + // 填充知识库表格 + const row = document.createElement('tr'); + row.innerHTML = ` + ${kb.id} + ${kb.name} + ${kb.description || '-'} + ${new Date(kb.create_time).toLocaleString()} + + + + + `; + tbody.appendChild(row); + + // 填充知识库选择器 + const option = document.createElement('option'); + option.value = kb.id; + option.textContent = kb.name; + kbSelector.appendChild(option); + }); + + // 添加编辑和删除按钮的事件 + document.querySelectorAll('.edit-kb').forEach(btn => { + btn.addEventListener('click', function() { + showKbModal(this.getAttribute('data-id')); + }); + }); + + document.querySelectorAll('.delete-kb').forEach(btn => { + btn.addEventListener('click', function() { + deleteKb(this.getAttribute('data-id')); + }); + }); + } catch (error) { + console.error('加载知识库列表失败:', error); + alert('加载知识库列表失败'); + } +} + +// 加载文件列表 +async function loadFileList(kbId) { + if (!kbId) return; + + try { + const response = await axios.get(`${API_BASE_URL}/kb_files?kb_id=${kbId}`); + const fileList = response.data; + + const tbody = document.getElementById('file-table-body'); + tbody.innerHTML = ''; + + fileList.forEach(file => { + const row = document.createElement('tr'); + row.innerHTML = ` + ${file.id} + ${file.file_name} + ${formatFileSize(file.file_size)} + ${file.file_type} + ${getFileStatusText(file.state)} + ${new Date(file.create_time).toLocaleString()} + + + + `; + tbody.appendChild(row); + }); + + // 添加删除按钮的事件 + document.querySelectorAll('.delete-file').forEach(btn => { + btn.addEventListener('click', function() { + deleteFile(this.getAttribute('data-id')); + }); + }); + } catch (error) { + console.error('加载文件列表失败:', error); + alert('加载文件列表失败'); + } +} + +// 辅助函数:格式化文件大小 +function formatFileSize(bytes) { + if (bytes === 0) return '0 Bytes'; + const k = 1024; + const sizes = ['Bytes', 'KB', 'MB', 'GB']; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; +} + +// 辅助函数:获取文件状态文本 +function getFileStatusText(state) { + switch (state) { + case 0: return '待处理'; + case 1: return '已处理'; + case 2: return '处理失败'; + default: return '未知状态'; + } +} + +// 显示知识库模态框 +function showKbModal(kbId = null) { + // 实现知识库添加/编辑模态框逻辑 +} + +// 显示文件上传模态框 +function showFileModal() { + // 实现文件上传模态框逻辑 +} + +// 删除知识库 +async function deleteKb(kbId) { + if (!confirm('确定要删除这个知识库吗?')) return; + + try { + await axios.delete(`${API_BASE_URL}/kb/${kbId}`); + alert('删除成功'); + loadKbList(); + } catch (error) { + console.error('删除知识库失败:', error); + alert('删除知识库失败'); + } +} + +// 删除文件 +async function deleteFile(fileId) { + if (!confirm('确定要删除这个文件吗?')) return; + + try { + await axios.delete(`${API_BASE_URL}/kb_files/${fileId}`); + alert('删除成功'); + const kbId = document.getElementById('kb-selector').value; + if (kbId) loadFileList(kbId); + } catch (error) { + console.error('删除文件失败:', error); + alert('删除文件失败'); + } +} \ No newline at end of file