增加环绕侦察场景适配
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
101
tools/test_validate/modules/json_visualizer.py
Normal file
101
tools/test_validate/modules/json_visualizer.py
Normal file
@@ -0,0 +1,101 @@
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
import time
|
||||
from .visualizer import generate_visualization
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(level=logging.INFO, format='%(message)s')
|
||||
|
||||
def run_json_visualization():
|
||||
print("\n🚀 进入 JSON 文件可视化模式")
|
||||
print("说明: 读取包含行为树(Pytree)结构的 JSON 文件并生成 PNG 图片。")
|
||||
print(" 支持的 JSON 结构: 直接是 Pytree 根节点对象,或包含 'root'/'data' 字段的对象。")
|
||||
|
||||
while True:
|
||||
try:
|
||||
file_path = input("\n请输入 JSON 文件路径 (输入 'q' 返回): ").strip()
|
||||
|
||||
if file_path.lower() in ['q', 'exit', 'quit']:
|
||||
break
|
||||
|
||||
if not file_path:
|
||||
continue
|
||||
|
||||
# 处理相对路径
|
||||
if not os.path.isabs(file_path):
|
||||
# 尝试相对于当前工作目录
|
||||
if not os.path.exists(file_path):
|
||||
# 尝试相对于 tools/test_validate
|
||||
base_dir = os.path.dirname(os.path.dirname(__file__))
|
||||
alt_path = os.path.join(base_dir, file_path)
|
||||
if os.path.exists(alt_path):
|
||||
file_path = alt_path
|
||||
|
||||
if not os.path.exists(file_path):
|
||||
print(f"❌ 文件不存在: {file_path}")
|
||||
continue
|
||||
|
||||
if not os.path.isfile(file_path):
|
||||
print(f"❌ 路径不是一个文件: {file_path}")
|
||||
continue
|
||||
|
||||
print(f"📖 正在读取: {file_path}")
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"❌ JSON 解析失败: {e}")
|
||||
continue
|
||||
except Exception as e:
|
||||
print(f"❌ 读取文件失败: {e}")
|
||||
continue
|
||||
|
||||
# 尝试提取 root 节点
|
||||
root_node = None
|
||||
|
||||
# 情况 1: 顶层就是 root 节点 (包含 name 和 type)
|
||||
if isinstance(data, dict) and 'name' in data and 'type' in data:
|
||||
root_node = data
|
||||
print("ℹ️ 识别到顶层即为 Pytree 根节点")
|
||||
|
||||
# 情况 2: 包含 root 字段
|
||||
elif isinstance(data, dict) and 'root' in data:
|
||||
root_node = data['root']
|
||||
print("ℹ️ 从 'root' 字段提取节点")
|
||||
|
||||
# 情况 3: 包含 data 字段,data 里有 root
|
||||
elif isinstance(data, dict) and 'data' in data and isinstance(data['data'], dict) and 'root' in data['data']:
|
||||
root_node = data['data']['root']
|
||||
print("ℹ️ 从 'data.root' 字段提取节点")
|
||||
|
||||
# 情况 4: 包含 data 字段,data 本身就是 root
|
||||
elif isinstance(data, dict) and 'data' in data and isinstance(data['data'], dict) and 'name' in data['data']:
|
||||
root_node = data['data']
|
||||
print("ℹ️ 从 'data' 字段提取节点")
|
||||
|
||||
if not root_node:
|
||||
print("❌ 无法识别 Pytree 结构。JSON 对象必须包含 'name' 和 'type' 字段,或在 'root'/'data' 字段中包含它们。")
|
||||
continue
|
||||
|
||||
# 生成输出路径
|
||||
dir_name = os.path.dirname(file_path)
|
||||
base_name = os.path.splitext(os.path.basename(file_path))[0]
|
||||
output_path = os.path.join(dir_name, f"{base_name}.png")
|
||||
|
||||
print("🎨 正在生成可视化...")
|
||||
if generate_visualization(root_node, output_path):
|
||||
print(f"✅ 可视化图已生成: {output_path}")
|
||||
# 尝试打开图片 (仅限支持的系统)
|
||||
# if os.name == 'posix':
|
||||
# os.system(f"xdg-open '{output_path}'")
|
||||
else:
|
||||
print("❌ 生成失败,请检查 graphviz 是否安装正确")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n已取消")
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"❌ 发生未预期的错误: {e}")
|
||||
|
||||
print("\n已返回主菜单")
|
||||
@@ -97,6 +97,11 @@ def _add_nodes_and_edges(node: dict, dot, parent_id: str | None = None) -> str:
|
||||
shape = 'ellipse'
|
||||
style = 'filled'
|
||||
fillcolor = '#e1d5e7' # 紫色
|
||||
elif node_type == 'decorator':
|
||||
shape = 'diamond'
|
||||
style = 'filled'
|
||||
fillcolor = '#f5f5f5' # 浅灰
|
||||
border_color = '#333333'
|
||||
|
||||
# 特别标记安全相关节点
|
||||
if node.get('name') in ['battery_above', 'gps_status', 'SafetyMonitor']:
|
||||
@@ -111,6 +116,11 @@ def _add_nodes_and_edges(node: dict, dot, parent_id: str | None = None) -> str:
|
||||
|
||||
# 递归处理子节点
|
||||
children = node.get("children", [])
|
||||
|
||||
# 处理 decorator 类型的 child 字段(单一子节点)
|
||||
if node_type == 'decorator' and 'child' in node:
|
||||
children = [node['child']]
|
||||
|
||||
if not children:
|
||||
return current_id
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from modules.interactive_test import run_interactive_test
|
||||
from modules.batch_runner import run_batch_test
|
||||
from modules.json_visualizer import run_json_visualization
|
||||
|
||||
def clear_screen():
|
||||
os.system('cls' if os.name == 'nt' else 'clear')
|
||||
@@ -82,10 +83,11 @@ def main():
|
||||
print(" - 读取指令文件,支持多轮压力测试,生成统计报告")
|
||||
print("3. 上传任务到无人机 (Drone Uploader)")
|
||||
print("4. LLM 服务连通性测试 (LLM Tester)")
|
||||
print("5. JSON 文件可视化 (Visualize JSON File)")
|
||||
print("0. 退出")
|
||||
print("-" * 60)
|
||||
|
||||
choice = input("请输入选项 [0-4]: ").strip()
|
||||
choice = input("请输入选项 [0-5]: ").strip()
|
||||
|
||||
if choice == '1':
|
||||
try:
|
||||
@@ -106,6 +108,9 @@ def main():
|
||||
|
||||
elif choice == '4':
|
||||
run_legacy_module("llm_tester.py")
|
||||
|
||||
elif choice == '5':
|
||||
run_json_visualization()
|
||||
|
||||
elif choice == '0':
|
||||
print("\n👋 再见!")
|
||||
|
||||
Reference in New Issue
Block a user