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.

161 lines
5.0 KiB

3 months ago
import json
import traceback
3 months ago
import uuid
3 months ago
from util.neo4j_utils import Neo4jUtil, neo4j_client
3 months ago
import httpx
from robyn import jsonify, Response
from app import app
from controller.client import client
# --- 核心工具函数:解决元组返回错误及中文乱码 ---
def create_response(status_code, data_dict):
"""
统一响应格式封装
1. 确保返回的是 Robyn 预期的 Response 对象
2. description 必须是字符串json.dumps 结果
3. 强制使用 UTF-8 防止中文乱码
"""
return Response(
status_code=status_code,
description=json.dumps(data_dict, ensure_ascii=False),
headers={"Content-Type": "application/json; charset=utf-8"}
)
3 months ago
3 months ago
def convert_to_g6_format(data):
entities = data.get("entities", [])
relations = data.get("relations", [])
3 months ago
# 创建实体名称到唯一ID的映射
name_to_id = {}
nodes = []
for ent in entities:
name = ent.get("n")
if name and name not in name_to_id:
3 months ago
node_id = str(uuid.uuid4())
name_to_id[name] = node_id
nodes.append({
"id": node_id,
"label": name,
3 months ago
"data": {
"type": ent.get("t") # 用于 G6 的节点样式区分
3 months ago
}
3 months ago
})
3 months ago
# 构建边,并为每条边生成唯一 ID
3 months ago
edges = []
for rel in relations:
e1 = rel.get("e1")
e2 = rel.get("e2")
r = rel.get("r")
3 months ago
source_id = name_to_id.get(e1)
target_id = name_to_id.get(e2)
3 months ago
3 months ago
if source_id and target_id:
edge_id = str(uuid.uuid4())
3 months ago
edges.append({
"id": edge_id,
3 months ago
"source": source_id,
"target": target_id,
"label": r,
3 months ago
"data": {
"label": r
3 months ago
}
3 months ago
})
else:
print(f"Warning: Entity not found for relation: {rel}")
return {
"nodes": nodes,
"edges": edges
}
3 months ago
@app.post("/api/qa/analyze")
async def analyze(request):
body = request.json()
input_text = body.get("text", "").strip()
3 months ago
if not input_text:
# 使用 create_response 统一返回格式,避免使用 jsonify 可能带来的元组嵌套问题
return create_response(400, {"error": "缺少 text 字段"})
3 months ago
try:
# 1. 提取实体
3 months ago
resp = await client.post(
"/getEntity",
json={"text": input_text},
timeout=1800.0
3 months ago
)
qaList = []
if resp.status_code in (200, 202):
3 months ago
resp_json = resp.json()
# 处理字符串形式的 data 字段
resp_json_data = resp_json.get("data", "{}")
if isinstance(resp_json_data, str):
resp_json_data = json.loads(resp_json_data)
3 months ago
entities = resp_json_data.get("entities", [])
print(f"提取到的实体: {entities}")
# 查询 Neo4j 邻居(此逻辑保留,虽目前未直接放入 qaList,可能用于后续扩展)
3 months ago
for name in entities:
neo4j_client.find_neighbors_with_relationshipsAI(
3 months ago
node_label=None,
direction="both",
node_properties={"name": name},
3 months ago
rel_type=None
3 months ago
)
# 2. 问答代理获取答案列表
resp_agent = await client.post(
3 months ago
"/question_agent",
json={"neo4j_data": [], "text": input_text},
timeout=1800.0
3 months ago
)
3 months ago
resp_data = resp_agent.json()
inner_data = json.loads(resp_data["data"])
items = inner_data.get("json", [])
3 months ago
# 按权重排序取前5
sorted_items = sorted(items, key=lambda x: x.get("sort", 0), reverse=True)
3 months ago
top5 = sorted_items[:5]
# 3. 对每个答案提取关系图谱
3 months ago
for item in top5:
resp_ext = await client.post(
3 months ago
"/extract_entities_and_relations",
json={"text": item['answer']},
timeout=1800.0
3 months ago
)
if resp_ext.status_code in (200, 202):
result = resp_ext.json()
3 months ago
g6_data = convert_to_g6_format(result)
3 months ago
qaList.append({
"answer": item["answer"],
3 months ago
"result": g6_data,
})
print(f"处理成功 xh: {item.get('xh')}, sort: {item.get('sort')}")
# --- 修复点:使用 create_response 返回解析后的数组 ---
return create_response(200, qaList)
3 months ago
else:
return create_response(resp.status_code, {
3 months ago
"error": "提交失败",
"detail": resp.text
})
3 months ago
except Exception as e:
error_trace = traceback.format_exc()
print("❌ 发生异常:")
print(error_trace)
return create_response(500, {"error": str(e), "traceback": error_trace})