Sina Media Lab commited on
Commit
58956eb
·
1 Parent(s): e6e6e74
Files changed (2) hide show
  1. app.py +57 -42
  2. modules/valid_invalid_numbers.py +42 -204
app.py CHANGED
@@ -1,5 +1,4 @@
1
  import streamlit as st
2
- import importlib
3
  import os
4
  from fpdf import FPDF
5
  import uuid
@@ -22,6 +21,10 @@ if 'module_question_count' not in st.session_state:
22
  st.session_state.module_question_count = {}
23
  if 'pdf_data' not in st.session_state:
24
  st.session_state.pdf_data = None
 
 
 
 
25
 
26
  def reset_pdf_cache():
27
  st.session_state.pdf_data = None
@@ -81,11 +84,12 @@ def load_modules():
81
  for filename in os.listdir(module_dir):
82
  if filename.endswith(".py") and filename != "__init__.py":
83
  module_name = filename[:-3]
84
- module = importlib.import_module(f"{module_dir}.{module_name}")
 
85
  modules[module_name] = {
86
  "title": getattr(module, "title", module_name),
87
  "description": getattr(module, "description", "No description available."),
88
- "generate_question": module.generate_question
89
  }
90
  return modules
91
 
@@ -104,34 +108,60 @@ def navigate_question(direction):
104
  if direction == "prev" and st.session_state.current_index > 0:
105
  st.session_state.current_index -= 1
106
  elif direction == "next":
107
- if st.session_state.current_index < len(st.session_state.questions) - 1:
108
- st.session_state.current_index += 1
109
- else:
110
- # Generate a new question if at the end of the list
111
- new_question = generate_new_question(st.session_state.current_module, modules[st.session_state.current_module])
112
- st.session_state.questions.append(new_question)
113
- st.session_state.current_index += 1
114
 
115
  # Load all modules dynamically
116
  modules = load_modules()
117
 
118
  # Streamlit interface
119
  st.sidebar.title("Quiz Modules")
120
- module_name = st.sidebar.radio("Choose a module:", list(modules.keys()), index=0)
 
 
 
 
 
 
121
 
122
- if module_name != st.session_state.current_module:
123
- st.session_state.current_module = module_name
124
  st.session_state.current_index = 0
125
- st.session_state.questions = [generate_new_question(module_name, modules[module_name])]
126
- st.session_state.module_question_count[module_name] = 0
127
- st.session_state.module_correct_count[module_name] = 0
 
 
128
 
129
  # Load the current module's question
130
  current_question = st.session_state.questions[st.session_state.current_index]
131
 
132
  # Display module title and description
133
- st.title(modules[module_name]["title"])
134
- st.write(modules[module_name]["description"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  st.write(current_question["question"])
136
 
137
  # Use a form to prevent rerun on option selection
@@ -142,7 +172,10 @@ with st.form(key=f'question_form_{st.session_state.current_index}'):
142
  key=f"question_{st.session_state.current_index}_options",
143
  index=None # No pre-selection
144
  )
145
- submit_button = st.form_submit_button(label="Submit")
 
 
 
146
 
147
  if submit_button and not current_question.get('answered', False):
148
  if selected_answer is None:
@@ -151,11 +184,14 @@ if submit_button and not current_question.get('answered', False):
151
  # Process the answer
152
  current_question['selected'] = selected_answer
153
  current_question['answered'] = True
154
- st.session_state.module_question_count[module_name] += 1
155
 
156
  if selected_answer == current_question['correct_answer']:
157
  st.session_state.correct_count += 1
158
- st.session_state.module_correct_count[module_name] += 1
 
 
 
159
 
160
  # Show correct/incorrect feedback after submission
161
  if current_question.get('answered', False):
@@ -172,24 +208,3 @@ if current_question.get('answered', False):
172
  st.write("**Step-by-Step Solution:**")
173
  for step in current_question['step_by_step_solution']:
174
  st.write(step)
175
-
176
- # Navigation buttons (placed after question and options)
177
- col1, col2 = st.columns([1, 1])
178
- with col1:
179
- if st.button("⬅️ Prev", key=f'prev_button_{st.session_state.current_index}', disabled=st.session_state.current_index == 0):
180
- navigate_question("prev")
181
-
182
- with col2:
183
- if st.button("➡️ Next", key=f'next_button_{st.session_state.current_index}'):
184
- navigate_question("next")
185
-
186
- # PDF Download Button (at the bottom)
187
- if len(st.session_state.questions) > 0:
188
- pdf = generate_pdf_report()
189
- st.session_state.pdf_data = pdf # Reset PDF cache
190
- st.download_button(
191
- label="Download PDF Report 📄",
192
- data=st.session_state.pdf_data,
193
- file_name="quiz_report.pdf",
194
- mime="application/pdf"
195
- )
 
1
  import streamlit as st
 
2
  import os
3
  from fpdf import FPDF
4
  import uuid
 
21
  st.session_state.module_question_count = {}
22
  if 'pdf_data' not in st.session_state:
23
  st.session_state.pdf_data = None
24
+ if 'submit_disabled' not in st.session_state:
25
+ st.session_state.submit_disabled = True
26
+ if 'next_disabled' not in st.session_state:
27
+ st.session_state.next_disabled = True
28
 
29
  def reset_pdf_cache():
30
  st.session_state.pdf_data = None
 
84
  for filename in os.listdir(module_dir):
85
  if filename.endswith(".py") and filename != "__init__.py":
86
  module_name = filename[:-3]
87
+ # Dynamically import the module only when needed
88
+ module = __import__(f"{module_dir}.{module_name}", fromlist=[''])
89
  modules[module_name] = {
90
  "title": getattr(module, "title", module_name),
91
  "description": getattr(module, "description", "No description available."),
92
+ "generate_question": module.generate_question # Access the generate_question function
93
  }
94
  return modules
95
 
 
108
  if direction == "prev" and st.session_state.current_index > 0:
109
  st.session_state.current_index -= 1
110
  elif direction == "next":
111
+ new_question = generate_new_question(st.session_state.current_module, modules[st.session_state.current_module])
112
+ st.session_state.questions.append(new_question)
113
+ st.session_state.current_index = len(st.session_state.questions) - 1
 
 
 
 
114
 
115
  # Load all modules dynamically
116
  modules = load_modules()
117
 
118
  # Streamlit interface
119
  st.sidebar.title("Quiz Modules")
120
+ module_name = st.sidebar.radio("Choose a module:", [modules[module]["title"] for module in modules], index=0)
121
+
122
+ selected_module = None
123
+ for module in modules:
124
+ if modules[module]["title"] == module_name:
125
+ selected_module = module
126
+ break
127
 
128
+ if selected_module != st.session_state.current_module:
129
+ st.session_state.current_module = selected_module
130
  st.session_state.current_index = 0
131
+ st.session_state.questions = [generate_new_question(selected_module, modules[selected_module])]
132
+ st.session_state.module_question_count[selected_module] = 0
133
+ st.session_state.module_correct_count[selected_module] = 0
134
+ st.session_state.submit_disabled = True
135
+ st.session_state.next_disabled = True
136
 
137
  # Load the current module's question
138
  current_question = st.session_state.questions[st.session_state.current_index]
139
 
140
  # Display module title and description
141
+ st.title(modules[selected_module]["title"])
142
+ st.write(modules[selected_module]["description"])
143
+
144
+ # Navigation and PDF report buttons
145
+ col1, col2, col3 = st.columns([1, 1, 2])
146
+ with col1:
147
+ if st.button("⬅️ Prev", disabled=st.session_state.current_index == 0):
148
+ navigate_question("prev")
149
+ with col2:
150
+ if st.button("➡️ Next", disabled=st.session_state.next_disabled):
151
+ st.session_state.submit_disabled = True
152
+ st.session_state.next_disabled = True
153
+ navigate_question("next")
154
+ with col3:
155
+ if len(st.session_state.questions) > 0:
156
+ pdf = generate_pdf_report()
157
+ st.session_state.pdf_data = pdf # Reset PDF cache
158
+ st.download_button(
159
+ label="Download PDF Report 📄",
160
+ data=st.session_state.pdf_data,
161
+ file_name="quiz_report.pdf",
162
+ mime="application/pdf"
163
+ )
164
+
165
  st.write(current_question["question"])
166
 
167
  # Use a form to prevent rerun on option selection
 
172
  key=f"question_{st.session_state.current_index}_options",
173
  index=None # No pre-selection
174
  )
175
+ submit_button = st.form_submit_button(label="Submit", disabled=st.session_state.submit_disabled)
176
+
177
+ if selected_answer and st.session_state.submit_disabled:
178
+ st.session_state.submit_disabled = False
179
 
180
  if submit_button and not current_question.get('answered', False):
181
  if selected_answer is None:
 
184
  # Process the answer
185
  current_question['selected'] = selected_answer
186
  current_question['answered'] = True
187
+ st.session_state.module_question_count[selected_module] += 1
188
 
189
  if selected_answer == current_question['correct_answer']:
190
  st.session_state.correct_count += 1
191
+ st.session_state.module_correct_count[selected_module] += 1
192
+
193
+ st.session_state.submit_disabled = True
194
+ st.session_state.next_disabled = False
195
 
196
  # Show correct/incorrect feedback after submission
197
  if current_question.get('answered', False):
 
208
  st.write("**Step-by-Step Solution:**")
209
  for step in current_question['step_by_step_solution']:
210
  st.write(step)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
modules/valid_invalid_numbers.py CHANGED
@@ -1,210 +1,48 @@
1
- import streamlit as st
2
- import os
3
- from fpdf import FPDF
4
- import uuid
5
 
6
- # Initialize session state variables
7
- if 'session_id' not in st.session_state:
8
- st.session_state.session_id = str(uuid.uuid4())
9
 
10
- if 'questions' not in st.session_state:
11
- st.session_state.questions = []
12
- if 'current_index' not in st.session_state:
13
- st.session_state.current_index = 0
14
- if 'current_module' not in st.session_state:
15
- st.session_state.current_module = None
16
- if 'correct_count' not in st.session_state:
17
- st.session_state.correct_count = 0
18
- if 'module_correct_count' not in st.session_state:
19
- st.session_state.module_correct_count = {}
20
- if 'module_question_count' not in st.session_state:
21
- st.session_state.module_question_count = {}
22
- if 'pdf_data' not in st.session_state:
23
- st.session_state.pdf_data = None
24
- if 'submit_disabled' not in st.session_state:
25
- st.session_state.submit_disabled = True
26
- if 'next_disabled' not in st.session_state:
27
- st.session_state.next_disabled = True
28
-
29
- def reset_pdf_cache():
30
- st.session_state.pdf_data = None
31
-
32
- def generate_pdf_report():
33
- pdf = FPDF()
34
- pdf.add_page()
35
- pdf.set_font("Arial", size=12)
36
 
37
- pdf.cell(200, 10, txt="Quiz Report", ln=True, align="C")
38
- pdf.ln(10)
39
-
40
- for module, data in st.session_state.module_question_count.items():
41
- correct_count = st.session_state.module_correct_count.get(module, 0)
42
- total_count = data
43
- pdf.cell(200, 10, txt=f"Module: {module}", ln=True, align="L")
44
- pdf.ln(5)
45
- pdf.cell(200, 10, txt=f"Correct Answers: {correct_count}/{total_count}", ln=True, align="L")
46
- pdf.ln(5)
47
-
48
- for entry in st.session_state.questions:
49
- if entry['module'] == module:
50
- question, options, selected, correct, explanation, step_by_step_solution = (
51
- entry['question'],
52
- entry['options'],
53
- entry['selected'] if entry['selected'] is not None else "Not Answered",
54
- entry['correct_answer'],
55
- entry['explanation'],
56
- entry['step_by_step_solution']
57
- )
58
- pdf.multi_cell(0, 10, f"Q: {question}")
59
- for option in options:
60
- if option == correct:
61
- pdf.set_text_color(0, 128, 0) # Green for correct
62
- pdf.multi_cell(0, 10, f"{option}")
63
- elif option == selected:
64
- pdf.set_text_color(255, 0, 0) # Red for incorrect
65
- pdf.multi_cell(0, 10, f"{option}")
66
- else:
67
- pdf.set_text_color(0, 0, 0) # Default color for others
68
- pdf.multi_cell(0, 10, f" {option}")
69
- pdf.set_text_color(0, 0, 0) # Reset color
70
- pdf.multi_cell(0, 10, f"Explanation: {explanation}")
71
- pdf.ln(5)
72
- pdf.multi_cell(0, 10, "Step-by-Step Solution:")
73
- for step in step_by_step_solution:
74
- pdf.multi_cell(0, 10, step)
75
- pdf.ln(10)
76
-
77
- pdf.ln(10) # Add space after each module
78
-
79
- return pdf.output(dest='S').encode('latin1', 'replace')
80
-
81
- def load_modules():
82
- modules = {}
83
- module_dir = "modules"
84
- for filename in os.listdir(module_dir):
85
- if filename.endswith(".py") and filename != "__init__.py":
86
- module_name = filename[:-3]
87
- # Dynamically import the module only when needed
88
- module = __import__(f"{module_dir}.{module_name}", fromlist=[''])
89
- modules[module_name] = {
90
- "title": getattr(module, "title", module_name),
91
- "description": getattr(module, "description", "No description available."),
92
- "generate_question": module.generate_question # Access the generate_question function
93
- }
94
- return modules
95
-
96
- def generate_new_question(module_name, module):
97
- question_data = module['generate_question']()
98
- # Ensure 'answered' is initialized to False and add the 'module' and 'selected' keys
99
- question_data['answered'] = False
100
- question_data['module'] = module_name # Add the module name to the question data
101
- question_data['selected'] = None # Initialize 'selected' to None
102
- # Ensure there are exactly 4 options
103
- if len(question_data['options']) != 4:
104
- st.warning(f"Question in module '{module_name}' does not have 4 options. Found {len(question_data['options'])}.")
105
- return question_data
106
-
107
- def navigate_question(direction):
108
- if direction == "prev" and st.session_state.current_index > 0:
109
- st.session_state.current_index -= 1
110
- elif direction == "next":
111
- new_question = generate_new_question(st.session_state.current_module, modules[st.session_state.current_module])
112
- st.session_state.questions.append(new_question)
113
- st.session_state.current_index = len(st.session_state.questions) - 1
114
-
115
- # Load all modules dynamically
116
- modules = load_modules()
117
-
118
- # Streamlit interface
119
- st.sidebar.title("Quiz Modules")
120
- module_name = st.sidebar.radio("Choose a module:", [modules[module]["title"] for module in modules], index=0)
121
-
122
- selected_module = None
123
- for module in modules:
124
- if modules[module]["title"] == module_name:
125
- selected_module = module
126
- break
127
-
128
- if selected_module != st.session_state.current_module:
129
- st.session_state.current_module = selected_module
130
- st.session_state.current_index = 0
131
- st.session_state.questions = [generate_new_question(selected_module, modules[selected_module])]
132
- st.session_state.module_question_count[selected_module] = 0
133
- st.session_state.module_correct_count[selected_module] = 0
134
- st.session_state.submit_disabled = True
135
- st.session_state.next_disabled = True
136
-
137
- # Load the current module's question
138
- current_question = st.session_state.questions[st.session_state.current_index]
139
-
140
- # Display module title and description
141
- st.title(modules[selected_module]["title"])
142
- st.write(modules[selected_module]["description"])
143
-
144
- # Navigation and PDF report buttons
145
- col1, col2, col3 = st.columns([1, 1, 2])
146
- with col1:
147
- if st.button("⬅️ Prev", disabled=st.session_state.current_index == 0):
148
- navigate_question("prev")
149
- with col2:
150
- if st.button("➡️ Next", disabled=st.session_state.next_disabled):
151
- st.session_state.submit_disabled = True
152
- st.session_state.next_disabled = True
153
- navigate_question("next")
154
- with col3:
155
- if len(st.session_state.questions) > 0:
156
- pdf = generate_pdf_report()
157
- st.session_state.pdf_data = pdf # Reset PDF cache
158
- st.download_button(
159
- label="Download PDF Report 📄",
160
- data=st.session_state.pdf_data,
161
- file_name="quiz_report.pdf",
162
- mime="application/pdf"
163
- )
164
-
165
- st.write(current_question["question"])
166
-
167
- # Use a form to prevent rerun on option selection
168
- with st.form(key=f'question_form_{st.session_state.current_index}'):
169
- selected_answer = st.radio(
170
- "Choose an answer:",
171
- options=current_question['options'],
172
- key=f"question_{st.session_state.current_index}_options",
173
- index=None # No pre-selection
174
- )
175
- submit_button = st.form_submit_button(label="Submit", disabled=st.session_state.submit_disabled)
176
-
177
- if selected_answer and st.session_state.submit_disabled:
178
- st.session_state.submit_disabled = False
179
-
180
- if submit_button and not current_question.get('answered', False):
181
- if selected_answer is None:
182
- st.warning("Please select an answer before submitting.")
183
- else:
184
- # Process the answer
185
- current_question['selected'] = selected_answer
186
- current_question['answered'] = True
187
- st.session_state.module_question_count[selected_module] += 1
188
-
189
- if selected_answer == current_question['correct_answer']:
190
- st.session_state.correct_count += 1
191
- st.session_state.module_correct_count[selected_module] += 1
192
 
193
- st.session_state.submit_disabled = True
194
- st.session_state.next_disabled = False
195
 
196
- # Show correct/incorrect feedback after submission
197
- if current_question.get('answered', False):
198
- for option in current_question['options']:
199
- if option == current_question['correct_answer']:
200
- st.markdown(f"<span style='color:green;'>{option} ✅</span>", unsafe_allow_html=True)
201
- elif option == current_question['selected']:
202
- st.markdown(f"<span style='color:red;'>{option} ❌</span>", unsafe_allow_html=True)
203
- else:
204
- st.markdown(f"{option}")
 
 
 
 
 
 
205
 
206
- # Show explanation and step-by-step solution
207
- st.write(f"**Explanation:** {current_question['explanation']}")
208
- st.write("**Step-by-Step Solution:**")
209
- for step in current_question['step_by_step_solution']:
210
- st.write(step)
 
 
 
1
+ # modules/valid_invalid_numbers.py
 
 
 
2
 
3
+ title = "Validity of Numbers in Bases"
4
+ description = "This module helps determine the validity of numbers in different bases like binary, octal, decimal, and hexadecimal."
 
5
 
6
+ def generate_question():
7
+ import random
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
+ base = random.choice([2, 8, 10, 16])
10
+ length = random.randint(3, 5)
11
+
12
+ def generate_valid_number():
13
+ return ''.join([str(random.randint(0, base - 1)) for _ in range(length)])
14
+
15
+ def generate_invalid_number():
16
+ valid_digits = ''.join([str(random.randint(0, base - 1)) for _ in range(length - 1)])
17
+ if base < 10:
18
+ invalid_digit = str(random.randint(base, 9)) # For bases < 10, pick an invalid digit from [base, 9]
19
+ else:
20
+ invalid_digit = random.choice('ABCDEF') # For bases >= 10, pick a hex digit to make it invalid
21
+ return valid_digits + invalid_digit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
+ correct_answer = generate_invalid_number()
24
+ options = [correct_answer]
25
 
26
+ # Generate valid options
27
+ while len(options) < 4:
28
+ valid_option = generate_valid_number()
29
+ if valid_option not in options:
30
+ options.append(valid_option)
31
+
32
+ random.shuffle(options)
33
+
34
+ question = f"Which of the following is an invalid number in base {base}?"
35
+ explanation = f"The number {correct_answer} is invalid in base {base} because it contains a digit outside the range 0-{base-1}."
36
+ step_by_step_solution = [
37
+ "Step 1: Identify the valid digits for the base.",
38
+ "Step 2: Check each option to see if it contains any invalid digits.",
39
+ "Step 3: The correct answer will have a digit that is not allowed in the specified base."
40
+ ]
41
 
42
+ return {
43
+ "question": question,
44
+ "options": options,
45
+ "correct_answer": correct_answer,
46
+ "explanation": explanation,
47
+ "step_by_step_solution": step_by_step_solution
48
+ }