|
import streamlit as st |
|
import os |
|
from fpdf import FPDF |
|
import uuid |
|
|
|
|
|
if 'session_id' not in st.session_state: |
|
st.session_state.session_id = str(uuid.uuid4()) |
|
|
|
if 'questions' not in st.session_state: |
|
st.session_state.questions = [] |
|
if 'current_index' not in st.session_state: |
|
st.session_state.current_index = 0 |
|
if 'current_module' not in st.session_state: |
|
st.session_state.current_module = None |
|
if 'correct_count' not in st.session_state: |
|
st.session_state.correct_count = 0 |
|
if 'module_correct_count' not in st.session_state: |
|
st.session_state.module_correct_count = {} |
|
if 'module_question_count' not in st.session_state: |
|
st.session_state.module_question_count = {} |
|
if 'pdf_data' not in st.session_state: |
|
st.session_state.pdf_data = None |
|
if 'selected_answer' not in st.session_state: |
|
st.session_state.selected_answer = None |
|
if 'state' not in st.session_state: |
|
st.session_state.state = "NewQuestion" |
|
|
|
def reset_pdf_cache(): |
|
st.session_state.pdf_data = None |
|
|
|
def generate_pdf_report(): |
|
pdf = FPDF() |
|
pdf.add_page() |
|
pdf.set_font("Arial", size=12) |
|
|
|
pdf.cell(200, 10, txt="Quiz Report", ln=True, align="C") |
|
pdf.ln(10) |
|
|
|
for module, data in st.session_state.module_question_count.items(): |
|
correct_count = st.session_state.module_correct_count.get(module, 0) |
|
total_count = data |
|
pdf.cell(200, 10, txt=f"Module: {module}", ln=True, align="L") |
|
pdf.ln(5) |
|
pdf.cell(200, 10, txt=f"Correct Answers: {correct_count}/{total_count}", ln=True, align="L") |
|
pdf.ln(5) |
|
|
|
for entry in st.session_state.questions: |
|
if entry['module'] == module: |
|
question, options, selected, correct, explanation, step_by_step_solution = ( |
|
entry['question'], |
|
entry['options'], |
|
entry['selected'] if entry['selected'] is not None else "Not Answered", |
|
entry['correct_answer'], |
|
entry['explanation'], |
|
entry['step_by_step_solution'] |
|
) |
|
pdf.multi_cell(0, 10, f"Q: {question}") |
|
for option in options: |
|
if option == correct: |
|
pdf.set_text_color(0, 128, 0) |
|
pdf.multi_cell(0, 10, f"{option}") |
|
elif option == selected: |
|
pdf.set_text_color(255, 0, 0) |
|
pdf.multi_cell(0, 10, f"{option}") |
|
else: |
|
pdf.set_text_color(0, 0, 0) |
|
pdf.multi_cell(0, 10, f" {option}") |
|
pdf.set_text_color(0, 0, 0) |
|
pdf.multi_cell(0, 10, f"Explanation: {explanation}") |
|
pdf.ln(5) |
|
pdf.multi_cell(0, 10, "Step-by-Step Solution:") |
|
for step in step_by_step_solution: |
|
pdf.multi_cell(0, 10, step) |
|
pdf.ln(10) |
|
|
|
pdf.ln(10) |
|
|
|
return pdf.output(dest='S').encode('latin1', 'replace') |
|
|
|
def load_modules(): |
|
modules = {} |
|
module_dir = "modules" |
|
for filename in os.listdir(module_dir): |
|
if filename.endswith(".py") and filename != "__init__.py": |
|
module_name = filename[:-3] |
|
|
|
module = __import__(f"{module_dir}.{module_name}", fromlist=['']) |
|
modules[module_name] = { |
|
"title": getattr(module, "title", module_name), |
|
"description": getattr(module, "description", "No description available."), |
|
"generate_question": module.generate_question |
|
} |
|
return modules |
|
|
|
def generate_new_question(module_name, module): |
|
question_data = module['generate_question']() |
|
question_data['answered'] = False |
|
question_data['module'] = module_name |
|
question_data['selected'] = None |
|
st.session_state.selected_answer = None |
|
st.session_state.state = "NewQuestion" |
|
return question_data |
|
|
|
def navigate_question(direction): |
|
if direction == "prev" and st.session_state.current_index > 0: |
|
st.session_state.current_index -= 1 |
|
elif direction == "next" and st.session_state.current_index < len(st.session_state.questions) - 1: |
|
st.session_state.current_index += 1 |
|
elif direction == "new": |
|
new_question = generate_new_question(st.session_state.current_module, modules[st.session_state.current_module]) |
|
st.session_state.questions.append(new_question) |
|
st.session_state.current_index = len(st.session_state.questions) - 1 |
|
|
|
|
|
|
|
modules = load_modules() |
|
|
|
|
|
st.sidebar.title("Quiz Modules") |
|
module_name = st.sidebar.radio("Choose a module:", [modules[module]["title"] for module in modules], index=0) |
|
|
|
selected_module = None |
|
for module in modules: |
|
if modules[module]["title"] == module_name: |
|
selected_module = module |
|
break |
|
|
|
if selected_module != st.session_state.current_module: |
|
st.session_state.current_module = selected_module |
|
st.session_state.current_index = 0 |
|
st.session_state.questions = [generate_new_question(selected_module, modules[selected_module])] |
|
st.session_state.module_question_count[selected_module] = 0 |
|
st.session_state.module_correct_count[selected_module] = 0 |
|
st.session_state.selected_answer = None |
|
st.session_state.state = "NewQuestion" |
|
|
|
|
|
current_question = st.session_state.questions[st.session_state.current_index] |
|
|
|
|
|
st.title(modules[selected_module]["title"]) |
|
st.write(modules[selected_module]["description"]) |
|
|
|
|
|
col1, col2, col3 = st.columns([1, 1, 2]) |
|
with col1: |
|
if st.button("⬅️ Prev", disabled=st.session_state.current_index == 0): |
|
navigate_question("prev") |
|
with col2: |
|
if st.button("➡️ Next", disabled=st.session_state.current_index >= len(st.session_state.questions) - 1): |
|
navigate_question("next") |
|
with col3: |
|
if len(st.session_state.questions) > 0: |
|
pdf = generate_pdf_report() |
|
st.session_state.pdf_data = pdf |
|
st.download_button( |
|
label="Download PDF Report 📄", |
|
data=st.session_state.pdf_data, |
|
file_name="quiz_report.pdf", |
|
mime="application/pdf" |
|
) |
|
|
|
st.write(current_question["question"]) |
|
|
|
|
|
selected_answer = st.radio( |
|
"Choose an answer:", |
|
options=current_question['options'], |
|
key=f"question_{st.session_state.current_index}_options", |
|
index=None |
|
) |
|
|
|
|
|
if selected_answer: |
|
st.session_state.selected_answer = selected_answer |
|
st.session_state.state = "OptionSelected" |
|
|
|
|
|
if st.session_state.state == "NewQuestion": |
|
action = st.radio( |
|
"Choose an action:", |
|
("Submit", "New"), |
|
index=None, |
|
key="action_radio_new", |
|
horizontal=True |
|
) |
|
|
|
|
|
if action == "Submit": |
|
st.warning("Please select an option before submitting.", icon="⚠️") |
|
st.session_state.action = None |
|
elif action == "New": |
|
navigate_question("new") |
|
|
|
elif st.session_state.state == "OptionSelected": |
|
action = st.radio( |
|
"Choose an action:", |
|
("Submit", "New"), |
|
index=None, |
|
key="action_radio_submit", |
|
horizontal=True |
|
) |
|
|
|
|
|
if action == "Submit": |
|
|
|
current_question['selected'] = st.session_state.selected_answer |
|
current_question['answered'] = True |
|
st.session_state.module_question_count[selected_module] += 1 |
|
|
|
if st.session_state.selected_answer == current_question['correct_answer']: |
|
st.session_state.correct_count += 1 |
|
st.session_state.module_correct_count[selected_module] += 1 |
|
|
|
|
|
for option in current_question['options']: |
|
if option == current_question['correct_answer']: |
|
st.markdown(f"<span style='color:green;'>{option} ✅</span>", unsafe_allow_html=True) |
|
elif option == current_question['selected']: |
|
st.markdown(f"<span style='color:red;'>{option} ❌</span>", unsafe_allow_html=True) |
|
else: |
|
st.markdown(f"{option}") |
|
|
|
st.write(f"**Explanation:** {current_question['explanation']}") |
|
st.write("**Step-by-Step Solution:**") |
|
for step in current_question['step_by_step_solution']: |
|
st.write(step) |
|
|
|
st.session_state.state = "NewQuestion" |
|
|
|
elif action == "New": |
|
navigate_question("new") |
|
st.session_state.state = "NewQuestion" |
|
|