Spaces:
Running
Running
Ugly text boxes
Browse files
app.py
CHANGED
@@ -4,14 +4,53 @@ import numpy as np
|
|
4 |
import gradio as gr
|
5 |
|
6 |
|
7 |
-
# Sample
|
8 |
MODELS = {
|
9 |
-
"llama"
|
10 |
-
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
}
|
13 |
|
14 |
-
def plot_model_stats(model_name: str) -> plt.Figure:
|
15 |
"""Draws a pie chart of model's passed, failed, skipped, and error stats."""
|
16 |
model_stats = MODELS[model_name]
|
17 |
|
@@ -23,10 +62,15 @@ def plot_model_stats(model_name: str) -> plt.Figure:
|
|
23 |
'error': '#8B0000' # Dark red
|
24 |
}
|
25 |
|
|
|
|
|
|
|
|
|
26 |
# Filter out categories with 0 values for cleaner visualization
|
27 |
-
|
|
|
28 |
|
29 |
-
if not
|
30 |
# Handle case where all values are 0 - minimal empty state
|
31 |
fig, ax = plt.subplots(figsize=(10, 8), facecolor='#000000')
|
32 |
ax.set_facecolor('#000000')
|
@@ -37,17 +81,27 @@ def plot_model_stats(model_name: str) -> plt.Figure:
|
|
37 |
ax.set_xlim(0, 1)
|
38 |
ax.set_ylim(0, 1)
|
39 |
ax.axis('off')
|
40 |
-
return fig
|
41 |
|
42 |
# Create figure with two subplots side by side with padding
|
43 |
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(18, 9), facecolor='#000000')
|
44 |
ax1.set_facecolor('#000000')
|
45 |
ax2.set_facecolor('#000000')
|
46 |
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
# Create minimal pie chart - full pie, no donut effect
|
52 |
wedges, texts, autotexts = ax.pie(
|
53 |
filtered_stats.values(),
|
@@ -81,18 +135,19 @@ def plot_model_stats(model_name: str) -> plt.Figure:
|
|
81 |
fontfamily='monospace')
|
82 |
|
83 |
# Create both pie charts with device labels
|
84 |
-
create_pie_chart(ax1, "
|
85 |
-
create_pie_chart(ax2, "
|
86 |
|
87 |
-
# Add subtle separation line between charts
|
88 |
line_x = 0.5
|
89 |
-
fig.add_artist(plt.Line2D([line_x, line_x], [0.
|
90 |
color='#333333', linewidth=1, alpha=0.5,
|
91 |
transform=fig.transFigure))
|
92 |
|
93 |
# Add central shared title for model name and test count
|
94 |
-
|
95 |
-
|
|
|
96 |
fontsize=18, weight='normal', color='#CCCCCC',
|
97 |
fontfamily='monospace', y=0.95)
|
98 |
|
@@ -100,14 +155,26 @@ def plot_model_stats(model_name: str) -> plt.Figure:
|
|
100 |
plt.tight_layout()
|
101 |
plt.subplots_adjust(top=0.85, wspace=0.4) # Added wspace for padding between charts
|
102 |
|
103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
|
105 |
def get_model_stats_summary(model_name: str) -> tuple:
|
106 |
"""Get summary stats for a model (total tests, success rate, status indicator)."""
|
107 |
stats = MODELS[model_name]
|
108 |
-
|
109 |
-
|
110 |
-
|
|
|
|
|
|
|
|
|
|
|
111 |
|
112 |
# Determine status indicator color
|
113 |
if success_rate >= 80:
|
@@ -281,6 +348,21 @@ h1, h2, h3, p, .markdown {
|
|
281 |
padding: 20px !important;
|
282 |
margin-left: 300px !important;
|
283 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
284 |
"""
|
285 |
|
286 |
# Create the Gradio interface with sidebar and dark theme
|
@@ -313,18 +395,39 @@ with gr.Blocks(title="Model Test Results Dashboard", css=dark_theme_css) as demo
|
|
313 |
format="png",
|
314 |
elem_classes=["plot-container"]
|
315 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
316 |
|
317 |
# Set up click handlers for each button
|
318 |
for i, (model_name, button) in enumerate(zip(MODELS.keys(), model_buttons)):
|
319 |
button.click(
|
320 |
fn=lambda name=model_name: plot_model_stats(name),
|
321 |
-
outputs=plot_output
|
322 |
)
|
323 |
|
324 |
# Initialize with the first model
|
325 |
demo.load(
|
326 |
fn=lambda: plot_model_stats(list(MODELS.keys())[0]),
|
327 |
-
outputs=plot_output
|
328 |
)
|
329 |
|
330 |
if __name__ == "__main__":
|
|
|
4 |
import gradio as gr
|
5 |
|
6 |
|
7 |
+
# Sample test results with test names
|
8 |
MODELS = {
|
9 |
+
"llama": {
|
10 |
+
"amd": {
|
11 |
+
"passed": ["auth_login", "data_validation", "api_response", "file_upload", "cache_hit", "user_permissions", "db_query", "session_mgmt", "input_sanitize", "rate_limit", "error_handling", "memory_alloc", "thread_safety", "backup_restore"],
|
12 |
+
"failed": ["network_timeout"],
|
13 |
+
"skipped": ["gpu_accel", "cuda_ops", "ml_inference", "tensor_ops", "distributed", "multi_gpu"],
|
14 |
+
"error": []
|
15 |
+
},
|
16 |
+
"nvidia": {
|
17 |
+
"passed": ["auth_login", "data_validation", "api_response", "file_upload", "cache_hit", "user_permissions", "db_query", "session_mgmt", "input_sanitize", "rate_limit", "error_handling", "memory_alloc", "thread_safety", "backup_restore", "gpu_accel", "cuda_ops", "ml_inference", "tensor_ops"],
|
18 |
+
"failed": ["network_timeout", "distributed"],
|
19 |
+
"skipped": ["multi_gpu"],
|
20 |
+
"error": []
|
21 |
+
}
|
22 |
+
},
|
23 |
+
"gemma3": {
|
24 |
+
"amd": {
|
25 |
+
"passed": ["auth_login", "data_validation", "api_response", "file_upload", "cache_hit", "user_permissions", "db_query", "session_mgmt", "input_sanitize", "rate_limit", "error_handling", "memory_alloc", "thread_safety", "backup_restore", "config_load", "log_rotation", "health_check", "metrics", "alerts", "monitoring", "security_scan", "password_hash", "jwt_token", "oauth_flow", "csrf_protect", "xss_filter", "sql_injection", "rate_limiter", "load_balance", "circuit_break", "retry_logic", "timeout_handle", "graceful_shutdown", "hot_reload", "config_watch", "env_vars", "secrets_mgmt", "tls_cert", "encryption", "compression", "serialization", "deserialization", "validation"],
|
26 |
+
"failed": ["gpu_accel", "cuda_ops", "ml_inference", "tensor_ops", "distributed", "multi_gpu"],
|
27 |
+
"skipped": ["perf_test", "stress_test", "load_test", "endurance", "benchmark", "profiling", "memory_leak", "cpu_usage", "disk_io", "network_bw", "latency", "throughput"],
|
28 |
+
"error": []
|
29 |
+
},
|
30 |
+
"nvidia": {
|
31 |
+
"passed": ["auth_login", "data_validation", "api_response", "file_upload", "cache_hit", "user_permissions", "db_query", "session_mgmt", "input_sanitize", "rate_limit", "error_handling", "memory_alloc", "thread_safety", "backup_restore", "config_load", "log_rotation", "health_check", "metrics", "alerts", "monitoring", "security_scan", "password_hash", "jwt_token", "oauth_flow", "csrf_protect", "xss_filter", "sql_injection", "rate_limiter", "load_balance", "circuit_break", "retry_logic", "timeout_handle", "graceful_shutdown", "hot_reload", "config_watch", "env_vars", "secrets_mgmt", "tls_cert", "encryption", "compression", "serialization", "deserialization", "validation", "gpu_accel", "cuda_ops", "ml_inference", "tensor_ops"],
|
32 |
+
"failed": ["distributed", "multi_gpu"],
|
33 |
+
"skipped": ["perf_test", "stress_test", "load_test", "endurance", "benchmark", "profiling", "memory_leak", "cpu_usage", "disk_io", "network_bw"],
|
34 |
+
"error": []
|
35 |
+
}
|
36 |
+
},
|
37 |
+
"csm": {
|
38 |
+
"amd": {
|
39 |
+
"passed": [],
|
40 |
+
"failed": [],
|
41 |
+
"skipped": [],
|
42 |
+
"error": ["system_crash"]
|
43 |
+
},
|
44 |
+
"nvidia": {
|
45 |
+
"passed": [],
|
46 |
+
"failed": [],
|
47 |
+
"skipped": [],
|
48 |
+
"error": ["system_crash"]
|
49 |
+
}
|
50 |
+
}
|
51 |
}
|
52 |
|
53 |
+
def plot_model_stats(model_name: str) -> tuple[plt.Figure, str, str]:
|
54 |
"""Draws a pie chart of model's passed, failed, skipped, and error stats."""
|
55 |
model_stats = MODELS[model_name]
|
56 |
|
|
|
62 |
'error': '#8B0000' # Dark red
|
63 |
}
|
64 |
|
65 |
+
# Convert test lists to counts for chart display
|
66 |
+
amd_stats = {k: len(v) for k, v in model_stats['amd'].items()}
|
67 |
+
nvidia_stats = {k: len(v) for k, v in model_stats['nvidia'].items()}
|
68 |
+
|
69 |
# Filter out categories with 0 values for cleaner visualization
|
70 |
+
amd_filtered = {k: v for k, v in amd_stats.items() if v > 0}
|
71 |
+
nvidia_filtered = {k: v for k, v in nvidia_stats.items() if v > 0}
|
72 |
|
73 |
+
if not amd_filtered and not nvidia_filtered:
|
74 |
# Handle case where all values are 0 - minimal empty state
|
75 |
fig, ax = plt.subplots(figsize=(10, 8), facecolor='#000000')
|
76 |
ax.set_facecolor('#000000')
|
|
|
81 |
ax.set_xlim(0, 1)
|
82 |
ax.set_ylim(0, 1)
|
83 |
ax.axis('off')
|
84 |
+
return fig, "", ""
|
85 |
|
86 |
# Create figure with two subplots side by side with padding
|
87 |
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(18, 9), facecolor='#000000')
|
88 |
ax1.set_facecolor('#000000')
|
89 |
ax2.set_facecolor('#000000')
|
90 |
|
91 |
+
def create_pie_chart(ax, device_label, filtered_stats):
|
92 |
+
if not filtered_stats:
|
93 |
+
ax.text(0.5, 0.5, 'No test results',
|
94 |
+
horizontalalignment='center', verticalalignment='center',
|
95 |
+
transform=ax.transAxes, fontsize=14, color='#888888',
|
96 |
+
fontfamily='monospace', weight='normal')
|
97 |
+
ax.set_title(device_label,
|
98 |
+
fontsize=28, weight='bold', pad=2, color='#FFFFFF',
|
99 |
+
fontfamily='monospace')
|
100 |
+
ax.axis('off')
|
101 |
+
return
|
102 |
+
|
103 |
+
chart_colors = [colors[category] for category in filtered_stats.keys()]
|
104 |
+
|
105 |
# Create minimal pie chart - full pie, no donut effect
|
106 |
wedges, texts, autotexts = ax.pie(
|
107 |
filtered_stats.values(),
|
|
|
135 |
fontfamily='monospace')
|
136 |
|
137 |
# Create both pie charts with device labels
|
138 |
+
create_pie_chart(ax1, "amd", amd_filtered)
|
139 |
+
create_pie_chart(ax2, "nvidia", nvidia_filtered)
|
140 |
|
141 |
+
# Add subtle separation line between charts - longer to match layout
|
142 |
line_x = 0.5
|
143 |
+
fig.add_artist(plt.Line2D([line_x, line_x], [0.05, 0.9],
|
144 |
color='#333333', linewidth=1, alpha=0.5,
|
145 |
transform=fig.transFigure))
|
146 |
|
147 |
# Add central shared title for model name and test count
|
148 |
+
total_amd = sum(amd_stats.values())
|
149 |
+
total_nvidia = sum(nvidia_stats.values())
|
150 |
+
fig.suptitle(f'{model_name.lower()} • amd: {total_amd} tests, nvidia: {total_nvidia} tests',
|
151 |
fontsize=18, weight='normal', color='#CCCCCC',
|
152 |
fontfamily='monospace', y=0.95)
|
153 |
|
|
|
155 |
plt.tight_layout()
|
156 |
plt.subplots_adjust(top=0.85, wspace=0.4) # Added wspace for padding between charts
|
157 |
|
158 |
+
# Generate separate failed tests info for AMD and NVIDIA
|
159 |
+
amd_failed = model_stats['amd']['failed']
|
160 |
+
nvidia_failed = model_stats['nvidia']['failed']
|
161 |
+
|
162 |
+
amd_failed_info = "\n".join(amd_failed) if amd_failed else "None"
|
163 |
+
nvidia_failed_info = "\n".join(nvidia_failed) if nvidia_failed else "None"
|
164 |
+
|
165 |
+
return fig, amd_failed_info, nvidia_failed_info
|
166 |
|
167 |
def get_model_stats_summary(model_name: str) -> tuple:
|
168 |
"""Get summary stats for a model (total tests, success rate, status indicator)."""
|
169 |
stats = MODELS[model_name]
|
170 |
+
# Combine AMD and NVIDIA results
|
171 |
+
total_passed = len(stats['amd']['passed']) + len(stats['nvidia']['passed'])
|
172 |
+
total_failed = len(stats['amd']['failed']) + len(stats['nvidia']['failed'])
|
173 |
+
total_skipped = len(stats['amd']['skipped']) + len(stats['nvidia']['skipped'])
|
174 |
+
total_error = len(stats['amd']['error']) + len(stats['nvidia']['error'])
|
175 |
+
|
176 |
+
total = total_passed + total_failed + total_skipped + total_error
|
177 |
+
success_rate = (total_passed / total * 100) if total > 0 else 0
|
178 |
|
179 |
# Determine status indicator color
|
180 |
if success_rate >= 80:
|
|
|
348 |
padding: 20px !important;
|
349 |
margin-left: 300px !important;
|
350 |
}
|
351 |
+
|
352 |
+
/* Failed tests display */
|
353 |
+
.failed-tests {
|
354 |
+
background-color: #1a1a1a !important;
|
355 |
+
color: #CCCCCC !important;
|
356 |
+
font-family: monospace !important;
|
357 |
+
font-size: 12px !important;
|
358 |
+
padding: 15px !important;
|
359 |
+
margin-top: 20px !important;
|
360 |
+
border-radius: 5px !important;
|
361 |
+
border: 1px solid #333333 !important;
|
362 |
+
max-height: 200px !important;
|
363 |
+
overflow-y: auto !important;
|
364 |
+
white-space: pre-line !important;
|
365 |
+
}
|
366 |
"""
|
367 |
|
368 |
# Create the Gradio interface with sidebar and dark theme
|
|
|
395 |
format="png",
|
396 |
elem_classes=["plot-container"]
|
397 |
)
|
398 |
+
|
399 |
+
# Create two separate failed tests displays in a row layout
|
400 |
+
with gr.Row():
|
401 |
+
with gr.Column(scale=1):
|
402 |
+
amd_failed_tests_output = gr.Textbox(
|
403 |
+
label="AMD Failed Tests",
|
404 |
+
value="",
|
405 |
+
lines=8,
|
406 |
+
max_lines=8,
|
407 |
+
interactive=False,
|
408 |
+
elem_classes=["failed-tests"]
|
409 |
+
)
|
410 |
+
with gr.Column(scale=1):
|
411 |
+
nvidia_failed_tests_output = gr.Textbox(
|
412 |
+
label="NVIDIA Failed Tests",
|
413 |
+
value="",
|
414 |
+
lines=8,
|
415 |
+
max_lines=8,
|
416 |
+
interactive=False,
|
417 |
+
elem_classes=["failed-tests"]
|
418 |
+
)
|
419 |
|
420 |
# Set up click handlers for each button
|
421 |
for i, (model_name, button) in enumerate(zip(MODELS.keys(), model_buttons)):
|
422 |
button.click(
|
423 |
fn=lambda name=model_name: plot_model_stats(name),
|
424 |
+
outputs=[plot_output, amd_failed_tests_output, nvidia_failed_tests_output]
|
425 |
)
|
426 |
|
427 |
# Initialize with the first model
|
428 |
demo.load(
|
429 |
fn=lambda: plot_model_stats(list(MODELS.keys())[0]),
|
430 |
+
outputs=[plot_output, amd_failed_tests_output, nvidia_failed_tests_output]
|
431 |
)
|
432 |
|
433 |
if __name__ == "__main__":
|