Spaces:
Running
Running
mah-diaa
commited on
Commit
Β·
6e60f8d
1
Parent(s):
6d3815b
Fix quiz submission: prevent double-counting, ensure feedback visibility, prevent infinite loops
Browse files- .gitignore +2 -0
- app.py +45 -7
- data/preloaded_concepts.json +2 -0
- mcp_server.py +2 -0
.gitignore
CHANGED
|
@@ -35,3 +35,5 @@ secrets/
|
|
| 35 |
|
| 36 |
|
| 37 |
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
|
| 37 |
|
| 38 |
+
|
| 39 |
+
|
app.py
CHANGED
|
@@ -1404,6 +1404,7 @@ with gr.Blocks(title="Gnosis Tutor") as app:
|
|
| 1404 |
"""Handle answer submission."""
|
| 1405 |
print(f"π [SUBMIT] Answer submitted - selected: {selected}, type: {type(selected)}, idx: {idx}")
|
| 1406 |
print(f"π [SUBMIT] quiz_data type: {type(quiz_data)}, length: {len(quiz_data) if quiz_data else 'None'}")
|
|
|
|
| 1407 |
|
| 1408 |
# If quiz_data is empty or None, try to get it from user_state
|
| 1409 |
if not quiz_data or (isinstance(quiz_data, list) and len(quiz_data) == 0):
|
|
@@ -1423,7 +1424,7 @@ with gr.Blocks(title="Gnosis Tutor") as app:
|
|
| 1423 |
gr.update(visible=False),
|
| 1424 |
gr.update(value=0),
|
| 1425 |
gr.update(value={"correct": 0, "total": 0}),
|
| 1426 |
-
gr.update(
|
| 1427 |
)
|
| 1428 |
|
| 1429 |
# Check if answer was selected
|
|
@@ -1440,7 +1441,7 @@ with gr.Blocks(title="Gnosis Tutor") as app:
|
|
| 1440 |
gr.update(visible=False), # quiz_next_btn
|
| 1441 |
gr.update(value=idx), # current_question_idx
|
| 1442 |
gr.update(value=score), # quiz_score_state (don't update)
|
| 1443 |
-
gr.update(
|
| 1444 |
)
|
| 1445 |
|
| 1446 |
# Ensure idx is valid - fix the index bug
|
|
@@ -1450,12 +1451,18 @@ with gr.Blocks(title="Gnosis Tutor") as app:
|
|
| 1450 |
|
| 1451 |
print(f"π [SUBMIT] Processing question {idx + 1} of {len(quiz_data)}")
|
| 1452 |
q = quiz_data[idx]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1453 |
question_type = q.get('type', '').lower()
|
| 1454 |
correct_answer = q.get('correct_answer', '')
|
| 1455 |
is_correct = False
|
| 1456 |
user_selected_idx = None
|
| 1457 |
|
| 1458 |
print(f"π [SUBMIT] Question type: {question_type}, correct_answer: {correct_answer}, options: {q.get('options', [])}")
|
|
|
|
| 1459 |
|
| 1460 |
if question_type == 'mcq':
|
| 1461 |
options = q.get('options', [])
|
|
@@ -1503,6 +1510,16 @@ with gr.Blocks(title="Gnosis Tutor") as app:
|
|
| 1503 |
# Store user's selected answer in the question data for reference
|
| 1504 |
q['user_selected_answer'] = user_selected_idx if user_selected_idx is not None else selected
|
| 1505 |
q['is_correct'] = is_correct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1506 |
|
| 1507 |
new_score = {
|
| 1508 |
"correct": score["correct"] + (1 if is_correct else 0),
|
|
@@ -1562,15 +1579,19 @@ with gr.Blocks(title="Gnosis Tutor") as app:
|
|
| 1562 |
# Store explanation in user_state to be picked up by chat
|
| 1563 |
user_state["last_quiz_explanation"] = chat_message
|
| 1564 |
|
|
|
|
|
|
|
|
|
|
| 1565 |
# Return exactly 7 values matching the outputs
|
|
|
|
| 1566 |
return (
|
| 1567 |
gr.update(visible=True, value=feedback), # quiz_feedback - MAKE SURE IT'S VISIBLE
|
| 1568 |
gr.update(visible=True, value=explanation), # quiz_explanation - MAKE SURE IT'S VISIBLE
|
| 1569 |
-
gr.update(visible=False), # quiz_submit_btn (hide after submission)
|
| 1570 |
gr.update(visible=idx < len(quiz_data) - 1), # quiz_next_btn
|
| 1571 |
gr.update(value=idx), # current_question_idx
|
| 1572 |
gr.update(value=new_score), # quiz_score_state
|
| 1573 |
-
gr.update(
|
| 1574 |
)
|
| 1575 |
|
| 1576 |
def next_question(quiz_data, idx, score):
|
|
@@ -1665,7 +1686,7 @@ with gr.Blocks(title="Gnosis Tutor") as app:
|
|
| 1665 |
gr.update(visible=False),
|
| 1666 |
gr.update(value=0),
|
| 1667 |
gr.update(value={"correct": 0, "total": 0}),
|
| 1668 |
-
gr.update(
|
| 1669 |
)
|
| 1670 |
try:
|
| 1671 |
result = submit_answer(selected, quiz_data, idx, score)
|
|
@@ -1682,7 +1703,7 @@ with gr.Blocks(title="Gnosis Tutor") as app:
|
|
| 1682 |
gr.update(visible=False),
|
| 1683 |
gr.update(value=idx),
|
| 1684 |
gr.update(value=score),
|
| 1685 |
-
gr.update(
|
| 1686 |
)
|
| 1687 |
|
| 1688 |
quiz_submit_btn.click(
|
|
@@ -2090,13 +2111,30 @@ if __name__ == "__main__":
|
|
| 2090 |
/* Quiz Block - Uses EXACT same styling as left sidebar (glass-tabs-container) */
|
| 2091 |
/* All quiz elements inherit from glass-tabs-container styling automatically */
|
| 2092 |
|
| 2093 |
-
/* Quiz feedback and explanation visibility */
|
| 2094 |
.quiz-feedback,
|
| 2095 |
.quiz-explanation {
|
| 2096 |
display: block !important;
|
| 2097 |
visibility: visible !important;
|
| 2098 |
opacity: 1 !important;
|
| 2099 |
margin: 1rem 0 !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2100 |
}
|
| 2101 |
|
| 2102 |
/* Chat Interface Glass - Enhanced & Fully Rounded */
|
|
|
|
| 1404 |
"""Handle answer submission."""
|
| 1405 |
print(f"π [SUBMIT] Answer submitted - selected: {selected}, type: {type(selected)}, idx: {idx}")
|
| 1406 |
print(f"π [SUBMIT] quiz_data type: {type(quiz_data)}, length: {len(quiz_data) if quiz_data else 'None'}")
|
| 1407 |
+
print(f"π [SUBMIT] Current score: {score}")
|
| 1408 |
|
| 1409 |
# If quiz_data is empty or None, try to get it from user_state
|
| 1410 |
if not quiz_data or (isinstance(quiz_data, list) and len(quiz_data) == 0):
|
|
|
|
| 1424 |
gr.update(visible=False),
|
| 1425 |
gr.update(value=0),
|
| 1426 |
gr.update(value={"correct": 0, "total": 0}),
|
| 1427 |
+
gr.update() # Don't update quiz_data_state to avoid loops
|
| 1428 |
)
|
| 1429 |
|
| 1430 |
# Check if answer was selected
|
|
|
|
| 1441 |
gr.update(visible=False), # quiz_next_btn
|
| 1442 |
gr.update(value=idx), # current_question_idx
|
| 1443 |
gr.update(value=score), # quiz_score_state (don't update)
|
| 1444 |
+
gr.update() # Don't update quiz_data_state to avoid loops
|
| 1445 |
)
|
| 1446 |
|
| 1447 |
# Ensure idx is valid - fix the index bug
|
|
|
|
| 1451 |
|
| 1452 |
print(f"π [SUBMIT] Processing question {idx + 1} of {len(quiz_data)}")
|
| 1453 |
q = quiz_data[idx]
|
| 1454 |
+
|
| 1455 |
+
# Check if this question was already answered to prevent double-counting
|
| 1456 |
+
was_answered = q.get('is_answered', False)
|
| 1457 |
+
previous_correct = q.get('is_correct', False)
|
| 1458 |
+
|
| 1459 |
question_type = q.get('type', '').lower()
|
| 1460 |
correct_answer = q.get('correct_answer', '')
|
| 1461 |
is_correct = False
|
| 1462 |
user_selected_idx = None
|
| 1463 |
|
| 1464 |
print(f"π [SUBMIT] Question type: {question_type}, correct_answer: {correct_answer}, options: {q.get('options', [])}")
|
| 1465 |
+
print(f"π [SUBMIT] Question already answered: {was_answered}, previous correct: {previous_correct}")
|
| 1466 |
|
| 1467 |
if question_type == 'mcq':
|
| 1468 |
options = q.get('options', [])
|
|
|
|
| 1510 |
# Store user's selected answer in the question data for reference
|
| 1511 |
q['user_selected_answer'] = user_selected_idx if user_selected_idx is not None else selected
|
| 1512 |
q['is_correct'] = is_correct
|
| 1513 |
+
q['is_answered'] = True # Mark as answered
|
| 1514 |
+
|
| 1515 |
+
# Calculate new score - only increment if question wasn't already answered
|
| 1516 |
+
if was_answered:
|
| 1517 |
+
# Question was already answered, adjust score based on new answer
|
| 1518 |
+
# Remove previous answer's contribution
|
| 1519 |
+
if previous_correct:
|
| 1520 |
+
score["correct"] = max(0, score["correct"] - 1)
|
| 1521 |
+
score["total"] = max(0, score["total"] - 1)
|
| 1522 |
+
print(f"π [SUBMIT] Question was already answered, adjusting score: {score}")
|
| 1523 |
|
| 1524 |
new_score = {
|
| 1525 |
"correct": score["correct"] + (1 if is_correct else 0),
|
|
|
|
| 1579 |
# Store explanation in user_state to be picked up by chat
|
| 1580 |
user_state["last_quiz_explanation"] = chat_message
|
| 1581 |
|
| 1582 |
+
# Update user_state with the modified quiz_data
|
| 1583 |
+
user_state["current_quiz"] = quiz_data
|
| 1584 |
+
|
| 1585 |
# Return exactly 7 values matching the outputs
|
| 1586 |
+
# Use gr.update() without value for quiz_data_state to avoid triggering change events
|
| 1587 |
return (
|
| 1588 |
gr.update(visible=True, value=feedback), # quiz_feedback - MAKE SURE IT'S VISIBLE
|
| 1589 |
gr.update(visible=True, value=explanation), # quiz_explanation - MAKE SURE IT'S VISIBLE
|
| 1590 |
+
gr.update(visible=False, interactive=False), # quiz_submit_btn (hide after submission)
|
| 1591 |
gr.update(visible=idx < len(quiz_data) - 1), # quiz_next_btn
|
| 1592 |
gr.update(value=idx), # current_question_idx
|
| 1593 |
gr.update(value=new_score), # quiz_score_state
|
| 1594 |
+
gr.update() # quiz_data_state - don't update to avoid infinite loops
|
| 1595 |
)
|
| 1596 |
|
| 1597 |
def next_question(quiz_data, idx, score):
|
|
|
|
| 1686 |
gr.update(visible=False),
|
| 1687 |
gr.update(value=0),
|
| 1688 |
gr.update(value={"correct": 0, "total": 0}),
|
| 1689 |
+
gr.update() # Don't update quiz_data_state to avoid loops
|
| 1690 |
)
|
| 1691 |
try:
|
| 1692 |
result = submit_answer(selected, quiz_data, idx, score)
|
|
|
|
| 1703 |
gr.update(visible=False),
|
| 1704 |
gr.update(value=idx),
|
| 1705 |
gr.update(value=score),
|
| 1706 |
+
gr.update() # Don't update quiz_data_state to avoid loops
|
| 1707 |
)
|
| 1708 |
|
| 1709 |
quiz_submit_btn.click(
|
|
|
|
| 2111 |
/* Quiz Block - Uses EXACT same styling as left sidebar (glass-tabs-container) */
|
| 2112 |
/* All quiz elements inherit from glass-tabs-container styling automatically */
|
| 2113 |
|
| 2114 |
+
/* Quiz feedback and explanation visibility - Force visibility when content exists */
|
| 2115 |
.quiz-feedback,
|
| 2116 |
.quiz-explanation {
|
| 2117 |
display: block !important;
|
| 2118 |
visibility: visible !important;
|
| 2119 |
opacity: 1 !important;
|
| 2120 |
margin: 1rem 0 !important;
|
| 2121 |
+
z-index: 100 !important;
|
| 2122 |
+
position: relative !important;
|
| 2123 |
+
}
|
| 2124 |
+
|
| 2125 |
+
/* Ensure feedback is visible even when Gradio tries to hide it */
|
| 2126 |
+
.quiz-feedback[style*="display: none"],
|
| 2127 |
+
.quiz-explanation[style*="display: none"] {
|
| 2128 |
+
display: block !important;
|
| 2129 |
+
visibility: visible !important;
|
| 2130 |
+
}
|
| 2131 |
+
|
| 2132 |
+
/* Make sure HTML content inside feedback is visible */
|
| 2133 |
+
.quiz-feedback > div,
|
| 2134 |
+
.quiz-explanation > div {
|
| 2135 |
+
display: block !important;
|
| 2136 |
+
visibility: visible !important;
|
| 2137 |
+
opacity: 1 !important;
|
| 2138 |
}
|
| 2139 |
|
| 2140 |
/* Chat Interface Glass - Enhanced & Fully Rounded */
|
data/preloaded_concepts.json
CHANGED
|
@@ -50,3 +50,5 @@
|
|
| 50 |
|
| 51 |
|
| 52 |
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
|
| 52 |
|
| 53 |
+
|
| 54 |
+
|
mcp_server.py
CHANGED
|
@@ -354,3 +354,5 @@ if __name__ == "__main__":
|
|
| 354 |
mcp.run()
|
| 355 |
|
| 356 |
|
|
|
|
|
|
|
|
|
| 354 |
mcp.run()
|
| 355 |
|
| 356 |
|
| 357 |
+
|
| 358 |
+
|