File size: 12,893 Bytes
7ba3b4e c9ca893 bad6a07 e0f928e a2ef5f6 d924141 c9ca893 e0f928e e9df8e8 9d6157e e9df8e8 795b9ba 169cec0 c9ca893 169cec0 c9ca893 9d5f38a d719d03 be0b9ff c63a46d a086503 a2ef5f6 9d5f38a d719d03 32f2e18 795b9ba 0fdb658 169cec0 c1018ca d4c89e6 eda0b5b 14697cf 31d5315 700a11e bad6a07 8aa4295 c0c50e8 8aa4295 c0c50e8 8aa4295 852a54f 8aa4295 a58f65d 32f2e18 c9ca893 74a6085 45705e3 bacb566 74a6085 45705e3 bacb566 74a6085 45705e3 74a6085 bacb566 74a6085 bacb566 c9ca893 74a6085 c9ca893 67f54db 81e422f 74a6085 67f54db 92fe395 67f54db a2ef5f6 67f54db b2acba8 81e422f ee53acf c9ca893 eda4dad 3949aee e48e9e2 c1018ca 0fdb658 14697cf 0fdb658 3949aee eda4dad fcee975 74a6085 fcee975 12e8aed 74a6085 45705e3 12e8aed 45705e3 74a6085 1596a24 12e8aed 1596a24 12e8aed 1596a24 12e8aed 9935146 12e8aed 9935146 12e8aed 9935146 eda4dad 12e8aed b09d39c 12e8aed 74a6085 12e8aed 74a6085 12e8aed 852a54f 12e8aed |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
import streamlit as st
import os
from fpdf import FPDF
import uuid
import time
# Initialize session state variables
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 'button_label' not in st.session_state:
st.session_state.button_label = "Submit/New"
if 'start_time' not in st.session_state:
st.session_state.start_time = time.time()
def reset_pdf_cache():
st.session_state.pdf_data = None
def generate_pdf_report():
pdf = FPDF()
pdf.add_page()
pdf.set_font("Arial", style='B', size=18)
# Title of the report with a link
pdf.set_text_color(0, 0, 255) # Set color to blue for the link
pdf.cell(0, 10, txt="πͺ Magic Math Quiz!", ln=True, align="C", link="https://huggingface.co/spaces/tofighi/math")
pdf.set_text_color(0, 0, 0) # Reset color to black
pdf.ln(5)
# Load the image from the URL, scaled down and centered
pdf.image("assets/gt.png", x=(210 - 25) / 2, w=25, link="https://ghassem.com") # Centered horizontally and scaled down
pdf.ln(10)
for i, entry in enumerate(st.session_state.questions):
# Add Category > Module as a header
pdf.set_fill_color(0, 0, 0) # Black background
pdf.set_text_color(255, 255, 255) # White text
pdf.set_font("Arial", style='B', size=12)
pdf.cell(0, 10, f"{entry['category']} > {entry['module_title']}", ln=True, align="L", fill=True)
pdf.set_text_color(0, 0, 0) # Reset text color to black
pdf.set_font("Arial", size=12)
pdf.ln(5)
# Question number and text
pdf.set_font("Arial", style='B', size=12)
pdf.multi_cell(0, 10, f"Q{i+1}: {entry['question']}")
pdf.ln(3)
# Time taken
pdf.set_font("Arial", size=10)
pdf.multi_cell(0, 10, f"Time Taken: {entry['time_taken']} seconds")
pdf.ln(3)
# Options and correct/incorrect answer
pdf.set_font("Arial", size=10)
options = ['a', 'b', 'c', 'd']
for j, option in enumerate(entry['options']):
if option == entry['correct_answer']:
pdf.set_text_color(0, 128, 0) # Green for correct
elif option == entry['selected']:
pdf.set_text_color(255, 0, 0) # Red for incorrect
else:
pdf.set_text_color(0, 0, 0) # Default color
pdf.multi_cell(0, 10, f"{options[j]}. {option}")
pdf.set_text_color(0, 0, 0) # Reset color
pdf.ln(5)
# Explanation and Step-by-Step Solution
pdf.set_font("Arial", style='B', size=10)
pdf.multi_cell(0, 10, "Explanation:")
pdf.set_font("Arial", size=10)
pdf.multi_cell(0, 10, entry['explanation'])
pdf.ln(3)
pdf.set_font("Arial", style='B', size=10)
pdf.multi_cell(0, 10, "Step-by-Step Solution:")
pdf.set_font("Arial", size=10)
for step in entry['step_by_step_solution']:
pdf.multi_cell(0, 10, step)
pdf.ln(10) # Add space after each question
return pdf.output(dest='S').encode('latin1', 'replace')
def load_modules():
modules = {}
base_dir = "modules"
for category in os.listdir(base_dir):
category_dir = os.path.join(base_dir, category)
if os.path.isdir(category_dir):
config_path = os.path.join(category_dir, "config.py")
if os.path.exists(config_path):
config = {}
with open(config_path) as f:
exec(f.read(), config)
category_title = config.get("title", category.title().replace("_", " "))
category_description = config.get("description", "No description available.")
order = config.get("order", 100) # Default order is 100 if not specified
else:
category_title = category.title().replace("_", " ")
category_description = "No description available."
order = 100
modules[category_title] = {"order": order, "description": category_description, "modules": {}}
for filename in os.listdir(category_dir):
if filename.endswith(".py") and filename != "__init__.py" and filename != "config.py":
module_name = filename[:-3]
module = __import__(f"{category_dir.replace('/', '.')}.{module_name}", fromlist=[''])
modules[category_title]["modules"][module_name] = {
"title": getattr(module, "title", module_name.replace("_", " ").title()),
"description": getattr(module, "description", "No description available."),
"generate_question": module.generate_question # Access the generate_question function
}
# Sort categories by the order value
sorted_categories = sorted(modules.items(), key=lambda x: x[1]['order'])
return {category: data["modules"] for category, data in sorted_categories}
def generate_new_question(category_name, module_name, module):
question_data = module['generate_question']()
# Ensure 'answered' is initialized to False and add the 'module' and 'selected' keys
question_data['answered'] = False
question_data['category'] = category_name # Add the category name to the question data
question_data['module'] = module_name # Add the module name to the question data
question_data['module_title'] = module['title'] # Add the module title to the question data
question_data['selected'] = None # Initialize 'selected' to None
question_data['time_taken'] = 0 # Initialize time taken to 0
# Ensure there are exactly 4 options
if len(question_data['options']) != 4:
st.warning(f"Question in module '{module_name}' does not have 4 options. Found {len(question_data['options'])}.")
return question_data
# Load all modules dynamically
modules = load_modules()
# Streamlit sidebar
st.sidebar.markdown(
"""
<div style='background-color: white; padding: 10px; border-radius: 10px; text-align: center; color: black;'>
<h1 style='margin: 0;'>
<a href="https://huggingface.co/spaces/tofighi/math" target="_blank" style="color: black; text-decoration: none;">
πͺ Magic Math Quiz!<sup>Beta</sup>
</a>
</h1>
<a href="https://ghassem.com" target="_blank">
<img src="https://huggingface.co/spaces/tofighi/math/resolve/main/assets/gt.png" alt="Logo" style="width:50%; margin-top: 10px;">
</a>
</div>
""", unsafe_allow_html=True)
# Sidebar content
st.sidebar.title("Quiz Categories")
selected_category = st.sidebar.selectbox("Choose a category:", list(modules.keys()))
# Get category description for tooltip
category_description = modules[selected_category]["description"] if selected_category and selected_category in modules else "No description available."
if selected_category:
module_options = [modules[selected_category][module]["title"] for module in modules[selected_category]]
selected_module = st.sidebar.radio(
"Choose a module:",
module_options
)
for module_name, module_data in modules[selected_category].items():
if module_data["title"] == selected_module:
selected_module_data = module_data
break
# Create a horizontal layout with the category title and the PDF download button
col1, col2 = st.columns([3, 1])
with col1:
st.markdown(
f"""
<div style="background-color: #333; color: white; padding: 10px; border-radius: 10px;">
<h2 style="margin: 0;">{selected_category} > {selected_module}</h2>
<p>{selected_module_data['description']}</p>
</div>
""", unsafe_allow_html=True
)
with col2:
if st.button("Download PDF Report", key="download_pdf"):
st.session_state.pdf_data = generate_pdf_report()
st.download_button(
label="Download PDF Report",
data=st.session_state.pdf_data,
file_name=f"quiz_report_{st.session_state.session_id}.pdf",
mime="application/pdf"
)
if selected_module_data:
if st.button(st.session_state.button_label):
if st.session_state.button_label == "Submit":
if st.session_state.selected_answer is not None:
question = st.session_state.questions[st.session_state.current_index]
question['answered'] = True
if st.session_state.selected_answer == question['correct_answer']:
st.session_state.correct_count += 1
st.session_state.module_correct_count[selected_module] = st.session_state.module_correct_count.get(selected_module, 0) + 1
else:
st.session_state.module_correct_count[selected_module] = st.session_state.module_correct_count.get(selected_module, 0)
st.session_state.questions[st.session_state.current_index] = question
st.session_state.current_index += 1
st.session_state.selected_answer = None
st.session_state.button_label = "Next Question"
st.session_state.pdf_data = None # Reset PDF cache when moving to the next question
else:
st.warning("Please select an answer before submitting.")
elif st.session_state.button_label == "Next Question":
if st.session_state.current_index < len(st.session_state.questions):
question = st.session_state.questions[st.session_state.current_index]
st.session_state.selected_answer = None
st.session_state.button_label = "Submit"
else:
st.session_state.button_label = "Submit/New"
st.session_state.current_index = 0
st.session_state.questions = []
st.session_state.correct_count = 0
st.session_state.module_correct_count = {}
st.session_state.pdf_data = generate_pdf_report()
st.experimental_rerun()
if st.session_state.questions:
question = st.session_state.questions[st.session_state.current_index]
st.write(f"**Q{st.session_state.current_index + 1}:** {question['question']}")
options = ['a', 'b', 'c', 'd']
for i, option in enumerate(question['options']):
is_selected = st.session_state.selected_answer == options[i]
option_text = f"{options[i]}. {option}"
if question['answered']:
if options[i] == question['correct_answer']:
st.markdown(f"<p style='color: green;'>{option_text}</p>", unsafe_allow_html=True)
elif is_selected:
st.markdown(f"<p style='color: red;'>{option_text}</p>", unsafe_allow_html=True)
else:
st.markdown(f"<p>{option_text}</p>", unsafe_allow_html=True)
else:
if is_selected:
st.markdown(f"<p style='color: blue;'>{option_text}</p>", unsafe_allow_html=True)
else:
st.markdown(f"<p>{option_text}</p>", unsafe_allow_html=True)
if not question['answered']:
if st.radio("Options", options, key=question['question'], index=options.index(st.session_state.selected_answer) if st.session_state.selected_answer else -1) == options[i]:
st.session_state.selected_answer = options[i]
else:
st.write("No questions available.")
else:
st.write("Please select a category and module.")
# Footer
st.markdown(
"""
<div style='text-align: center; color: grey; font-size: 12px;'>
<p>By Ghassem Tofighi</p>
</div>
""", unsafe_allow_html=True
)
|