added type
Browse files- app.py +5 -6
- requirements.txt +0 -0
- utils.py +90 -25
app.py
CHANGED
|
@@ -2,20 +2,19 @@ import utils
|
|
| 2 |
import gradio as gr
|
| 3 |
import parameters
|
| 4 |
|
| 5 |
-
with gr.Blocks() as demo:
|
| 6 |
-
# gr.Tab(label="Error Metrics Dashboard")
|
| 7 |
gr.Markdown("# Error Metrics Dashboard")
|
| 8 |
with gr.Row():
|
| 9 |
-
project = gr.Textbox(
|
| 10 |
start_date = gr.Textbox(label="Start Date (YYYY-MM-DD)", value="2025-02-20")
|
| 11 |
end_date = gr.Textbox(label="End Date (YYYY-MM-DD)", value="2025-02-21")
|
| 12 |
submit_btn = gr.Button("Process")
|
| 13 |
-
output = gr.
|
| 14 |
|
| 15 |
submit_btn.click(
|
| 16 |
fn=utils.process_dates,
|
| 17 |
-
inputs=[start_date, end_date,project],
|
| 18 |
outputs=output
|
| 19 |
)
|
| 20 |
|
| 21 |
-
demo.launch(share
|
|
|
|
| 2 |
import gradio as gr
|
| 3 |
import parameters
|
| 4 |
|
| 5 |
+
with gr.Blocks(title="Opik Error Dashboard") as demo:
|
|
|
|
| 6 |
gr.Markdown("# Error Metrics Dashboard")
|
| 7 |
with gr.Row():
|
| 8 |
+
project = gr.Textbox(value=parameters.project, interactive=True)
|
| 9 |
start_date = gr.Textbox(label="Start Date (YYYY-MM-DD)", value="2025-02-20")
|
| 10 |
end_date = gr.Textbox(label="End Date (YYYY-MM-DD)", value="2025-02-21")
|
| 11 |
submit_btn = gr.Button("Process")
|
| 12 |
+
output = gr.HTML(label="Results", min_height="200px")
|
| 13 |
|
| 14 |
submit_btn.click(
|
| 15 |
fn=utils.process_dates,
|
| 16 |
+
inputs=[start_date, end_date, project],
|
| 17 |
outputs=output
|
| 18 |
)
|
| 19 |
|
| 20 |
+
demo.launch(share=True)
|
requirements.txt
CHANGED
|
Binary files a/requirements.txt and b/requirements.txt differ
|
|
|
utils.py
CHANGED
|
@@ -139,23 +139,26 @@ def find_errors_and_metrics(traces, spans):
|
|
| 139 |
error_spans = []
|
| 140 |
error_metrics = defaultdict(list)
|
| 141 |
|
| 142 |
-
|
| 143 |
for span in spans:
|
| 144 |
content = span['content']
|
| 145 |
output = content.get("output")
|
|
|
|
|
|
|
| 146 |
if isinstance(output, dict) and 'output' in output:
|
| 147 |
-
output_value = output.get("output")
|
| 148 |
else:
|
| 149 |
output_value = output
|
| 150 |
-
|
| 151 |
-
if (output_value is None or
|
| 152 |
-
|
| 153 |
error_spans.append({
|
| 154 |
"trace_id": span["trace_id"],
|
| 155 |
"span_id": span["span_id"],
|
| 156 |
-
"error_content": output
|
|
|
|
| 157 |
})
|
| 158 |
-
|
|
|
|
| 159 |
|
| 160 |
print(f"Found {len(error_spans)} outputs with errors (empty/null)")
|
| 161 |
|
|
@@ -175,40 +178,102 @@ def find_errors_and_metrics(traces, spans):
|
|
| 175 |
print("Step 10: Calculating metrics")
|
| 176 |
metrics = {
|
| 177 |
"total_errors": len(error_spans),
|
| 178 |
-
"
|
| 179 |
error_type: {
|
| 180 |
-
"count": len(
|
| 181 |
-
"
|
|
|
|
|
|
|
|
|
|
| 182 |
}
|
| 183 |
-
for error_type,
|
| 184 |
}
|
| 185 |
}
|
| 186 |
-
print(f"Metrics calculated: {len(metrics['
|
|
|
|
|
|
|
|
|
|
|
|
|
| 187 |
return metrics
|
| 188 |
|
| 189 |
except Exception as e:
|
| 190 |
print(f"Error in find_errors_and_metrics: {e}")
|
| 191 |
return {}
|
| 192 |
|
| 193 |
-
def process_dates(start_date, end_date,project):
|
| 194 |
try:
|
| 195 |
print("Pipeline Start: Processing dates")
|
| 196 |
traces, spans = get_traces_on_date(start_date, end_date, project, parameters.api_key)
|
| 197 |
metrics = find_errors_and_metrics(traces, spans)
|
| 198 |
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
print("Pipeline End: Results formatted")
|
| 211 |
-
return
|
|
|
|
| 212 |
except Exception as e:
|
| 213 |
print(f"Error processing dates: {e}")
|
| 214 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
error_spans = []
|
| 140 |
error_metrics = defaultdict(list)
|
| 141 |
|
|
|
|
| 142 |
for span in spans:
|
| 143 |
content = span['content']
|
| 144 |
output = content.get("output")
|
| 145 |
+
error_info = content.get("error_info", {})
|
| 146 |
+
|
| 147 |
if isinstance(output, dict) and 'output' in output:
|
| 148 |
+
output_value = output.get("output")
|
| 149 |
else:
|
| 150 |
output_value = output
|
| 151 |
+
|
| 152 |
+
if ((output_value is None or (isinstance(output, list) and len(output) == 0)) and len(error_info) > 0):
|
| 153 |
+
error_type = error_info.get("exception_type", "unknown_error")
|
| 154 |
error_spans.append({
|
| 155 |
"trace_id": span["trace_id"],
|
| 156 |
"span_id": span["span_id"],
|
| 157 |
+
"error_content": output,
|
| 158 |
+
"exception_type": error_type
|
| 159 |
})
|
| 160 |
+
|
| 161 |
+
error_metrics[error_type].append({"trace_id": span["trace_id"], "span_id": span["span_id"]})
|
| 162 |
|
| 163 |
print(f"Found {len(error_spans)} outputs with errors (empty/null)")
|
| 164 |
|
|
|
|
| 178 |
print("Step 10: Calculating metrics")
|
| 179 |
metrics = {
|
| 180 |
"total_errors": len(error_spans),
|
| 181 |
+
"error_types": {
|
| 182 |
error_type: {
|
| 183 |
+
"count": len(entries),
|
| 184 |
+
"instances": [
|
| 185 |
+
{"trace_id": entry["trace_id"], "span_id": entry["span_id"]}
|
| 186 |
+
for entry in entries
|
| 187 |
+
]
|
| 188 |
}
|
| 189 |
+
for error_type, entries in error_metrics.items()
|
| 190 |
}
|
| 191 |
}
|
| 192 |
+
print(f"Metrics calculated: {len(metrics['error_types'])} error types")
|
| 193 |
+
for error_type, data in metrics["error_types"].items():
|
| 194 |
+
print(f"Error Type: {error_type}, Count: {data['count']}")
|
| 195 |
+
for instance in data["instances"]:
|
| 196 |
+
print(f" Trace ID: {instance['trace_id']}, Span ID: {instance['span_id']}")
|
| 197 |
return metrics
|
| 198 |
|
| 199 |
except Exception as e:
|
| 200 |
print(f"Error in find_errors_and_metrics: {e}")
|
| 201 |
return {}
|
| 202 |
|
| 203 |
+
def process_dates(start_date, end_date, project):
|
| 204 |
try:
|
| 205 |
print("Pipeline Start: Processing dates")
|
| 206 |
traces, spans = get_traces_on_date(start_date, end_date, project, parameters.api_key)
|
| 207 |
metrics = find_errors_and_metrics(traces, spans)
|
| 208 |
|
| 209 |
+
html_output = """
|
| 210 |
+
<div style='font-family: Arial, sans-serif; padding: 20px; background-color: #f5f5f5; border-radius: 10px;'>
|
| 211 |
+
<h2 style='color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 5px;'>Metrics Report</h2>
|
| 212 |
+
|
| 213 |
+
<div style='margin: 15px 0;'>
|
| 214 |
+
<span style='color: #e74c3c; font-weight: bold;'>Total Empty/Null Outputs Found: </span>
|
| 215 |
+
<span style='color: #2980b9'>{empty_count}</span>
|
| 216 |
+
</div>
|
| 217 |
+
|
| 218 |
+
<div style='margin: 15px 0;'>
|
| 219 |
+
<span style='color: #27ae60; font-weight: bold;'>Total Traces Found: </span>
|
| 220 |
+
<span style='color: #2980b9'>{traces_count}</span>
|
| 221 |
+
<br>
|
| 222 |
+
<span style='color: #27ae60; font-weight: bold;'>Total Spans Processed: </span>
|
| 223 |
+
<span style='color: #2980b9'>{spans_count}</span>
|
| 224 |
+
</div>
|
| 225 |
|
| 226 |
+
<h3 style='color: #8e44ad; margin-top: 20px;'>Error Metrics</h3>
|
| 227 |
+
{error_section}
|
| 228 |
+
</div>
|
| 229 |
+
"""
|
| 230 |
+
|
| 231 |
+
if metrics.get('error_types', {}):
|
| 232 |
+
error_html = "<div style='background-color: #fff; padding: 15px; border-radius: 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);'>"
|
| 233 |
+
for error_type, data in metrics.get('error_types', {}).items():
|
| 234 |
+
error_html += f"""
|
| 235 |
+
<div style='margin: 10px 0;'>
|
| 236 |
+
<span style='color: #d35400; font-weight: bold;'>{error_type.replace('_', ' ').title()}: </span>
|
| 237 |
+
<span style='color: #2980b9'>{data['count']} occurrences</span>
|
| 238 |
+
<div style='margin-left: 20px;'>
|
| 239 |
+
<span style='color: #7f8c8d;'>Instances:</span>
|
| 240 |
+
<ul style='list-style-type: none; padding-left: 10px;'>
|
| 241 |
+
"""
|
| 242 |
+
for instance in data['instances'][:5]:
|
| 243 |
+
error_html += f"""
|
| 244 |
+
<li style='color: #34495e;'>
|
| 245 |
+
Trace ID: <span style='color: #16a085'>{instance['trace_id']}</span>,
|
| 246 |
+
Span ID: <span style='color: #16a085'>{instance['span_id']}</span>
|
| 247 |
+
</li>
|
| 248 |
+
"""
|
| 249 |
+
if len(data['instances']) > 5:
|
| 250 |
+
error_html += "<li style='color: #7f8c8d;'>... (and more)</li>"
|
| 251 |
+
error_html += "</ul></div></div>"
|
| 252 |
+
error_html += "</div>"
|
| 253 |
+
else:
|
| 254 |
+
error_html = """
|
| 255 |
+
<div style='color: #27ae60; background-color: #ecf0f1; padding: 10px; border-radius: 5px;'>
|
| 256 |
+
No empty or null outputs with exceptions detected.
|
| 257 |
+
</div>
|
| 258 |
+
"""
|
| 259 |
+
|
| 260 |
+
formatted_output = html_output.format(
|
| 261 |
+
empty_count=metrics.get('total_errors', 0),
|
| 262 |
+
traces_count=len(traces),
|
| 263 |
+
spans_count=len(spans),
|
| 264 |
+
error_section=error_html
|
| 265 |
+
)
|
| 266 |
+
|
| 267 |
print("Pipeline End: Results formatted")
|
| 268 |
+
return formatted_output
|
| 269 |
+
|
| 270 |
except Exception as e:
|
| 271 |
print(f"Error processing dates: {e}")
|
| 272 |
+
error_html = f"""
|
| 273 |
+
<div style='font-family: Arial, sans-serif; padding: 20px; background-color: #f5f5f5; border-radius: 10px;'>
|
| 274 |
+
<h2 style='color: #e74c3c;'>Error Occurred</h2>
|
| 275 |
+
<p style='color: #c0392b;'>Error processing dates: {str(e)}</p>
|
| 276 |
+
</div>
|
| 277 |
+
"""
|
| 278 |
+
return error_html
|
| 279 |
+
|