feat: 完善批量可视化测试验证逻辑(仅提交业务代码)
826
tools/api_test_qwen2.5_vl_3b.log
Normal file
0
tools/api_test_qwen3_4b.log
Normal file
568
tools/api_test_qwen3_vl_2b.log
Normal file
548
tools/api_test_qwen3_vl_4b.log
Normal file
@@ -14,7 +14,8 @@ BASE_URL = "http://127.0.0.1:8000"
|
||||
ENDPOINT = "/generate_plan"
|
||||
|
||||
# The user prompt we will send for the test
|
||||
TEST_PROMPT = "起飞"
|
||||
#TEST_PROMPT = "无人机起飞到一米高度后,先移动至搜索区,搜索并锁定任一穿黑色衣服的人,在对其进行跟踪30秒后进行打击操作"
|
||||
TEST_PROMPT = "已知目标检测红色气球危险性高于蓝色气球高于绿色气球,飞往搜索区搜索并锁定危险性最高的气球,对其跟踪30秒"
|
||||
|
||||
# Log file path (will be created in the same directory as this script)
|
||||
LOG_FILE = os.path.join(os.path.dirname(__file__), "api_test.log")
|
||||
|
||||
1618
tools/test_validate/api_test_log_qwen2_vl_2b.txt
Normal file
3938
tools/test_validate/api_test_log_qwen3_vl_2b.txt
Normal file
3646
tools/test_validate/api_test_log_qwen3_vl_4b.txt
Normal file
269
tools/test_validate/batch_visualize.py
Normal file
@@ -0,0 +1,269 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
从API测试日志中提取JSON响应并批量可视化
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import logging
|
||||
import platform
|
||||
import random
|
||||
import html
|
||||
from typing import Dict, List, Tuple
|
||||
from collections import defaultdict
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
|
||||
def sanitize_filename(text: str) -> str:
|
||||
"""将文本转换为安全的文件名"""
|
||||
# 移除或替换不安全的字符
|
||||
text = re.sub(r'[<>:"/\\|?*]', '_', text)
|
||||
# 限制长度
|
||||
if len(text) > 100:
|
||||
text = text[:100]
|
||||
return text
|
||||
|
||||
def _pick_zh_font():
|
||||
"""选择合适的中文字体"""
|
||||
sys = platform.system()
|
||||
if sys == "Windows":
|
||||
return "Microsoft YaHei"
|
||||
elif sys == "Darwin":
|
||||
return "PingFang SC"
|
||||
else:
|
||||
return "Noto Sans CJK SC"
|
||||
|
||||
def _add_nodes_and_edges(node: dict, dot, parent_id: str | None = None) -> str:
|
||||
"""递归辅助函数,用于添加节点和边。"""
|
||||
try:
|
||||
from graphviz import Digraph
|
||||
except ImportError:
|
||||
logging.critical("错误:未安装graphviz库。请运行: pip install graphviz")
|
||||
return ""
|
||||
|
||||
current_id = f"{id(node)}_{random.randint(1000, 9999)}"
|
||||
|
||||
# 准备节点标签(HTML-like,正确换行与转义)
|
||||
name = html.escape(str(node.get('name', '')))
|
||||
ntype = html.escape(str(node.get('type', '')))
|
||||
label_parts = [f"<B>{name}</B> <FONT POINT-SIZE='10'><I>({ntype})</I></FONT>"]
|
||||
|
||||
# 格式化参数显示
|
||||
params = node.get('params') or {}
|
||||
if params:
|
||||
params_lines = []
|
||||
for key, value in params.items():
|
||||
k = html.escape(str(key))
|
||||
if isinstance(value, float):
|
||||
value_str = f"{value:.2f}".rstrip('0').rstrip('.')
|
||||
else:
|
||||
value_str = str(value)
|
||||
v = html.escape(value_str)
|
||||
params_lines.append(f"{k}: {v}")
|
||||
params_text = "<BR ALIGN='LEFT'/>".join(params_lines)
|
||||
label_parts.append(f"<FONT POINT-SIZE='9' COLOR='#555555'>{params_text}</FONT>")
|
||||
|
||||
node_label = f"<{'<BR/>'.join(label_parts)}>"
|
||||
|
||||
# 根据类型设置节点样式和颜色
|
||||
node_type = (node.get('type') or '').lower()
|
||||
shape = 'ellipse'
|
||||
style = 'filled'
|
||||
fillcolor = '#e6e6e6' # 默认灰色填充
|
||||
border_color = '#666666' # 默认描边色
|
||||
|
||||
if node_type == 'action':
|
||||
shape = 'box'
|
||||
style = 'rounded,filled'
|
||||
fillcolor = "#cde4ff" # 浅蓝
|
||||
elif node_type == 'condition':
|
||||
shape = 'diamond'
|
||||
style = 'filled'
|
||||
fillcolor = "#fff2cc" # 浅黄
|
||||
elif node_type == 'sequence':
|
||||
shape = 'ellipse'
|
||||
style = 'filled'
|
||||
fillcolor = '#d5e8d4' # 绿色
|
||||
elif node_type == 'selector':
|
||||
shape = 'ellipse'
|
||||
style = 'filled'
|
||||
fillcolor = '#ffe6cc' # 橙色
|
||||
elif node_type == 'parallel':
|
||||
shape = 'ellipse'
|
||||
style = 'filled'
|
||||
fillcolor = '#e1d5e7' # 紫色
|
||||
|
||||
# 特别标记安全相关节点
|
||||
if node.get('name') in ['battery_above', 'gps_status', 'SafetyMonitor']:
|
||||
border_color = '#ff0000' # 红色边框突出显示安全节点
|
||||
style = 'filled,bold' # 加粗
|
||||
|
||||
dot.node(current_id, label=node_label, shape=shape, style=style, fillcolor=fillcolor, color=border_color)
|
||||
|
||||
# 连接父节点
|
||||
if parent_id:
|
||||
dot.edge(parent_id, current_id)
|
||||
|
||||
# 递归处理子节点
|
||||
children = node.get("children", [])
|
||||
if not children:
|
||||
return current_id
|
||||
|
||||
# 记录所有子节点的ID
|
||||
child_ids = []
|
||||
|
||||
# 正确的递归连接:每个子节点都连接到当前节点
|
||||
for child in children:
|
||||
child_id = _add_nodes_and_edges(child, dot, current_id)
|
||||
child_ids.append(child_id)
|
||||
|
||||
# 子节点同级排列(横向排布,更直观地表现同层)
|
||||
if len(child_ids) > 1:
|
||||
with dot.subgraph(name=f"rank_{current_id}") as s:
|
||||
s.attr(rank='same')
|
||||
for cid in child_ids:
|
||||
s.node(cid)
|
||||
|
||||
return current_id
|
||||
|
||||
def _visualize_pytree(node: Dict, file_path: str):
|
||||
"""
|
||||
使用Graphviz将Pytree字典可视化,并保存到指定路径。
|
||||
"""
|
||||
try:
|
||||
from graphviz import Digraph
|
||||
except ImportError:
|
||||
logging.critical("错误:未安装graphviz库。请运行: pip install graphviz")
|
||||
return
|
||||
|
||||
fontname = _pick_zh_font()
|
||||
|
||||
dot = Digraph('Pytree', comment='Drone Mission Plan')
|
||||
dot.attr(rankdir='TB', label='Drone Mission Plan', fontsize='20', fontname=fontname)
|
||||
dot.attr('node', shape='box', style='rounded,filled', fontname=fontname)
|
||||
dot.attr('edge', fontname=fontname)
|
||||
|
||||
_add_nodes_and_edges(node, dot)
|
||||
|
||||
try:
|
||||
# 确保输出目录存在,并避免生成 .png.png
|
||||
base_path, ext = os.path.splitext(file_path)
|
||||
render_path = base_path if ext.lower() == '.png' else file_path
|
||||
|
||||
out_dir = os.path.dirname(render_path)
|
||||
if out_dir and not os.path.exists(out_dir):
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
|
||||
# 保存为 .png 文件,并自动删除源码 .gv 文件
|
||||
output_path = dot.render(render_path, format='png', cleanup=True, view=False)
|
||||
logging.info(f"✅ 可视化成功: {output_path}")
|
||||
except Exception as e:
|
||||
logging.error(f"❌ 生成可视化图形失败: {e}")
|
||||
|
||||
def parse_log_file(log_file_path: str) -> Dict[str, List[Dict]]:
|
||||
"""
|
||||
解析日志文件,提取原始指令和完整API响应JSON
|
||||
返回: {原始指令: [JSON响应列表]}
|
||||
"""
|
||||
with open(log_file_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# 按分隔符分割条目
|
||||
entries = re.split(r'={80,}', content)
|
||||
|
||||
results = defaultdict(list)
|
||||
|
||||
for entry in entries:
|
||||
if not entry.strip():
|
||||
continue
|
||||
|
||||
# 提取原始指令
|
||||
instruction_match = re.search(r'原始指令:\s*(.+)', entry)
|
||||
if not instruction_match:
|
||||
continue
|
||||
|
||||
original_instruction = instruction_match.group(1).strip()
|
||||
|
||||
# 提取完整API响应JSON
|
||||
json_match = re.search(r'完整API响应:\s*\n(\{.*\})', entry, re.DOTALL)
|
||||
if not json_match:
|
||||
logging.warning(f"未找到指令 '{original_instruction}' 的JSON响应")
|
||||
continue
|
||||
|
||||
json_str = json_match.group(1).strip()
|
||||
|
||||
try:
|
||||
json_obj = json.loads(json_str)
|
||||
results[original_instruction].append(json_obj)
|
||||
logging.info(f"成功提取指令 '{original_instruction}' 的JSON响应")
|
||||
except json.JSONDecodeError as e:
|
||||
logging.error(f"解析指令 '{original_instruction}' 的JSON失败: {e}")
|
||||
continue
|
||||
|
||||
return results
|
||||
|
||||
def process_and_visualize(log_file_path: str, output_dir: str):
|
||||
"""
|
||||
处理日志文件并批量可视化
|
||||
"""
|
||||
# 创建输出目录
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
# 解析日志文件
|
||||
logging.info(f"开始解析日志文件: {log_file_path}")
|
||||
instruction_responses = parse_log_file(log_file_path)
|
||||
|
||||
logging.info(f"共找到 {len(instruction_responses)} 个不同的原始指令")
|
||||
|
||||
# 处理每个指令的所有响应
|
||||
for instruction, responses in instruction_responses.items():
|
||||
logging.info(f"\n处理指令: {instruction} (共 {len(responses)} 个响应)")
|
||||
|
||||
# 创建指令目录(使用安全的文件名)
|
||||
safe_instruction_name = sanitize_filename(instruction)
|
||||
instruction_dir = os.path.join(output_dir, safe_instruction_name)
|
||||
os.makedirs(instruction_dir, exist_ok=True)
|
||||
|
||||
# 处理每个响应
|
||||
for idx, response in enumerate(responses, 1):
|
||||
try:
|
||||
# 提取root节点
|
||||
root_node = response.get('root')
|
||||
if not root_node:
|
||||
logging.warning(f"响应 #{idx} 没有root节点,跳过")
|
||||
continue
|
||||
|
||||
# 生成文件名
|
||||
json_filename = f"response_{idx}.json"
|
||||
png_filename = f"response_{idx}.png"
|
||||
|
||||
json_path = os.path.join(instruction_dir, json_filename)
|
||||
png_path = os.path.join(instruction_dir, png_filename)
|
||||
|
||||
# 保存JSON文件
|
||||
with open(json_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(response, f, ensure_ascii=False, indent=2)
|
||||
|
||||
logging.info(f" 保存JSON: {json_filename}")
|
||||
|
||||
# 生成可视化
|
||||
_visualize_pytree(root_node, png_path)
|
||||
logging.info(f" 生成可视化: {png_filename}")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"处理响应 #{idx} 时出错: {e}")
|
||||
continue
|
||||
|
||||
logging.info(f"\n✅ 所有处理完成!结果保存在: {output_dir}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
log_file = "/home/iscas/WorkSpace/code/DronePlanning/tools/test_validate/api_test_log.txt"
|
||||
output_directory = "/home/iscas/WorkSpace/code/DronePlanning/tools/test_validate/validation"
|
||||
|
||||
process_and_visualize(log_file, output_directory)
|
||||
|
||||
@@ -10,5 +10,6 @@
|
||||
飞到学生宿舍上方搜索方圆10米范围内的蓝色车辆
|
||||
飞到学生宿舍上方搜索半径为10米区域范围内的蓝色车辆
|
||||
起飞到学生宿舍搜索有没有被困人员,然后抛洒救援物资
|
||||
|
||||
无人机起飞到一米高度后,先移动至搜索区,搜索并锁定任一穿黑色衣服的人,在对其进行跟踪30秒后进行打击操作
|
||||
已知目标检测红色气球危险性高于蓝色气球高于绿色气球,飞往搜索区搜索并锁定危险性最高的气球,对其跟踪30秒
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
instruction_index,instruction,run_number,success,attempts,response_time,plan_id,error,timestamp
|
||||
1,起飞,1,True,1,2.4630444049835205,42903026-b02b-4089-859d-aec5cfa2435e,,2025-12-03 17:09:32
|
||||
2,起飞后移动到学生宿舍上方降落,1,True,1,10.017558574676514,86238ad2-e275-4d50-905c-175bd2f26fd0,,2025-12-03 17:09:43
|
||||
3,起飞后移动到学生宿舍上方查找蓝色的车,1,True,1,12.420023202896118,d8345bc3-b70f-41d7-b9fc-3e4898d7409e,,2025-12-03 17:09:56
|
||||
4,起飞后移动到学生宿舍上方寻找蓝色的车,1,True,1,12.864884614944458,29b5ee20-c809-4511-af08-80a85240c729,,2025-12-03 17:10:10
|
||||
5,起飞后移动到学生宿舍上方检测蓝色的车,1,True,1,10.438142538070679,5e7eb8c7-287a-469a-b6c0-a4102c1b0dac,,2025-12-03 17:10:21
|
||||
6,飞到学生宿舍上方查找蓝色的车,1,True,1,11.751057386398315,ef3d1981-1d51-433d-b2f4-2e92838075fd,,2025-12-03 17:10:34
|
||||
7,飞到学生宿舍上方查找蓝色车辆并进行打击,1,True,1,32.890604972839355,d8fc4658-08af-4910-89c4-b029c9a5daa0,,2025-12-03 17:11:08
|
||||
8,起飞后移动到学生宿舍上方搜索蓝色车辆,并进行打击,1,False,1,33.2862343788147,,,2025-12-03 17:11:42
|
||||
9,起飞到学生宿舍上方搜索被困人员,并为被困人员投递救援物资,1,True,1,12.312166213989258,7fbf0091-f7d3-4c3a-a6b7-4c0bfd4df66e,,2025-12-03 17:11:56
|
||||
10,飞到学生宿舍上方搜索方圆10米范围内的蓝色车辆,1,True,1,12.204660892486572,3ae0b258-b7e4-460c-9cfe-4b224266edc4,,2025-12-03 17:12:09
|
||||
11,飞到学生宿舍上方搜索半径为10米区域范围内的蓝色车辆,1,True,1,12.808414936065674,2acb84cf-c89e-460d-a4d9-8d1edb4ee69a,,2025-12-03 17:12:23
|
||||
12,起飞到学生宿舍搜索有没有被困人员,然后抛洒救援物资,1,True,1,11.071707487106323,c05d46c9-1b1b-4c8d-b64b-86b76d0c4099,,2025-12-03 17:12:35
|
||||
1,起飞,1,True,1,0.3463160991668701,0ffa333d-574d-453d-99cd-f8852411b7be,,2025-12-08 16:08:41
|
||||
2,起飞后移动到学生宿舍上方降落,1,True,1,0.1823880672454834,46c5741f-1e51-4cbe-bd5a-1e099d0d53f5,,2025-12-08 16:08:42
|
||||
3,起飞后移动到学生宿舍上方查找蓝色的车,1,True,1,0.24654889106750488,636bfbb8-c3be-42b6-93cf-caf87ac6424c,,2025-12-08 16:08:43
|
||||
4,起飞后移动到学生宿舍上方寻找蓝色的车,1,True,1,0.23946380615234375,744d6e87-5067-4f91-9f73-7f65432e1b83,,2025-12-08 16:08:45
|
||||
5,起飞后移动到学生宿舍上方检测蓝色的车,1,True,1,3.5440704822540283,1bf6820d-0c04-4961-b624-49e9d919ac56,,2025-12-08 16:08:49
|
||||
6,飞到学生宿舍上方查找蓝色的车,1,False,1,3.451496124267578,,,2025-12-08 16:08:54
|
||||
7,飞到学生宿舍上方查找蓝色车辆并进行打击,1,False,1,3.321821689605713,,,2025-12-08 16:08:58
|
||||
8,起飞后移动到学生宿舍上方搜索蓝色车辆,并进行打击,1,False,1,18.552793502807617,,,2025-12-08 16:09:17
|
||||
9,起飞到学生宿舍上方搜索被困人员,并为被困人员投递救援物资,1,True,1,1.5930235385894775,1ae38dbd-4e25-4a51-ac4f-8ed851fe8b1f,,2025-12-08 16:09:20
|
||||
10,飞到学生宿舍上方搜索方圆10米范围内的蓝色车辆,1,False,1,17.402809381484985,,,2025-12-08 16:09:38
|
||||
11,飞到学生宿舍上方搜索半径为10米区域范围内的蓝色车辆,1,True,1,1.269315481185913,24b02e2d-291d-4213-9e0f-acdd1165a1f1,,2025-12-08 16:09:41
|
||||
12,起飞到学生宿舍搜索有没有被困人员,然后抛洒救援物资,1,True,1,3.885636329650879,685b1d6d-8a82-463c-ab68-051348403c89,,2025-12-08 16:09:46
|
||||
13,无人机起飞到一米高度后,先移动至搜索区,搜索并锁定任一穿黑色衣服的人,在对其进行跟踪30秒后进行打击操作,1,False,1,16.88854742050171,,,2025-12-08 16:10:04
|
||||
14,已知目标检测红色气球危险性高于蓝色气球高于绿色气球,飞往搜索区搜索并锁定危险性最高的气球,对其跟踪30秒,1,False,1,3.594463586807251,,,2025-12-08 16:10:08
|
||||
|
||||
|
@@ -1,13 +1,15 @@
|
||||
instruction_index,instruction,total_runs,successful_runs,success_rate,avg_response_time,min_response_time,max_response_time,total_response_time
|
||||
1,起飞,1,1,100.00%,2.46s,2.46s,2.46s,2.46s
|
||||
2,起飞后移动到学生宿舍上方降落,1,1,100.00%,10.02s,10.02s,10.02s,10.02s
|
||||
3,起飞后移动到学生宿舍上方查找蓝色的车,1,1,100.00%,12.42s,12.42s,12.42s,12.42s
|
||||
4,起飞后移动到学生宿舍上方寻找蓝色的车,1,1,100.00%,12.86s,12.86s,12.86s,12.86s
|
||||
5,起飞后移动到学生宿舍上方检测蓝色的车,1,1,100.00%,10.44s,10.44s,10.44s,10.44s
|
||||
6,飞到学生宿舍上方查找蓝色的车,1,1,100.00%,11.75s,11.75s,11.75s,11.75s
|
||||
7,飞到学生宿舍上方查找蓝色车辆并进行打击,1,1,100.00%,32.89s,32.89s,32.89s,32.89s
|
||||
1,起飞,1,1,100.00%,0.35s,0.35s,0.35s,0.35s
|
||||
2,起飞后移动到学生宿舍上方降落,1,1,100.00%,0.18s,0.18s,0.18s,0.18s
|
||||
3,起飞后移动到学生宿舍上方查找蓝色的车,1,1,100.00%,0.25s,0.25s,0.25s,0.25s
|
||||
4,起飞后移动到学生宿舍上方寻找蓝色的车,1,1,100.00%,0.24s,0.24s,0.24s,0.24s
|
||||
5,起飞后移动到学生宿舍上方检测蓝色的车,1,1,100.00%,3.54s,3.54s,3.54s,3.54s
|
||||
6,飞到学生宿舍上方查找蓝色的车,1,0,0.00%,N/A,N/A,N/A,0.00s
|
||||
7,飞到学生宿舍上方查找蓝色车辆并进行打击,1,0,0.00%,N/A,N/A,N/A,0.00s
|
||||
8,起飞后移动到学生宿舍上方搜索蓝色车辆,并进行打击,1,0,0.00%,N/A,N/A,N/A,0.00s
|
||||
9,起飞到学生宿舍上方搜索被困人员,并为被困人员投递救援物资,1,1,100.00%,12.31s,12.31s,12.31s,12.31s
|
||||
10,飞到学生宿舍上方搜索方圆10米范围内的蓝色车辆,1,1,100.00%,12.20s,12.20s,12.20s,12.20s
|
||||
11,飞到学生宿舍上方搜索半径为10米区域范围内的蓝色车辆,1,1,100.00%,12.81s,12.81s,12.81s,12.81s
|
||||
12,起飞到学生宿舍搜索有没有被困人员,然后抛洒救援物资,1,1,100.00%,11.07s,11.07s,11.07s,11.07s
|
||||
9,起飞到学生宿舍上方搜索被困人员,并为被困人员投递救援物资,1,1,100.00%,1.59s,1.59s,1.59s,1.59s
|
||||
10,飞到学生宿舍上方搜索方圆10米范围内的蓝色车辆,1,0,0.00%,N/A,N/A,N/A,0.00s
|
||||
11,飞到学生宿舍上方搜索半径为10米区域范围内的蓝色车辆,1,1,100.00%,1.27s,1.27s,1.27s,1.27s
|
||||
12,起飞到学生宿舍搜索有没有被困人员,然后抛洒救援物资,1,1,100.00%,3.89s,3.89s,3.89s,3.89s
|
||||
13,无人机起飞到一米高度后,先移动至搜索区,搜索并锁定任一穿黑色衣服的人,在对其进行跟踪30秒后进行打击操作,1,0,0.00%,N/A,N/A,N/A,0.00s
|
||||
14,已知目标检测红色气球危险性高于蓝色气球高于绿色气球,飞往搜索区搜索并锁定危险性最高的气球,对其跟踪30秒,1,0,0.00%,N/A,N/A,N/A,0.00s
|
||||
|
||||
|
@@ -505,4 +505,4 @@ def main():
|
||||
print(f"统计摘要: {SUMMARY_CSV}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
||||
|
After Width: | Height: | Size: 183 KiB |
|
After Width: | Height: | Size: 183 KiB |
BIN
tools/test_validate/validation_qwen2.5_vl_3b/起飞/response_1.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 183 KiB |
|
After Width: | Height: | Size: 183 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 177 KiB |
|
After Width: | Height: | Size: 177 KiB |
|
After Width: | Height: | Size: 177 KiB |
|
After Width: | Height: | Size: 174 KiB |
BIN
tools/test_validate/validation_qwen2_vl_2b/起飞/response_1.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 182 KiB |
|
After Width: | Height: | Size: 185 KiB |
BIN
tools/test_validate/validation_qwen3_vl_2b/起飞/response_1.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 182 KiB |
|
After Width: | Height: | Size: 192 KiB |
|
After Width: | Height: | Size: 210 KiB |
|
After Width: | Height: | Size: 180 KiB |
|
After Width: | Height: | Size: 210 KiB |
|
After Width: | Height: | Size: 180 KiB |
|
After Width: | Height: | Size: 155 KiB |
|
After Width: | Height: | Size: 180 KiB |
|
After Width: | Height: | Size: 188 KiB |
|
After Width: | Height: | Size: 177 KiB |
|
After Width: | Height: | Size: 180 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 150 KiB |
BIN
tools/test_validate/validation_qwen3_vl_4b/起飞/response_1.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 187 KiB |
|
After Width: | Height: | Size: 177 KiB |
|
After Width: | Height: | Size: 167 KiB |