Browse Source

子图谱查询及知识更新接口

yuchengwei 1 month ago
parent
commit
2a20dc4fee

+ 55 - 4
agent/libs/graph.py

@@ -37,6 +37,23 @@ class GraphBusiness:
         self.db.commit()
         return node
 
+    def delete_node(self, graph_id: int, id: int):
+        node = self.db.query(DbKgNode).filter(DbKgNode.graph_id == graph_id, DbKgNode.id == id).first()
+        if not node:
+            return False
+        node.status = -1
+        self.db.commit()
+        return True
+
+    def update_node(self, graph_id: int, id: int, name:str):
+        node = self.db.query(DbKgNode).filter(DbKgNode.graph_id == graph_id, DbKgNode.id == id).first()
+        if not node:
+            return False
+        node.name = name
+        self.db.commit()
+        self.db.refresh(node)
+        return node
+
     def create_edge(self, graph_id: int, src_id: int, dest_id: int, category: str, name: str, props: dict):
         edge = self.db.query(DbKgEdge).filter(DbKgEdge.graph_id == graph_id, DbKgEdge.src_id == src_id, DbKgEdge.dest_id == dest_id, DbKgEdge.category == category, DbKgEdge.name == name).first()
         if edge:
@@ -54,7 +71,31 @@ class GraphBusiness:
             self.create_edge_prop(category=1, ref_id=edge.id, prop_name=key, prop_value=value, prop_title=key)
         self.db.commit()
         return edge
-        
+
+    def delete_edge(self, graph_id: int, src_id: int, dest_id: int, category: str, name: str):
+        edge = self.db.query(DbKgEdge).filter(DbKgEdge.graph_id == graph_id, DbKgEdge.src_id == src_id, DbKgEdge.dest_id == dest_id, DbKgEdge.category == category, DbKgEdge.name == name).first()
+        if edge:
+            edge.status = -1
+            self.db.commit()
+            self.db.refresh(edge)
+            return True
+        return False
+
+    def search_edges(self, graph_id: int, category: str):
+        edges = self.db.query(DbKgEdge).filter(DbKgEdge.graph_id == graph_id, DbKgEdge.category.like(f"%{category}%")).distinct(DbKgEdge.category).all()
+        return edges    
+
+    def update_edges(self, graph_id: int, old_category:str, new_category: str):
+        edges = self.db.query(DbKgEdge).filter(DbKgEdge.graph_id == graph_id, DbKgEdge.category == old_category).all()
+        if not edges:
+            return False
+        for edge in edges:
+            edge.category = new_category
+            edge.name = new_category
+            self.db.commit()
+            self.db.refresh(edge)
+        return True 
+
     def create_node_prop(self, category:str, ref_id: int, prop_name: str, prop_value: str, prop_title:str, commit=False):
         prop = DbKgProp(category=category, ref_id=ref_id, prop_name=prop_name, prop_value=prop_value, prop_title=prop_title)
         self.db.add(prop)  
@@ -62,6 +103,16 @@ class GraphBusiness:
             self.db.commit()
             self.db.refresh(prop)
         return prop
+
+    def update_node_prop(self, ref_id: int, prop_name: str, prop_value: str):
+        prop = self.db.query(DbKgEdgeProp).filter(DbKgEdgeProp.ref_id == ref_id, DbKgEdgeProp.prop_name == prop_name).first()
+        if not prop:
+            return False
+        prop.prop_value = prop_value
+        self.db.commit()
+        self.db.refresh(prop)
+        return True
+
     def create_edge_prop(self, category:str, ref_id: int, prop_name: str, prop_value: str, prop_title:str, commit=False):
         prop = DbKgEdgeProp(category=category, ref_id=ref_id, prop_name=prop_name, prop_value=prop_value, prop_title=prop_title)
         self.db.add(prop)  
@@ -70,14 +121,14 @@ class GraphBusiness:
             self.db.refresh(prop)
         return prop
     
-    def search_like_node_by_name(self, name: str, category: str, graph_id: int):
+    def search_like_node_by_name(self, name: str, category: str, graph_id: int, limit: int = 100):
         if name == "":
             name = "%"
         if category == "" or category == "any":
-            nodes = self.db.query(DbKgNode).filter(DbKgNode.name.like(f"%{name}%"), DbKgNode.graph_id == graph_id).limit(100).all()
+            nodes = self.db.query(DbKgNode).filter(DbKgNode.name.like(f"%{name}%"), DbKgNode.graph_id == graph_id).limit(limit).all()
             return nodes
         nodes = self.db.query(DbKgNode)\
-            .filter(DbKgNode.name.like(f"%{name}%"), DbKgNode.category == category, DbKgNode.graph_id == graph_id).limit(100).all()
+            .filter(DbKgNode.name.like(f"%{name}%"), DbKgNode.category == category, DbKgNode.graph_id == graph_id).limit(limit).all()
         return nodes
     
     def get_nodes_by_page(self, graph_id: int, page: int, page_size: int):

+ 1 - 1
agent/libs/user_data_relation.py

@@ -1,6 +1,6 @@
 from datetime import datetime
 from sqlalchemy.orm import Session
-from ..models.db.graph import DbUserDataRelation
+from graph.db.models import DbUserDataRelation
 
 class UserDataRelationBusiness:
     def __init__(self, db: Session):

+ 269 - 0
agent/openapi.yaml

@@ -257,6 +257,156 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/HTTPValidationError'
+  /user/roles:
+    get:
+      tags:
+      - agent job interface
+      summary: Get Roles Endpoint
+      operationId: get_roles_endpoint_user_roles_get
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+    post:
+      tags:
+      - agent job interface
+      summary: Create Role With Permissions Endpoint
+      operationId: create_role_with_permissions_endpoint_user_roles_post
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/RoleCreateWithPermissionsRequest'
+        required: true
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /user/permissions:
+    get:
+      tags:
+      - agent job interface
+      summary: Get Permissions Endpoint
+      operationId: get_permissions_endpoint_user_permissions_get
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+    post:
+      tags:
+      - agent job interface
+      summary: Create Permission Endpoint
+      operationId: create_permission_endpoint_user_permissions_post
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/PermissionCreateRequest'
+        required: true
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /user/users/roles:
+    post:
+      tags:
+      - agent job interface
+      summary: Assign Roles To User Endpoint
+      operationId: assign_roles_to_user_endpoint_user_users_roles_post
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/UserRoleAssignmentRequest'
+        required: true
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /user/users:
+    get:
+      tags:
+      - agent job interface
+      summary: Get Users Endpoint
+      operationId: get_users_endpoint_user_users_get
+      parameters:
+      - name: userName
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+          - type: 'null'
+          description: "\u7528\u6237\u540D\uFF0C\u7528\u4E8E\u6A21\u7CCA\u67E5\u8BE2"
+          title: Username
+        description: "\u7528\u6237\u540D\uFF0C\u7528\u4E8E\u6A21\u7CCA\u67E5\u8BE2"
+      - name: pageNo
+        in: query
+        required: false
+        schema:
+          type: integer
+          minimum: 1
+          description: "\u9875\u7801\uFF0C\u4ECE1\u5F00\u59CB"
+          default: 1
+          title: Pageno
+        description: "\u9875\u7801\uFF0C\u4ECE1\u5F00\u59CB"
+      - name: pageSize
+        in: query
+        required: false
+        schema:
+          type: integer
+          maximum: 100
+          minimum: 1
+          description: "\u6BCF\u9875\u6570\u91CF\uFF0C\u6700\u5927100"
+          default: 10
+          title: Pagesize
+        description: "\u6BCF\u9875\u6570\u91CF\uFF0C\u6700\u5927100"
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
   /kb/summary:
     post:
       tags:
@@ -332,6 +482,46 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/HTTPValidationError'
+  /kb/graph_data:
+    get:
+      tags:
+      - knowledge build interface
+      summary: Get Graph Data
+      description: "\u83B7\u53D6\u7528\u6237\u5173\u8054\u7684\u56FE\u8C31\u6570\u636E\
+        \n- \u4ECEsession_id\u83B7\u53D6user_id\n- \u67E5\u8BE2DbUserDataRelation\u83B7\
+        \u53D6\u7528\u6237\u5173\u8054\u7684\u6570\u636E\n- \u8FD4\u56DE\u4E0EJava\u7AEF\
+        \u4E00\u81F4\u7684\u6570\u636E\u7ED3\u6784"
+      operationId: get_graph_data_kb_graph_data_get
+      parameters:
+      - name: label_name
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+          - type: 'null'
+          title: Label Name
+      - name: input_str
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+          - type: 'null'
+          title: Input Str
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
   /knowledge-base/:
     post:
       tags:
@@ -869,6 +1059,40 @@ components:
       required:
       - name
       title: KnowledgeBaseUpdate
+    PermissionCreateRequest:
+      properties:
+        name:
+          type: string
+          title: Name
+        description:
+          anyOf:
+          - type: string
+          - type: 'null'
+          title: Description
+        menu_name:
+          anyOf:
+          - type: string
+          - type: 'null'
+          title: Menu Name
+        menu_route:
+          anyOf:
+          - type: string
+          - type: 'null'
+          title: Menu Route
+        menu_icon:
+          anyOf:
+          - type: string
+          - type: 'null'
+          title: Menu Icon
+        parent_id:
+          anyOf:
+          - type: integer
+          - type: 'null'
+          title: Parent Id
+      type: object
+      required:
+      - name
+      title: PermissionCreateRequest
     ResponseModel:
       properties:
         code:
@@ -892,6 +1116,31 @@ components:
       - message
       - data
       title: ResponseModel
+    RoleCreateWithPermissionsRequest:
+      properties:
+        role_id:
+          anyOf:
+          - type: integer
+          - type: 'null'
+          title: Role Id
+        name:
+          type: string
+          title: Name
+        description:
+          anyOf:
+          - type: string
+          - type: 'null'
+          title: Description
+        permission_ids:
+          items:
+            type: integer
+          type: array
+          title: Permission Ids
+          default: []
+      type: object
+      required:
+      - name
+      title: RoleCreateWithPermissionsRequest
     StandardResponse:
       properties:
         code:
@@ -912,8 +1161,28 @@ components:
           type: array
           title: Records
           default: []
+        total:
+          anyOf:
+          - type: integer
+          - type: 'null'
+          title: Total
       type: object
       title: StandardResponse
+    UserRoleAssignmentRequest:
+      properties:
+        user_id:
+          type: integer
+          title: User Id
+        role_ids:
+          items:
+            type: integer
+          type: array
+          title: Role Ids
+      type: object
+      required:
+      - user_id
+      - role_ids
+      title: UserRoleAssignmentRequest
     ValidationError:
       properties:
         loc:

+ 294 - 0
agent/router/graph_router.py

@@ -0,0 +1,294 @@
+from re import S
+from fastapi import FastAPI, HTTPException
+from fastapi import APIRouter, Depends, Query
+# from networkx import graph
+from pydantic import BaseModel
+from typing import List, Optional, Dict
+from sqlalchemy import create_engine, Column, Integer, String, Boolean, JSON
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy.orm import properties, sessionmaker
+from sqlalchemy.orm import Session
+import logging
+from agent.libs.graph import GraphBusiness
+from agent.libs.user_data_relation import UserDataRelationBusiness
+from agent.libs.user import UserBusiness
+from agent.db.database import get_db
+from agent.models.web.response import StandardResponse,FAILED,SUCCESS
+
+router = APIRouter(prefix="/graph_mg", tags=["knowledge graph management interface"])
+logger = logging.getLogger(__name__)
+
+
+# Pydantic models
+class CreateEntity(BaseModel):
+    user_id: int
+    graph_id: int
+    label: str
+    name: str
+    properties: Optional[Dict] = None
+
+class DeleteEntity(BaseModel):
+    user_id: int
+    graph_id: int
+    node_id: int
+
+class UpdateEntity(BaseModel):
+    user_id: int
+    graph_id: int
+    node_id: int
+    name: str
+
+
+class FindEntity(BaseModel):
+    user_id: int
+    graph_id: int
+    node_id: int
+
+class SearchEntity(BaseModel):
+    user_id: int
+    graph_id: int
+    label: str
+    name: str
+
+class EntityVO(BaseModel):
+    user_id: int
+    graph_id: int
+    label: str
+    node_id: int
+    properties: Dict
+
+
+class DeleteProperty(BaseModel):
+    user_id: int
+    graph_id: int
+    node_id: int
+    property_name: str
+
+
+class UpdateProperty(BaseModel):
+    user_id: int
+    graph_id: int
+    node_id: int
+    property_name: str
+    property_value: str
+
+
+class RelationshipVO(BaseModel):
+    user_id: int
+    graph_id: int
+    start_id: int
+    end_id: int
+    start_label: str
+    end_label: str
+    relationship_type: str
+    property: Optional[Dict] = None
+
+
+class RelationshipNameVO(BaseModel):
+    user_id: int
+    graph_id: int
+    relationship_type: str
+
+
+class UpdateRelationTypeVO(BaseModel):
+    user_id: int
+    graph_id: int
+    old_relationship_type: str
+    new_relationship_type: str
+
+
+# Entity endpoints
+@router.post("/entity/create", response_model=StandardResponse)
+def create_entity(entities: List[CreateEntity], db: Session = Depends(get_db)):
+    try:
+        results = []
+        graph_business = GraphBusiness(db)
+        user_data_relation_business = UserDataRelationBusiness(db)
+        user_business = UserBusiness(db)
+        user_id = entities[0].user_id
+        user = user_business.get_user(user_id)
+        if not user:
+            raise HTTPException(status_code=404, detail="User not found")    
+        for entity in entities:
+            node = graph_business.create_node(graph_id=entity.graph_id, name=entity.name, category=entity.label, props=entity.properties if entity.properties else {})
+            user_data_relation_business.create_relation(user_id=entity.user_id, data_category="DbKgNode", data_id=node.id, user_name=user.username, role_id=user.roles[0].id, role_name=user.roles[0].name)
+            results.append({"id": node.id, "label": node.category, "name": node.name})
+        return StandardResponse(records=results, code=SUCCESS, message="Success") 
+    except Exception as e:
+        logger.error(f"Error creating entity: {str(e)}")
+        raise HTTPException(status_code=500, detail="Internal Server Error")
+
+
+@router.post("/entity/delete", response_model=StandardResponse)
+def delete_entity(entities: List[DeleteEntity], db: Session = Depends(get_db)):
+    
+    try:
+        graph_business = GraphBusiness(db)
+        for entity in entities:
+            graph_business.delete_node(entity.graph_id,entity.node_id)
+        return StandardResponse(records=[], code=SUCCESS, message="Success")
+    except Exception as e:
+        logger.error(f"Error deleting entity: {str(e)}")
+        raise HTTPException(status_code=500, detail="Internal Server Error")
+
+
+@router.post("/entity/update", response_model=StandardResponse)
+def update_entity(entities: List[UpdateEntity], db: Session = Depends(get_db)):
+    try:
+        results = []
+        graph_business = GraphBusiness(db)
+        for entity in entities:
+            node = graph_business.update_node(graph_id=entity.graph_id, id=entity.node_id, name=entity.name)
+            if not node:
+                continue
+            results.append({"id": node.id, "label": node.category, "name": node.name})
+        return StandardResponse(records=results, code=SUCCESS, message="Success")
+    except Exception as e:
+        logger.error(f"Error updating entity: {str(e)}")
+        raise HTTPException(status_code=500, detail="Internal Server Error")
+
+
+@router.post("/entity/find", response_model=StandardResponse)
+def find_entity(entity: FindEntity, db: Session = Depends(get_db)):
+    
+    try:
+        graph_business = GraphBusiness(db)
+        node = graph_business.get_node_by_id(entity.graph_id, entity.node_id)
+        if not node:
+            raise HTTPException(status_code=404, detail="Entity not found")
+        props = []
+        if node.props:
+            for prop in node.props:
+                props.append({
+                    "name": prop.prop_name,
+                    "title": prop.prop_title,
+                    "value": prop.prop_value
+                })
+        result = {"id": node.id, "label": node.category, "name": node.name, "properties": props}
+        return StandardResponse(records=[result], code=SUCCESS, message="Success")
+    except Exception as e:
+        logger.error(f"Error finding entity: {str(e)}")
+        raise HTTPException(status_code=500, detail="Internal Server Error")
+
+
+@router.post("/entity/search", response_model=StandardResponse)
+def search_entity(entity: SearchEntity, db: Session = Depends(get_db)):
+    try:
+        graph_business = GraphBusiness(db)
+        nodes = graph_business.search_like_node_by_name(entity.name, entity.label, entity.graph_id,20)
+        results = [{"id": node.id, "label": node.category, "name": node.name} for node in nodes]
+        return StandardResponse(records=results, code=SUCCESS, message="Success")
+        
+    except Exception as e:
+        logger.error(f"Error searching entity: {str(e)}")
+        raise HTTPException(status_code=500, detail="Internal Server Error")
+        
+
+
+# Property endpoints
+@router.post("/property/create", response_model=StandardResponse)
+def create_property(entities: List[EntityVO], db: Session = Depends(get_db)):
+    try:
+        results = []
+        graph_business = GraphBusiness(db)
+        for entity in entities:
+            node = graph_business.get_node_by_id(entity.graph_id, entity.node_id)
+            if not node:
+                continue
+            property = entity.properties
+            props = graph_business.create_node_prop(category=entity.label, ref_id=entity.node_id, prop_name=property["name"], prop_value=property["value"],prop_title=property["name"])
+            properties = []
+            for prop in props:
+                properties.append({
+                    "name": prop.prop_name,
+                    "title": prop.prop_title,
+                    "value": prop.prop_value
+                })
+            results.append({"id": node.id, "properties": properties})
+        
+        return StandardResponse(records=results, code=SUCCESS, message="Success")
+    except Exception as e:
+        logger.error(f"Error creating property: {str(e)}")
+        raise HTTPException(status_code=500, detail="Internal Server Error")
+
+
+# @router.post("/property/delete", response_model=StandardResponse)
+# def delete_property(properties: List[DeleteProperty], db: Session = Depends(get_db)):
+#     try:
+#         results = []
+#         graph_business = GraphBusiness(db)
+#         for property in properties:
+#             node = graph_business.get_node_by_id(property.graph_id, property.node_id)
+#             if not node:
+#                 continue
+#             graph_business.delete_node_prop(property.graph_id, property.node_id, property.property_name)
+#     except Exception as e:
+#         logger.error(f"Error deleting property: {str(e)}")
+#         raise HTTPException(status_code=500, detail="Internal Server Error")
+
+
+@router.post("/property/update", response_model=StandardResponse)
+def update_property(property: UpdateProperty, db: Session = Depends(get_db)):
+    try:
+        graph_business = GraphBusiness(db)
+        node = graph_business.get_node_by_id(property.graph_id, property.node_id)
+        if not node or not node.props:
+            raise HTTPException(status_code=404, detail="Entity or property not found")
+        graph_business.update_node_prop(property.node_id, property.property_name, property.property_value)
+        return StandardResponse(records=[], code=SUCCESS, message="Success")
+    except Exception as e:
+        logger.error(f"Error updating property: {str(e)}")
+        raise HTTPException(status_code=500, detail="Internal Server Error")
+
+
+# Relationship endpoints
+@router.post("/relationship/create", response_model=StandardResponse)
+def create_relationship(relationships: List[RelationshipVO], db: Session = Depends(get_db)):
+    try:
+        graph_business = GraphBusiness(db)
+        for rel in relationships:
+            graph_business.create_edge(graph_id=rel.graph_id, src_id=rel.start_id, dest_id=rel.end_id, category=rel.relationship_type, name=rel.relationship_type, props=rel.property if rel.property else {})
+            
+        return StandardResponse(records=[], code=SUCCESS, message="Success")
+    except Exception as e:
+        logger.error(f"Error creating relationship: {str(e)}")
+        raise HTTPException(status_code=500, detail="Internal Server Error")
+
+
+@router.post("/relationship/delete", response_model=StandardResponse)
+def delete_relationship(relationships: List[RelationshipVO], db: Session = Depends(get_db)):
+    try:
+        graph_business = GraphBusiness(db)
+        for rel in relationships:
+            graph_business.delete_edge(graph_id=rel.graph_id, src_id=rel.start_id, dest_id=rel.end_id, category=rel.relationship_type, name=rel.relationship_type)            
+        return StandardResponse(records=[], code=SUCCESS, message="Success")
+    except Exception as e:
+        logger.error(f"Error deleting relationship: {str(e)}")
+        raise HTTPException(status_code=500, detail="Internal Server Error")
+
+
+@router.post("/relationship/search", response_model=StandardResponse)
+def search_relationship(relation: RelationshipNameVO, db: Session = Depends(get_db)):
+    try:
+        graph_business = GraphBusiness(db)
+        edges = graph_business.search_edges(graph_id=relation.graph_id, category=relation.relationship_type)
+        if not edges:
+            raise HTTPException(status_code=404, detail="Relationship not found")
+        return StandardResponse(records=[edge.category for edge in edges], code=SUCCESS, message="Success")
+    except Exception as e:
+        logger.error(f"Error searching relationship: {str(e)}")
+        raise HTTPException(status_code=500, detail="Internal Server Error")
+
+
+@router.post("/relationship/update", response_model=StandardResponse)
+def update_relationship(updates: List[UpdateRelationTypeVO], db: Session = Depends(get_db)):
+    try:
+        graph_business = GraphBusiness(db)
+        for update in updates:
+            graph_business.update_edges(graph_id=update.graph_id, old_category=update.old_relationship_type, new_category=update.new_relationship_type)
+        return StandardResponse(records=[], code=SUCCESS, message="Success")
+    except Exception as e:
+        logger.error(f"Error updating relationship: {str(e)}")
+        raise HTTPException(status_code=500, detail="Internal Server Error")
+
+graph_router = router

+ 354 - 68
agent/router/kb_router.py

@@ -13,6 +13,11 @@ from agent.libs.graph import GraphBusiness
 from agent.libs.auth import verify_session_id, SessionValues
 import logging
 from typing import Optional, List
+from agent.models.db.graph import DbKgNode
+from agent.models.db.tree_structure import TreeStructure,KgGraphCategory
+import string
+import json
+from agent.tree_utils import get_tree_dto
 
 router = APIRouter(prefix="/kb", tags=["knowledge build interface"])
 logger = logging.getLogger(__name__)
@@ -120,10 +125,11 @@ async def get_node_properties(node_id: int, db: Session) -> dict:
 
 @router.get("/graph_data", response_model=StandardResponse)
 async def get_graph_data(
-    label_name: Optional[str] = Query(None),
-    input_str: Optional[str] = Query(None),
+    label_name: str,
+    user_id: int,
+    graph_id: int,
     db: Session = Depends(get_db),
-    sess:SessionValues = Depends(verify_session_id)
+    input_str: Optional[str] = None
 ):
     """
     获取用户关联的图谱数据
@@ -133,9 +139,34 @@ async def get_graph_data(
     """
     try:
         # 1. 从session获取user_id
-        user_id = sess.user_id
-        if not user_id:
-            return StandardResponse(code=FAILED, message="user not found", records=[])
+        # user_id = sess.user_id
+        # if not user_id:
+        #     return StandardResponse(code=FAILED, message="user not found", records=[])
+        
+        # 处理input_str为空的情况
+        if not input_str:
+            # 根据user_id、graph_id和label_name从kg_nodes表中获取一个name
+            get_name_sql = text("""
+            SELECT n.name 
+            FROM user_data_relations udr
+            JOIN kg_nodes n ON udr.data_id = n.id AND udr.data_category = 'DbKgNode'
+            WHERE udr.user_id = :user_id
+            AND n.category = :label_name
+            AND n.status = '0'
+            AND n.graph_id = :graph_id
+            LIMIT 1
+            """)
+            
+            name_result = db.execute(get_name_sql, {
+                'user_id': user_id,
+                'label_name': label_name,
+                'graph_id': graph_id
+            }).fetchone()
+            
+            if not name_result:
+                return StandardResponse(code=FAILED, message="No node found for given parameters", records=[])
+                
+            input_str = name_result._mapping['name']
         
         # 2. 使用JOIN查询用户关联的图谱数据
         sql = text("""
@@ -155,6 +186,7 @@ async def get_graph_data(
             AND n.category = :label_name
             AND n.name = :input_str
             AND n.status = '0'
+            AND n.graph_id = :graph_id
         )
         SELECT rType, target_id, target_name, target_label, pCount
         FROM RankedRelations
@@ -163,7 +195,7 @@ async def get_graph_data(
         """)
         
         # 3. 组装返回数据结构
-        categories = ["中心词", "关系"]
+        categories = [{"name": "中心词"}, {"name": "关系"}]
         nodes = []
         links = []
         
@@ -175,94 +207,155 @@ async def get_graph_data(
         WHERE udr.user_id = :user_id
         AND n.category = :label_name
         AND n.name = :input_str
-        AND n.status = '0'
+        AND n.status = '0' AND n.graph_id= :graph_id limit 1
         """)
         
         # 执行查询并处理结果
         center_node = None
-        rtype_map = {}
-         
+        c_map = {"中心词": 0, "关系": 1}
+        node_id = 0
+        
+        # 构建graph_dto数据结构
+        graph_dto = {
+            "label": "",
+            "name": "",
+            "id": 0,
+            "properties": {},
+            "ENodeRSDTOS": []
+        }
+        
         # 1. 查询中心节点
         center_result = db.execute(center_sql, {
              'user_id': user_id,
              'label_name': label_name,
-             'input_str': input_str
+             'input_str': input_str,
+             'graph_id': graph_id
         }).fetchall()
          
         if center_result:
              for row in center_result:
-                 center_node = {
-                     "id": 0,
-                     "name": row._mapping['name'],
-                     "label": row._mapping['category'],
-                     "symbolSize": 50,
-                     "symbol": "circle",
-                     "properties": await get_node_properties(row._mapping['id'], db)
-                 }
-                 nodes.append(center_node)
+                 graph_dto["label"] = row._mapping['category']
+                 graph_dto["name"] = row._mapping['name']
+                 graph_dto["id"] = row._mapping['id']
+                 graph_dto["properties"] = await get_node_properties(row._mapping['id'], db)
                  break
-         
+        
         # 2. 查询关联的边和目标节点
         relation_result = db.execute(sql, {
              'user_id': user_id,
              'label_name': label_name,
-             'input_str': input_str
+             'input_str': input_str,
+             'graph_id': graph_id
         }).fetchall()
          
         if relation_result:
+             rs_id = 2
              for row in relation_result:
                  r_type = row._mapping['rtype']
-                 target_node = {
-                     "id": row._mapping['target_id'],
-                     "name": row._mapping['target_name'],
-                     "label": row._mapping['target_label'],
-                     "symbolSize": 28,
-                     "symbol": "circle",
-                     "properties": await get_node_properties(row._mapping['target_id'], db)
-                 }
-                 
-                 if r_type not in rtype_map:
-                     rtype_map[r_type] = []
-                 rtype_map[r_type].append(target_node)
                  
-                 if r_type not in categories:
-                     categories.append(r_type)
-         
-         # 3. 组装返回结果
-        if center_node:
-             for r_type, targets in rtype_map.items():
-                 # 添加关系节点
-                 relation_node = {
-                     "id": len(nodes),
-                     "name": "",
-                     "label": center_node['label'],
-                     "symbolSize": 10,
-                     "symbol": "diamond",
-                     "properties": {}
+                 # 添加到graph_dto
+                 e_node_rs = {
+                     "RType": r_type,
+                     "ENodeDTOS": [{
+                         "Label": row._mapping['target_label'],
+                         "Name": row._mapping['target_name'],
+                         "Id": row._mapping['target_id'],
+                         "PCount": row._mapping['pcount'],
+                         "properties": await get_node_properties(row._mapping['target_id'], db)
+                     }]
                  }
-                 nodes.append(relation_node)
                  
-                 # 添加中心节点到关系节点的链接
-                 links.append({
-                     "source": center_node['name'],
-                     "target": "",
-                     "name": r_type,
-                     "category": r_type
-                 })
+                 # 检查是否已有该关系类型
+                 existing_rs = next((rs for rs in graph_dto["ENodeRSDTOS"] if rs["RType"] == r_type), None)
+                 if existing_rs:
+                     existing_rs["ENodeDTOS"].extend(e_node_rs["ENodeDTOS"])
+                 else:
+                     graph_dto["ENodeRSDTOS"].append(e_node_rs)
                  
-                 # 添加关系节点到目标节点的链接
-                 for target in targets:
-                     links.append({
-                         "source": "",
-                         "target": target['name'],
-                         "name": "",
-                         "category": r_type
-                     })
+                 if r_type not in c_map:
+                     c_map[r_type] = rs_id
+                     categories.append({"name": r_type})
+                     rs_id += 1
+        
+        print("graph_dto:", graph_dto)  # 打印graph_dto
          
-        final_data={
-                "categories": categories,
-                "nodes": nodes,
-                "links": links
+        # 构建中心节点
+        center_node = {
+            "label": graph_dto["name"],
+            'type': graph_dto["label"],
+            "category": 0,
+            "name": "0",
+            # "id": graph_dto["id"],
+            "symbol": "circle",
+            "symbolSize": 50,
+            "properties": graph_dto["properties"],
+            "nodeId": graph_dto["id"],
+            "itemStyle": {"display": True}
+        }
+        nodes.append(center_node)
+
+        # 处理关系类型
+        rs_id = 2
+        
+        for rs in graph_dto["ENodeRSDTOS"]:
+            r_type = rs["RType"]
+            
+            if r_type not in c_map:
+                c_map[r_type] = rs_id
+                categories.append({"name": r_type})
+                rs_id += 1
+            
+            # 关系节点
+            relation_node = {
+                "label": "",
+                'type': graph_dto["label"],
+                "category": 1,
+                "name": str(len(nodes)),
+                # "id": len(nodes),
+                "symbol": "diamond",
+                "symbolSize": 10,
+                "properties": graph_dto["properties"],
+                "nodeId": len(nodes),
+                "itemStyle": {"display": True}
+            }
+            nodes.append(relation_node)
+            
+            # 添加链接
+            links.append({
+                "source": "0",
+                "target": str(nodes.index(relation_node)),
+                "value": r_type,
+                "relationType": r_type
+            })
+
+            # 处理子节点
+            for e_node in rs["ENodeDTOS"]:
+                item_style = {"display": e_node["PCount"] > 0}
+                child_node = {
+                    "label": e_node["Name"],
+                    "type": e_node["Label"],
+                    "category": c_map[r_type],
+                    "name": str(len(nodes)),
+                    # "id": e_node["Id"],
+                    "symbol": "circle",
+                    "symbolSize": 28,
+                    "properties": e_node["properties"],
+                    "nodeId": e_node["Id"],
+                    "itemStyle": item_style
+                }
+                nodes.append(child_node)
+                
+                links.append({
+                    "source": str(nodes.index(relation_node)),
+                "target": str(nodes.index(child_node)),
+                    "value": "",
+                    "relationType": r_type
+                })
+        
+        final_data = {
+            "categories": categories,
+            "node": nodes,
+            "links": links
         }
         return StandardResponse(
             records=[{"records": final_data}],
@@ -274,6 +367,199 @@ async def get_graph_data(
             message=str(e)
         )
 
+
+
+        
+        
+@router.get("/user_sub_graphs", response_model=StandardResponse)
+async def get_user_sub_graphs(
+    user_id: int,
+    pageNo: int = 1,
+    pageSize: int = 10,
+    db: Session = Depends(get_db)
+):
+    """
+    获取用户关联的子图列表
+    - 根据user_id和data_category='sub_graph'查询user_data_relations表
+    - 关联jobs表获取job_name
+    - 返回data_id和job_name列表
+    - 支持分页查询,参数pageNo(默认1)和pageSize(默认10)
+    """
+    try:
+        # 查询用户关联的子图
+        offset = (pageNo - 1) * pageSize
+        sql = text("""
+        SELECT udr.data_id, j.job_name
+        FROM user_data_relations udr
+        LEFT JOIN jobs j ON udr.data_id = j.id
+        WHERE udr.user_id = :user_id
+        AND udr.data_category = 'sub_graph' order by udr.data_id desc
+        LIMIT :pageSize OFFSET :offset
+        """)
+        
+        result = db.execute(sql, {'user_id': user_id, 'pageSize': pageSize, 'offset': offset}).fetchall()
+        
+        records = []
+        for row in result:
+            records.append({
+                "graph_id": row._mapping['data_id'],
+                "graph_name": row._mapping['job_name']
+            })
+            
+        return StandardResponse(
+            records=records,
+            message="User sub graphs retrieved"
+        )
+    except Exception as e:
+        return StandardResponse(
+            code=500,
+            message=str(e)
+        )
+
+def build_disease_tree(disease_nodes: list, root_name: str = "疾病") -> dict:
+    """
+    构建疾病树状结构的公共方法
+    :param disease_nodes: 疾病节点列表,每个节点需包含name属性
+    :param root_name: 根节点名称,默认为"疾病"
+    :return: 树状结构字典
+    """
+    if not disease_nodes:
+        return {"name": root_name, "sNode": []}
+    
+    # 按拼音首字母分类
+    letter_groups = {letter: [] for letter in string.ascii_uppercase}
+    letter_groups['其他'] = []
+    
+    for node in disease_nodes:
+        name = node.name if hasattr(node, 'name') else str(node)
+        first_letter = get_first_letter(name)
+        letter_groups[first_letter].append(name)
+    
+    # 构建JSON结构
+    tree_structure = {
+        "name": root_name,
+        "sNode": []
+    }
+    
+    # 先添加A-Z的分类
+    for letter in string.ascii_uppercase:
+        if letter_groups[letter]:
+            letter_node = {
+                "name": letter,
+                "sNode": [{"name": disease, "sNode": []} for disease in sorted(letter_groups[letter])]
+            }
+            tree_structure["sNode"].append(letter_node)
+    
+    # 最后添加"其他"分类(如果有的话)
+    if letter_groups['其他']:
+        other_node = {
+            "name": "其他",
+            "sNode": [{"name": disease, "sNode": []} for disease in sorted(letter_groups['其他'])]
+        }
+        tree_structure["sNode"].append(other_node)
+    # content=json.dumps(tree_structure, ensure_ascii=False)
+    # print(content)
+    # tree_dto=get_tree_dto(content)
+    # print(tree_dto)
+    return tree_structure
+
+def get_first_letter(word):
+    """获取中文词语的拼音首字母"""
+    if not word:
+        return '其他'
+    
+    # 获取第一个汉字的拼音首字母
+    first_char = word[0]
+    try:
+        import pypinyin
+        first_letter = pypinyin.pinyin(first_char, style=pypinyin.FIRST_LETTER)[0][0].upper()
+        return first_letter if first_letter in string.ascii_uppercase else '其他'
+    except Exception as e:
+        print(str(e))
+        return '其他'
+
+@router.get('/disease_tree')
+async def get_disease_tree(graph_id: int, db: Session = Depends(get_db)):
+    """
+    根据graph_id查询kg_nodes表中category是疾病的数据并构建树状结构
+    严格按照字母A-Z顺序进行归类,中文首字母归类到对应拼音首字母
+    """
+    # 查询疾病节点
+    disease_nodes = db.query(DbKgNode).filter(
+        DbKgNode.graph_id == graph_id,
+        DbKgNode.category == '疾病'
+    ).all()
+    
+    tree_structure = build_disease_tree(disease_nodes)
+    return StandardResponse(records=[{"records": tree_structure}]) 
+               
+
+@router.get('/graph_categories')
+async def get_graph_categories(
+    user_id: int, 
+    graph_id: int,
+    db: Session = Depends(get_db)
+):
+    """
+    根据user_id和graph_id查询kg_graph_category表中的category列表
+    返回category的字符串列表(按照id正序排列)
+    """
+    try:
+        # 查询category列表(按照id正序)
+        categories = db.query(KgGraphCategory.category).filter(
+            KgGraphCategory.user_id == user_id,
+            KgGraphCategory.graph_id == graph_id
+        ).order_by(KgGraphCategory.id).all()
+        
+        if not categories:
+            return StandardResponse(code=FAILED, message="No categories found")
+        
+        # 转换为字符串列表
+        category_list = [category[0] for category in categories]
         
+        return StandardResponse(
+            records=[{"records": category_list}],
+            message="Graph categories retrieved"
+        )
+    except Exception as e:
+        return StandardResponse(
+            code=500,
+            message=str(e)
+        )
+        
+@router.get('/tree_structure')
+async def get_tree_structure(
+    user_id: int, 
+    graph_id: int,
+    db: Session = Depends(get_db)
+):
+    """
+    根据user_id和graph_id获取树状结构数据
+    1. 查询kg_tree_structures表获取content
+    2. 调用get_tree_dto方法转换数据格式
+    3. 返回转换后的数据
+    """
+    try:
+        # 查询树状结构数据
+        tree_structure = db.query(TreeStructure).filter(
+            TreeStructure.user_id == user_id,
+            TreeStructure.graph_id == graph_id
+        ).first()
+        
+        if not tree_structure:
+            return StandardResponse(code=FAILED, message="Tree structure not found")
+        
+        # 转换数据格式
+        tree_dto = get_tree_dto(tree_structure.content)
         
+        return StandardResponse(
+            records=[{"records": tree_dto}],
+            message="Tree structure retrieved"
+        )
+    except Exception as e:
+        return StandardResponse(
+            code=500,
+            message=str(e)
+        )
+
 kb_router = router

+ 5 - 0
agent/server.py

@@ -77,13 +77,18 @@ app.include_router(kb_router)
 
 from router.knowledge_base_router import knowledge_base_router
 app.include_router(knowledge_base_router)
+
+from router.graph_router import graph_router
+app.include_router(graph_router)
 save_api_spec(app)
 
 app.mount("/static", StaticFiles(directory="static"), name="static")
 
 
+# 定义一个异步函数,用于返回自定义的Swagger UI HTML页面
 @app.get("/docs", include_in_schema=False)
 async def custom_swagger_ui_html():
+    # 调用get_swagger_ui_html函数,传入openapi_url、title、oauth2_redirect_url、swagger_js_url和swagger_css_url参数
     return get_swagger_ui_html(
         openapi_url=app.openapi_url,
         title=app.title + " - Swagger UI",

+ 1 - 0
config/site.py

@@ -41,6 +41,7 @@ class SiteConfig:
             'POSTGRESQL_DATABASE':  os.getenv("POSTGRESQL_DATABASE","kg"),
             'POSTGRESQL_USER':  os.getenv("POSTGRESQL_USER","dify"),
             'POSTGRESQL_PASSWORD':  os.getenv("POSTGRESQL_PASSWORD",quote("difyai123456")),
+            'JOB_PATH': os.getenv("JOB_PATH","/app/agent/jobs"),
         }
     def get_config(self, config_name, default=None): 
         config_name = config_name.upper()     

+ 86 - 7
executor/job_script/standard_kb_build.py

@@ -52,20 +52,22 @@ def parse_json(data):
                 
 def import_entities(graph_id, entities_list, relations_list):
     from agent.libs.user_data_relation import UserDataRelationBusiness
-    from agent.models.db.user import User, Role
     from agent.libs.user import UserBusiness
-    
+    from agent.libs.agent import AgentBusiness
+
+    agent_biz = AgentBusiness(db=SessionLocal())
+
     # 获取job信息
-    job = graphBiz.db.query(graphBiz.DbJob).filter(graphBiz.DbJob.id == graph_id).first()
+    job = agent_biz.get_job(graph_id)
     if not job:
         logger.error(f"Job not found with id: {graph_id}")
         return entities
-        
+
     # 从job_creator中提取user_id
     user_id = int(job.job_creator.split('/')[1])
-    
+
     # 获取用户角色
-    user_biz = UserBusiness(graphBiz.db)
+    user_biz = UserBusiness(db=SessionLocal())
     user = user_biz.get_user(user_id)
     if not user or not user.roles:
         logger.error(f"User {user_id} has no roles assigned")
@@ -75,7 +77,10 @@ def import_entities(graph_id, entities_list, relations_list):
     role_name = user.roles[0].name
     
     # 创建用户数据关系业务对象
-    relation_biz = UserDataRelationBusiness(graphBiz.db)
+    relation_biz = UserDataRelationBusiness(db=SessionLocal())
+
+    # 创建子图谱数据关联
+    relation_biz.create_relation(user_id, 'sub_graph', graph_id, role_id)
     
     for text, ent in entities_list.items():
         id = ent['id']
@@ -112,7 +117,81 @@ def import_entities(graph_id, entities_list, relations_list):
         # 创建边数据关联
         if edge:
             relation_biz.create_relation(user_id, 'DbKgEdge', edge.id, role_id, user_name, role_name)
+
+
+
+    # 构建树状结构并存储到数据库
+    disease_nodes = [ent for ent in entities_list.values() if '疾病' in ent.get('type', [])]
+    if disease_nodes:
+        # 按照名称字母排序
+        disease_nodes.sort(key=lambda x: x['name'])
+        
+        # 构建树状结构
+        tree_structure = {"name": "疾病", "sNode": []}
+        current_letter = None
+        letter_group = None
         
+        for node in disease_nodes:
+            first_letter = node['name'][0].upper()
+            if first_letter != current_letter:
+                current_letter = first_letter
+                letter_group = {"name": current_letter, "sNode": []}
+                tree_structure["sNode"].append(letter_group)
+            letter_group["sNode"].append({"name": node['name'], "sNode": []})
+        
+        # 存储到数据库
+        from agent.models.db.tree_structure import TreeStructure
+        db = SessionLocal()
+        try:
+            tree_record = TreeStructure(
+                user_id=user_id,
+                graph_id=graph_id,
+                content=json.dumps(tree_structure, ensure_ascii=False)
+            )
+            db.add(tree_record)
+            db.commit()
+        except Exception as e:
+            db.rollback()
+            logger.error(f"Failed to save tree structure: {e}")
+        finally:
+            db.close()
+    
+    # 构建树状结构并存储到数据库
+    disease_nodes = [ent for ent in entities_list.values() if '疾病' in ent.get('type', [])]
+    if disease_nodes:
+        # 按照名称字母排序
+        disease_nodes.sort(key=lambda x: x['name'])
+        
+        # 构建树状结构
+        tree_structure = {"name": "症状", "sNode": []}
+        current_letter = None
+        letter_group = None
+        
+        for node in disease_nodes:
+            first_letter = node['name'][0].upper()
+            if first_letter != current_letter:
+                current_letter = first_letter
+                letter_group = {"name": current_letter, "sNode": []}
+                tree_structure["sNode"].append(letter_group)
+            letter_group["sNode"].append({"name": node['name'], "sNode": []})
+        
+        # 存储到数据库
+        from agent.models.db.tree_structure import TreeStructure
+        db = SessionLocal()
+        try:
+            tree_record = TreeStructure(
+                user_id=user_id,
+                graph_id=graph_id,
+                content=json.dumps(tree_structure, ensure_ascii=False)
+            )
+            db.add(tree_record)
+            db.commit()
+        except Exception as e:
+            db.rollback()
+            logger.error(f"Failed to save tree structure: {e}")
+        finally:
+            db.close()
+    
     return entities
 if __name__ == "__main__":
     if len(sys.argv) != 2:

+ 1 - 1
executor/main.py

@@ -17,7 +17,7 @@ import re
 config = SiteConfig()
 logging.basicConfig(level=logging.INFO)
 
-handler = logging.FileHandler('/app/logs/job-executor.log', mode='w',encoding="utf-8")
+handler = logging.FileHandler('/datadisk/self-constructing-graph/logs/job-executor.log', mode='w',encoding="utf-8")
 handler.setLevel(logging.INFO)
 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
 handler.setFormatter(formatter)

+ 8 - 1
graph/db/database.py

@@ -1,7 +1,14 @@
 from sqlalchemy import create_engine
 from sqlalchemy.ext.declarative import declarative_base
 from sqlalchemy.orm import sessionmaker
-from config.site import POSTGRESQL_USER,POSTGRESQL_PASSWORD,POSTGRESQL_HOST,POSTGRESQL_DATABASE
+from config.site import SiteConfig
+
+config = SiteConfig()
+
+POSTGRESQL_HOST = config.get_config("POSTGRESQL_HOST")
+POSTGRESQL_DATABASE = config.get_config("POSTGRESQL_DATABASE")
+POSTGRESQL_USER = config.get_config("POSTGRESQL_USER")
+POSTGRESQL_PASSWORD = config.get_config("POSTGRESQL_PASSWORD")
 
 DATABASE_URL = f"postgresql+psycopg2://{POSTGRESQL_USER}:{POSTGRESQL_PASSWORD}@{POSTGRESQL_HOST}/{POSTGRESQL_DATABASE}"
 

+ 2 - 0
graph/db/models.py

@@ -187,6 +187,8 @@ class DbUserDataRelation(Base):
     role_id = Column(Integer, nullable=False)  # 用户角色ID
     created = Column(DateTime, nullable=False)
     updated = Column(DateTime, nullable=False)
+    user_name = Column(String(64), nullable=False)
+    role_name = Column(String(64), nullable=False)
     
     user = relationship("DbUsers", back_populates="data_relations")
 

+ 725 - 6
openapi.yaml

@@ -495,12 +495,22 @@ paths:
       parameters:
       - name: label_name
         in: query
-        required: false
+        required: true
         schema:
-          anyOf:
-          - type: string
-          - type: 'null'
+          type: string
           title: Label Name
+      - name: user_id
+        in: query
+        required: true
+        schema:
+          type: integer
+          title: User Id
+      - name: graph_id
+        in: query
+        required: true
+        schema:
+          type: integer
+          title: Graph Id
       - name: input_str
         in: query
         required: false
@@ -522,6 +532,150 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/HTTPValidationError'
+  /kb/user_sub_graphs:
+    get:
+      tags:
+      - knowledge build interface
+      summary: Get User Sub Graphs
+      description: "\u83B7\u53D6\u7528\u6237\u5173\u8054\u7684\u5B50\u56FE\u5217\u8868\
+        \n- \u6839\u636Euser_id\u548Cdata_category='sub_graph'\u67E5\u8BE2user_data_relations\u8868\
+        \n- \u5173\u8054jobs\u8868\u83B7\u53D6job_name\n- \u8FD4\u56DEdata_id\u548C\
+        job_name\u5217\u8868\n- \u652F\u6301\u5206\u9875\u67E5\u8BE2\uFF0C\u53C2\u6570\
+        pageNo(\u9ED8\u8BA41)\u548CpageSize(\u9ED8\u8BA410)"
+      operationId: get_user_sub_graphs_kb_user_sub_graphs_get
+      parameters:
+      - name: user_id
+        in: query
+        required: true
+        schema:
+          type: integer
+          title: User Id
+      - name: pageNo
+        in: query
+        required: false
+        schema:
+          type: integer
+          default: 1
+          title: Pageno
+      - name: pageSize
+        in: query
+        required: false
+        schema:
+          type: integer
+          default: 10
+          title: Pagesize
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /kb/disease_tree:
+    get:
+      tags:
+      - knowledge build interface
+      summary: Get Disease Tree
+      description: "\u6839\u636Egraph_id\u67E5\u8BE2kg_nodes\u8868\u4E2Dcategory\u662F\
+        \u75BE\u75C5\u7684\u6570\u636E\u5E76\u6784\u5EFA\u6811\u72B6\u7ED3\u6784\n\
+        \u4E25\u683C\u6309\u7167\u5B57\u6BCDA-Z\u987A\u5E8F\u8FDB\u884C\u5F52\u7C7B\
+        \uFF0C\u4E2D\u6587\u9996\u5B57\u6BCD\u5F52\u7C7B\u5230\u5BF9\u5E94\u62FC\u97F3\
+        \u9996\u5B57\u6BCD"
+      operationId: get_disease_tree_kb_disease_tree_get
+      parameters:
+      - name: graph_id
+        in: query
+        required: true
+        schema:
+          type: integer
+          title: Graph Id
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema: {}
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /kb/graph_categories:
+    get:
+      tags:
+      - knowledge build interface
+      summary: Get Graph Categories
+      description: "\u6839\u636Euser_id\u548Cgraph_id\u67E5\u8BE2kg_graph_category\u8868\
+        \u4E2D\u7684category\u5217\u8868\n\u8FD4\u56DEcategory\u7684\u5B57\u7B26\u4E32\
+        \u5217\u8868(\u6309\u7167id\u6B63\u5E8F\u6392\u5217)"
+      operationId: get_graph_categories_kb_graph_categories_get
+      parameters:
+      - name: user_id
+        in: query
+        required: true
+        schema:
+          type: integer
+          title: User Id
+      - name: graph_id
+        in: query
+        required: true
+        schema:
+          type: integer
+          title: Graph Id
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema: {}
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /kb/tree_structure:
+    get:
+      tags:
+      - knowledge build interface
+      summary: Get Tree Structure
+      description: "\u6839\u636Euser_id\u548Cgraph_id\u83B7\u53D6\u6811\u72B6\u7ED3\
+        \u6784\u6570\u636E\n1. \u67E5\u8BE2kg_tree_structures\u8868\u83B7\u53D6content\n\
+        2. \u8C03\u7528get_tree_dto\u65B9\u6CD5\u8F6C\u6362\u6570\u636E\u683C\u5F0F\
+        \n3. \u8FD4\u56DE\u8F6C\u6362\u540E\u7684\u6570\u636E"
+      operationId: get_tree_structure_kb_tree_structure_get
+      parameters:
+      - name: user_id
+        in: query
+        required: true
+        schema:
+          type: integer
+          title: User Id
+      - name: graph_id
+        in: query
+        required: true
+        schema:
+          type: integer
+          title: Graph Id
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema: {}
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
   /knowledge-base/:
     post:
       tags:
@@ -860,6 +1014,40 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/HTTPValidationError'
+  /files/{file_id}/changeStatus:
+    get:
+      tags:
+      - knowledge base interface
+      summary: Change File Status
+      operationId: change_file_status_files__file_id__changeStatus_get
+      parameters:
+      - name: file_id
+        in: path
+        required: true
+        schema:
+          type: integer
+          title: File Id
+      - name: status
+        in: query
+        required: true
+        schema:
+          type: boolean
+          title: Status
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                type: object
+                additionalProperties: true
+                title: Response Change File Status Files  File Id  Changestatus Get
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
   /files/batch-update:
     put:
       tags:
@@ -885,6 +1073,302 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/HTTPValidationError'
+  /graph_mg/entity/create:
+    post:
+      tags:
+      - knowledge graph management interface
+      summary: Create Entity
+      operationId: create_entity_graph_mg_entity_create_post
+      requestBody:
+        content:
+          application/json:
+            schema:
+              items:
+                $ref: '#/components/schemas/CreateEntity'
+              type: array
+              title: Entities
+        required: true
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /graph_mg/entity/delete:
+    post:
+      tags:
+      - knowledge graph management interface
+      summary: Delete Entity
+      operationId: delete_entity_graph_mg_entity_delete_post
+      requestBody:
+        content:
+          application/json:
+            schema:
+              items:
+                $ref: '#/components/schemas/DeleteEntity'
+              type: array
+              title: Entities
+        required: true
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /graph_mg/entity/update:
+    post:
+      tags:
+      - knowledge graph management interface
+      summary: Update Entity
+      operationId: update_entity_graph_mg_entity_update_post
+      requestBody:
+        content:
+          application/json:
+            schema:
+              items:
+                $ref: '#/components/schemas/UpdateEntity'
+              type: array
+              title: Entities
+        required: true
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /graph_mg/entity/find:
+    post:
+      tags:
+      - knowledge graph management interface
+      summary: Find Entity
+      operationId: find_entity_graph_mg_entity_find_post
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/FindEntity'
+        required: true
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /graph_mg/entity/search:
+    post:
+      tags:
+      - knowledge graph management interface
+      summary: Search Entity
+      operationId: search_entity_graph_mg_entity_search_post
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/SearchEntity'
+        required: true
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /graph_mg/property/create:
+    post:
+      tags:
+      - knowledge graph management interface
+      summary: Create Property
+      operationId: create_property_graph_mg_property_create_post
+      requestBody:
+        content:
+          application/json:
+            schema:
+              items:
+                $ref: '#/components/schemas/EntityVO'
+              type: array
+              title: Entities
+        required: true
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /graph_mg/property/update:
+    post:
+      tags:
+      - knowledge graph management interface
+      summary: Update Property
+      operationId: update_property_graph_mg_property_update_post
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/UpdateProperty'
+        required: true
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /graph_mg/relationship/create:
+    post:
+      tags:
+      - knowledge graph management interface
+      summary: Create Relationship
+      operationId: create_relationship_graph_mg_relationship_create_post
+      requestBody:
+        content:
+          application/json:
+            schema:
+              items:
+                $ref: '#/components/schemas/RelationshipVO'
+              type: array
+              title: Relationships
+        required: true
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /graph_mg/relationship/delete:
+    post:
+      tags:
+      - knowledge graph management interface
+      summary: Delete Relationship
+      operationId: delete_relationship_graph_mg_relationship_delete_post
+      requestBody:
+        content:
+          application/json:
+            schema:
+              items:
+                $ref: '#/components/schemas/RelationshipVO'
+              type: array
+              title: Relationships
+        required: true
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /graph_mg/relationship/search:
+    post:
+      tags:
+      - knowledge graph management interface
+      summary: Search Relationship
+      operationId: search_relationship_graph_mg_relationship_search_post
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/RelationshipNameVO'
+        required: true
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
+  /graph_mg/relationship/update:
+    post:
+      tags:
+      - knowledge graph management interface
+      summary: Update Relationship
+      operationId: update_relationship_graph_mg_relationship_update_post
+      requestBody:
+        content:
+          application/json:
+            schema:
+              items:
+                $ref: '#/components/schemas/UpdateRelationTypeVO'
+              type: array
+              title: Updates
+        required: true
+      responses:
+        '200':
+          description: Successful Response
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/StandardResponse'
+        '422':
+          description: Validation Error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/HTTPValidationError'
 components:
   schemas:
     BasicRequest:
@@ -968,6 +1452,76 @@ components:
       required:
       - files
       title: Body_upload_files_knowledge_base__kb_id__files__post
+    CreateEntity:
+      properties:
+        user_id:
+          type: integer
+          title: User Id
+        graph_id:
+          type: integer
+          title: Graph Id
+        label:
+          type: string
+          title: Label
+        name:
+          type: string
+          title: Name
+        properties:
+          anyOf:
+          - additionalProperties: true
+            type: object
+          - type: 'null'
+          title: Properties
+      type: object
+      required:
+      - user_id
+      - graph_id
+      - label
+      - name
+      title: CreateEntity
+    DeleteEntity:
+      properties:
+        user_id:
+          type: integer
+          title: User Id
+        graph_id:
+          type: integer
+          title: Graph Id
+        node_id:
+          type: integer
+          title: Node Id
+      type: object
+      required:
+      - user_id
+      - graph_id
+      - node_id
+      title: DeleteEntity
+    EntityVO:
+      properties:
+        user_id:
+          type: integer
+          title: User Id
+        graph_id:
+          type: integer
+          title: Graph Id
+        label:
+          type: string
+          title: Label
+        node_id:
+          type: integer
+          title: Node Id
+        properties:
+          additionalProperties: true
+          type: object
+          title: Properties
+      type: object
+      required:
+      - user_id
+      - graph_id
+      - label
+      - node_id
+      - properties
+      title: EntityVO
     FileUpdate:
       properties:
         id:
@@ -1012,6 +1566,23 @@ components:
       required:
       - id
       title: FileUpdate
+    FindEntity:
+      properties:
+        user_id:
+          type: integer
+          title: User Id
+        graph_id:
+          type: integer
+          title: Graph Id
+        node_id:
+          type: integer
+          title: Node Id
+      type: object
+      required:
+      - user_id
+      - graph_id
+      - node_id
+      title: FindEntity
     HTTPValidationError:
       properties:
         detail:
@@ -1033,7 +1604,9 @@ components:
           title: Description
         tags:
           anyOf:
-          - type: string
+          - items:
+              type: string
+            type: array
           - type: 'null'
           title: Tags
       type: object
@@ -1052,7 +1625,9 @@ components:
           title: Description
         tags:
           anyOf:
-          - type: string
+          - items:
+              type: string
+            type: array
           - type: 'null'
           title: Tags
       type: object
@@ -1093,6 +1668,62 @@ components:
       required:
       - name
       title: PermissionCreateRequest
+    RelationshipNameVO:
+      properties:
+        user_id:
+          type: integer
+          title: User Id
+        graph_id:
+          type: integer
+          title: Graph Id
+        relationship_type:
+          type: string
+          title: Relationship Type
+      type: object
+      required:
+      - user_id
+      - graph_id
+      - relationship_type
+      title: RelationshipNameVO
+    RelationshipVO:
+      properties:
+        user_id:
+          type: integer
+          title: User Id
+        graph_id:
+          type: integer
+          title: Graph Id
+        start_id:
+          type: integer
+          title: Start Id
+        end_id:
+          type: integer
+          title: End Id
+        start_label:
+          type: string
+          title: Start Label
+        end_label:
+          type: string
+          title: End Label
+        relationship_type:
+          type: string
+          title: Relationship Type
+        property:
+          anyOf:
+          - additionalProperties: true
+            type: object
+          - type: 'null'
+          title: Property
+      type: object
+      required:
+      - user_id
+      - graph_id
+      - start_id
+      - end_id
+      - start_label
+      - end_label
+      - relationship_type
+      title: RelationshipVO
     ResponseModel:
       properties:
         code:
@@ -1141,6 +1772,27 @@ components:
       required:
       - name
       title: RoleCreateWithPermissionsRequest
+    SearchEntity:
+      properties:
+        user_id:
+          type: integer
+          title: User Id
+        graph_id:
+          type: integer
+          title: Graph Id
+        label:
+          type: string
+          title: Label
+        name:
+          type: string
+          title: Name
+      type: object
+      required:
+      - user_id
+      - graph_id
+      - label
+      - name
+      title: SearchEntity
     StandardResponse:
       properties:
         code:
@@ -1168,6 +1820,73 @@ components:
           title: Total
       type: object
       title: StandardResponse
+    UpdateEntity:
+      properties:
+        user_id:
+          type: integer
+          title: User Id
+        graph_id:
+          type: integer
+          title: Graph Id
+        node_id:
+          type: integer
+          title: Node Id
+        name:
+          type: string
+          title: Name
+      type: object
+      required:
+      - user_id
+      - graph_id
+      - node_id
+      - name
+      title: UpdateEntity
+    UpdateProperty:
+      properties:
+        user_id:
+          type: integer
+          title: User Id
+        graph_id:
+          type: integer
+          title: Graph Id
+        node_id:
+          type: integer
+          title: Node Id
+        property_name:
+          type: string
+          title: Property Name
+        property_value:
+          type: string
+          title: Property Value
+      type: object
+      required:
+      - user_id
+      - graph_id
+      - node_id
+      - property_name
+      - property_value
+      title: UpdateProperty
+    UpdateRelationTypeVO:
+      properties:
+        user_id:
+          type: integer
+          title: User Id
+        graph_id:
+          type: integer
+          title: Graph Id
+        old_relationship_type:
+          type: string
+          title: Old Relationship Type
+        new_relationship_type:
+          type: string
+          title: New Relationship Type
+      type: object
+      required:
+      - user_id
+      - graph_id
+      - old_relationship_type
+      - new_relationship_type
+      title: UpdateRelationTypeVO
     UserRoleAssignmentRequest:
       properties:
         user_id: