You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

191 lines
7.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import logging
from typing import List
from fastapi import HTTPException
from app.database import neo4j_conn
from app.schemas.user import ChapterRelationCreate, ChapterRelationResponse
async def get_graph_relations():
"""
查询知识图谱中的所有节点及关系的详细信息
:return: 列表,每一项为 ChapterRelationResponse 对象
"""
query = """
MATCH (start)-[r]->(end)
RETURN
properties(start) AS start_properties,
labels(start) AS start_labels,
TYPE(r) AS relation,
properties(end) AS end_properties,
labels(end) AS end_labels
"""
async with neo4j_conn.get_session() as session:
result = await session.run(query)
records = await result.data()
responses = []
for record in records:
response = ChapterRelationResponse(
# start_id=record["start_id"],
start_labels=record["start_labels"],
start_properties=record["start_properties"],
relation=record["relation"],
# relation_properties=record["relation_properties"],
#
# end_id=record["end_id"],
end_labels=record["end_labels"],
end_properties=record["end_properties"]
)
responses.append(response)
return responses
async def search_chapters(search_term: str) -> List[ChapterRelationResponse]:
"""
根据搜索关键字模糊查询章节及其相关章节
:param search_term: 搜索关键字
:return: 列表,每一项为 ChapterRelationResponse 对象
"""
# 使用参数化查询以防止Cypher注入
query = """
MATCH (start)-[r]->(end)
WHERE toLower(start.name) CONTAINS toLower($search_term)
or toLower(end.name) CONTAINS toLower($search_term)
RETURN
properties(start) AS start_properties,
labels(start) AS start_labels,
TYPE(r) AS relation,
properties(end) AS end_properties,
labels(end) AS end_labels
"""
try:
async with neo4j_conn.get_session() as session:
result = await session.run(query, parameters={"search_term": search_term})
records = await result.data()
responses = [
ChapterRelationResponse(
start_labels=record.get("start_labels", []),
start_properties=record.get("start_properties", {}),
relation=record.get("relation", ""),
end_labels=record.get("end_labels", []),
end_properties=record.get("end_properties", {}),
)
for record in records
]
return responses
except Exception as e:
logging.error(f"Error during search_chapters: {e}")
return []
async def get_relations_to_level_simple(level: int) -> List[ChapterRelationResponse]:
"""
简化版:根据目标层级查询从 Root 到目标层级的所有节点和关系
:param level: 目标层级1 -> Root & Subject, 2 -> Root, Subject, Topic, ..., 5 -> Problem
:return: 列表,每一项为 ChapterRelationResponse 对象
"""
hierarchy = ["Root", "Subject", "Topic", "Section", "SubSection", "Problem"]
if level < 0 or level > len(hierarchy):
raise ValueError("层级参数必须在 0 到 5 之间")
# 特殊处理 level=0 的情况
if level == 0:
query = """
MATCH (start)
WHERE ANY(label IN labels(start) WHERE label = 'Root')
RETURN
properties(start) AS start_properties,
labels(start) AS start_labels
"""
try:
async with neo4j_conn.get_session() as session:
result = await session.run(query)
records = await result.data()
return [
ChapterRelationResponse(
start_labels=record.get("start_labels", []),
start_properties=record.get("start_properties", {}),
relation="", # 没有关系信息
end_labels=[], # 没有终点节点
end_properties={}, # 没有终点节点属性
)
for record in records
]
except Exception as e:
logging.error(f"Error during get_relations_to_level_simple (level=0): {e}")
return []
# 获取从 Root 到目标层级的所有标签
target_labels = hierarchy[:level + 1]
query = """
MATCH (start)-[r]->(end)
WHERE ANY(label IN labels(start) WHERE label IN $target_labels)
AND ANY(label IN labels(end) WHERE label IN $target_labels)
RETURN
properties(start) AS start_properties,
labels(start) AS start_labels,
TYPE(r) AS relation,
properties(end) AS end_properties,
labels(end) AS end_labels
"""
try:
async with neo4j_conn.get_session() as session:
result = await session.run(query, parameters={"target_labels": target_labels})
records = await result.data()
return [
ChapterRelationResponse(
start_labels=record.get("start_labels", []),
start_properties=record.get("start_properties", {}),
relation=record.get("relation", ""),
end_labels=record.get("end_labels", []),
end_properties=record.get("end_properties", {}),
)
for record in records
]
except Exception as e:
logging.error(f"Error during get_relations_to_level_simple: {e}")
return []
async def get_chapter_relations(chapter: str) -> List[ChapterRelationResponse]:
"""
根据章节名称查找该章节及其相关节点和关系
:param chapter_name: 章节名称
:return: 列表,每一项为 ChapterRelationResponse 对象
"""
query = """
MATCH (start)-[r]->(end)
WHERE start.chapter = $chapter and end.chapter = $chapter
RETURN
properties(start) AS start_properties,
labels(start) AS start_labels,
TYPE(r) AS relation,
properties(end) AS end_properties,
labels(end) AS end_labels
"""
try:
async with neo4j_conn.get_session() as session:
result = await session.run(query, parameters={"chapter": chapter})
records = await result.data()
return [
ChapterRelationResponse(
start_labels=record.get("start_labels", []),
start_properties=record.get("start_properties", {}),
relation=record.get("relation", ""),
end_labels=record.get("end_labels", []),
end_properties=record.get("end_properties", {}),
)
for record in records
]
except Exception as e:
logging.error(f"Error during get_chapter_relations: {e}")
return []