Spaces:
Sleeping
Sleeping
Update src/app.py
Browse files- src/app.py +83 -41
src/app.py
CHANGED
|
@@ -569,6 +569,10 @@ with tab3:
|
|
| 569 |
quiz = QuizEngine()
|
| 570 |
qs = st.session_state.quiz_state
|
| 571 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 572 |
# Display Streak
|
| 573 |
with col_streak:
|
| 574 |
st.metric("Current Streak", qs["streak"])
|
|
@@ -576,51 +580,60 @@ with tab3:
|
|
| 576 |
|
| 577 |
st.divider()
|
| 578 |
|
| 579 |
-
#
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
if
|
| 586 |
-
|
| 587 |
-
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
qs["feedback"] = None
|
| 591 |
-
qs["generated_question_text"] = q_data["question"]
|
| 592 |
-
st.rerun()
|
| 593 |
-
else:
|
| 594 |
-
st.error("No acronyms found! Run the extractor first.")
|
| 595 |
-
|
| 596 |
-
# MODE B: DOCUMENTS
|
| 597 |
else:
|
| 598 |
-
|
| 599 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 600 |
|
| 601 |
-
|
| 602 |
-
|
| 603 |
-
|
|
|
|
|
|
|
|
|
|
| 604 |
|
| 605 |
-
if
|
| 606 |
-
|
| 607 |
-
|
| 608 |
-
|
| 609 |
-
|
| 610 |
-
|
| 611 |
-
|
| 612 |
-
|
| 613 |
-
|
| 614 |
-
qs["active"] = True
|
| 615 |
-
qs["question_data"] = q_ctx
|
| 616 |
-
qs["generated_question_text"] = question_text
|
| 617 |
-
qs["feedback"] = None
|
| 618 |
-
st.rerun()
|
| 619 |
-
|
| 620 |
-
if not valid_question_found:
|
| 621 |
-
st.warning("Tried to find a good engineering question but the available text was too administrative. Try uploading denser technical notes!")
|
| 622 |
|
| 623 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 624 |
if qs["active"]:
|
| 625 |
st.markdown(f"### {qs['generated_question_text']}")
|
| 626 |
|
|
@@ -658,6 +671,35 @@ with tab3:
|
|
| 658 |
|
| 659 |
st.rerun()
|
| 660 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 661 |
# 4. FEEDBACK AREA (MERGED & FIXED)
|
| 662 |
if qs["feedback"]:
|
| 663 |
st.divider()
|
|
|
|
| 569 |
quiz = QuizEngine()
|
| 570 |
qs = st.session_state.quiz_state
|
| 571 |
|
| 572 |
+
# NEW: Trigger State for "Next Question" chaining
|
| 573 |
+
if "quiz_trigger" not in st.session_state:
|
| 574 |
+
st.session_state.quiz_trigger = False
|
| 575 |
+
|
| 576 |
# Display Streak
|
| 577 |
with col_streak:
|
| 578 |
st.metric("Current Streak", qs["streak"])
|
|
|
|
| 580 |
|
| 581 |
st.divider()
|
| 582 |
|
| 583 |
+
# --- GENERATION FUNCTION (Reused for Button AND Auto-Trigger) ---
|
| 584 |
+
def generate_question():
|
| 585 |
+
with st.spinner("Consulting the Board..."):
|
| 586 |
+
# MODE A: ACRONYMS
|
| 587 |
+
if "Acronym" in quiz_mode:
|
| 588 |
+
q_data = quiz.get_random_acronym()
|
| 589 |
+
if q_data:
|
| 590 |
+
qs["active"] = True
|
| 591 |
+
qs["question_data"] = q_data
|
| 592 |
+
qs["feedback"] = None
|
| 593 |
+
qs["generated_question_text"] = q_data["question"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 594 |
else:
|
| 595 |
+
st.error("No acronyms found! Run the extractor first.")
|
| 596 |
+
|
| 597 |
+
# MODE B: DOCUMENTS
|
| 598 |
+
else:
|
| 599 |
+
valid_question_found = False
|
| 600 |
+
attempts = 0
|
| 601 |
+
|
| 602 |
+
while not valid_question_found and attempts < 3:
|
| 603 |
+
attempts += 1
|
| 604 |
+
q_ctx = quiz.get_document_context(st.session_state.username)
|
| 605 |
|
| 606 |
+
if q_ctx:
|
| 607 |
+
prompt = quiz.construct_question_generation_prompt(q_ctx["context_text"])
|
| 608 |
+
question_text, usage = query_model_universal(
|
| 609 |
+
[{"role": "user", "content": prompt}],
|
| 610 |
+
300, model_choice, st.session_state.get("user_openai_key")
|
| 611 |
+
)
|
| 612 |
|
| 613 |
+
if "SKIP" not in question_text and len(question_text) > 10:
|
| 614 |
+
valid_question_found = True
|
| 615 |
+
qs["active"] = True
|
| 616 |
+
qs["question_data"] = q_ctx
|
| 617 |
+
qs["generated_question_text"] = question_text
|
| 618 |
+
qs["feedback"] = None
|
| 619 |
+
|
| 620 |
+
if not valid_question_found:
|
| 621 |
+
st.warning("Tried to find a good engineering question but the available text was too administrative. Try uploading denser technical notes!")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 622 |
|
| 623 |
+
# 2. AUTO-TRIGGER CHECK
|
| 624 |
+
# If the user clicked "Next Question", this runs immediately on rerun
|
| 625 |
+
if st.session_state.quiz_trigger:
|
| 626 |
+
st.session_state.quiz_trigger = False # Reset flag
|
| 627 |
+
generate_question()
|
| 628 |
+
st.rerun() # Rerun to display the new question
|
| 629 |
+
|
| 630 |
+
# 3. MANUAL START BUTTON
|
| 631 |
+
if not qs["active"]:
|
| 632 |
+
if st.button("🚀 Generate New Question", type="primary"):
|
| 633 |
+
generate_question()
|
| 634 |
+
st.rerun()
|
| 635 |
+
|
| 636 |
+
# 4. QUIZ INTERFACE
|
| 637 |
if qs["active"]:
|
| 638 |
st.markdown(f"### {qs['generated_question_text']}")
|
| 639 |
|
|
|
|
| 671 |
|
| 672 |
st.rerun()
|
| 673 |
|
| 674 |
+
# 5. FEEDBACK AREA
|
| 675 |
+
if qs["feedback"]:
|
| 676 |
+
st.divider()
|
| 677 |
+
if "PASS" in qs["feedback"]:
|
| 678 |
+
st.success("✅ CORRECT")
|
| 679 |
+
else:
|
| 680 |
+
if "FAIL" in qs["feedback"]:
|
| 681 |
+
st.error("❌ INCORRECT")
|
| 682 |
+
else:
|
| 683 |
+
st.warning("⚠️ PARTIAL / COMMENTARY")
|
| 684 |
+
|
| 685 |
+
st.markdown(qs["feedback"])
|
| 686 |
+
|
| 687 |
+
# Display Correct Answer
|
| 688 |
+
data = qs["question_data"]
|
| 689 |
+
if data["type"] == "acronym":
|
| 690 |
+
st.info(f"**Official Definition:** {data['correct_definition']}")
|
| 691 |
+
elif data["type"] == "document":
|
| 692 |
+
with st.expander("Show Source Text (Answer Key)"):
|
| 693 |
+
st.info(data["context_text"])
|
| 694 |
+
|
| 695 |
+
# FIXED: "Next Question" now sets the trigger flag instead of just resetting state
|
| 696 |
+
if st.button("Next Question ➡️"):
|
| 697 |
+
st.session_state.quiz_trigger = True
|
| 698 |
+
qs["active"] = False
|
| 699 |
+
qs["question_data"] = None
|
| 700 |
+
qs["feedback"] = None
|
| 701 |
+
st.rerun()
|
| 702 |
+
|
| 703 |
# 4. FEEDBACK AREA (MERGED & FIXED)
|
| 704 |
if qs["feedback"]:
|
| 705 |
st.divider()
|