Phase 5: 知识推理与问答增强
- 新增 knowledge_reasoner.py 推理引擎 - 支持因果/对比/时序/关联四种推理类型 - 智能项目总结 API (全面/高管/技术/风险) - 实体关联路径发现功能 - 前端推理面板 UI 和交互 - 更新 API 端点和健康检查 Refs: Phase 5 开发任务
This commit is contained in:
171
backend/main.py
171
backend/main.py
@@ -61,6 +61,12 @@ try:
|
||||
except ImportError:
|
||||
LLM_CLIENT_AVAILABLE = False
|
||||
|
||||
try:
|
||||
from knowledge_reasoner import get_knowledge_reasoner, KnowledgeReasoner, ReasoningType
|
||||
REASONER_AVAILABLE = True
|
||||
except ImportError:
|
||||
REASONER_AVAILABLE = False
|
||||
|
||||
app = FastAPI(title="InsightFlow", version="0.3.0")
|
||||
|
||||
app.add_middleware(
|
||||
@@ -983,14 +989,15 @@ async def get_entity_mentions(entity_id: str):
|
||||
async def health_check():
|
||||
return {
|
||||
"status": "ok",
|
||||
"version": "0.5.0",
|
||||
"phase": "Phase 5 - Timeline View",
|
||||
"version": "0.6.0",
|
||||
"phase": "Phase 5 - Knowledge Reasoning",
|
||||
"oss_available": OSS_AVAILABLE,
|
||||
"tingwu_available": TINGWU_AVAILABLE,
|
||||
"db_available": DB_AVAILABLE,
|
||||
"doc_processor_available": DOC_PROCESSOR_AVAILABLE,
|
||||
"aligner_available": ALIGNER_AVAILABLE,
|
||||
"llm_client_available": LLM_CLIENT_AVAILABLE
|
||||
"llm_client_available": LLM_CLIENT_AVAILABLE,
|
||||
"reasoner_available": REASONER_AVAILABLE
|
||||
}
|
||||
|
||||
|
||||
@@ -1336,6 +1343,164 @@ async def get_entity_timeline(entity_id: str):
|
||||
}
|
||||
|
||||
|
||||
# ==================== Phase 5: 知识推理与问答增强 API ====================
|
||||
|
||||
class ReasoningQuery(BaseModel):
|
||||
query: str
|
||||
reasoning_depth: str = "medium" # shallow/medium/deep
|
||||
stream: bool = False
|
||||
|
||||
|
||||
@app.post("/api/v1/projects/{project_id}/reasoning/query")
|
||||
async def reasoning_query(project_id: str, query: ReasoningQuery):
|
||||
"""
|
||||
增强问答 - 基于知识推理的智能问答
|
||||
|
||||
支持多种推理类型:
|
||||
- 因果推理:分析原因和影响
|
||||
- 对比推理:比较实体间的异同
|
||||
- 时序推理:分析时间线和演变
|
||||
- 关联推理:发现隐含关联
|
||||
"""
|
||||
if not DB_AVAILABLE or not REASONER_AVAILABLE:
|
||||
raise HTTPException(status_code=500, detail="Knowledge reasoner not available")
|
||||
|
||||
db = get_db_manager()
|
||||
reasoner = get_knowledge_reasoner()
|
||||
|
||||
project = db.get_project(project_id)
|
||||
if not project:
|
||||
raise HTTPException(status_code=404, detail="Project not found")
|
||||
|
||||
# 获取项目上下文
|
||||
project_context = db.get_project_summary(project_id)
|
||||
|
||||
# 获取知识图谱数据
|
||||
entities = db.list_project_entities(project_id)
|
||||
relations = db.list_project_relations(project_id)
|
||||
|
||||
graph_data = {
|
||||
"entities": [{"id": e.id, "name": e.name, "type": e.type, "definition": e.definition} for e in entities],
|
||||
"relations": relations
|
||||
}
|
||||
|
||||
# 执行增强问答
|
||||
result = await reasoner.enhanced_qa(
|
||||
query=query.query,
|
||||
project_context=project_context,
|
||||
graph_data=graph_data,
|
||||
reasoning_depth=query.reasoning_depth
|
||||
)
|
||||
|
||||
return {
|
||||
"answer": result.answer,
|
||||
"reasoning_type": result.reasoning_type.value,
|
||||
"confidence": result.confidence,
|
||||
"evidence": result.evidence,
|
||||
"knowledge_gaps": result.gaps,
|
||||
"project_id": project_id
|
||||
}
|
||||
|
||||
|
||||
@app.post("/api/v1/projects/{project_id}/reasoning/inference-path")
|
||||
async def find_inference_path(
|
||||
project_id: str,
|
||||
start_entity: str,
|
||||
end_entity: str
|
||||
):
|
||||
"""
|
||||
发现两个实体之间的推理路径
|
||||
|
||||
在知识图谱中搜索从 start_entity 到 end_entity 的路径
|
||||
"""
|
||||
if not DB_AVAILABLE or not REASONER_AVAILABLE:
|
||||
raise HTTPException(status_code=500, detail="Knowledge reasoner not available")
|
||||
|
||||
db = get_db_manager()
|
||||
reasoner = get_knowledge_reasoner()
|
||||
|
||||
project = db.get_project(project_id)
|
||||
if not project:
|
||||
raise HTTPException(status_code=404, detail="Project not found")
|
||||
|
||||
# 获取知识图谱数据
|
||||
entities = db.list_project_entities(project_id)
|
||||
relations = db.list_project_relations(project_id)
|
||||
|
||||
graph_data = {
|
||||
"entities": [{"id": e.id, "name": e.name, "type": e.type} for e in entities],
|
||||
"relations": relations
|
||||
}
|
||||
|
||||
# 查找推理路径
|
||||
paths = reasoner.find_inference_paths(start_entity, end_entity, graph_data)
|
||||
|
||||
return {
|
||||
"start_entity": start_entity,
|
||||
"end_entity": end_entity,
|
||||
"paths": [
|
||||
{
|
||||
"path": path.path,
|
||||
"strength": path.strength,
|
||||
"path_description": " -> ".join([p["entity"] for p in path.path])
|
||||
}
|
||||
for path in paths[:5] # 最多返回5条路径
|
||||
],
|
||||
"total_paths": len(paths)
|
||||
}
|
||||
|
||||
|
||||
class SummaryRequest(BaseModel):
|
||||
summary_type: str = "comprehensive" # comprehensive/executive/technical/risk
|
||||
|
||||
|
||||
@app.post("/api/v1/projects/{project_id}/reasoning/summary")
|
||||
async def project_summary(project_id: str, req: SummaryRequest):
|
||||
"""
|
||||
项目智能总结
|
||||
|
||||
根据类型生成不同侧重点的总结:
|
||||
- comprehensive: 全面总结
|
||||
- executive: 高管摘要
|
||||
- technical: 技术总结
|
||||
- risk: 风险分析
|
||||
"""
|
||||
if not DB_AVAILABLE or not REASONER_AVAILABLE:
|
||||
raise HTTPException(status_code=500, detail="Knowledge reasoner not available")
|
||||
|
||||
db = get_db_manager()
|
||||
reasoner = get_knowledge_reasoner()
|
||||
|
||||
project = db.get_project(project_id)
|
||||
if not project:
|
||||
raise HTTPException(status_code=404, detail="Project not found")
|
||||
|
||||
# 获取项目上下文
|
||||
project_context = db.get_project_summary(project_id)
|
||||
|
||||
# 获取知识图谱数据
|
||||
entities = db.list_project_entities(project_id)
|
||||
relations = db.list_project_relations(project_id)
|
||||
|
||||
graph_data = {
|
||||
"entities": [{"id": e.id, "name": e.name, "type": e.type} for e in entities],
|
||||
"relations": relations
|
||||
}
|
||||
|
||||
# 生成总结
|
||||
summary = await reasoner.summarize_project(
|
||||
project_context=project_context,
|
||||
graph_data=graph_data,
|
||||
summary_type=req.summary_type
|
||||
)
|
||||
|
||||
return {
|
||||
"project_id": project_id,
|
||||
"summary_type": req.summary_type,
|
||||
**summary
|
||||
}
|
||||
|
||||
|
||||
# Serve frontend - MUST be last to not override API routes
|
||||
app.mount("/", StaticFiles(directory="frontend", html=True), name="frontend")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user