bharathmunakala commited on
Commit
d5cdd87
·
verified ·
1 Parent(s): 17f1f8e

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +601 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,603 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
1
  import streamlit as st
2
+ from educhain import Educhain, LLMConfig
3
+ from educhain.engines import qna_engine
4
+ from langchain_openai import ChatOpenAI
5
+ import os
6
+ from dotenv import load_dotenv
7
+ import json
8
+ from datetime import datetime
9
+ import pandas as pd
10
+ import random
11
+
12
+ # Load environment variables if available
13
+ load_dotenv()
14
+
15
+ # Set page configuration at the very top of the script
16
+ st.set_page_config(page_title="Multilingual Quiz App", page_icon="🧠", layout="wide")
17
+
18
+ # Define supported languages
19
+ languages = [
20
+ "English", "Hindi", "Gujarati", "Bengali", "Tamil",
21
+ "Telugu", "Kannada", "Malayalam", "Punjabi", "Marathi",
22
+ "Urdu", "Assamese", "Odia", "Sanskrit", "Korean",
23
+ "Japanese", "Arabic", "French", "German", "Spanish",
24
+ "Portuguese", "Russian", "Chinese", "Vietnamese", "Thai",
25
+ "Indonesian", "Turkish", "Polish", "Ukrainian", "Dutch",
26
+ "Italian", "Greek", "Hebrew", "Persian", "Swedish",
27
+ "Norwegian", "Danish", "Finnish", "Czech", "Hungarian",
28
+ "Romanian", "Bulgarian", "Croatian", "Serbian", "Slovak",
29
+ "Slovenian", "Estonian", "Latvian", "Lithuanian", "Malay",
30
+ "Tagalog", "Swahili"
31
+ ]
32
+
33
+ # Define question types
34
+ question_types = ["Multiple Choice", "True/False"]
35
+
36
+ # Define difficulty levels
37
+ difficulty_levels = ["Easy", "Medium", "Hard"]
38
+
39
+ # Initialize session state
40
+ if 'current_quiz' not in st.session_state:
41
+ st.session_state.current_quiz = None
42
+ if 'quiz_in_progress' not in st.session_state:
43
+ st.session_state.quiz_in_progress = False
44
+ if 'current_question' not in st.session_state:
45
+ st.session_state.current_question = 0
46
+ if 'user_answers' not in st.session_state:
47
+ st.session_state.user_answers = []
48
+ if 'user_score' not in st.session_state:
49
+ st.session_state.user_score = 0
50
+ if 'quiz_completed' not in st.session_state:
51
+ st.session_state.quiz_completed = False
52
+ if 'saved_quizzes' not in st.session_state:
53
+ st.session_state.saved_quizzes = []
54
+ if 'page' not in st.session_state:
55
+ st.session_state.page = "create" # Options: "create", "take", "history"
56
+
57
+ # --- Sidebar Navigation ---
58
+ with st.sidebar:
59
+ st.sidebar.image("https://framerusercontent.com/images/T5kFJeyNUyAYJBz4PaWuP7Bfr0.png", use_container_width=True)
60
+ st.title("Multilingual Quiz App")
61
+
62
+ # Navigation
63
+ st.subheader("📚 Navigation")
64
+ if st.button("Create Quiz", use_container_width=True):
65
+ st.session_state.page = "create"
66
+ if st.button("Saved Quizzes", use_container_width=True):
67
+ st.session_state.page = "saved"
68
+ if st.button("Quiz History", use_container_width=True):
69
+ st.session_state.page = "history"
70
+
71
+ st.header("⚙️ Configuration")
72
+
73
+ # Use environment variable if available, otherwise hide API key input
74
+ api_key = os.getenv("SUTRA_API_KEY", "")
75
+ if not api_key:
76
+ api_key = st.text_input("Sutra API Key", value="", type="password")
77
+ if not api_key:
78
+ st.warning("Please set your Sutra API Key as an environment variable or enter it above")
79
+
80
+ st.markdown("---")
81
+ st.markdown("**Powered by** [Educhain](https://github.com/satvik314/educhain)")
82
+ st.markdown("**Using** [Sutra LLM](https://docs.two.ai/) for multilingual")
83
+ st.write("❤️ Built with [Streamlit](https://streamlit.io)")
84
+
85
+ # --- Initialize Educhain with Sutra Model ---
86
+ @st.cache_resource
87
+ def initialize_educhain(api_key):
88
+ if not api_key:
89
+ return None # Return None if API key is missing
90
+
91
+ sutra_model = ChatOpenAI(
92
+ api_key=api_key,
93
+ base_url="https://api.two.ai/v2",
94
+ model="sutra-v2",
95
+ temperature=0.9
96
+ )
97
+ llm_config = LLMConfig(custom_model=sutra_model)
98
+ return Educhain(llm_config)
99
+
100
+ # --- Utility Function to Convert Questions to Quiz Format ---
101
+ def convert_to_quiz_format(questions_obj, topic, language, difficulty):
102
+ quiz = {
103
+ "title": f"{topic} Quiz ({difficulty})",
104
+ "language": language,
105
+ "difficulty": difficulty,
106
+ "topic": topic,
107
+ "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
108
+ "questions": []
109
+ }
110
+
111
+ if hasattr(questions_obj, "questions"):
112
+ for q in questions_obj.questions:
113
+ question_data = {
114
+ "question": q.question,
115
+ "answer": q.answer
116
+ }
117
+
118
+ if hasattr(q, 'options'):
119
+ question_data["type"] = "multiple_choice"
120
+ question_data["options"] = q.options
121
+ else:
122
+ question_data["type"] = "true_false"
123
+ question_data["options"] = ["True", "False"]
124
+
125
+ if hasattr(q, 'explanation') and q.explanation:
126
+ question_data["explanation"] = q.explanation
127
+
128
+ quiz["questions"].append(question_data)
129
+
130
+ return quiz
131
+
132
+ # --- Save Quiz Function ---
133
+ def save_quiz(quiz):
134
+ # Create a unique ID for the quiz
135
+ quiz_id = f"{len(st.session_state.saved_quizzes) + 1}_{datetime.now().strftime('%Y%m%d%H%M%S')}"
136
+ quiz["id"] = quiz_id
137
+
138
+ # Add to saved quizzes
139
+ st.session_state.saved_quizzes.append(quiz)
140
+
141
+ # Also save to disk (optional)
142
+ try:
143
+ # Check if file exists and load existing data
144
+ if os.path.exists("saved_quizzes.json"):
145
+ with open("saved_quizzes.json", "r") as f:
146
+ existing_quizzes = json.load(f)
147
+ else:
148
+ existing_quizzes = []
149
+
150
+ # Append new quiz
151
+ existing_quizzes.append(quiz)
152
+
153
+ # Save updated list
154
+ with open("saved_quizzes.json", "w") as f:
155
+ json.dump(existing_quizzes, f)
156
+ except Exception as e:
157
+ st.warning(f"Could not save quiz to disk: {str(e)}")
158
+
159
+ return quiz_id
160
+
161
+ # --- Start Quiz Function ---
162
+ def start_quiz(quiz):
163
+ st.session_state.current_quiz = quiz
164
+ st.session_state.quiz_in_progress = True
165
+ st.session_state.current_question = 0
166
+ st.session_state.user_answers = [None] * len(quiz["questions"])
167
+ st.session_state.user_score = 0
168
+ st.session_state.quiz_completed = False
169
+
170
+ # --- Submit Answer Function ---
171
+ def submit_answer(answer_index):
172
+ current_q = st.session_state.current_question
173
+ st.session_state.user_answers[current_q] = answer_index
174
+
175
+ # Check if answer is correct
176
+ correct_answer = st.session_state.current_quiz["questions"][current_q]["answer"]
177
+
178
+ # For multiple choice, the answer might be the option text or the option index
179
+ if st.session_state.current_quiz["questions"][current_q]["type"] == "multiple_choice":
180
+ # Try to match by index first (if answer is A, B, C, D)
181
+ if correct_answer in ["A", "B", "C", "D"]:
182
+ correct_index = ord(correct_answer) - ord("A")
183
+ if answer_index == correct_index:
184
+ st.session_state.user_score += 1
185
+ # Otherwise, match by option text
186
+ else:
187
+ options = st.session_state.current_quiz["questions"][current_q]["options"]
188
+ if answer_index < len(options) and options[answer_index] == correct_answer:
189
+ st.session_state.user_score += 1
190
+ # For true/false
191
+ else:
192
+ options = ["True", "False"]
193
+ user_answer = options[answer_index]
194
+ # Convert both answers to lowercase strings for comparison
195
+ if str(user_answer).lower() == str(correct_answer).lower():
196
+ st.session_state.user_score += 1
197
+
198
+ # Move to next question or end quiz
199
+ if current_q < len(st.session_state.current_quiz["questions"]) - 1:
200
+ st.session_state.current_question += 1
201
+ else:
202
+ st.session_state.quiz_completed = True
203
+ # Save quiz results to history
204
+ save_quiz_result()
205
+
206
+ # --- Save Quiz Result Function ---
207
+ def save_quiz_result():
208
+ result = {
209
+ "quiz_title": st.session_state.current_quiz["title"],
210
+ "language": st.session_state.current_quiz["language"],
211
+ "topic": st.session_state.current_quiz["topic"],
212
+ "difficulty": st.session_state.current_quiz["difficulty"],
213
+ "score": st.session_state.user_score,
214
+ "total": len(st.session_state.current_quiz["questions"]),
215
+ "date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
216
+ }
217
+
218
+ # Initialize history if not exists
219
+ if 'quiz_history' not in st.session_state:
220
+ st.session_state.quiz_history = []
221
+
222
+ # Add to history
223
+ st.session_state.quiz_history.append(result)
224
+
225
+ # Also save to disk (optional)
226
+ try:
227
+ # Check if file exists and load existing data
228
+ if os.path.exists("quiz_history.json"):
229
+ with open("quiz_history.json", "r") as f:
230
+ existing_history = json.load(f)
231
+ else:
232
+ existing_history = []
233
+
234
+ # Append new result
235
+ existing_history.append(result)
236
+
237
+ # Save updated list
238
+ with open("quiz_history.json", "w") as f:
239
+ json.dump(existing_history, f)
240
+ except Exception as e:
241
+ st.warning(f"Could not save quiz history to disk: {str(e)}")
242
+
243
+ # --- Create Quiz Page ---
244
+ def show_create_quiz_page():
245
+ st.markdown(
246
+ f'<h1><img src="https://framerusercontent.com/images/9vH8BcjXKRcC5OrSfkohhSyDgX0.png" width="60"/> Create Multilingual Quiz</h1>',
247
+ unsafe_allow_html=True
248
+ )
249
+
250
+ # --- Initialize Educhain client if API key is provided ---
251
+ api_key = os.getenv("SUTRA_API_KEY", "")
252
+ if not api_key:
253
+ api_key = st.sidebar.text_input("Sutra API Key", value="", type="password")
254
+
255
+ if api_key:
256
+ educhain_client = initialize_educhain(api_key)
257
+ if educhain_client:
258
+ qna_engine = educhain_client.qna_engine
259
+ else:
260
+ st.error("Failed to initialize Educhain. Please check your Sutra API key.")
261
+ return
262
+ else:
263
+ st.warning("Please enter your Sutra API Key in the sidebar or set it as an environment variable to continue.")
264
+ return
265
+
266
+ # Quiz configuration
267
+ col1, col2, col3 = st.columns(3)
268
+ with col1:
269
+ selected_language = st.selectbox("Language:", languages)
270
+ with col2:
271
+ selected_question_type = st.selectbox("Question Type:", question_types)
272
+ with col3:
273
+ selected_difficulty = st.selectbox("Difficulty:", difficulty_levels)
274
+
275
+ topic = st.text_input("Quiz Topic:", "General Knowledge")
276
+ num_questions = st.slider("Number of Questions", 3, 10, 5)
277
+
278
+ custom_instructions = st.text_area(
279
+ "Custom Instructions (optional):",
280
+ placeholder=f"e.g. 'Focus on {selected_difficulty.lower()} concepts for {topic}'",
281
+ height=100
282
+ )
283
+
284
+ # Add language instruction to custom instructions
285
+ language_custom_instructions = f"Generate all questions, options, answers and explanations in {selected_language} language. Make questions {selected_difficulty.lower()} difficulty. {custom_instructions}"
286
+
287
+ # Generate quiz button
288
+ if st.button("Generate Quiz"):
289
+ with st.spinner(f"Generating {num_questions} {selected_question_type.lower()} questions in {selected_language}..."):
290
+ # Use the appropriate method based on question type
291
+ if selected_question_type == "Multiple Choice":
292
+ questions = qna_engine.generate_questions(
293
+ topic=topic,
294
+ num=num_questions,
295
+ question_type="Multiple Choice",
296
+ custom_instructions=language_custom_instructions
297
+ )
298
+ else: # True/False
299
+ questions = qna_engine.generate_questions(
300
+ topic=topic,
301
+ num=num_questions,
302
+ question_type="True/False",
303
+ custom_instructions=language_custom_instructions
304
+ )
305
+
306
+ # Convert to quiz format and save
307
+ quiz = convert_to_quiz_format(questions, topic, selected_language, selected_difficulty)
308
+ quiz_id = save_quiz(quiz)
309
+
310
+ st.success(f"Quiz generated successfully! Quiz ID: {quiz_id}")
311
+
312
+ # Preview quiz
313
+ with st.expander("Preview Quiz"):
314
+ for i, q in enumerate(quiz["questions"]):
315
+ st.subheader(f"Question {i+1}: {q['question']}")
316
+ st.write("Options:")
317
+ for j, opt in enumerate(q["options"]):
318
+ st.write(f" {chr(65 + j)}. {opt}")
319
+ st.write(f"**Correct Answer:** {q['answer']}")
320
+ if "explanation" in q and q["explanation"]:
321
+ st.write(f"**Explanation:** {q['explanation']}")
322
+ st.markdown("---")
323
+
324
+ # Button to start quiz
325
+ if st.button("Start This Quiz"):
326
+ start_quiz(quiz)
327
+ st.session_state.page = "take"
328
+ st.rerun()
329
+
330
+ # --- Saved Quizzes Page ---
331
+ def show_saved_quizzes_page():
332
+ st.markdown(
333
+ f'<h1><img src="https://framerusercontent.com/images/9vH8BcjXKRcC5OrSfkohhSyDgX0.png" width="60"/> Saved Quizzes</h1>',
334
+ unsafe_allow_html=True
335
+ )
336
+
337
+ if not st.session_state.saved_quizzes:
338
+ st.info("No saved quizzes yet. Create one first!")
339
+ return
340
+
341
+ # Create a dataframe for better display
342
+ quiz_data = []
343
+ for quiz in st.session_state.saved_quizzes:
344
+ quiz_data.append({
345
+ "ID": quiz.get("id", "Unknown"),
346
+ "Title": quiz.get("title", "Untitled"),
347
+ "Topic": quiz.get("topic", "Unknown"),
348
+ "Language": quiz.get("language", "Unknown"),
349
+ "Difficulty": quiz.get("difficulty", "Unknown"),
350
+ "Questions": len(quiz.get("questions", [])),
351
+ "Created": quiz.get("created_at", "Unknown")
352
+ })
353
+
354
+ df = pd.DataFrame(quiz_data)
355
+ st.dataframe(df, use_container_width=True)
356
+
357
+ # Select quiz to take
358
+ selected_quiz_id = st.selectbox(
359
+ "Select a quiz to take:",
360
+ options=[quiz.get("id", "Unknown") for quiz in st.session_state.saved_quizzes],
361
+ format_func=lambda x: next((q["title"] for q in st.session_state.saved_quizzes if q.get("id") == x), x)
362
+ )
363
+
364
+ # Start selected quiz
365
+ if st.button("Start Selected Quiz"):
366
+ selected_quiz = next((q for q in st.session_state.saved_quizzes if q.get("id") == selected_quiz_id), None)
367
+ if selected_quiz:
368
+ start_quiz(selected_quiz)
369
+ st.session_state.page = "take"
370
+ st.rerun()
371
+
372
+ # Option to delete a quiz
373
+ if st.button("Delete Selected Quiz"):
374
+ st.session_state.saved_quizzes = [q for q in st.session_state.saved_quizzes if q.get("id") != selected_quiz_id]
375
+ st.success("Quiz deleted successfully!")
376
+ st.rerun()
377
+
378
+ # --- Take Quiz Page ---
379
+ def show_take_quiz_page():
380
+ if not st.session_state.quiz_in_progress or not st.session_state.current_quiz:
381
+ st.warning("No quiz is currently in progress.")
382
+ if st.button("Go to Saved Quizzes"):
383
+ st.session_state.page = "saved"
384
+ st.rerun()
385
+ return
386
+
387
+ quiz = st.session_state.current_quiz
388
+
389
+ # Display quiz header
390
+ st.markdown(
391
+ f'<h1>{quiz["title"]}</h1>',
392
+ unsafe_allow_html=True
393
+ )
394
+ st.write(f"Language: {quiz['language']} | Difficulty: {quiz['difficulty']} | Topic: {quiz['topic']}")
395
+
396
+ # If quiz is completed, show results
397
+ if st.session_state.quiz_completed:
398
+ st.balloons()
399
+ st.markdown(f"## Quiz Completed!")
400
+ st.markdown(f"### Your Score: {st.session_state.user_score}/{len(quiz['questions'])}")
401
+
402
+ # Calculate percentage
403
+ percentage = (st.session_state.user_score / len(quiz['questions'])) * 100
404
+ st.progress(percentage / 100)
405
+
406
+ # Different messages based on score
407
+ if percentage >= 80:
408
+ st.success("Excellent! You've mastered this topic!")
409
+ elif percentage >= 60:
410
+ st.info("Good job! You have a solid understanding of the material.")
411
+ else:
412
+ st.warning("You might want to review this topic again.")
413
+
414
+ # Show answers and explanations
415
+ with st.expander("Review Questions and Answers"):
416
+ for i, (question, user_answer) in enumerate(zip(quiz["questions"], st.session_state.user_answers)):
417
+ correct_answer = question["answer"]
418
+ is_correct = False
419
+
420
+ # Determine if the answer was correct
421
+ if question["type"] == "multiple_choice":
422
+ if correct_answer in ["A", "B", "C", "D"]:
423
+ correct_index = ord(correct_answer) - ord("A")
424
+ is_correct = (user_answer == correct_index)
425
+ else:
426
+ is_correct = (question["options"][user_answer] == correct_answer)
427
+ else: # true/false
428
+ options = ["True", "False"]
429
+ # Convert both answers to lowercase strings for comparison
430
+ is_correct = (str(options[user_answer]).lower() == str(correct_answer).lower())
431
+
432
+ # Display question and answer
433
+ st.markdown(f"**Question {i+1}:** {question['question']}")
434
+
435
+ if question["type"] == "multiple_choice":
436
+ st.write("Options:")
437
+ for j, opt in enumerate(question["options"]):
438
+ prefix = "✅ " if (is_correct and user_answer == j) else "❌ " if (not is_correct and user_answer == j) else ""
439
+ highlight = "**" if (correct_answer in ["A", "B", "C", "D"] and j == ord(correct_answer) - ord("A")) or \
440
+ (correct_answer not in ["A", "B", "C", "D"] and opt == correct_answer) else ""
441
+ st.write(f" {prefix}{chr(65 + j)}. {highlight}{opt}{highlight}")
442
+ else: # true/false
443
+ st.write("Options:")
444
+ for j, opt in enumerate(["True", "False"]):
445
+ prefix = "✅ " if (is_correct and user_answer == j) else "❌ " if (not is_correct and user_answer == j) else ""
446
+ highlight = "**" if str(opt).lower() == str(correct_answer).lower() else ""
447
+ st.write(f" {prefix}{opt} {highlight}")
448
+
449
+ if "explanation" in question and question["explanation"]:
450
+ st.write(f"**Explanation:** {question['explanation']}")
451
+
452
+ st.markdown("---")
453
+
454
+ # Button to go back to saved quizzes
455
+ if st.button("Choose Another Quiz"):
456
+ st.session_state.page = "saved"
457
+ st.rerun()
458
+
459
+ # Button to create a new quiz
460
+ if st.button("Create New Quiz"):
461
+ st.session_state.page = "create"
462
+ st.rerun()
463
+
464
+ # If quiz is in progress, show current question
465
+ else:
466
+ current_q_index = st.session_state.current_question
467
+ total_questions = len(quiz["questions"])
468
+ current_q = quiz["questions"][current_q_index]
469
+
470
+ # Progress bar
471
+ st.progress((current_q_index) / total_questions)
472
+ st.write(f"Question {current_q_index + 1} of {total_questions}")
473
+
474
+ # Display question
475
+ st.markdown(f"## {current_q['question']}")
476
+
477
+ # Display options based on question type
478
+ if current_q["type"] == "multiple_choice":
479
+ for i, option in enumerate(current_q["options"]):
480
+ if st.button(f"{chr(65 + i)}. {option}", key=f"opt_{i}"):
481
+ submit_answer(i)
482
+ st.rerun()
483
+ else: # true/false
484
+ col1, col2 = st.columns(2)
485
+ with col1:
486
+ if st.button("True", use_container_width=True):
487
+ submit_answer(0)
488
+ st.rerun()
489
+ with col2:
490
+ if st.button("False", use_container_width=True):
491
+ submit_answer(1)
492
+ st.rerun()
493
+
494
+ # Option to skip question
495
+ if st.button("Skip Question"):
496
+ submit_answer(random.randint(0, len(current_q["options"]) - 1)) # Submit random answer
497
+ st.rerun()
498
+
499
+ # --- Quiz History Page ---
500
+ def show_history_page():
501
+ st.markdown(
502
+ f'<h1><img src="https://framerusercontent.com/images/9vH8BcjXKRcC5OrSfkohhSyDgX0.png" width="60"/> Quiz History</h1>',
503
+ unsafe_allow_html=True
504
+ )
505
+
506
+ # Initialize quiz_history if not exists
507
+ if 'quiz_history' not in st.session_state:
508
+ st.session_state.quiz_history = []
509
+
510
+ # Try to load from disk
511
+ try:
512
+ if os.path.exists("quiz_history.json"):
513
+ with open("quiz_history.json", "r") as f:
514
+ st.session_state.quiz_history = json.load(f)
515
+ except Exception:
516
+ pass
517
+
518
+ if not st.session_state.quiz_history:
519
+ st.info("No quiz history yet. Take a quiz first!")
520
+ return
521
+
522
+ # Create a dataframe for better display
523
+ history_data = []
524
+ for result in st.session_state.quiz_history:
525
+ percentage = (result["score"] / result["total"]) * 100
526
+ history_data.append({
527
+ "Date": result["date"],
528
+ "Quiz": result["quiz_title"],
529
+ "Topic": result["topic"],
530
+ "Language": result["language"],
531
+ "Difficulty": result["difficulty"],
532
+ "Score": f"{result['score']}/{result['total']} ({percentage:.1f}%)"
533
+ })
534
+
535
+ # Sort by date, newest first
536
+ history_data.sort(key=lambda x: x["Date"], reverse=True)
537
+
538
+ df = pd.DataFrame(history_data)
539
+ st.dataframe(df, use_container_width=True)
540
+
541
+ # Some analytics
542
+ if len(history_data) > 1:
543
+ st.subheader("Your Progress")
544
+
545
+ # Calculate average score by topic
546
+ topic_data = {}
547
+ for result in st.session_state.quiz_history:
548
+ topic = result["topic"]
549
+ if topic not in topic_data:
550
+ topic_data[topic] = {"total": 0, "correct": 0, "count": 0}
551
+ topic_data[topic]["correct"] += result["score"]
552
+ topic_data[topic]["total"] += result["total"]
553
+ topic_data[topic]["count"] += 1
554
+
555
+ # Create chart data
556
+ chart_data = []
557
+ for topic, data in topic_data.items():
558
+ percentage = (data["correct"] / data["total"]) * 100
559
+ chart_data.append({
560
+ "Topic": topic,
561
+ "Percentage": percentage,
562
+ "Quizzes Taken": data["count"]
563
+ })
564
+
565
+ # Display chart
566
+ if chart_data:
567
+ chart_df = pd.DataFrame(chart_data)
568
+ st.bar_chart(chart_df.set_index("Topic")["Percentage"])
569
+
570
+ # Clear history button
571
+ if st.button("Clear History"):
572
+ st.session_state.quiz_history = []
573
+ # Also delete from disk
574
+ if os.path.exists("quiz_history.json"):
575
+ os.remove("quiz_history.json")
576
+ st.success("History cleared!")
577
+ st.rerun()
578
+
579
+ # --- Main App Logic ---
580
+ def main():
581
+ # Load saved quizzes from disk on startup
582
+ if 'saved_quizzes' not in st.session_state or not st.session_state.saved_quizzes:
583
+ try:
584
+ if os.path.exists("saved_quizzes.json"):
585
+ with open("saved_quizzes.json", "r") as f:
586
+ st.session_state.saved_quizzes = json.load(f)
587
+ except Exception:
588
+ pass
589
+
590
+ # Display the appropriate page
591
+ if st.session_state.page == "create":
592
+ show_create_quiz_page()
593
+ elif st.session_state.page == "saved":
594
+ show_saved_quizzes_page()
595
+ elif st.session_state.page == "take" and st.session_state.quiz_in_progress:
596
+ show_take_quiz_page()
597
+ elif st.session_state.page == "history":
598
+ show_history_page()
599
+ else:
600
+ show_create_quiz_page()
601
 
602
+ if __name__ == "__main__":
603
+ main()