- Introduced the Report Agent module to facilitate the automatic generation of simulation analysis reports using LangChain and Zep, following the ReACT model. - Added functionality for report outline planning, segmented content generation, and user interaction through a dialogue interface. - Implemented new API endpoints for report generation, status checking, and retrieval, enhancing the overall reporting capabilities. - Updated README.md to include detailed instructions on the new report generation features and API usage. - Enhanced the project structure to accommodate the new report management functionalities, including report storage and retrieval mechanisms.
829 lines
24 KiB
Python
829 lines
24 KiB
Python
"""
|
||
Report API路由
|
||
提供模拟报告生成、获取、对话等接口
|
||
"""
|
||
|
||
import os
|
||
import traceback
|
||
import threading
|
||
from flask import request, jsonify, send_file
|
||
|
||
from . import report_bp
|
||
from ..config import Config
|
||
from ..services.report_agent import ReportAgent, ReportManager, ReportStatus
|
||
from ..services.simulation_manager import SimulationManager
|
||
from ..models.project import ProjectManager
|
||
from ..models.task import TaskManager, TaskStatus
|
||
from ..utils.logger import get_logger
|
||
|
||
logger = get_logger('mirofish.api.report')
|
||
|
||
|
||
# ============== 报告生成接口 ==============
|
||
|
||
@report_bp.route('/generate', methods=['POST'])
|
||
def generate_report():
|
||
"""
|
||
生成模拟分析报告(异步任务)
|
||
|
||
这是一个耗时操作,接口会立即返回task_id,
|
||
使用 GET /api/report/generate/status 查询进度
|
||
|
||
请求(JSON):
|
||
{
|
||
"simulation_id": "sim_xxxx", // 必填,模拟ID
|
||
"force_regenerate": false // 可选,强制重新生成
|
||
}
|
||
|
||
返回:
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"simulation_id": "sim_xxxx",
|
||
"task_id": "task_xxxx",
|
||
"status": "generating",
|
||
"message": "报告生成任务已启动"
|
||
}
|
||
}
|
||
"""
|
||
try:
|
||
data = request.get_json() or {}
|
||
|
||
simulation_id = data.get('simulation_id')
|
||
if not simulation_id:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": "请提供 simulation_id"
|
||
}), 400
|
||
|
||
force_regenerate = data.get('force_regenerate', False)
|
||
|
||
# 获取模拟信息
|
||
manager = SimulationManager()
|
||
state = manager.get_simulation(simulation_id)
|
||
|
||
if not state:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": f"模拟不存在: {simulation_id}"
|
||
}), 404
|
||
|
||
# 检查是否已有报告
|
||
if not force_regenerate:
|
||
existing_report = ReportManager.get_report_by_simulation(simulation_id)
|
||
if existing_report and existing_report.status == ReportStatus.COMPLETED:
|
||
return jsonify({
|
||
"success": True,
|
||
"data": {
|
||
"simulation_id": simulation_id,
|
||
"report_id": existing_report.report_id,
|
||
"status": "completed",
|
||
"message": "报告已存在",
|
||
"already_generated": True
|
||
}
|
||
})
|
||
|
||
# 获取项目信息
|
||
project = ProjectManager.get_project(state.project_id)
|
||
if not project:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": f"项目不存在: {state.project_id}"
|
||
}), 404
|
||
|
||
graph_id = state.graph_id or project.graph_id
|
||
if not graph_id:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": "缺少图谱ID,请确保已构建图谱"
|
||
}), 400
|
||
|
||
simulation_requirement = project.simulation_requirement
|
||
if not simulation_requirement:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": "缺少模拟需求描述"
|
||
}), 400
|
||
|
||
# 创建异步任务
|
||
task_manager = TaskManager()
|
||
task_id = task_manager.create_task(
|
||
task_type="report_generate",
|
||
metadata={
|
||
"simulation_id": simulation_id,
|
||
"graph_id": graph_id
|
||
}
|
||
)
|
||
|
||
# 定义后台任务
|
||
def run_generate():
|
||
try:
|
||
task_manager.update_task(
|
||
task_id,
|
||
status=TaskStatus.PROCESSING,
|
||
progress=0,
|
||
message="初始化Report Agent..."
|
||
)
|
||
|
||
# 创建Report Agent
|
||
agent = ReportAgent(
|
||
graph_id=graph_id,
|
||
simulation_id=simulation_id,
|
||
simulation_requirement=simulation_requirement
|
||
)
|
||
|
||
# 进度回调
|
||
def progress_callback(stage, progress, message):
|
||
task_manager.update_task(
|
||
task_id,
|
||
progress=progress,
|
||
message=f"[{stage}] {message}"
|
||
)
|
||
|
||
# 生成报告
|
||
report = agent.generate_report(progress_callback=progress_callback)
|
||
|
||
# 保存报告
|
||
ReportManager.save_report(report)
|
||
|
||
if report.status == ReportStatus.COMPLETED:
|
||
task_manager.complete_task(
|
||
task_id,
|
||
result={
|
||
"report_id": report.report_id,
|
||
"simulation_id": simulation_id,
|
||
"status": "completed"
|
||
}
|
||
)
|
||
else:
|
||
task_manager.fail_task(task_id, report.error or "报告生成失败")
|
||
|
||
except Exception as e:
|
||
logger.error(f"报告生成失败: {str(e)}")
|
||
task_manager.fail_task(task_id, str(e))
|
||
|
||
# 启动后台线程
|
||
thread = threading.Thread(target=run_generate, daemon=True)
|
||
thread.start()
|
||
|
||
return jsonify({
|
||
"success": True,
|
||
"data": {
|
||
"simulation_id": simulation_id,
|
||
"task_id": task_id,
|
||
"status": "generating",
|
||
"message": "报告生成任务已启动,请通过 /api/report/generate/status 查询进度",
|
||
"already_generated": False
|
||
}
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"启动报告生成任务失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"error": str(e),
|
||
"traceback": traceback.format_exc()
|
||
}), 500
|
||
|
||
|
||
@report_bp.route('/generate/status', methods=['POST'])
|
||
def get_generate_status():
|
||
"""
|
||
查询报告生成任务进度
|
||
|
||
请求(JSON):
|
||
{
|
||
"task_id": "task_xxxx", // 可选,generate返回的task_id
|
||
"simulation_id": "sim_xxxx" // 可选,模拟ID
|
||
}
|
||
|
||
返回:
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"task_id": "task_xxxx",
|
||
"status": "processing|completed|failed",
|
||
"progress": 45,
|
||
"message": "..."
|
||
}
|
||
}
|
||
"""
|
||
try:
|
||
data = request.get_json() or {}
|
||
|
||
task_id = data.get('task_id')
|
||
simulation_id = data.get('simulation_id')
|
||
|
||
# 如果提供了simulation_id,先检查是否已有完成的报告
|
||
if simulation_id:
|
||
existing_report = ReportManager.get_report_by_simulation(simulation_id)
|
||
if existing_report and existing_report.status == ReportStatus.COMPLETED:
|
||
return jsonify({
|
||
"success": True,
|
||
"data": {
|
||
"simulation_id": simulation_id,
|
||
"report_id": existing_report.report_id,
|
||
"status": "completed",
|
||
"progress": 100,
|
||
"message": "报告已生成",
|
||
"already_completed": True
|
||
}
|
||
})
|
||
|
||
if not task_id:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": "请提供 task_id 或 simulation_id"
|
||
}), 400
|
||
|
||
task_manager = TaskManager()
|
||
task = task_manager.get_task(task_id)
|
||
|
||
if not task:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": f"任务不存在: {task_id}"
|
||
}), 404
|
||
|
||
return jsonify({
|
||
"success": True,
|
||
"data": task.to_dict()
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"查询任务状态失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"error": str(e)
|
||
}), 500
|
||
|
||
|
||
# ============== 报告获取接口 ==============
|
||
|
||
@report_bp.route('/<report_id>', methods=['GET'])
|
||
def get_report(report_id: str):
|
||
"""
|
||
获取报告详情
|
||
|
||
返回:
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"report_id": "report_xxxx",
|
||
"simulation_id": "sim_xxxx",
|
||
"status": "completed",
|
||
"outline": {...},
|
||
"markdown_content": "...",
|
||
"created_at": "...",
|
||
"completed_at": "..."
|
||
}
|
||
}
|
||
"""
|
||
try:
|
||
report = ReportManager.get_report(report_id)
|
||
|
||
if not report:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": f"报告不存在: {report_id}"
|
||
}), 404
|
||
|
||
return jsonify({
|
||
"success": True,
|
||
"data": report.to_dict()
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"获取报告失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"error": str(e),
|
||
"traceback": traceback.format_exc()
|
||
}), 500
|
||
|
||
|
||
@report_bp.route('/by-simulation/<simulation_id>', methods=['GET'])
|
||
def get_report_by_simulation(simulation_id: str):
|
||
"""
|
||
根据模拟ID获取报告
|
||
|
||
返回:
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"report_id": "report_xxxx",
|
||
...
|
||
}
|
||
}
|
||
"""
|
||
try:
|
||
report = ReportManager.get_report_by_simulation(simulation_id)
|
||
|
||
if not report:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": f"该模拟暂无报告: {simulation_id}",
|
||
"has_report": False
|
||
}), 404
|
||
|
||
return jsonify({
|
||
"success": True,
|
||
"data": report.to_dict(),
|
||
"has_report": True
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"获取报告失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"error": str(e),
|
||
"traceback": traceback.format_exc()
|
||
}), 500
|
||
|
||
|
||
@report_bp.route('/list', methods=['GET'])
|
||
def list_reports():
|
||
"""
|
||
列出所有报告
|
||
|
||
Query参数:
|
||
simulation_id: 按模拟ID过滤(可选)
|
||
limit: 返回数量限制(默认50)
|
||
|
||
返回:
|
||
{
|
||
"success": true,
|
||
"data": [...],
|
||
"count": 10
|
||
}
|
||
"""
|
||
try:
|
||
simulation_id = request.args.get('simulation_id')
|
||
limit = request.args.get('limit', 50, type=int)
|
||
|
||
reports = ReportManager.list_reports(
|
||
simulation_id=simulation_id,
|
||
limit=limit
|
||
)
|
||
|
||
return jsonify({
|
||
"success": True,
|
||
"data": [r.to_dict() for r in reports],
|
||
"count": len(reports)
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"列出报告失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"error": str(e),
|
||
"traceback": traceback.format_exc()
|
||
}), 500
|
||
|
||
|
||
@report_bp.route('/<report_id>/download', methods=['GET'])
|
||
def download_report(report_id: str):
|
||
"""
|
||
下载报告(Markdown格式)
|
||
|
||
返回Markdown文件
|
||
"""
|
||
try:
|
||
report = ReportManager.get_report(report_id)
|
||
|
||
if not report:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": f"报告不存在: {report_id}"
|
||
}), 404
|
||
|
||
md_path = ReportManager._get_report_markdown_path(report_id)
|
||
|
||
if not os.path.exists(md_path):
|
||
# 如果MD文件不存在,生成一个临时文件
|
||
import tempfile
|
||
with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
|
||
f.write(report.markdown_content)
|
||
temp_path = f.name
|
||
|
||
return send_file(
|
||
temp_path,
|
||
as_attachment=True,
|
||
download_name=f"{report_id}.md"
|
||
)
|
||
|
||
return send_file(
|
||
md_path,
|
||
as_attachment=True,
|
||
download_name=f"{report_id}.md"
|
||
)
|
||
|
||
except Exception as e:
|
||
logger.error(f"下载报告失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"error": str(e),
|
||
"traceback": traceback.format_exc()
|
||
}), 500
|
||
|
||
|
||
@report_bp.route('/<report_id>', methods=['DELETE'])
|
||
def delete_report(report_id: str):
|
||
"""删除报告"""
|
||
try:
|
||
success = ReportManager.delete_report(report_id)
|
||
|
||
if not success:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": f"报告不存在: {report_id}"
|
||
}), 404
|
||
|
||
return jsonify({
|
||
"success": True,
|
||
"message": f"报告已删除: {report_id}"
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"删除报告失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"error": str(e),
|
||
"traceback": traceback.format_exc()
|
||
}), 500
|
||
|
||
|
||
# ============== Report Agent对话接口 ==============
|
||
|
||
@report_bp.route('/chat', methods=['POST'])
|
||
def chat_with_report_agent():
|
||
"""
|
||
与Report Agent对话
|
||
|
||
Report Agent可以在对话中自主调用检索工具来回答问题
|
||
|
||
请求(JSON):
|
||
{
|
||
"simulation_id": "sim_xxxx", // 必填,模拟ID
|
||
"message": "请解释一下舆情走向", // 必填,用户消息
|
||
"chat_history": [ // 可选,对话历史
|
||
{"role": "user", "content": "..."},
|
||
{"role": "assistant", "content": "..."}
|
||
]
|
||
}
|
||
|
||
返回:
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"response": "Agent回复...",
|
||
"tool_calls": [调用的工具列表],
|
||
"sources": [信息来源]
|
||
}
|
||
}
|
||
"""
|
||
try:
|
||
data = request.get_json() or {}
|
||
|
||
simulation_id = data.get('simulation_id')
|
||
message = data.get('message')
|
||
chat_history = data.get('chat_history', [])
|
||
|
||
if not simulation_id:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": "请提供 simulation_id"
|
||
}), 400
|
||
|
||
if not message:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": "请提供 message"
|
||
}), 400
|
||
|
||
# 获取模拟和项目信息
|
||
manager = SimulationManager()
|
||
state = manager.get_simulation(simulation_id)
|
||
|
||
if not state:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": f"模拟不存在: {simulation_id}"
|
||
}), 404
|
||
|
||
project = ProjectManager.get_project(state.project_id)
|
||
if not project:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": f"项目不存在: {state.project_id}"
|
||
}), 404
|
||
|
||
graph_id = state.graph_id or project.graph_id
|
||
if not graph_id:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": "缺少图谱ID"
|
||
}), 400
|
||
|
||
simulation_requirement = project.simulation_requirement or ""
|
||
|
||
# 创建Agent并进行对话
|
||
agent = ReportAgent(
|
||
graph_id=graph_id,
|
||
simulation_id=simulation_id,
|
||
simulation_requirement=simulation_requirement
|
||
)
|
||
|
||
result = agent.chat(message=message, chat_history=chat_history)
|
||
|
||
return jsonify({
|
||
"success": True,
|
||
"data": result
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"对话失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"error": str(e),
|
||
"traceback": traceback.format_exc()
|
||
}), 500
|
||
|
||
|
||
# ============== 报告进度与分章节接口 ==============
|
||
|
||
@report_bp.route('/<report_id>/progress', methods=['GET'])
|
||
def get_report_progress(report_id: str):
|
||
"""
|
||
获取报告生成进度(实时)
|
||
|
||
返回:
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"status": "generating",
|
||
"progress": 45,
|
||
"message": "正在生成章节: 关键发现",
|
||
"current_section": "关键发现",
|
||
"completed_sections": ["执行摘要", "模拟背景"],
|
||
"updated_at": "2025-12-09T..."
|
||
}
|
||
}
|
||
"""
|
||
try:
|
||
progress = ReportManager.get_progress(report_id)
|
||
|
||
if not progress:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": f"报告不存在或进度信息不可用: {report_id}"
|
||
}), 404
|
||
|
||
return jsonify({
|
||
"success": True,
|
||
"data": progress
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"获取报告进度失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"error": str(e),
|
||
"traceback": traceback.format_exc()
|
||
}), 500
|
||
|
||
|
||
@report_bp.route('/<report_id>/sections', methods=['GET'])
|
||
def get_report_sections(report_id: str):
|
||
"""
|
||
获取已生成的章节列表(分章节输出)
|
||
|
||
前端可以轮询此接口获取已生成的章节内容,无需等待整个报告完成
|
||
|
||
返回:
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"report_id": "report_xxxx",
|
||
"sections": [
|
||
{
|
||
"filename": "section_01.md",
|
||
"section_index": 1,
|
||
"content": "## 执行摘要\\n\\n..."
|
||
},
|
||
...
|
||
],
|
||
"total_sections": 3,
|
||
"is_complete": false
|
||
}
|
||
}
|
||
"""
|
||
try:
|
||
sections = ReportManager.get_generated_sections(report_id)
|
||
|
||
# 获取报告状态
|
||
report = ReportManager.get_report(report_id)
|
||
is_complete = report is not None and report.status == ReportStatus.COMPLETED
|
||
|
||
return jsonify({
|
||
"success": True,
|
||
"data": {
|
||
"report_id": report_id,
|
||
"sections": sections,
|
||
"total_sections": len(sections),
|
||
"is_complete": is_complete
|
||
}
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"获取章节列表失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"error": str(e),
|
||
"traceback": traceback.format_exc()
|
||
}), 500
|
||
|
||
|
||
@report_bp.route('/<report_id>/section/<int:section_index>', methods=['GET'])
|
||
def get_single_section(report_id: str, section_index: int):
|
||
"""
|
||
获取单个章节内容
|
||
|
||
返回:
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"filename": "section_01.md",
|
||
"content": "## 执行摘要\\n\\n..."
|
||
}
|
||
}
|
||
"""
|
||
try:
|
||
section_path = ReportManager._get_section_path(report_id, section_index)
|
||
|
||
if not os.path.exists(section_path):
|
||
return jsonify({
|
||
"success": False,
|
||
"error": f"章节不存在: section_{section_index:02d}.md"
|
||
}), 404
|
||
|
||
with open(section_path, 'r', encoding='utf-8') as f:
|
||
content = f.read()
|
||
|
||
return jsonify({
|
||
"success": True,
|
||
"data": {
|
||
"filename": f"section_{section_index:02d}.md",
|
||
"section_index": section_index,
|
||
"content": content
|
||
}
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"获取章节内容失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"error": str(e),
|
||
"traceback": traceback.format_exc()
|
||
}), 500
|
||
|
||
|
||
# ============== 报告状态检查接口 ==============
|
||
|
||
@report_bp.route('/check/<simulation_id>', methods=['GET'])
|
||
def check_report_status(simulation_id: str):
|
||
"""
|
||
检查模拟是否有报告,以及报告状态
|
||
|
||
用于前端判断是否解锁Interview功能
|
||
|
||
返回:
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"simulation_id": "sim_xxxx",
|
||
"has_report": true,
|
||
"report_status": "completed",
|
||
"report_id": "report_xxxx",
|
||
"interview_unlocked": true
|
||
}
|
||
}
|
||
"""
|
||
try:
|
||
report = ReportManager.get_report_by_simulation(simulation_id)
|
||
|
||
has_report = report is not None
|
||
report_status = report.status.value if report else None
|
||
report_id = report.report_id if report else None
|
||
|
||
# 只有报告完成后才解锁interview
|
||
interview_unlocked = has_report and report.status == ReportStatus.COMPLETED
|
||
|
||
return jsonify({
|
||
"success": True,
|
||
"data": {
|
||
"simulation_id": simulation_id,
|
||
"has_report": has_report,
|
||
"report_status": report_status,
|
||
"report_id": report_id,
|
||
"interview_unlocked": interview_unlocked
|
||
}
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"检查报告状态失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"error": str(e),
|
||
"traceback": traceback.format_exc()
|
||
}), 500
|
||
|
||
|
||
# ============== 工具调用接口(供调试使用)==============
|
||
|
||
@report_bp.route('/tools/search', methods=['POST'])
|
||
def search_graph_tool():
|
||
"""
|
||
图谱搜索工具接口(供调试使用)
|
||
|
||
请求(JSON):
|
||
{
|
||
"graph_id": "mirofish_xxxx",
|
||
"query": "搜索查询",
|
||
"limit": 10
|
||
}
|
||
"""
|
||
try:
|
||
data = request.get_json() or {}
|
||
|
||
graph_id = data.get('graph_id')
|
||
query = data.get('query')
|
||
limit = data.get('limit', 10)
|
||
|
||
if not graph_id or not query:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": "请提供 graph_id 和 query"
|
||
}), 400
|
||
|
||
from ..services.zep_tools import ZepToolsService
|
||
|
||
tools = ZepToolsService()
|
||
result = tools.search_graph(
|
||
graph_id=graph_id,
|
||
query=query,
|
||
limit=limit
|
||
)
|
||
|
||
return jsonify({
|
||
"success": True,
|
||
"data": result.to_dict()
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"图谱搜索失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"error": str(e),
|
||
"traceback": traceback.format_exc()
|
||
}), 500
|
||
|
||
|
||
@report_bp.route('/tools/statistics', methods=['POST'])
|
||
def get_graph_statistics_tool():
|
||
"""
|
||
图谱统计工具接口(供调试使用)
|
||
|
||
请求(JSON):
|
||
{
|
||
"graph_id": "mirofish_xxxx"
|
||
}
|
||
"""
|
||
try:
|
||
data = request.get_json() or {}
|
||
|
||
graph_id = data.get('graph_id')
|
||
|
||
if not graph_id:
|
||
return jsonify({
|
||
"success": False,
|
||
"error": "请提供 graph_id"
|
||
}), 400
|
||
|
||
from ..services.zep_tools import ZepToolsService
|
||
|
||
tools = ZepToolsService()
|
||
result = tools.get_graph_statistics(graph_id)
|
||
|
||
return jsonify({
|
||
"success": True,
|
||
"data": result
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"获取图谱统计失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"error": str(e),
|
||
"traceback": traceback.format_exc()
|
||
}), 500
|