jingrow-framework/apps/jingrow/jingrow/api/node_definitions.py

190 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from fastapi import APIRouter, HTTPException
from typing import Dict, Any, List
from pathlib import Path
import json
from jingrow.utils.fs import atomic_write_json
from jingrow.utils.jingrow_api import get_record_id, create_record
router = APIRouter()
@router.post("/jingrow/node-definitions/export")
async def export_node_definition(payload: Dict[str, Any]):
"""
导出节点定义metadata + schema为 JSON 文件backend/nodes/{type}/{type}.json
"""
try:
metadata = payload.get("metadata") or {}
schema = payload.get("schema") or {}
node_type = metadata.get("type")
if not node_type:
raise ValueError("metadata.type is required")
export_data = {"metadata": metadata, **(schema or {})}
current_file = Path(__file__).resolve()
jingrow_root = current_file.parents[1] # 修正路径层级
new_root = jingrow_root / "ai" / "pagetype" / "local_ai_agent" / "nodes"
target = new_root / node_type / f"{node_type}.json"
atomic_write_json(target, export_data)
return {"success": True, "path": str(target)}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
@router.post("/jingrow/node-definitions/import-local")
async def import_local_node_definitions():
"""
扫描本地节点定义目录,按 metadata 去重后导入到 Local Ai Node。
"""
try:
current_file = Path(__file__).resolve()
jingrow_root = current_file.parents[1] # 修正路径层级
nodes_root = jingrow_root / "ai" / "pagetype" / "local_ai_agent" / "nodes"
if not nodes_root.exists():
return {"success": True, "matched": 0, "imported": 0, "skipped_existing": 0}
matched: int = 0
imported: int = 0
skipped: int = 0
errors: List[str] = []
for node_dir in nodes_root.iterdir():
if not node_dir.is_dir():
continue
json_file = node_dir / f"{node_dir.name}.json"
if not json_file.exists():
continue
matched += 1
try:
with open(json_file, "r", encoding="utf-8") as f:
data = json.load(f)
if not isinstance(data, dict):
continue
metadata = data.get("metadata") or {}
node_type = metadata.get("type")
if not node_type:
continue
# 去重:按 node_type 查询是否已存在
exists_res = get_record_id(
pagetype="Local Ai Node",
field="node_type",
value=node_type,
)
if exists_res.get("success"):
skipped += 1
continue
# 生成 schema移除 metadata 的剩余部分)
schema = dict(data)
schema.pop("metadata", None)
payload = {
"node_type": node_type,
"node_label": metadata.get("label") or node_type,
"node_icon": metadata.get("icon") or "fa-cube",
"node_color": metadata.get("color") or "#6b7280",
"node_group": metadata.get("group") or "",
"node_component": metadata.get("component_type") or "GenericNode",
"node_description": metadata.get("description") or "",
"status": "Published",
"node_schema": schema,
}
res = create_record("Local Ai Node", payload)
if res.get("success"):
imported += 1
else:
errors.append(f"{node_type}: {res.get('error')}")
except Exception as e:
errors.append(f"{json_file.name}: {str(e)}")
return {
"success": True,
"matched": matched,
"imported": imported,
"skipped_existing": skipped,
"errors": errors,
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/jingrow/node-definitions/metadata")
async def get_all_node_metadata():
"""
获取所有节点的元数据,用于流程编排界面
"""
try:
current_file = Path(__file__).resolve()
jingrow_root = current_file.parents[1] # 修正路径层级
nodes_root = jingrow_root / "ai" / "pagetype" / "local_ai_agent" / "nodes"
if not nodes_root.exists():
return {"success": True, "data": {}}
metadata_map = {}
for node_dir in nodes_root.iterdir():
if not node_dir.is_dir():
continue
json_file = node_dir / f"{node_dir.name}.json"
if not json_file.exists():
continue
try:
with open(json_file, "r", encoding="utf-8") as f:
data = json.load(f)
metadata = data.get("metadata") or {}
node_type = metadata.get("type")
if not node_type:
continue
metadata_map[node_type] = {
"type": node_type,
"label": metadata.get("label") or node_type,
"icon": metadata.get("icon") or "fa-cube",
"color": metadata.get("color") or "#6b7280",
"description": metadata.get("description") or "",
"group": metadata.get("group") or "其他",
"component": metadata.get("component_type") or "GenericNode"
}
except Exception:
continue
return {"success": True, "data": metadata_map}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/jingrow/node-definitions/schema/{node_type}")
async def get_node_schema(node_type: str):
"""
获取指定节点类型的Schema配置
"""
try:
current_file = Path(__file__).resolve()
jingrow_root = current_file.parents[1]
nodes_root = jingrow_root / "ai" / "pagetype" / "local_ai_agent" / "nodes"
json_file = nodes_root / node_type / f"{node_type}.json"
if not json_file.exists():
raise HTTPException(status_code=404, detail=f"节点类型 {node_type} 不存在")
with open(json_file, "r", encoding="utf-8") as f:
data = json.load(f)
schema = dict(data)
schema.pop("metadata", None)
return {"success": True, "data": schema}
except FileNotFoundError:
raise HTTPException(status_code=404, detail=f"节点类型 {node_type} 不存在")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))