This commit is contained in:
Boshuang Zhao 2026-01-12 11:13:01 +08:00
parent 59ed66e687
commit 44f87d3951
19 changed files with 68 additions and 36 deletions

View File

@ -313,7 +313,7 @@ async def ws_execute_graph(websocket: WebSocket):
"source_port": s_handle, "source_port": s_handle,
"target": edge.get("target"), "target": edge.get("target"),
"target_port": t_handle, "target_port": t_handle,
"dimension_mode": edge.get("dimension_mode"), "dimension_mode": DimensionMode(edge.get("dimension_mode")),
}) })
settings = init_msg.get("settings") or {} settings = init_msg.get("settings") or {}

View File

@ -40,6 +40,8 @@ async def list_files(
try: try:
for item in target_path.iterdir(): for item in target_path.iterdir():
# 统一使用正斜杠格式 # 统一使用正斜杠格式
if item.name.startswith("__"):
continue # 跳过隐藏文件
relative_path = str(item.relative_to(CLOUD_ROOT)).replace('\\', '/') relative_path = str(item.relative_to(CLOUD_ROOT)).replace('\\', '/')
items.append({ items.append({
"name": item.name, "name": item.name,

View File

@ -65,9 +65,7 @@ class TraceLoader_Metadata(TraceNode):
print("TraceLoader_Metadata: process called with utrace_file =", utrace_file, ", tokens =", tokens) print("TraceLoader_Metadata: process called with utrace_file =", utrace_file, ", tokens =", tokens)
if not utrace_file: if not utrace_file:
time.sleep(3.5) raise ValueError("必须指定 utrace_file 参数")
return {}
#raise ValueError("必须指定 utrace_file 参数")
# 加载系统配置 # 加载系统配置
config = load_system_config() config = load_system_config()
@ -91,7 +89,7 @@ class TraceLoader_Metadata(TraceNode):
# 确保输出目录存在 # 确保输出目录存在
csv_full_path.parent.mkdir(parents=True, exist_ok=True) csv_full_path.parent.mkdir(parents=True, exist_ok=True)
if csv_full_path.exists(): if csv_full_path.exists() and False:
df = pl.read_csv(csv_full_path) df = pl.read_csv(csv_full_path)
return { return {
"metadata": df, "metadata": df,

View File

@ -132,6 +132,8 @@ async def list_files(
# 获取所有文件和文件夹 # 获取所有文件和文件夹
items: List[FileInfo] = [] items: List[FileInfo] = []
for item in sorted(target_path.iterdir(), key=lambda x: (not x.is_dir(), x.name.lower())): for item in sorted(target_path.iterdir(), key=lambda x: (not x.is_dir(), x.name.lower())):
if item.name.startswith("__"):
continue # 跳过隐藏文件
try: try:
items.append(get_file_info(item)) items.append(get_file_info(item))
except Exception as e: except Exception as e:

View File

@ -9,7 +9,7 @@ import yaml
from pathlib import Path from pathlib import Path
from server.app.api import endpoints_graph, endpoints_upload from server.app.api import endpoints_graph, endpoints_upload
from server.api_spec import mock_schema from server.tests.api_spec import mock_schema
from server.app.core.user_manager import init_base_structure from server.app.core.user_manager import init_base_structure
from server.app.core.node_loader import reload_custom_nodes from server.app.core.node_loader import reload_custom_nodes
from server.app.core.cache_manager import CacheManager from server.app.core.cache_manager import CacheManager

View File

@ -6,6 +6,8 @@
/** /**
* nodes/edges * nodes/edges
*/ */
import { PortModel } from '../model/PortModel'
export function toExecutorPayload(data: { export function toExecutorPayload(data: {
nodes: any[] nodes: any[]
edges: any[] edges: any[]
@ -62,14 +64,52 @@ export function toExecutorPayload(data: {
} }
}) })
// 转换边 // Helper: get port type from node meta
const edgesOut = edges.map((e: any) => ({ const findPortType = (node: any, portName: string, portSide: 'outputs' | 'inputs') => {
source: e.source, const meta = node?.meta || node?.data?.meta || {}
source_port: e.source_port || e.sourceHandle?.replace(/^output-/, '') || 'output', const ports = meta[portSide] || []
target: e.target, if (!ports || !Array.isArray(ports)) return undefined
target_port: e.target_port || e.targetHandle?.replace(/^input-/, '') || 'input', const p = ports.find((x: PortModel) => x && x.name === portName)
dimension_mode: e.dimension_mode || 'none' return PortModel.getTypeInfo(p.type || '')
})) }
// 转换边并重新计算 dimension_mode
const edgesOut = edges.map((e: any) => {
const source = e.source
const target = e.target
const source_port = e.source_port
const target_port = e.target_port
const srcNode = nodes.find((n: any) => n.id === source) || {}
const tgtNode = nodes.find((n: any) => n.id === target) || {}
const srcInfo = findPortType(srcNode, source_port, 'outputs')
const tgtInfo = findPortType(tgtNode, target_port, 'inputs')
const upDimension = srcNode.upDimension
const srcDim = (srcInfo.dim || 0) + (upDimension || 0)
const tgtDim = tgtInfo.dim || 0
// default to provided or 'none'
let dimension_mode = e.dimension_mode || 'none'
// If multiple edges into same port, mark as 'up' (collapse/pack)
if (srcDim < tgtDim) {
dimension_mode = 'up'
}else if (srcDim > tgtDim) {
dimension_mode = 'down'
} else {
dimension_mode = 'none'
}
return {
source,
source_port,
target,
target_port,
dimension_mode
}
})
const payload: any = { const payload: any = {
nodes: nodesOut, nodes: nodesOut,
@ -138,18 +178,3 @@ function normalizeOutputs(raw: any): Array<any> {
return [] return []
} }
/**
*
*/
export function getTypeInfo(type: string = 'any') {
const typeMap: Record<string, { dim: number; color: string }> = {
'any': { dim: 1, color: '#8b5cf6' },
'number': { dim: 1, color: '#3b82f6' },
'string': { dim: 1, color: '#10b981' },
'array': { dim: 2, color: '#f59e0b' },
'dataframe': { dim: 2, color: '#f59e0b' },
'image': { dim: 2, color: '#ec4899' },
'tensor': { dim: 3, color: '#ef4444' },
}
return typeMap[type] || { dim: 1, color: '#6b7280' }
}

View File

@ -1,4 +1,5 @@
import NodeModel from './NodeModel' import NodeModel from './NodeModel'
import { PortModel } from '../model/PortModel'
// 类型颜色映射 // 类型颜色映射
const TYPE_COLORS: Record<string, string> = { const TYPE_COLORS: Record<string, string> = {
DataTable: '#3b82f6', // 蓝色 DataTable: '#3b82f6', // 蓝色
@ -80,9 +81,9 @@ export class GraphModel {
if(!srcNode) continue if(!srcNode) continue
const srcOutput = srcNode.outputs.find((o:any) => o.name === (e.source_port || 'output')) const srcOutput = srcNode.outputs.find((o:any) => o.name === (e.source_port || 'output'))
const tgtInput = node.inputs.find((i:any) => i.name === (e.target_port || 'input')) const tgtInput = node.inputs.find((i:any) => i.name === (e.target_port || 'input'))
const srcDimInfo = srcOutput?.getTypeInfo ? srcOutput.getTypeInfo() : { type: '', dim: 0 } const srcDimInfo = PortModel.getTypeInfo(srcOutput?.type || '')
const tgtDimInfo = tgtInput?.getTypeInfo ? tgtInput.getTypeInfo() : { type: '', dim: 0 } const tgtDimInfo = PortModel.getTypeInfo(tgtInput?.type || '')
const srcDim = srcDimInfo.dim || 0 const srcDim = srcDimInfo.dim || 0 + (srcNode.upDimension || 0)
const tgtDim = tgtDimInfo.dim || 0 const tgtDim = tgtDimInfo.dim || 0
const diff = srcDim - tgtDim const diff = srcDim - tgtDim
if(diff > newUp) newUp = diff if(diff > newUp) newUp = diff

View File

@ -8,7 +8,10 @@ export class PortModel {
} }
getTypeInfo(): {type: string; dim: number } { getTypeInfo(): {type: string; dim: number } {
const type = this.type const result = PortModel.getTypeInfo(this.type || '')
return result
}
static getTypeInfo(type: string): {type: string; dim: number } {
if (!type) return {type: '', dim: 0 } if (!type) return {type: '', dim: 0 }
const str = String(type).trim() const str = String(type).trim()
if (typeDimMap.has(str)) return typeDimMap.get(str)! if (typeDimMap.has(str)) return typeDimMap.get(str)!

View File

@ -119,7 +119,7 @@ export class StudioRuntime {
} }
public exportWorkflow(){ public exportWorkflow(){
if(!this.graph) return { nodes: [], edges: [] } if(!this.graph) return { nodes: [], edges: [] }
const nodes = Array.from(this.graph.nodes.values()).map(n => ({ id: n.id, schemaName: n.schemaName, position: n.position, params: n.params, meta: n.meta })) const nodes = Array.from(this.graph.nodes.values()).map(n => ({ id: n.id, schemaName: n.schemaName, position: n.position, params: n.params, meta: n.meta , upDimension: n.upDimension } ))
const edges = Array.from(this.graph.edges.values()).map((e:any) => ({ id: e.id, source: e.source, source_port: e.source_port, target: e.target, target_port: e.target_port, dimension_mode: e.dimension_mode, style: e.style, animated: !!e.animated })) const edges = Array.from(this.graph.edges.values()).map((e:any) => ({ id: e.id, source: e.source, source_port: e.source_port, target: e.target, target_port: e.target_port, dimension_mode: e.dimension_mode, style: e.style, animated: !!e.animated }))
const viewport = this.viewport || null const viewport = this.viewport || null
return { nodes, edges, viewport } return { nodes, edges, viewport }

View File

@ -1,5 +1,6 @@
import useRuntimeStore from '../store/runtimeStore' import useRuntimeStore from '../store/runtimeStore'
import { runtime } from '../model/StudioRuntime' import { runtime } from '../model/StudioRuntime'
import { PortModel } from '../model/PortModel';
const GraphService = { const GraphService = {
// Graph mutations // Graph mutations
@ -16,8 +17,8 @@ const GraphService = {
const srcOutput = srcModel.outputs.find((o: any) => o.name === srcPort) const srcOutput = srcModel.outputs.find((o: any) => o.name === srcPort)
const tgtInput = tgtModel.inputs.find((i: any) => i.name === tgtPort) const tgtInput = tgtModel.inputs.find((i: any) => i.name === tgtPort)
const srcTypeInfo = srcOutput?.getTypeInfo() || { type: '', dim: 0 } const srcTypeInfo = PortModel.getTypeInfo(srcOutput?.type || '')
const tgtTypeInfo = tgtInput?.getTypeInfo() || { type: '', dim: 0 } const tgtTypeInfo = PortModel.getTypeInfo(tgtInput?.type || '')
if(srcTypeInfo.type != tgtTypeInfo.type){ console.warn('GraphService.createEdge: type mismatch'); return null } if(srcTypeInfo.type != tgtTypeInfo.type){ console.warn('GraphService.createEdge: type mismatch'); return null }
const srcDim = srcTypeInfo.dim + srcModel.upDimension const srcDim = srcTypeInfo.dim + srcModel.upDimension