import json import traceback from app import app from robyn import jsonify, Response from service.OperationService import OperationService from urllib.parse import unquote # 实例化业务逻辑对象 operation_service = OperationService() def create_response(status_code, data_dict): """ 统一响应格式封装,强制使用 UTF-8 防止中文乱码。 """ return Response( status_code=status_code, description=jsonify(data_dict), headers={"Content-Type": "application/json; charset=utf-8"} ) def parse_request_body(req): """ 通用请求体解析器:解决解析 bytes、字符串或多重序列化的情况。 """ body = req.body try: if isinstance(body, (bytes, bytearray)): body = json.loads(body.decode('utf-8')) if isinstance(body, str): body = json.loads(body) return body if isinstance(body, dict) else {} except Exception as e: print(f"Request Body Parse Error: {e}") return {} # --- 1. 获取全量动态标签 --- @app.get("/api/kg/labels") def get_labels(req): try: labels = operation_service.get_all_labels() return create_response(200, {"code": 200, "data": labels, "msg": "success"}) except Exception as e: traceback.print_exc() return create_response(500, {"code": 500, "msg": f"获取标签失败: {str(e)}"}) # --- 2. 输入联想建议 --- @app.get("/api/kg/node/suggest") def suggest_node(req): try: query_data = getattr(req, "queries", getattr(req, "query_params", {})) raw_keyword = query_data.get("keyword", "") keyword = raw_keyword[0] if isinstance(raw_keyword, list) and raw_keyword else str(raw_keyword) clean_keyword = unquote(keyword).strip() suggestions = operation_service.suggest_nodes(clean_keyword) return create_response(200, {"code": 200, "data": suggestions, "msg": "success"}) except Exception as e: traceback.print_exc() return create_response(500, {"code": 500, "msg": str(e)}) # --- 3. 获取分页节点列表 --- @app.get("/api/kg/nodes") def get_nodes(req): try: query_data = getattr(req, "queries", getattr(req, "query_params", {})) page = int(query_data.get("page", "1")) page_size = int(query_data.get("pageSize", "20")) res_data = operation_service.get_nodes_subset(page, page_size) return create_response(200, {"code": 200, "data": res_data, "msg": "success"}) except Exception as e: traceback.print_exc() return create_response(500, {"code": 500, "msg": f"获取节点列表失败: {str(e)}"}) # --- 4. 获取分页关系列表 --- @app.get("/api/kg/relationships") def get_relationships(req): try: query_data = getattr(req, "queries", getattr(req, "query_params", {})) page = int(query_data.get("page", "1")) page_size = int(query_data.get("pageSize", "20")) res_data = operation_service.get_relationships_subset(page, page_size) return create_response(200, {"code": 200, "data": res_data, "msg": "success"}) except Exception as e: traceback.print_exc() return create_response(500, {"code": 500, "msg": f"获取关系列表失败: {str(e)}"}) # --- 5. 新增节点 --- @app.post("/api/kg/node/add") def add_node(req): try: body = parse_request_body(req) # 增加 strip() 防止空格导致的匹配失败 label = str(body.get("label", "Drug")).strip() name = str(body.get("name", "")).strip() if not name: return create_response(200, {"code": 400, "msg": "添加失败:节点名称不能为空"}) result = operation_service.add_node(label, name) return create_response(200, {"code": 200 if result["success"] else 400, "msg": result["msg"]}) except Exception as e: traceback.print_exc() return create_response(200, {"code": 500, "msg": f"服务器内部错误: {str(e)}"}) # --- 6. 修改节点 --- @app.post("/api/kg/node/update") def update_node(req): try: body = parse_request_body(req) node_id = body.get("id") name = str(body.get("name", "")).strip() label = str(body.get("label", "")).strip() if not node_id or not name: return create_response(200, {"code": 400, "msg": "修改失败:参数缺失(ID或Name)"}) result = operation_service.update_node(node_id, name, label) return create_response(200, {"code": 200 if result["success"] else 400, "msg": result["msg"]}) except Exception as e: traceback.print_exc() return create_response(200, {"code": 500, "msg": str(e)}) # --- 7. 新增关系 --- @app.post("/api/kg/rel/add") def add_relationship(req): try: body = parse_request_body(req) # 强制格式化所有字符串,彻底杜绝数据类型导致的 MATCH 失败 source = str(body.get("source", "")).strip() target = str(body.get("target", "")).strip() rel_type = str(body.get("type", "")).strip() rel_label = str(body.get("label", "")).strip() if not all([source, target, rel_type]): return create_response(200, {"code": 400, "msg": "添加失败:起始点、结束点和类型不能为空"}) result = operation_service.add_relationship(source, target, rel_type, rel_label) return create_response(200, {"code": 200 if result["success"] else 400, "msg": result["msg"]}) except Exception as e: traceback.print_exc() return create_response(200, {"code": 500, "msg": f"新增关系异常: {str(e)}"}) # --- 8. 修改关系 --- @app.post("/api/kg/rel/update") def update_rel(req): try: body = parse_request_body(req) rel_id = body.get("id") source = str(body.get("source", "")).strip() target = str(body.get("target", "")).strip() rel_type = str(body.get("type", "")).strip() rel_label = str(body.get("label", "")).strip() if not all([rel_id, source, target, rel_type]): return create_response(200, {"code": 400, "msg": "修改失败:必要参数(ID/Source/Target/Type)缺失"}) result = operation_service.update_relationship(rel_id, source, target, rel_type, rel_label) return create_response(200, {"code": 200 if result["success"] else 400, "msg": result["msg"]}) except Exception as e: traceback.print_exc() return create_response(200, {"code": 500, "msg": str(e)}) # --- 9. 删除节点 --- @app.post("/api/kg/node/delete") def delete_node(req): try: body = parse_request_body(req) node_id = body.get("id") if not node_id: return create_response(200, {"code": 400, "msg": "删除失败:节点ID不能为空"}) operation_service.delete_node(node_id) return create_response(200, {"code": 200, "msg": "节点及其关联关系已成功删除"}) except Exception as e: traceback.print_exc() return create_response(200, {"code": 500, "msg": str(e)}) # --- 10. 删除关系 --- @app.post("/api/kg/rel/delete") def delete_rel(req): try: body = parse_request_body(req) rel_id = body.get("id") if not rel_id: return create_response(200, {"code": 400, "msg": "删除失败:关系ID不能为空"}) operation_service.delete_relationship(rel_id) return create_response(200, {"code": 200, "msg": "关系已成功从数据库移除"}) except Exception as e: traceback.print_exc() return create_response(200, {"code": 500, "msg": str(e)})