File size: 9,958 Bytes
7461958 ff40b9b eccc273 ff40b9b eccc273 ff40b9b eccc273 431839d 155cc1f ff40b9b 155cc1f eccc273 155cc1f eccc273 155cc1f eccc273 431839d 155cc1f 2be75a5 155cc1f ff40b9b 155cc1f 2be75a5 155cc1f 431839d 88ad4b4 155cc1f ff40b9b 88ad4b4 ff40b9b eccc273 ff40b9b eccc273 ff40b9b 431839d ff40b9b 88ad4b4 ff40b9b 88ad4b4 eccc273 ff40b9b 7461958 155cc1f 7461958 155cc1f 7461958 155cc1f 2e001b9 7461958 38dca3c 7461958 155cc1f 2be75a5 7461958 155cc1f 7461958 155cc1f 7461958 155cc1f 7461958 155cc1f 7ab6452 3ec2b4a 7461958 |
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 |
import streamlit as st
import google.generativeai as genai
import os
import re # For improved parsing
# Set up Streamlit page
st.title("Interactive Multiple Choice Quiz Generator")
st.markdown("Powered by Gemini API")
# API Key Input from User
gemini_api_key = st.text_input("Enter your Gemini API Key:", type="password")
if not gemini_api_key:
st.warning("Please enter your Gemini API key to generate a quiz.")
st.stop()
else:
genai.configure(api_key=gemini_api_key)
model = genai.GenerativeModel('gemini-pro')
# Security Warning
st.markdown("<font color='red'>**Warning:** Directly entering your API key is less secure than using Streamlit Secrets or environment variables. For production, use Secrets.</font>", unsafe_allow_html=True)
# Initialize session state for quiz data and progress
if 'quiz_data' not in st.session_state:
st.session_state.quiz_data = None
if 'current_question_index' not in st.session_state:
st.session_state.current_question_index = 0
if 'user_answers' not in st.session_state:
st.session_state.user_answers = []
if 'quiz_completed' not in st.session_state:
st.session_state.quiz_completed = False
if 'score' not in st.session_state:
st.session_state.score = 0
def parse_quiz_content(quiz_content):
"""Parses the quiz content and answer key into a structured format, handling title."""
questions = []
answer_key_dict = {}
quiz_parts = quiz_content.split("Answer Key:")
if len(quiz_parts) != 2:
st.warning("Could not reliably separate quiz questions and answer key. Parsing might be imperfect.")
return None, None
question_section = quiz_parts[0].strip()
answer_key_section = quiz_parts[1].strip()
# --- Split into blocks by double newline ---
blocks = re.split(r'\n\n+', question_section) # Split by one or more double newlines
# --- Handle Potential Title (First Block) ---
if blocks:
first_block = blocks[0].strip()
if not re.match(r'^\d+\.\s', first_block): # Check if the first block DOES NOT start with a question number
# Assume the first block is the title and remove it
blocks = blocks[1:] # Slice to remove the first block (title)
else:
st.warning("Unexpected format: First block starts with a question number. Title might not be removed correctly.")
# --- Process Question Blocks ---
for block in blocks:
block = block.strip()
if not block:
continue
lines = block.split('\n')
# --- First line is question text (after removing bold markdown) ---
question_text = re.sub(r'\*\*|\*', '', lines[0]).strip()
options = {}
for line in lines[1:]:
line = line.strip()
if re.match(r'^[A-D]\.\s', line): # Options are like "A. Elephant"
option_letter = line[0]
option_text = line[2:].strip()
options[option_letter] = option_text
if question_text: # Only append if we have a question text
questions.append({'question': question_text, 'options': options})
# --- Answer Key Parsing (No change needed) ---
answer_lines = answer_key_section.strip().split('\n')
for line in answer_lines:
line = line.strip()
match = re.match(r'(\d+)\.\s*([A-D])', line)
if match:
question_num = int(match.group(1)) - 1
correct_answer = match.group(2)
answer_key_dict[question_num] = correct_answer
# Basic validation
if not questions or not answer_key_dict:
st.error("Error parsing quiz content. Please try again or check the generated format.")
return None, None
if len(questions) != len(answer_key_dict):
st.warning(f"Number of questions parsed ({len(questions)}) does not match number of answers in answer key ({len(answer_key_dict)}). Parsing might be incomplete.")
# Combine parsed questions and answer key into quiz_data
quiz_data_list = []
for i, q_data in enumerate(questions):
correct_answer = answer_key_dict.get(i)
if correct_answer:
quiz_data_list.append({
'question': q_data['question'],
'options': q_data['options'],
'correct_answer': correct_answer
})
else:
st.warning(f"Could not find correct answer for question {i+1} in the answer key.")
return None, None
return quiz_data_list, answer_key_dict
def display_question():
"""Displays the current question and options for interactive quiz."""
if st.session_state.quiz_data is None:
st.error("Quiz data not loaded yet. Generate a quiz first.")
return
if st.session_state.current_question_index < len(st.session_state.quiz_data):
question_data = st.session_state.quiz_data[st.session_state.current_question_index]
question_number = st.session_state.current_question_index + 1
st.markdown(f"**Question {question_number}:** {question_data['question']}")
options_list = [f"{key}. {value}" for key, value in question_data['options'].items()]
user_choice = st.radio("Choose an answer:", options_list, key=f"q_{question_number}") # Unique key for radio buttons
if st.button("Submit Answer", key=f"submit_q_{question_number}"): # Unique key for submit button
selected_option_letter = user_choice.split('.')[0] # Extract A, B, C, or D
st.session_state.user_answers.append(selected_option_letter)
if st.session_state.current_question_index < len(st.session_state.quiz_data) - 1:
st.session_state.current_question_index += 1
else:
st.session_state.quiz_completed = True # Mark quiz as completed after last question
st.rerun()
def display_results():
"""Displays the quiz results after completion."""
if st.session_state.quiz_completed:
st.markdown("### Quiz Results")
correct_count = 0
for i in range(len(st.session_state.quiz_data)):
user_answer = st.session_state.user_answers[i] if i < len(st.session_state.user_answers) else None # Handle if user didn't answer all
correct_answer = st.session_state.quiz_data[i]['correct_answer']
if user_answer == correct_answer:
correct_count += 1
result_text = f"**Question {i+1}:** ✅ Correct! (Your answer: {user_answer}, Correct answer: {correct_answer})"
color = "green"
else:
result_text = f"**Question {i+1}:** ❌ Incorrect. (Your answer: {user_answer if user_answer else 'Not answered'}, Correct answer: {correct_answer})"
color = "red"
st.markdown(f"<font color='{color}'>{result_text}</font>", unsafe_allow_html=True)
percentage_correct = (correct_count / len(st.session_state.quiz_data)) * 100
st.markdown(f"### Final Score: {correct_count} out of {len(st.session_state.quiz_data)} correct ({percentage_correct:.2f}%)")
st.session_state.score = correct_count # Store score in session state
# User input for topic
topic = st.text_input("Enter the topic for your quiz:")
if topic:
if st.button("Generate Quiz"):
with st.spinner(f"Generating quiz on '{topic}'..."):
try:
prompt = f"""
Generate a multiple-choice quiz on the topic of "{topic}".
The quiz should have 5 questions.
For each question, provide four plausible options labeled A, B, C, and D.
Clearly indicate the correct answer for each question at the end in a separate section called "Answer Key".
Format the quiz clearly for easy reading.
"""
response = model.generate_content(prompt)
quiz_content = response.text
# --- DEBUGGING PRINTS ---
st.write("### Raw Quiz Content from Gemini:")
st.code(quiz_content) # Display raw content in a code block for readability
parsed_quiz_data, answer_key = parse_quiz_content(quiz_content)
st.write("### Parsed Quiz Data:")
st.write(parsed_quiz_data) # Display the parsed data structure
# --- END DEBUGGING PRINTS ---
if quiz_content: # Check if quiz_content was generated successfully (outer if)
if parsed_quiz_data: # Check if parsing was successful (inner if)
st.session_state.quiz_data = parsed_quiz_data
st.session_state.current_question_index = 0
st.session_state.user_answers = []
st.session_state.quiz_completed = False
st.session_state.score = 0
st.success(f"Quiz on '{topic}' generated successfully! Let's begin.")
else: # else associated with inner if parsed_quiz_data
st.error("Failed to parse quiz content. Please try generating again.")
st.session_state.quiz_data = None
else: # else associated with outer if quiz_content
st.error("Failed to generate quiz content. Please try again or check your API key.")
except Exception as e:
st.error(f"An error occurred: {e}")
st.error("Please check your API key and network connection. If the problem persists, try a different topic or try again later.")
# Quiz Display Logic
if st.session_state.quiz_data:
if not st.session_state.quiz_completed:
display_question()
else:
display_results()
elif topic and not st.session_state.quiz_data and not st.session_state.quiz_completed: # Message if topic entered but quiz not generated yet
st.info("Click 'Generate Quiz' to start the quiz.") |