Spaces:
Sleeping
Sleeping
Update src/app.py
Browse files- src/app.py +31 -41
src/app.py
CHANGED
|
@@ -556,7 +556,7 @@ with tab2:
|
|
| 556 |
with tab3:
|
| 557 |
st.header("⚓ Qualification Board Simulator")
|
| 558 |
|
| 559 |
-
# 1. MODE SELECTION
|
| 560 |
col_mode, col_streak = st.columns([3, 1])
|
| 561 |
with col_mode:
|
| 562 |
quiz_mode = st.radio(
|
|
@@ -564,14 +564,27 @@ with tab3:
|
|
| 564 |
["⚡ Acronym Lightning Round", "📖 Document Deep Dive"],
|
| 565 |
horizontal=True
|
| 566 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 567 |
|
| 568 |
-
# Initialize State
|
| 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:
|
|
@@ -580,7 +593,7 @@ with tab3:
|
|
| 580 |
|
| 581 |
st.divider()
|
| 582 |
|
| 583 |
-
# --- GENERATION FUNCTION
|
| 584 |
def generate_question():
|
| 585 |
with st.spinner("Consulting the Board..."):
|
| 586 |
# MODE A: ACRONYMS
|
|
@@ -610,6 +623,7 @@ with tab3:
|
|
| 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
|
|
@@ -620,12 +634,11 @@ with tab3:
|
|
| 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
|
| 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
|
| 627 |
generate_question()
|
| 628 |
-
st.rerun()
|
| 629 |
|
| 630 |
# 3. MANUAL START BUTTON
|
| 631 |
if not qs["active"]:
|
|
@@ -637,9 +650,11 @@ with tab3:
|
|
| 637 |
if qs["active"]:
|
| 638 |
st.markdown(f"### {qs['generated_question_text']}")
|
| 639 |
|
|
|
|
| 640 |
if "document" in qs.get("question_data", {}).get("type", ""):
|
| 641 |
st.caption(f"Source: *{qs['question_data']['source_file']}*")
|
| 642 |
|
|
|
|
| 643 |
with st.form(key="quiz_response"):
|
| 644 |
user_ans = st.text_area("Your Answer:")
|
| 645 |
sub = st.form_submit_button("Submit Answer")
|
|
@@ -648,6 +663,7 @@ with tab3:
|
|
| 648 |
with st.spinner("Grading..."):
|
| 649 |
data = qs["question_data"]
|
| 650 |
|
|
|
|
| 651 |
if data["type"] == "acronym":
|
| 652 |
prompt = quiz.construct_acronym_grading_prompt(
|
| 653 |
data["term"], data["correct_definition"], user_ans
|
|
@@ -664,6 +680,7 @@ with tab3:
|
|
| 664 |
|
| 665 |
qs["feedback"] = grade
|
| 666 |
|
|
|
|
| 667 |
if "GRADE:** PASS" in grade or "GRADE:** Pass" in grade:
|
| 668 |
qs["streak"] += 1
|
| 669 |
elif "GRADE:** FAIL" in grade:
|
|
@@ -671,7 +688,7 @@ with tab3:
|
|
| 671 |
|
| 672 |
st.rerun()
|
| 673 |
|
| 674 |
-
# 5. FEEDBACK AREA
|
| 675 |
if qs["feedback"]:
|
| 676 |
st.divider()
|
| 677 |
if "PASS" in qs["feedback"]:
|
|
@@ -684,7 +701,7 @@ with tab3:
|
|
| 684 |
|
| 685 |
st.markdown(qs["feedback"])
|
| 686 |
|
| 687 |
-
# Display
|
| 688 |
data = qs["question_data"]
|
| 689 |
if data["type"] == "acronym":
|
| 690 |
st.info(f"**Official Definition:** {data['correct_definition']}")
|
|
@@ -692,36 +709,9 @@ with tab3:
|
|
| 692 |
with st.expander("Show Source Text (Answer Key)"):
|
| 693 |
st.info(data["context_text"])
|
| 694 |
|
| 695 |
-
#
|
| 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()
|
| 706 |
-
if "PASS" in qs["feedback"]:
|
| 707 |
-
st.success("✅ CORRECT")
|
| 708 |
-
else:
|
| 709 |
-
if "FAIL" in qs["feedback"]:
|
| 710 |
-
st.error("❌ INCORRECT")
|
| 711 |
-
else:
|
| 712 |
-
st.warning("⚠️ PARTIAL / COMMENTARY")
|
| 713 |
-
|
| 714 |
-
st.markdown(qs["feedback"])
|
| 715 |
-
|
| 716 |
-
# Display Correct Answer based on type
|
| 717 |
-
data = qs["question_data"]
|
| 718 |
-
if data["type"] == "acronym":
|
| 719 |
-
st.info(f"**Official Definition:** {data['correct_definition']}")
|
| 720 |
-
elif data["type"] == "document":
|
| 721 |
-
with st.expander("Show Source Text (Answer Key)"):
|
| 722 |
-
st.info(data["context_text"])
|
| 723 |
-
|
| 724 |
-
if st.button("Next Question ➡️"):
|
| 725 |
qs["active"] = False
|
| 726 |
qs["question_data"] = None
|
| 727 |
qs["feedback"] = None
|
|
|
|
| 556 |
with tab3:
|
| 557 |
st.header("⚓ Qualification Board Simulator")
|
| 558 |
|
| 559 |
+
# 1. MODE SELECTION & RESET LOGIC
|
| 560 |
col_mode, col_streak = st.columns([3, 1])
|
| 561 |
with col_mode:
|
| 562 |
quiz_mode = st.radio(
|
|
|
|
| 564 |
["⚡ Acronym Lightning Round", "📖 Document Deep Dive"],
|
| 565 |
horizontal=True
|
| 566 |
)
|
| 567 |
+
|
| 568 |
+
# Initialize Session State Variables if missing
|
| 569 |
+
if "last_quiz_mode" not in st.session_state:
|
| 570 |
+
st.session_state.last_quiz_mode = quiz_mode
|
| 571 |
+
|
| 572 |
+
if "quiz_trigger" not in st.session_state:
|
| 573 |
+
st.session_state.quiz_trigger = False
|
| 574 |
+
|
| 575 |
+
# GHOST IMAGE FIX: Detect Mode Switch
|
| 576 |
+
# If the user toggled the radio button since the last run, wipe the state.
|
| 577 |
+
if st.session_state.last_quiz_mode != quiz_mode:
|
| 578 |
+
st.session_state.quiz_state["active"] = False
|
| 579 |
+
st.session_state.quiz_state["question_data"] = None
|
| 580 |
+
st.session_state.quiz_state["feedback"] = None
|
| 581 |
+
st.session_state.quiz_state["generated_question_text"] = ""
|
| 582 |
+
st.session_state.last_quiz_mode = quiz_mode
|
| 583 |
+
st.rerun() # Force a clean refresh immediately
|
| 584 |
|
| 585 |
+
# Initialize Engine & Shortcut to State
|
| 586 |
quiz = QuizEngine()
|
| 587 |
qs = st.session_state.quiz_state
|
|
|
|
|
|
|
|
|
|
|
|
|
| 588 |
|
| 589 |
# Display Streak
|
| 590 |
with col_streak:
|
|
|
|
| 593 |
|
| 594 |
st.divider()
|
| 595 |
|
| 596 |
+
# --- GENERATION FUNCTION ---
|
| 597 |
def generate_question():
|
| 598 |
with st.spinner("Consulting the Board..."):
|
| 599 |
# MODE A: ACRONYMS
|
|
|
|
| 623 |
300, model_choice, st.session_state.get("user_openai_key")
|
| 624 |
)
|
| 625 |
|
| 626 |
+
# Filter out skips or empty responses
|
| 627 |
if "SKIP" not in question_text and len(question_text) > 10:
|
| 628 |
valid_question_found = True
|
| 629 |
qs["active"] = True
|
|
|
|
| 634 |
if not valid_question_found:
|
| 635 |
st.warning("Tried to find a good engineering question but the available text was too administrative. Try uploading denser technical notes!")
|
| 636 |
|
| 637 |
+
# 2. AUTO-TRIGGER (Chained Question Logic)
|
|
|
|
| 638 |
if st.session_state.quiz_trigger:
|
| 639 |
+
st.session_state.quiz_trigger = False
|
| 640 |
generate_question()
|
| 641 |
+
st.rerun()
|
| 642 |
|
| 643 |
# 3. MANUAL START BUTTON
|
| 644 |
if not qs["active"]:
|
|
|
|
| 650 |
if qs["active"]:
|
| 651 |
st.markdown(f"### {qs['generated_question_text']}")
|
| 652 |
|
| 653 |
+
# Context Hint
|
| 654 |
if "document" in qs.get("question_data", {}).get("type", ""):
|
| 655 |
st.caption(f"Source: *{qs['question_data']['source_file']}*")
|
| 656 |
|
| 657 |
+
# Answer Form
|
| 658 |
with st.form(key="quiz_response"):
|
| 659 |
user_ans = st.text_area("Your Answer:")
|
| 660 |
sub = st.form_submit_button("Submit Answer")
|
|
|
|
| 663 |
with st.spinner("Grading..."):
|
| 664 |
data = qs["question_data"]
|
| 665 |
|
| 666 |
+
# Grading Logic Branch
|
| 667 |
if data["type"] == "acronym":
|
| 668 |
prompt = quiz.construct_acronym_grading_prompt(
|
| 669 |
data["term"], data["correct_definition"], user_ans
|
|
|
|
| 680 |
|
| 681 |
qs["feedback"] = grade
|
| 682 |
|
| 683 |
+
# Streak Logic
|
| 684 |
if "GRADE:** PASS" in grade or "GRADE:** Pass" in grade:
|
| 685 |
qs["streak"] += 1
|
| 686 |
elif "GRADE:** FAIL" in grade:
|
|
|
|
| 688 |
|
| 689 |
st.rerun()
|
| 690 |
|
| 691 |
+
# 5. FEEDBACK AREA (Deduplicated)
|
| 692 |
if qs["feedback"]:
|
| 693 |
st.divider()
|
| 694 |
if "PASS" in qs["feedback"]:
|
|
|
|
| 701 |
|
| 702 |
st.markdown(qs["feedback"])
|
| 703 |
|
| 704 |
+
# Display Answer Key
|
| 705 |
data = qs["question_data"]
|
| 706 |
if data["type"] == "acronym":
|
| 707 |
st.info(f"**Official Definition:** {data['correct_definition']}")
|
|
|
|
| 709 |
with st.expander("Show Source Text (Answer Key)"):
|
| 710 |
st.info(data["context_text"])
|
| 711 |
|
| 712 |
+
# Next Question Button
|
| 713 |
if st.button("Next Question ➡️"):
|
| 714 |
st.session_state.quiz_trigger = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 715 |
qs["active"] = False
|
| 716 |
qs["question_data"] = None
|
| 717 |
qs["feedback"] = None
|