progress bar is constantly updated (#3)
Browse files- progress bar is constantly updated (1c83c43164e4fe3ad3d37a438c975818b434940c)
Co-authored-by: Furkan Eris <[email protected]>
app.py
CHANGED
|
@@ -517,31 +517,26 @@ class HallucinationDetectorApp:
|
|
| 517 |
# Get total feedback count
|
| 518 |
total_count = self.feedback_collection.count_documents({})
|
| 519 |
|
| 520 |
-
# Get
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
-
|
| 530 |
-
|
| 531 |
-
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
|
| 535 |
-
}}
|
| 536 |
-
]
|
| 537 |
-
avg_result = list(self.feedback_collection.aggregate(avg_pipeline))
|
| 538 |
-
avg_confidence = avg_result[0]["average"] if avg_result else 0
|
| 539 |
|
| 540 |
return {
|
| 541 |
"total_feedback": total_count,
|
| 542 |
-
"
|
| 543 |
-
"
|
| 544 |
-
"average_confidence": round(avg_confidence, 2)
|
| 545 |
}
|
| 546 |
except Exception as e:
|
| 547 |
logger.error("Error getting feedback stats: %s", str(e), exc_info=True)
|
|
@@ -1288,41 +1283,14 @@ def create_interface():
|
|
| 1288 |
None
|
| 1289 |
]
|
| 1290 |
|
| 1291 |
-
# Helper function to submit feedback
|
| 1292 |
def combine_feedback(fb_input, fb_text, results):
|
| 1293 |
combined_feedback = f"{fb_input}: {fb_text}" if fb_text else fb_input
|
| 1294 |
if not results:
|
| 1295 |
-
return "No results to attach feedback to."
|
| 1296 |
|
| 1297 |
response = detector.save_feedback(results, combined_feedback)
|
| 1298 |
-
|
| 1299 |
-
# Get updated stats
|
| 1300 |
-
stats = detector.get_feedback_stats()
|
| 1301 |
-
if stats:
|
| 1302 |
-
stats_html = f"""
|
| 1303 |
-
<div class="stats-section" style="margin-top: 15px;">
|
| 1304 |
-
<div class="stat-item">
|
| 1305 |
-
<div class="stat-value">{stats['total_feedback']}</div>
|
| 1306 |
-
<div class="stat-label">Total Feedback</div>
|
| 1307 |
-
</div>
|
| 1308 |
-
<div class="stat-item">
|
| 1309 |
-
<div class="stat-value">{stats['hallucinations_detected']}</div>
|
| 1310 |
-
<div class="stat-label">Hallucinations Found</div>
|
| 1311 |
-
</div>
|
| 1312 |
-
<div class="stat-item">
|
| 1313 |
-
<div class="stat-value">{stats['no_hallucinations']}</div>
|
| 1314 |
-
<div class="stat-label">No Hallucinations</div>
|
| 1315 |
-
</div>
|
| 1316 |
-
<div class="stat-item">
|
| 1317 |
-
<div class="stat-value">{stats['average_confidence']}</div>
|
| 1318 |
-
<div class="stat-label">Avg. Confidence</div>
|
| 1319 |
-
</div>
|
| 1320 |
-
</div>
|
| 1321 |
-
"""
|
| 1322 |
-
else:
|
| 1323 |
-
stats_html = ""
|
| 1324 |
-
|
| 1325 |
-
return response, stats_html
|
| 1326 |
|
| 1327 |
# Create the interface
|
| 1328 |
with gr.Blocks(css=css, theme=gr.themes.Soft()) as interface:
|
|
@@ -1416,6 +1384,102 @@ def create_interface():
|
|
| 1416 |
# Add feedback stats display
|
| 1417 |
feedback_stats = gr.HTML(visible=True)
|
| 1418 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1419 |
# Feedback section
|
| 1420 |
with gr.Accordion("Provide Feedback", open=False, visible=False) as feedback_accordion:
|
| 1421 |
gr.Markdown("### Help Improve the System")
|
|
@@ -1436,29 +1500,7 @@ def create_interface():
|
|
| 1436 |
feedback_button = gr.Button("Submit Feedback", variant="secondary")
|
| 1437 |
feedback_status = gr.Textbox(label="Feedback Status", interactive=False, visible=False)
|
| 1438 |
|
| 1439 |
-
#
|
| 1440 |
-
initial_stats = detector.get_feedback_stats()
|
| 1441 |
-
if initial_stats:
|
| 1442 |
-
feedback_stats.value = f"""
|
| 1443 |
-
<div class="stats-section">
|
| 1444 |
-
<div class="stat-item">
|
| 1445 |
-
<div class="stat-value">{initial_stats['total_feedback']}</div>
|
| 1446 |
-
<div class="stat-label">Total Feedback</div>
|
| 1447 |
-
</div>
|
| 1448 |
-
<div class="stat-item">
|
| 1449 |
-
<div class="stat-value">{initial_stats['hallucinations_detected']}</div>
|
| 1450 |
-
<div class="stat-label">Hallucinations Found</div>
|
| 1451 |
-
</div>
|
| 1452 |
-
<div class="stat-item">
|
| 1453 |
-
<div class="stat-value">{initial_stats['no_hallucinations']}</div>
|
| 1454 |
-
<div class="stat-label">No Hallucinations</div>
|
| 1455 |
-
</div>
|
| 1456 |
-
<div class="stat-item">
|
| 1457 |
-
<div class="stat-value">{initial_stats['average_confidence']}</div>
|
| 1458 |
-
<div class="stat-label">Avg. Confidence</div>
|
| 1459 |
-
</div>
|
| 1460 |
-
</div>
|
| 1461 |
-
"""
|
| 1462 |
|
| 1463 |
# Hidden state to store results for feedback
|
| 1464 |
hidden_results = gr.State()
|
|
@@ -1478,7 +1520,7 @@ def create_interface():
|
|
| 1478 |
feedback_button.click(
|
| 1479 |
fn=combine_feedback,
|
| 1480 |
inputs=[feedback_input, feedback_text, hidden_results],
|
| 1481 |
-
outputs=[feedback_status
|
| 1482 |
)
|
| 1483 |
|
| 1484 |
# Footer
|
|
|
|
| 517 |
# Get total feedback count
|
| 518 |
total_count = self.feedback_collection.count_documents({})
|
| 519 |
|
| 520 |
+
# Get accuracy stats based on user feedback
|
| 521 |
+
correct_predictions = 0
|
| 522 |
+
|
| 523 |
+
# Fetch all feedback documents
|
| 524 |
+
feedback_docs = list(self.feedback_collection.find({}, {"user_feedback": 1}))
|
| 525 |
+
|
| 526 |
+
# Count correct predictions based on user feedback
|
| 527 |
+
for doc in feedback_docs:
|
| 528 |
+
if "user_feedback" in doc:
|
| 529 |
+
# If feedback starts with "Yes", it's a correct prediction
|
| 530 |
+
if doc["user_feedback"].startswith("Yes"):
|
| 531 |
+
correct_predictions += 1
|
| 532 |
+
|
| 533 |
+
# Calculate accuracy percentage
|
| 534 |
+
accuracy = correct_predictions / max(total_count, 1)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 535 |
|
| 536 |
return {
|
| 537 |
"total_feedback": total_count,
|
| 538 |
+
"correct_predictions": correct_predictions,
|
| 539 |
+
"accuracy": accuracy
|
|
|
|
| 540 |
}
|
| 541 |
except Exception as e:
|
| 542 |
logger.error("Error getting feedback stats: %s", str(e), exc_info=True)
|
|
|
|
| 1283 |
None
|
| 1284 |
]
|
| 1285 |
|
| 1286 |
+
# Helper function to submit feedback
|
| 1287 |
def combine_feedback(fb_input, fb_text, results):
|
| 1288 |
combined_feedback = f"{fb_input}: {fb_text}" if fb_text else fb_input
|
| 1289 |
if not results:
|
| 1290 |
+
return "No results to attach feedback to."
|
| 1291 |
|
| 1292 |
response = detector.save_feedback(results, combined_feedback)
|
| 1293 |
+
return response
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1294 |
|
| 1295 |
# Create the interface
|
| 1296 |
with gr.Blocks(css=css, theme=gr.themes.Soft()) as interface:
|
|
|
|
| 1384 |
# Add feedback stats display
|
| 1385 |
feedback_stats = gr.HTML(visible=True)
|
| 1386 |
|
| 1387 |
+
# Function to continuously update stats
|
| 1388 |
+
def update_stats():
|
| 1389 |
+
stats = detector.get_feedback_stats()
|
| 1390 |
+
if stats:
|
| 1391 |
+
total = stats['total_feedback']
|
| 1392 |
+
correct = stats['correct_predictions']
|
| 1393 |
+
|
| 1394 |
+
# Get accuracy directly from the stats
|
| 1395 |
+
accuracy = stats['accuracy']
|
| 1396 |
+
|
| 1397 |
+
# Format accuracy percentage
|
| 1398 |
+
accuracy_pct = f"{accuracy * 100:.1f}%"
|
| 1399 |
+
|
| 1400 |
+
stats_html = f"""
|
| 1401 |
+
<div class="stats-section" style="background-color: #e8f5e9; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); margin-top: 5px;">
|
| 1402 |
+
<div class="stat-item">
|
| 1403 |
+
<div class="stat-value" style="font-size: 2em; color: #2e7d32;">{total}</div>
|
| 1404 |
+
<div class="stat-label" style="font-weight: bold;">Total Responses</div>
|
| 1405 |
+
</div>
|
| 1406 |
+
<div class="stat-item">
|
| 1407 |
+
<div class="stat-value" style="font-size: 2em; color: #2e7d32;">{accuracy_pct}</div>
|
| 1408 |
+
<div class="stat-label" style="font-weight: bold;">Correct Predictions</div>
|
| 1409 |
+
</div>
|
| 1410 |
+
</div>
|
| 1411 |
+
<div style="text-align: center; margin-top: 10px; font-style: italic; color: #666;">
|
| 1412 |
+
Based on user feedback: {correct} correct out of {total} total predictions
|
| 1413 |
+
</div>
|
| 1414 |
+
"""
|
| 1415 |
+
return stats_html
|
| 1416 |
+
return ""
|
| 1417 |
+
|
| 1418 |
+
# Set up interval to update stats
|
| 1419 |
+
with gr.Row(elem_id="stats-container"):
|
| 1420 |
+
with gr.Column():
|
| 1421 |
+
gr.Markdown("### 📊 Live Prediction Accuracy")
|
| 1422 |
+
gr.Markdown("_Auto-refreshes every 5 seconds from MongoDB based on user feedback_")
|
| 1423 |
+
live_stats = gr.HTML(update_stats())
|
| 1424 |
+
|
| 1425 |
+
# Add loading animation style
|
| 1426 |
+
gr.HTML("""
|
| 1427 |
+
<style>
|
| 1428 |
+
@keyframes pulse {
|
| 1429 |
+
0% { opacity: 0.6; }
|
| 1430 |
+
50% { opacity: 1; }
|
| 1431 |
+
100% { opacity: 0.6; }
|
| 1432 |
+
}
|
| 1433 |
+
.refreshing::after {
|
| 1434 |
+
content: "⟳";
|
| 1435 |
+
display: inline-block;
|
| 1436 |
+
margin-left: 8px;
|
| 1437 |
+
animation: pulse 1.5s infinite ease-in-out;
|
| 1438 |
+
color: #2e7d32;
|
| 1439 |
+
}
|
| 1440 |
+
#stats-container {
|
| 1441 |
+
border: 1px solid #e0e0e0;
|
| 1442 |
+
border-radius: 10px;
|
| 1443 |
+
padding: 15px;
|
| 1444 |
+
margin: 10px 0;
|
| 1445 |
+
background-color: #2762d7;
|
| 1446 |
+
}
|
| 1447 |
+
</style>
|
| 1448 |
+
<div class="refreshing" style="text-align: right; font-size: 0.8em; color: #666;">Auto-refreshing</div>
|
| 1449 |
+
""")
|
| 1450 |
+
|
| 1451 |
+
# Create a refresh button that will be auto-clicked
|
| 1452 |
+
refresh_btn = gr.Button("Refresh Stats", visible=False)
|
| 1453 |
+
refresh_btn.click(
|
| 1454 |
+
fn=update_stats,
|
| 1455 |
+
outputs=[live_stats]
|
| 1456 |
+
)
|
| 1457 |
+
|
| 1458 |
+
# Add JavaScript to auto-refresh the statistics
|
| 1459 |
+
gr.HTML("""
|
| 1460 |
+
<script>
|
| 1461 |
+
// Auto-refresh stats every 5 seconds
|
| 1462 |
+
function setupAutoRefresh() {
|
| 1463 |
+
const refreshInterval = 5000; // 5 seconds
|
| 1464 |
+
setInterval(() => {
|
| 1465 |
+
// Find the refresh button by its text and click it
|
| 1466 |
+
const refreshButtons = Array.from(document.querySelectorAll('button'));
|
| 1467 |
+
const refreshBtn = refreshButtons.find(btn => btn.textContent.includes('Refresh Stats'));
|
| 1468 |
+
if (refreshBtn) {
|
| 1469 |
+
refreshBtn.click();
|
| 1470 |
+
}
|
| 1471 |
+
}, refreshInterval);
|
| 1472 |
+
}
|
| 1473 |
+
|
| 1474 |
+
// Set up the auto-refresh after the page loads
|
| 1475 |
+
if (window.gradio_loaded) {
|
| 1476 |
+
setupAutoRefresh();
|
| 1477 |
+
} else {
|
| 1478 |
+
document.addEventListener('DOMContentLoaded', setupAutoRefresh);
|
| 1479 |
+
}
|
| 1480 |
+
</script>
|
| 1481 |
+
""")
|
| 1482 |
+
|
| 1483 |
# Feedback section
|
| 1484 |
with gr.Accordion("Provide Feedback", open=False, visible=False) as feedback_accordion:
|
| 1485 |
gr.Markdown("### Help Improve the System")
|
|
|
|
| 1500 |
feedback_button = gr.Button("Submit Feedback", variant="secondary")
|
| 1501 |
feedback_status = gr.Textbox(label="Feedback Status", interactive=False, visible=False)
|
| 1502 |
|
| 1503 |
+
# Stats are now displayed in the live stats section
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1504 |
|
| 1505 |
# Hidden state to store results for feedback
|
| 1506 |
hidden_results = gr.State()
|
|
|
|
| 1520 |
feedback_button.click(
|
| 1521 |
fn=combine_feedback,
|
| 1522 |
inputs=[feedback_input, feedback_text, hidden_results],
|
| 1523 |
+
outputs=[feedback_status]
|
| 1524 |
)
|
| 1525 |
|
| 1526 |
# Footer
|