This commit is contained in:
minecraft1024a
2025-11-07 20:21:36 +08:00
parent c253d60d6a
commit 80b040da2f

View File

@@ -5,22 +5,21 @@
"""
import asyncio
import orjson
import logging
# 添加项目根目录到 Python 路径
import sys
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional
from typing import Optional
from flask import Flask, jsonify, render_template, request
from flask_cors import CORS
# 添加项目根目录到 Python 路径
import sys
project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root))
from src.memory_graph.manager import MemoryManager
from src.memory_graph.models import EdgeType, MemoryType, NodeType
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@@ -48,13 +47,13 @@ def init_memory_manager():
raise
@app.route('/')
@app.route("/")
def index():
"""主页面"""
return render_template('visualizer.html')
return render_template("visualizer.html")
@app.route('/api/graph/full')
@app.route("/api/graph/full")
def get_full_graph():
"""
获取完整记忆图数据
@@ -79,28 +78,30 @@ def get_full_graph():
for memory in all_memories:
# 添加记忆信息
memory_info.append({
'id': memory.id,
'type': memory.memory_type.value,
'importance': memory.importance,
'activation': memory.activation,
'status': memory.status.value,
'created_at': memory.created_at.isoformat(),
'text': memory.to_text(),
'access_count': memory.access_count,
})
memory_info.append(
{
"id": memory.id,
"type": memory.memory_type.value,
"importance": memory.importance,
"activation": memory.activation,
"status": memory.status.value,
"created_at": memory.created_at.isoformat(),
"text": memory.to_text(),
"access_count": memory.access_count,
}
)
# 处理节点
for node in memory.nodes:
if node.id not in nodes_dict:
nodes_dict[node.id] = {
'id': node.id,
'label': node.content,
'type': node.node_type.value,
'group': node.node_type.name, # 用于颜色分组
'title': f"{node.node_type.value}: {node.content}",
'metadata': node.metadata,
'created_at': node.created_at.isoformat(),
"id": node.id,
"label": node.content,
"type": node.node_type.value,
"group": node.node_type.name, # 用于颜色分组
"title": f"{node.node_type.value}: {node.content}",
"metadata": node.metadata,
"created_at": node.created_at.isoformat(),
}
# 处理边 - 使用字典自动去重
@@ -114,43 +115,42 @@ def get_full_graph():
counter += 1
edges_dict[edge_id] = {
'id': edge_id,
'from': edge.source_id,
'to': edge.target_id,
'label': edge.relation,
'type': edge.edge_type.value,
'importance': edge.importance,
'title': f"{edge.edge_type.value}: {edge.relation}",
'arrows': 'to',
'memory_id': memory.id,
"id": edge_id,
"from": edge.source_id,
"to": edge.target_id,
"label": edge.relation,
"type": edge.edge_type.value,
"importance": edge.importance,
"title": f"{edge.edge_type.value}: {edge.relation}",
"arrows": "to",
"memory_id": memory.id,
}
nodes_list = list(nodes_dict.values())
edges_list = list(edges_dict.values())
return jsonify({
'success': True,
'data': {
'nodes': nodes_list,
'edges': edges_list,
'memories': memory_info,
'stats': {
'total_nodes': len(nodes_list),
'total_edges': len(edges_list),
'total_memories': len(all_memories),
}
return jsonify(
{
"success": True,
"data": {
"nodes": nodes_list,
"edges": edges_list,
"memories": memory_info,
"stats": {
"total_nodes": len(nodes_list),
"total_edges": len(edges_list),
"total_memories": len(all_memories),
},
},
}
})
)
except Exception as e:
logger.error(f"获取图数据失败: {e}", exc_info=True)
return jsonify({
'success': False,
'error': str(e)
}), 500
return jsonify({"success": False, "error": str(e)}), 500
@app.route('/api/memory/<memory_id>')
@app.route("/api/memory/<memory_id>")
def get_memory_detail(memory_id: str):
"""
获取特定记忆的详细信息
@@ -165,25 +165,16 @@ def get_memory_detail(memory_id: str):
memory = memory_manager.graph_store.get_memory_by_id(memory_id)
if memory is None:
return jsonify({
'success': False,
'error': '记忆不存在'
}), 404
return jsonify({"success": False, "error": "记忆不存在"}), 404
return jsonify({
'success': True,
'data': memory.to_dict()
})
return jsonify({"success": True, "data": memory.to_dict()})
except Exception as e:
logger.error(f"获取记忆详情失败: {e}", exc_info=True)
return jsonify({
'success': False,
'error': str(e)
}), 500
return jsonify({"success": False, "error": str(e)}), 500
@app.route('/api/search')
@app.route("/api/search")
def search_memories():
"""
搜索记忆
@@ -197,49 +188,45 @@ def search_memories():
if memory_manager is None:
init_memory_manager()
query = request.args.get('q', '')
memory_type = request.args.get('type', None)
limit = int(request.args.get('limit', 50))
query = request.args.get("q", "")
memory_type = request.args.get("type", None)
limit = int(request.args.get("limit", 50))
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
# 执行搜索
results = loop.run_until_complete(
memory_manager.search_memories(
query=query,
top_k=limit
)
)
results = loop.run_until_complete(memory_manager.search_memories(query=query, top_k=limit))
# 构建返回数据
memories = []
for memory in results:
memories.append({
'id': memory.id,
'text': memory.to_text(),
'type': memory.memory_type.value,
'importance': memory.importance,
'created_at': memory.created_at.isoformat(),
})
memories.append(
{
"id": memory.id,
"text": memory.to_text(),
"type": memory.memory_type.value,
"importance": memory.importance,
"created_at": memory.created_at.isoformat(),
}
)
return jsonify({
'success': True,
'data': {
'results': memories,
'count': len(memories),
return jsonify(
{
"success": True,
"data": {
"results": memories,
"count": len(memories),
},
}
})
)
except Exception as e:
logger.error(f"搜索失败: {e}", exc_info=True)
return jsonify({
'success': False,
'error': str(e)
}), 500
return jsonify({"success": False, "error": str(e)}), 500
@app.route('/api/stats')
@app.route("/api/stats")
def get_statistics():
"""
获取记忆图统计信息
@@ -259,36 +246,30 @@ def get_statistics():
all_edges += len(memory.edges)
stats = {
'total_memories': len(all_memories),
'total_nodes': len(all_nodes),
'total_edges': all_edges,
'node_types': {},
'memory_types': {},
"total_memories": len(all_memories),
"total_nodes": len(all_nodes),
"total_edges": all_edges,
"node_types": {},
"memory_types": {},
}
# 统计节点类型分布
for memory in all_memories:
mem_type = memory.memory_type.value
stats['memory_types'][mem_type] = stats['memory_types'].get(mem_type, 0) + 1
stats["memory_types"][mem_type] = stats["memory_types"].get(mem_type, 0) + 1
for node in memory.nodes:
node_type = node.node_type.value
stats['node_types'][node_type] = stats['node_types'].get(node_type, 0) + 1
stats["node_types"][node_type] = stats["node_types"].get(node_type, 0) + 1
return jsonify({
'success': True,
'data': stats
})
return jsonify({"success": True, "data": stats})
except Exception as e:
logger.error(f"获取统计信息失败: {e}", exc_info=True)
return jsonify({
'success': False,
'error': str(e)
}), 500
return jsonify({"success": False, "error": str(e)}), 500
@app.route('/api/files')
@app.route("/api/files")
def list_files():
"""
列出所有可用的数据文件
@@ -296,50 +277,48 @@ def list_files():
"""
try:
from pathlib import Path
data_dir = Path("data/memory_graph")
files = []
if data_dir.exists():
for f in data_dir.glob("*.json"):
stat = f.stat()
files.append({
'path': str(f),
'name': f.name,
'size': stat.st_size,
'size_kb': round(stat.st_size / 1024, 2),
'modified': datetime.fromtimestamp(stat.st_mtime).isoformat(),
'modified_readable': datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M:%S'),
'is_current': True # 完整版始终使用内存数据
})
files.append(
{
"path": str(f),
"name": f.name,
"size": stat.st_size,
"size_kb": round(stat.st_size / 1024, 2),
"modified": datetime.fromtimestamp(stat.st_mtime).isoformat(),
"modified_readable": datetime.fromtimestamp(stat.st_mtime).strftime("%Y-%m-%d %H:%M:%S"),
"is_current": True, # 完整版始终使用内存数据
}
)
return jsonify({
'success': True,
'files': files,
'count': len(files),
'current_file': 'memory_manager (实时数据)',
'note': '完整版服务器使用实时内存数据,如需切换文件请使用独立版服务器'
})
return jsonify(
{
"success": True,
"files": files,
"count": len(files),
"current_file": "memory_manager (实时数据)",
"note": "完整版服务器使用实时内存数据,如需切换文件请使用独立版服务器",
}
)
except Exception as e:
logger.error(f"获取文件列表失败: {e}", exc_info=True)
return jsonify({
'success': False,
'error': str(e)
}), 500
return jsonify({"success": False, "error": str(e)}), 500
@app.route('/api/reload')
@app.route("/api/reload")
def reload_data():
"""
重新加载数据
"""
return jsonify({
'success': True,
'message': '完整版服务器使用实时数据,无需重新加载',
'note': '数据始终是最新的'
})
return jsonify({"success": True, "message": "完整版服务器使用实时数据,无需重新加载", "note": "数据始终是最新的"})
def run_server(host: str = '127.0.0.1', port: int = 5000, debug: bool = False):
def run_server(host: str = "127.0.0.1", port: int = 5000, debug: bool = False):
"""
启动可视化服务器
@@ -352,5 +331,5 @@ def run_server(host: str = '127.0.0.1', port: int = 5000, debug: bool = False):
app.run(host=host, port=port, debug=debug)
if __name__ == '__main__':
if __name__ == "__main__":
run_server(debug=True)