293 lines
10 KiB
Python
293 lines
10 KiB
Python
"""
|
||
TraceStudio 后端服务
|
||
基于 FastAPI 的数据处理和节点执行引擎
|
||
"""
|
||
from fastapi import FastAPI
|
||
from fastapi.middleware.cors import CORSMiddleware
|
||
import uvicorn
|
||
|
||
app = FastAPI(
|
||
title="TraceStudio Server",
|
||
description="ComfyUI 风格的 Unreal Insights 数据分析后端",
|
||
version="0.1.0"
|
||
)
|
||
|
||
# 配置 CORS
|
||
app.add_middleware(
|
||
CORSMiddleware,
|
||
allow_origins=["*"], # 开发环境允许所有来源
|
||
allow_credentials=True,
|
||
allow_methods=["*"],
|
||
allow_headers=["*"],
|
||
)
|
||
|
||
|
||
@app.get("/")
|
||
async def root():
|
||
"""服务健康检查"""
|
||
return {
|
||
"status": "running",
|
||
"service": "TraceStudio Server",
|
||
"version": "0.1.0"
|
||
}
|
||
|
||
|
||
@app.get("/plugins")
|
||
async def get_plugins():
|
||
"""
|
||
返回所有可用的算子(节点)列表
|
||
前端从这里获取可拖拽的节点类型
|
||
"""
|
||
return {
|
||
"plugins": {
|
||
# Loaders 类别
|
||
"CSVLoader": {
|
||
"display_name": "CSV 数据加载器",
|
||
"function": "Loader", # 节点功能:加载器
|
||
"category": "Loader/CSV", # 树状目录:加载器/CSV
|
||
"node_logic": "standard", # 普通节点
|
||
"supports_preview": True,
|
||
"inputs": [],
|
||
"outputs": [{"name": "table", "type": "DataTable"}],
|
||
"param_schema": {
|
||
"file_path": {
|
||
"type": "string",
|
||
"default": "",
|
||
"description": "CSV 文件路径"
|
||
},
|
||
"delimiter": {
|
||
"type": "string",
|
||
"default": ",",
|
||
"description": "分隔符"
|
||
}
|
||
}
|
||
},
|
||
"UTraceLoader": {
|
||
"display_name": "UTrace 文件加载器",
|
||
"function": "Loader", # 节点功能:加载器
|
||
"category": "Loader", # 树状目录:加载器/Trace
|
||
"node_logic": "standard",
|
||
"supports_preview": True,
|
||
"inputs": [],
|
||
"outputs": [{"name": "events", "type": "DataTable"}],
|
||
"param_schema": {
|
||
"trace_file": {
|
||
"type": "string",
|
||
"default": "",
|
||
"description": "utrace 文件路径"
|
||
}
|
||
}
|
||
},
|
||
|
||
# Transforms 类别
|
||
"FilterRows": {
|
||
"display_name": "行过滤器",
|
||
"function": "Transform", # 节点功能:转换器
|
||
"category": "Transform/Filter", # 树状目录:转换器/过滤
|
||
"node_logic": "standard",
|
||
"supports_preview": True,
|
||
"inputs": [{"name": "input", "type": "DataTable"}],
|
||
"outputs": [{"name": "output", "type": "DataTable"}],
|
||
"param_schema": {
|
||
"column": {
|
||
"type": "string",
|
||
"default": "",
|
||
"description": "要过滤的列名",
|
||
"dynamic": True # 需要动态获取列名
|
||
},
|
||
"condition": {
|
||
"type": "string",
|
||
"default": ">",
|
||
"description": "条件运算符"
|
||
},
|
||
"value": {
|
||
"type": "string",
|
||
"default": "0",
|
||
"description": "比较值"
|
||
}
|
||
}
|
||
},
|
||
"SelectColumns": {
|
||
"display_name": "列选择器",
|
||
"function": "Transform",
|
||
"category": "Transform/Select",
|
||
"node_logic": "standard",
|
||
"supports_preview": True,
|
||
"inputs": [{"name": "input", "type": "DataTable"}],
|
||
"outputs": [{"name": "output", "type": "DataTable"}],
|
||
"param_schema": {
|
||
"columns": {
|
||
"type": "string",
|
||
"default": "",
|
||
"description": "要保留的列名(逗号分隔)",
|
||
"dynamic": True
|
||
}
|
||
}
|
||
},
|
||
"Aggregator": {
|
||
"display_name": "数据聚合",
|
||
"function": "Transform",
|
||
"category": "Transform/Aggregate",
|
||
"node_logic": "aggregate", # 聚合节点
|
||
"allow_multiple_inputs": True, # 允许多输入
|
||
"supports_preview": True,
|
||
"inputs": [{"name": "input", "type": "DataTable"}],
|
||
"outputs": [{"name": "result", "type": "DataTable"}],
|
||
"param_schema": {
|
||
"group_by": {
|
||
"type": "string",
|
||
"default": "",
|
||
"description": "分组字段",
|
||
"dynamic": True
|
||
},
|
||
"agg_func": {
|
||
"type": "string",
|
||
"default": "mean",
|
||
"description": "聚合函数(mean/sum/count)"
|
||
}
|
||
}
|
||
},
|
||
|
||
# Filters 类别
|
||
"TimeRangeFilter": {
|
||
"display_name": "时间范围过滤",
|
||
"function": "Transform",
|
||
"category": "Transform/Filter",
|
||
"node_logic": "standard",
|
||
"supports_preview": True,
|
||
"inputs": [{"name": "input", "type": "DataTable"}],
|
||
"outputs": [{"name": "output", "type": "DataTable"}],
|
||
"param_schema": {
|
||
"time_column": {
|
||
"type": "string",
|
||
"default": "timestamp",
|
||
"description": "时间列名",
|
||
"dynamic": True
|
||
},
|
||
"start_time": {
|
||
"type": "integer",
|
||
"default": 0,
|
||
"description": "开始时间"
|
||
},
|
||
"end_time": {
|
||
"type": "integer",
|
||
"default": 1000,
|
||
"description": "结束时间"
|
||
}
|
||
}
|
||
},
|
||
|
||
# Visualizers 类别
|
||
"ChartVisualizer": {
|
||
"display_name": "图表可视化",
|
||
"function": "Visualizer",
|
||
"category": "Visualizer/Chart",
|
||
"node_logic": "standard",
|
||
"supports_preview": True,
|
||
"inputs": [{"name": "data", "type": "DataTable"}],
|
||
"outputs": [],
|
||
"param_schema": {
|
||
"chart_type": {
|
||
"type": "string",
|
||
"default": "line",
|
||
"description": "图表类型(line/bar/scatter)"
|
||
},
|
||
"x_column": {
|
||
"type": "string",
|
||
"default": "",
|
||
"description": "X 轴列名",
|
||
"dynamic": True
|
||
},
|
||
"y_column": {
|
||
"type": "string",
|
||
"default": "",
|
||
"description": "Y 轴列名",
|
||
"dynamic": True
|
||
}
|
||
}
|
||
},
|
||
"TableOutput": {
|
||
"display_name": "表格输出",
|
||
"function": "Visualizer",
|
||
"category": "Visualizer/Table",
|
||
"node_logic": "standard",
|
||
"supports_preview": True,
|
||
"inputs": [{"name": "data", "type": "DataTable"}],
|
||
"outputs": [],
|
||
"param_schema": {
|
||
"max_rows": {
|
||
"type": "integer",
|
||
"default": 100,
|
||
"description": "最大显示行数"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
@app.post("/node/preview")
|
||
async def preview_node(payload: dict):
|
||
"""
|
||
预览节点的输出数据(采样模式)
|
||
这是一个占位实现,用于前端测试
|
||
"""
|
||
node = payload.get("node", {})
|
||
limit = payload.get("limit", 10)
|
||
|
||
# 模拟数据预览
|
||
node_type = node.get("type", "unknown")
|
||
|
||
if node_type == "Loader":
|
||
return {
|
||
"columns": ["timestamp", "frame_time", "cpu_usage", "memory_mb"],
|
||
"preview": [
|
||
{"timestamp": 0, "frame_time": 16.7, "cpu_usage": 45.2, "memory_mb": 1024},
|
||
{"timestamp": 16, "frame_time": 17.1, "cpu_usage": 48.5, "memory_mb": 1028},
|
||
{"timestamp": 32, "frame_time": 16.3, "cpu_usage": 43.8, "memory_mb": 1025},
|
||
{"timestamp": 48, "frame_time": 18.2, "cpu_usage": 52.1, "memory_mb": 1032},
|
||
{"timestamp": 64, "frame_time": 16.9, "cpu_usage": 46.7, "memory_mb": 1027},
|
||
][:limit]
|
||
}
|
||
elif node_type == "Transform":
|
||
return {
|
||
"columns": ["timestamp", "frame_time"],
|
||
"preview": [
|
||
{"timestamp": 0, "frame_time": 16.7},
|
||
{"timestamp": 16, "frame_time": 17.1},
|
||
{"timestamp": 32, "frame_time": 16.3},
|
||
][:limit]
|
||
}
|
||
else:
|
||
return {
|
||
"error": f"节点类型 '{node_type}' 暂未实现预览功能"
|
||
}
|
||
|
||
|
||
@app.post("/graph/execute")
|
||
async def execute_graph(payload: dict):
|
||
"""
|
||
执行完整的计算图
|
||
这是一个占位实现
|
||
"""
|
||
nodes = payload.get("nodes", [])
|
||
edges = payload.get("edges", [])
|
||
|
||
return {
|
||
"status": "success",
|
||
"message": f"成功执行了包含 {len(nodes)} 个节点和 {len(edges)} 条连接的计算图",
|
||
"execution_time": 0.123
|
||
}
|
||
|
||
|
||
if __name__ == "__main__":
|
||
print("🚀 启动 TraceStudio 服务器...")
|
||
print("📡 访问 http://127.0.0.1:8000/docs 查看 API 文档")
|
||
|
||
uvicorn.run(
|
||
app,
|
||
host="127.0.0.1",
|
||
port=8000,
|
||
reload=True # 开发模式自动重载
|
||
)
|