ruff
This commit is contained in:
@@ -5,22 +5,21 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import orjson
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
# 添加项目根目录到 Python 路径
|
||||||
|
import sys
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
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 import Flask, jsonify, render_template, request
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
|
|
||||||
# 添加项目根目录到 Python 路径
|
|
||||||
import sys
|
|
||||||
project_root = Path(__file__).parent.parent.parent
|
project_root = Path(__file__).parent.parent.parent
|
||||||
sys.path.insert(0, str(project_root))
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
from src.memory_graph.manager import MemoryManager
|
from src.memory_graph.manager import MemoryManager
|
||||||
from src.memory_graph.models import EdgeType, MemoryType, NodeType
|
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -48,61 +47,63 @@ def init_memory_manager():
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
def index():
|
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():
|
def get_full_graph():
|
||||||
"""
|
"""
|
||||||
获取完整记忆图数据
|
获取完整记忆图数据
|
||||||
|
|
||||||
返回所有节点和边,格式化为前端可用的结构
|
返回所有节点和边,格式化为前端可用的结构
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if memory_manager is None:
|
if memory_manager is None:
|
||||||
init_memory_manager()
|
init_memory_manager()
|
||||||
|
|
||||||
# 获取所有记忆
|
# 获取所有记忆
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
asyncio.set_event_loop(loop)
|
asyncio.set_event_loop(loop)
|
||||||
|
|
||||||
# 获取所有记忆
|
# 获取所有记忆
|
||||||
all_memories = memory_manager.graph_store.get_all_memories()
|
all_memories = memory_manager.graph_store.get_all_memories()
|
||||||
|
|
||||||
# 构建节点和边数据
|
# 构建节点和边数据
|
||||||
nodes_dict = {} # {node_id: node_data}
|
nodes_dict = {} # {node_id: node_data}
|
||||||
edges_dict = {} # {edge_id: edge_data} - 使用字典去重
|
edges_dict = {} # {edge_id: edge_data} - 使用字典去重
|
||||||
memory_info = []
|
memory_info = []
|
||||||
|
|
||||||
for memory in all_memories:
|
for memory in all_memories:
|
||||||
# 添加记忆信息
|
# 添加记忆信息
|
||||||
memory_info.append({
|
memory_info.append(
|
||||||
'id': memory.id,
|
{
|
||||||
'type': memory.memory_type.value,
|
"id": memory.id,
|
||||||
'importance': memory.importance,
|
"type": memory.memory_type.value,
|
||||||
'activation': memory.activation,
|
"importance": memory.importance,
|
||||||
'status': memory.status.value,
|
"activation": memory.activation,
|
||||||
'created_at': memory.created_at.isoformat(),
|
"status": memory.status.value,
|
||||||
'text': memory.to_text(),
|
"created_at": memory.created_at.isoformat(),
|
||||||
'access_count': memory.access_count,
|
"text": memory.to_text(),
|
||||||
})
|
"access_count": memory.access_count,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
# 处理节点
|
# 处理节点
|
||||||
for node in memory.nodes:
|
for node in memory.nodes:
|
||||||
if node.id not in nodes_dict:
|
if node.id not in nodes_dict:
|
||||||
nodes_dict[node.id] = {
|
nodes_dict[node.id] = {
|
||||||
'id': node.id,
|
"id": node.id,
|
||||||
'label': node.content,
|
"label": node.content,
|
||||||
'type': node.node_type.value,
|
"type": node.node_type.value,
|
||||||
'group': node.node_type.name, # 用于颜色分组
|
"group": node.node_type.name, # 用于颜色分组
|
||||||
'title': f"{node.node_type.value}: {node.content}",
|
"title": f"{node.node_type.value}: {node.content}",
|
||||||
'metadata': node.metadata,
|
"metadata": node.metadata,
|
||||||
'created_at': node.created_at.isoformat(),
|
"created_at": node.created_at.isoformat(),
|
||||||
}
|
}
|
||||||
|
|
||||||
# 处理边 - 使用字典自动去重
|
# 处理边 - 使用字典自动去重
|
||||||
for edge in memory.edges:
|
for edge in memory.edges:
|
||||||
edge_id = edge.id
|
edge_id = edge.id
|
||||||
@@ -112,82 +113,72 @@ def get_full_graph():
|
|||||||
while edge_id in edges_dict:
|
while edge_id in edges_dict:
|
||||||
edge_id = f"{original_edge_id}_{counter}"
|
edge_id = f"{original_edge_id}_{counter}"
|
||||||
counter += 1
|
counter += 1
|
||||||
|
|
||||||
edges_dict[edge_id] = {
|
edges_dict[edge_id] = {
|
||||||
'id': edge_id,
|
"id": edge_id,
|
||||||
'from': edge.source_id,
|
"from": edge.source_id,
|
||||||
'to': edge.target_id,
|
"to": edge.target_id,
|
||||||
'label': edge.relation,
|
"label": edge.relation,
|
||||||
'type': edge.edge_type.value,
|
"type": edge.edge_type.value,
|
||||||
'importance': edge.importance,
|
"importance": edge.importance,
|
||||||
'title': f"{edge.edge_type.value}: {edge.relation}",
|
"title": f"{edge.edge_type.value}: {edge.relation}",
|
||||||
'arrows': 'to',
|
"arrows": "to",
|
||||||
'memory_id': memory.id,
|
"memory_id": memory.id,
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes_list = list(nodes_dict.values())
|
nodes_list = list(nodes_dict.values())
|
||||||
edges_list = list(edges_dict.values())
|
edges_list = list(edges_dict.values())
|
||||||
|
|
||||||
return jsonify({
|
return jsonify(
|
||||||
'success': True,
|
{
|
||||||
'data': {
|
"success": True,
|
||||||
'nodes': nodes_list,
|
"data": {
|
||||||
'edges': edges_list,
|
"nodes": nodes_list,
|
||||||
'memories': memory_info,
|
"edges": edges_list,
|
||||||
'stats': {
|
"memories": memory_info,
|
||||||
'total_nodes': len(nodes_list),
|
"stats": {
|
||||||
'total_edges': len(edges_list),
|
"total_nodes": len(nodes_list),
|
||||||
'total_memories': len(all_memories),
|
"total_edges": len(edges_list),
|
||||||
}
|
"total_memories": len(all_memories),
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取图数据失败: {e}", exc_info=True)
|
logger.error(f"获取图数据失败: {e}", exc_info=True)
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": str(e)}), 500
|
||||||
'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):
|
def get_memory_detail(memory_id: str):
|
||||||
"""
|
"""
|
||||||
获取特定记忆的详细信息
|
获取特定记忆的详细信息
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
memory_id: 记忆ID
|
memory_id: 记忆ID
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if memory_manager is None:
|
if memory_manager is None:
|
||||||
init_memory_manager()
|
init_memory_manager()
|
||||||
|
|
||||||
memory = memory_manager.graph_store.get_memory_by_id(memory_id)
|
memory = memory_manager.graph_store.get_memory_by_id(memory_id)
|
||||||
|
|
||||||
if memory is None:
|
if memory is None:
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": "记忆不存在"}), 404
|
||||||
'success': False,
|
|
||||||
'error': '记忆不存在'
|
return jsonify({"success": True, "data": memory.to_dict()})
|
||||||
}), 404
|
|
||||||
|
|
||||||
return jsonify({
|
|
||||||
'success': True,
|
|
||||||
'data': memory.to_dict()
|
|
||||||
})
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取记忆详情失败: {e}", exc_info=True)
|
logger.error(f"获取记忆详情失败: {e}", exc_info=True)
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": str(e)}), 500
|
||||||
'success': False,
|
|
||||||
'error': str(e)
|
|
||||||
}), 500
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/search')
|
@app.route("/api/search")
|
||||||
def search_memories():
|
def search_memories():
|
||||||
"""
|
"""
|
||||||
搜索记忆
|
搜索记忆
|
||||||
|
|
||||||
Query参数:
|
Query参数:
|
||||||
- q: 搜索关键词
|
- q: 搜索关键词
|
||||||
- type: 记忆类型过滤
|
- type: 记忆类型过滤
|
||||||
@@ -196,50 +187,46 @@ def search_memories():
|
|||||||
try:
|
try:
|
||||||
if memory_manager is None:
|
if memory_manager is None:
|
||||||
init_memory_manager()
|
init_memory_manager()
|
||||||
|
|
||||||
query = request.args.get('q', '')
|
query = request.args.get("q", "")
|
||||||
memory_type = request.args.get('type', None)
|
memory_type = request.args.get("type", None)
|
||||||
limit = int(request.args.get('limit', 50))
|
limit = int(request.args.get("limit", 50))
|
||||||
|
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
asyncio.set_event_loop(loop)
|
asyncio.set_event_loop(loop)
|
||||||
|
|
||||||
# 执行搜索
|
# 执行搜索
|
||||||
results = loop.run_until_complete(
|
results = loop.run_until_complete(memory_manager.search_memories(query=query, top_k=limit))
|
||||||
memory_manager.search_memories(
|
|
||||||
query=query,
|
|
||||||
top_k=limit
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# 构建返回数据
|
# 构建返回数据
|
||||||
memories = []
|
memories = []
|
||||||
for memory in results:
|
for memory in results:
|
||||||
memories.append({
|
memories.append(
|
||||||
'id': memory.id,
|
{
|
||||||
'text': memory.to_text(),
|
"id": memory.id,
|
||||||
'type': memory.memory_type.value,
|
"text": memory.to_text(),
|
||||||
'importance': memory.importance,
|
"type": memory.memory_type.value,
|
||||||
'created_at': memory.created_at.isoformat(),
|
"importance": memory.importance,
|
||||||
})
|
"created_at": memory.created_at.isoformat(),
|
||||||
|
}
|
||||||
return jsonify({
|
)
|
||||||
'success': True,
|
|
||||||
'data': {
|
return jsonify(
|
||||||
'results': memories,
|
{
|
||||||
'count': len(memories),
|
"success": True,
|
||||||
|
"data": {
|
||||||
|
"results": memories,
|
||||||
|
"count": len(memories),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"搜索失败: {e}", exc_info=True)
|
logger.error(f"搜索失败: {e}", exc_info=True)
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": str(e)}), 500
|
||||||
'success': False,
|
|
||||||
'error': str(e)
|
|
||||||
}), 500
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/stats')
|
@app.route("/api/stats")
|
||||||
def get_statistics():
|
def get_statistics():
|
||||||
"""
|
"""
|
||||||
获取记忆图统计信息
|
获取记忆图统计信息
|
||||||
@@ -247,48 +234,42 @@ def get_statistics():
|
|||||||
try:
|
try:
|
||||||
if memory_manager is None:
|
if memory_manager is None:
|
||||||
init_memory_manager()
|
init_memory_manager()
|
||||||
|
|
||||||
# 获取统计信息
|
# 获取统计信息
|
||||||
all_memories = memory_manager.graph_store.get_all_memories()
|
all_memories = memory_manager.graph_store.get_all_memories()
|
||||||
all_nodes = set()
|
all_nodes = set()
|
||||||
all_edges = 0
|
all_edges = 0
|
||||||
|
|
||||||
for memory in all_memories:
|
for memory in all_memories:
|
||||||
for node in memory.nodes:
|
for node in memory.nodes:
|
||||||
all_nodes.add(node.id)
|
all_nodes.add(node.id)
|
||||||
all_edges += len(memory.edges)
|
all_edges += len(memory.edges)
|
||||||
|
|
||||||
stats = {
|
stats = {
|
||||||
'total_memories': len(all_memories),
|
"total_memories": len(all_memories),
|
||||||
'total_nodes': len(all_nodes),
|
"total_nodes": len(all_nodes),
|
||||||
'total_edges': all_edges,
|
"total_edges": all_edges,
|
||||||
'node_types': {},
|
"node_types": {},
|
||||||
'memory_types': {},
|
"memory_types": {},
|
||||||
}
|
}
|
||||||
|
|
||||||
# 统计节点类型分布
|
# 统计节点类型分布
|
||||||
for memory in all_memories:
|
for memory in all_memories:
|
||||||
mem_type = memory.memory_type.value
|
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:
|
for node in memory.nodes:
|
||||||
node_type = node.node_type.value
|
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({
|
return jsonify({"success": True, "data": stats})
|
||||||
'success': True,
|
|
||||||
'data': stats
|
|
||||||
})
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取统计信息失败: {e}", exc_info=True)
|
logger.error(f"获取统计信息失败: {e}", exc_info=True)
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": str(e)}), 500
|
||||||
'success': False,
|
|
||||||
'error': str(e)
|
|
||||||
}), 500
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/files')
|
@app.route("/api/files")
|
||||||
def list_files():
|
def list_files():
|
||||||
"""
|
"""
|
||||||
列出所有可用的数据文件
|
列出所有可用的数据文件
|
||||||
@@ -296,53 +277,51 @@ def list_files():
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
data_dir = Path("data/memory_graph")
|
data_dir = Path("data/memory_graph")
|
||||||
|
|
||||||
files = []
|
files = []
|
||||||
if data_dir.exists():
|
if data_dir.exists():
|
||||||
for f in data_dir.glob("*.json"):
|
for f in data_dir.glob("*.json"):
|
||||||
stat = f.stat()
|
stat = f.stat()
|
||||||
files.append({
|
files.append(
|
||||||
'path': str(f),
|
{
|
||||||
'name': f.name,
|
"path": str(f),
|
||||||
'size': stat.st_size,
|
"name": f.name,
|
||||||
'size_kb': round(stat.st_size / 1024, 2),
|
"size": stat.st_size,
|
||||||
'modified': datetime.fromtimestamp(stat.st_mtime).isoformat(),
|
"size_kb": round(stat.st_size / 1024, 2),
|
||||||
'modified_readable': datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M:%S'),
|
"modified": datetime.fromtimestamp(stat.st_mtime).isoformat(),
|
||||||
'is_current': True # 完整版始终使用内存数据
|
"modified_readable": datetime.fromtimestamp(stat.st_mtime).strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
})
|
"is_current": True, # 完整版始终使用内存数据
|
||||||
|
}
|
||||||
return jsonify({
|
)
|
||||||
'success': True,
|
|
||||||
'files': files,
|
return jsonify(
|
||||||
'count': len(files),
|
{
|
||||||
'current_file': 'memory_manager (实时数据)',
|
"success": True,
|
||||||
'note': '完整版服务器使用实时内存数据,如需切换文件请使用独立版服务器'
|
"files": files,
|
||||||
})
|
"count": len(files),
|
||||||
|
"current_file": "memory_manager (实时数据)",
|
||||||
|
"note": "完整版服务器使用实时内存数据,如需切换文件请使用独立版服务器",
|
||||||
|
}
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取文件列表失败: {e}", exc_info=True)
|
logger.error(f"获取文件列表失败: {e}", exc_info=True)
|
||||||
return jsonify({
|
return jsonify({"success": False, "error": str(e)}), 500
|
||||||
'success': False,
|
|
||||||
'error': str(e)
|
|
||||||
}), 500
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/reload')
|
@app.route("/api/reload")
|
||||||
def reload_data():
|
def reload_data():
|
||||||
"""
|
"""
|
||||||
重新加载数据
|
重新加载数据
|
||||||
"""
|
"""
|
||||||
return jsonify({
|
return jsonify({"success": True, "message": "完整版服务器使用实时数据,无需重新加载", "note": "数据始终是最新的"})
|
||||||
'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):
|
||||||
"""
|
"""
|
||||||
启动可视化服务器
|
启动可视化服务器
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
host: 服务器地址
|
host: 服务器地址
|
||||||
port: 端口号
|
port: 端口号
|
||||||
@@ -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)
|
app.run(host=host, port=port, debug=debug)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
run_server(debug=True)
|
run_server(debug=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user