123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- import sys,os
- current_path = os.getcwd()
- sys.path.append(current_path)
- from fastapi import APIRouter, Depends, Query
- from typing import Optional, List
- from agent.cdss.libs.cdss_helper import CDSSHelper
- from web.models.response import StandardResponse
- from web.models.request import GraphFilterRequest
- router = APIRouter(prefix="/graph", tags=["Knowledge Graph"])
- graph_helper = CDSSHelper()
- @router.get("/nodes/search", response_model=StandardResponse)
- async def search_nodes(
- keyword: str = Query(..., min_length=2),
- limit: int = Query(10, ge=1, le=100),
- node_type: Optional[str] = Query(None),
- min_degree: Optional[int] = Query(None)
- ):
- """
- 根据关键词和属性过滤条件搜索图谱节点
- """
- try:
- results = graph_helper.node_search(
- keyword,
- limit=limit,
- node_type=node_type,
- min_degree=min_degree
- )
- community_report_results = graph_helper.community_report_search(keyword)
- return StandardResponse(
- success=True,
- records={"nodes":results,"community_report":community_report_results},
- code = 0,
- error_msg=f"Found {len(results)} nodes"
- )
- except Exception as e:
- return StandardResponse(
- success=False,
- message=str(e)
- )
- @router.get("/nodes/neighbor_search", response_model=StandardResponse)
- async def neighbor_search(
- keyword: str = Query(..., min_length=2),
- limit: int = Query(10, ge=1, le=100),
- node_type: Optional[str] = Query(None),
- neighbor_type: Optional[str] = Query(None),
- min_degree: Optional[int] = Query(None)
- ):
- """
- 根据关键词和属性过滤条件搜索图谱节点
- """
- try:
- scores_factor = 1.7
- results = []
- diseases = {}
- # results = graph_helper.node_search(
- # keyword,
- # limit=limit,
- # node_type=node_type,
- # min_degree=min_degree
- # )
- print("搜索的结果数量:",len(results)) # 检查是否有结果返回,没有则进行关键词拆分搜索(仅针对症状),并检查拆分后的结果是否有结果返回,没有则返回空结果。如果有结果返回,则返回结果。(仅针对症状),并检查拆分后的结果是否有结果返回,没有则返回空结果。如果有结果返回,则返回结果。
- has_good_result = False
- # new_results = []
- # for item in results:
- # if item["score"] > scores_factor:
- # has_good_result = True
- # new_results.append(item)
- #results = new_results
- print("通过相似度过滤之后剩余的数量:",len(results))
- if not has_good_result:
- keywords = keyword.split(" ")
- new_results = []
- for item in keywords:
- if len(item) > 1:
- results = graph_helper.node_search(
- item,
- limit=limit,
- node_type=node_type,
- min_degree=min_degree
- )
-
- for result_item in results:
- if result_item["score"] > scores_factor:
- new_results.append(result_item)
- if result_item["type"] == "Disease":
- if result_item["id"] not in diseases:
- diseases[result_item["id"]] = {
- "id":result_item["id"],
- "type":result_item["type"],
- "count":1
- }
- else:
- diseases[result_item["id"]]["count"] = diseases[result_item["id"]]["count"] + 1
- has_good_result = True
- results = new_results
- print("扩展搜索的结果数量:",len(results))
-
- neighbors_data = {}
-
- for item in results:
- entities, relations = graph_helper.neighbor_search(item["id"], 1)
- max = 20 #因为类似发热这种疾病会有很多关联的疾病,所以需要防止检索范围过大,设置了上限
- for neighbor in entities:
- if neighbor["type"] == neighbor_type:
- #如果这里正好找到了要求检索的节点类型
- if neighbor["id"] not in neighbors_data:
- neighbors_data[neighbor["id"]] = {
- "id":neighbor["id"],
- "type":neighbor["type"],
- "count":1
- }
- else:
- neighbors_data[neighbor["id"]]["count"] = neighbors_data[neighbor["id"]]["count"] + 1
- else:
- #如果这里找到的节点是个疾病,那么就再检索一层,看看是否有符合要求的节点类型
- if neighbor["type"] == "Disease":
- if neighbor["id"] not in diseases:
- diseases[neighbor["id"]] = {
- "id":neighbor["id"],
- "type":neighbor["type"],
- "count":1
- }
- else:
- diseases[neighbor["id"]]["count"] = diseases[neighbor["id"]]["count"] + 1
- disease_entities, relations = graph_helper.neighbor_search(neighbor["id"], 1)
- for disease_neighbor in disease_entities:
- #有时候数据中会出现链接有的节点,但是节点数据中缺失的情况,所以这里要检查
- if "type" in disease_neighbor.keys():
- if disease_neighbor["type"] == neighbor_type:
- if disease_neighbor["id"] not in neighbors_data:
- neighbors_data[disease_neighbor["id"]] = {
- "id":disease_neighbor["id"],
- "type":disease_neighbor["type"],
- "count":1
- }
- else:
- neighbors_data[disease_neighbor["id"]]["count"] = neighbors_data[disease_neighbor["id"]]["count"] + 1
- #最多搜索的范围是max个疾病
- max = max - 1
- if max == 0:
- break
- disease_data = [diseases[k] for k in diseases]
- disease_data = sorted(disease_data, key=lambda x:x["count"],reverse=True)
- data = [neighbors_data[k] for k in neighbors_data]
- data = sorted(data, key=lambda x:x["count"],reverse=True)
-
- if len(data) > 10:
- data = data[:10]
- factor = 1.0
- total = 0.0
- for item in data:
- total = item["count"] * factor + total
- for item in data:
- item["count"] = item["count"] / total
- factor = factor * 0.9
-
- if len(disease_data) > 10:
- disease_data = disease_data[:10]
- factor = 1.0
- total = 0.0
- for item in disease_data:
- total = item["count"] * factor + total
- for item in disease_data:
- item["count"] = item["count"] / total
- factor = factor * 0.9
- return StandardResponse(
- success=True,
- records={"nodes":disease_data,"neighbors":data},
- error_code = 0,
- error_msg=f"Found {len(results)} nodes"
- )
- except Exception as e:
- return StandardResponse(
- success=False,
- error_code=500,
- error_msg=str(e)
- )
- @router.post("/nodes/filter", response_model=StandardResponse)
- async def filter_nodes(request: GraphFilterRequest):
- """
- 根据复杂条件过滤节点
- """
- try:
- results = graph_helper.filter_nodes(
- node_types=request.node_types,
- min_degree=request.min_degree,
- min_community_size=request.min_community_size,
- attributes=request.attributes
- )
- return StandardResponse(
- success=True,
- data={"nodes": results},
- message=f"Filtered {len(results)} nodes"
- )
- except Exception as e:
- return StandardResponse(
- success=False,
- message=str(e)
- )
- @router.get("/statistics", response_model=StandardResponse)
- async def get_graph_statistics():
- """
- 获取图谱统计信息
- """
- try:
- stats = graph_helper.get_graph_statistics()
- return StandardResponse(
- success=True,
- data=stats,
- message="Graph statistics retrieved"
- )
- except Exception as e:
- return StandardResponse(
- success=False,
- message=str(e)
- )
- @router.get("/community/{community_id}", response_model=StandardResponse)
- async def get_community_details(
- community_id: int,
- min_size: int = Query(3, ge=2)
- ):
- """
- 获取指定社区的详细信息
- """
- try:
- community_info = graph_helper.get_community_details(community_id, min_size)
- return StandardResponse(
- success=True,
- data=community_info,
- message="Community details retrieved"
- )
- except Exception as e:
- return StandardResponse(
- success=False,
- message=str(e)
- )
- # # 新增图谱路径分析接口
- # @router.post("/path-analysis", response_model=StandardResponse)
- # async def analyze_paths(request: GraphSearchRequest):
- # """
- # 分析节点间的潜在关系路径
- # """
- # try:
- # paths = graph_helper.find_paths(
- # source_id=request.source_id,
- # target_id=request.target_id,
- # max_depth=request.max_depth
- # )
- # return StandardResponse(
- # success=True,
- # data={"paths": paths},
- # message=f"Found {len(paths)} possible paths"
- # )
- # except Exception as e:
- # return StandardResponse(
- # success=False,
- # message=str(e)
- # )
- @router.get("/node/{node_id}", response_model=StandardResponse)
- async def get_node_details(
- node_id: str,
- with_relations: bool = False,
- relation_types: List[str] = Query(None),
- relation_limit: int = Query(10, ge=1, le=100)
- ):
- """
- 获取节点详细信息
- - relation_types: 过滤指定类型的关系
- - relation_limit: 返回关系数量限制
- """
- try:
- node_info = graph_helper.get_node_details(
- node_id,
- include_relations=with_relations,
- relation_types=relation_types,
- relation_limit=relation_limit
- )
- return StandardResponse(
- success=True,
- data=node_info,
- message="Node details retrieved"
- )
- except ValueError as e:
- return StandardResponse(
- success=False,
- message=str(e)
- )
- graph_router = router
|