diff --git a/dsRag/Start.py b/dsRag/Start.py index 1b1e1102..1166a77d 100644 --- a/dsRag/Start.py +++ b/dsRag/Start.py @@ -46,6 +46,7 @@ client = AsyncOpenAI( base_url=Config.MODEL_API_URL, ) + async def lifespan(app: FastAPI): # 抑制HTTPS相关警告 warnings.filterwarnings('ignore', message='Connecting to .* using TLS with verify_certs=False is insecure') @@ -173,25 +174,31 @@ async def get_tree_data(): await conn.ping() async with conn.cursor() as cur: await cur.execute(""" - SELECT id, title, parent_id, is_leaf, - prerequisite, related - FROM knowledge_points - ORDER BY parent_id, id - """) + SELECT id, + title, + parent_id, + is_leaf, + prerequisite, + related + FROM knowledge_points + ORDER BY parent_id, id + """) rows = await cur.fetchall() - + # 构建节点映射 nodes = {} for row in rows: prerequisite_data = json.loads(row[4]) if row[4] else [] # 转换先修知识格式 - if isinstance(prerequisite_data, list) and len(prerequisite_data) > 0 and isinstance(prerequisite_data[0], dict): + if isinstance(prerequisite_data, list) and len(prerequisite_data) > 0 and isinstance(prerequisite_data[0], + dict): # 已经是新格式 prerequisites = prerequisite_data else: # 转换为新格式 - prerequisites = [{"id": str(id), "title": title} for id, title in (prerequisite_data or [])] if prerequisite_data else None - + prerequisites = [{"id": str(id), "title": title} for id, title in + (prerequisite_data or [])] if prerequisite_data else None + nodes[row[0]] = { "id": row[0], "title": row[1], @@ -201,7 +208,7 @@ async def get_tree_data(): "related": json.loads(row[5]) if row[5] and len(json.loads(row[5])) > 0 else None, "open": True } - + # 构建树形结构 tree_data = [] for node_id, node in nodes.items(): @@ -213,39 +220,52 @@ async def get_tree_data(): if "children" not in nodes[parent_id]: nodes[parent_id]["children"] = [] nodes[parent_id]["children"].append(node) - + return {"code": 0, "data": tree_data} except Exception as e: return {"code": 1, "msg": str(e)} -@app.post("/api/update-prerequisites") -async def update_prerequisites(request: fastapi.Request): +@app.post("/api/update-knowledge") +async def update_knowledge(request: fastapi.Request): try: data = await request.json() node_id = data.get('node_id') - prerequisites = data.get('prerequisites', []) - + knowledge = data.get('knowledge', []) + update_type = data.get('update_type', 'prerequisite') # 默认为先修知识 + if not node_id: raise ValueError("Missing node_id") - + mysql_pool = await init_mysql_pool() async with mysql_pool.acquire() as conn: await conn.ping() async with conn.cursor() as cur: - await cur.execute( - """ - UPDATE knowledge_points - SET prerequisite = %s - WHERE id = %s - """, - (json.dumps([{"id": p["id"], "title": p["title"]} for p in prerequisites]), node_id) - ) + if update_type == 'prerequisite': + await cur.execute( + """ + UPDATE knowledge_points + SET prerequisite = %s + WHERE id = %s + """, + (json.dumps([{"id": p["id"], "title": p["title"]} for p in knowledge], ensure_ascii=False), + node_id) + ) + else: # related knowledge + await cur.execute( + """ + UPDATE knowledge_points + SET related = %s + WHERE id = %s + """, + (json.dumps([{"id": p["id"], "title": p["title"]} for p in knowledge], ensure_ascii=False), + node_id) + ) await conn.commit() - + return {"code": 0, "msg": "更新成功"} except Exception as e: - logger.error(f"更新先修知识失败: {str(e)}") + logger.error(f"更新知识失败: {str(e)}") return {"code": 1, "msg": str(e)} diff --git a/dsRag/Util/MySQLUtil.py b/dsRag/Util/MySQLUtil.py index a6269e93..59e878dc 100644 --- a/dsRag/Util/MySQLUtil.py +++ b/dsRag/Util/MySQLUtil.py @@ -20,6 +20,7 @@ MYSQL_CONFIG = { "db": MYSQL_DB_NAME, "minsize": 1, "maxsize": 20, + "charset": "utf8mb4" } @@ -40,7 +41,3 @@ async def save_chat_to_mysql(mysql_pool, person_id, prompt, result, audio_url, d image_height) ) await conn.commit() - - - - diff --git a/dsRag/Util/__pycache__/MySQLUtil.cpython-310.pyc b/dsRag/Util/__pycache__/MySQLUtil.cpython-310.pyc index 45ab5be6..9c44fc77 100644 Binary files a/dsRag/Util/__pycache__/MySQLUtil.cpython-310.pyc and b/dsRag/Util/__pycache__/MySQLUtil.cpython-310.pyc differ diff --git a/dsRag/static/tree.html b/dsRag/static/tree.html index e6c91d30..2fd3283c 100644 --- a/dsRag/static/tree.html +++ b/dsRag/static/tree.html @@ -50,7 +50,6 @@ #treeTable th:nth-child(2), #treeTable td:nth-child(2), #treeTable th:nth-child(3), #treeTable td:nth-child(3), - #treeTable th:nth-child(4), #treeTable td:nth-child(4) { width: 220px; min-width: 220px; @@ -132,7 +131,8 @@ const isThirdLevel = node.parent_id && allNodes.find(n => n.id === node.parent_id)?.parent_id; html += '' + (node.prerequisite && node.prerequisite.length > 0 ? node.prerequisite.map(p => p.title).join(', ') : '') + ''; - html += '' + (node.related || '') + ''; + html += '' + (node.related && node.related.length > 0 ? + node.related.map(r => r.title).join(', ') : '') + ''; html += '' + (isThirdLevel ? ' ' + '' : '') + ''; @@ -227,14 +227,97 @@ }); // 调用后端接口 - fetch('/api/update-prerequisites', { + fetch('/api/update-knowledge', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ node_id: nodeId, - prerequisites: selectedNodes + knowledge: selectedNodes, // 修改参数名 + update_type: 'prerequisite' + }) + }) + .then(response => response.json()) + .then(data => { + if (data.code === 0) { + layer.msg('保存成功', {icon: 1}); + setTimeout(() => location.reload(), 1000); + } else { + layer.msg('保存失败: ' + data.message, {icon: 2}); + } + }) + .catch(error => { + console.error('Error:', error); + layer.msg('保存出错', {icon: 2}); + }); + + layer.close(index); + } + }); + form.render(); + }); + } + + function relatedUpdate(nodeId) { + layui.use(['layer', 'form'], function () { + var layer = layui.layer; + var form = layui.form; + + // 获取当前节点 + const currentNode = findNodeById(treeData, nodeId); + + // 构建HTML内容 + let html = '
'; + html += '
'; + + allNodes.forEach(node => { + if (node.id !== nodeId && !node.isParent) { + const isSelected = currentNode && currentNode.related && + currentNode.related.some(p => p.id === node.id); + + // 获取父节点标题 + const parentTitle = findParentTitle(node); + const displayTitle = parentTitle ? `【${parentTitle}】${node.title}` : node.title; + + html += '
'; + html += ''; + html += '
'; + } + }); + + html += '
'; + html += '
'; + + // 弹出层 + layer.open({ + type: 1, + title: '选择相关知识', + content: html, + area: ['500px', '400px'], + btn: ['确定', '取消'], + yes: function (index, layero) { + const selectedNodes = []; + $('input[name="node"]:checked').each(function () { + const node = findNodeById(treeData, $(this).val()); + if (node) { + selectedNodes.push({ + id: node.id, + title: node.title + }); + } + }); + + // 调用后端接口 + fetch('/api/update-knowledge', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + node_id: nodeId, + knowledge: selectedNodes, // 修改参数名 + update_type: 'related' }) }) .then(response => response.json())