test / app.py
admin08077's picture
Update app.py
16a7e13 verified
import streamlit as st
from io import StringIO
import json
# Set the page configuration
st.set_page_config(page_title="πŸ“š Multiple Choice Test Creator", layout="wide")
# Initialize session state for storing tests
if 'tests' not in st.session_state:
st.session_state['tests'] = []
# Initialize session state for current questions being added
if 'current_questions' not in st.session_state:
st.session_state['current_questions'] = []
# Function to add a new question
def add_question():
if len(st.session_state['current_questions']) < 10:
st.session_state['current_questions'].append({
'question': '',
'options': {'A': '', 'B': '', 'C': '', 'D': ''},
'correct': 'A'
})
else:
st.warning("You can only add up to 10 questions.")
# Function to remove a question
def remove_question(index):
st.session_state['current_questions'].pop(index)
# Function to generate HTML content for the test
def generate_html(test_title, questions):
html_content = f"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{test_title}</title>
<style>
body {{
font-family: Arial, sans-serif;
margin: 40px;
background-color: #f9f9f9;
}}
.test-title {{
text-align: center;
font-size: 2em;
margin-bottom: 50px;
}}
.question {{
margin-bottom: 30px;
}}
.options label {{
display: block;
margin: 5px 0;
}}
</style>
</head>
<body>
<div class="test-title">{test_title}</div>
"""
for idx, q in enumerate(questions, 1):
html_content += f"""
<div class="question">
<div class="question-text"><strong>Question {idx}:</strong> {q['question']}</div>
<div class="options">
<label><input type="radio" name="q{idx}" value="A"> A. {q['options']['A']}</label>
<label><input type="radio" name="q{idx}" value="B"> B. {q['options']['B']}</label>
<label><input type="radio" name="q{idx}" value="C"> C. {q['options']['C']}</label>
<label><input type="radio" name="q{idx}" value="D"> D. {q['options']['D']}</label>
</div>
</div>
"""
html_content += """
</body>
</html>
"""
return html_content
# Tabs for navigation
tabs = st.tabs(["πŸ“ Create Test", "πŸ“– Take Test"])
# -------------------- Create Test Tab -------------------- #
with tabs[0]:
st.header("Create a New Multiple-Choice Test")
# Input for Test Title
test_title = st.text_input("Enter Test Title", "")
# Button to add a new question
st.button("βž• Add a Question", on_click=add_question)
# Display existing questions
for idx, q in enumerate(st.session_state['current_questions']):
with st.expander(f"Question {idx + 1}", expanded=True):
# Question Text
question_key = f"question_{idx}"
question_text = st.text_input("Question Text", value=q['question'], key=question_key)
st.session_state['current_questions'][idx]['question'] = question_text
# Answer Options
for option in ['A', 'B', 'C', 'D']:
option_key = f"question_{idx}_option_{option}"
option_text = st.text_input(f"Answer {option}", value=q['options'][option], key=option_key)
st.session_state['current_questions'][idx]['options'][option] = option_text
# Correct Answer Selector
correct_option_key = f"question_{idx}_correct"
correct_option = st.selectbox("Select Correct Answer", options=['A', 'B', 'C', 'D'],
index=['A','B','C','D'].index(q['correct']),
key=correct_option_key)
st.session_state['current_questions'][idx]['correct'] = correct_option
# Remove Question Button
if st.button("πŸ—‘οΈ Remove", key=f"remove_{idx}"):
remove_question(idx)
st.experimental_rerun()
# Button to create the test
if st.button("βœ… Create Test"):
if not test_title:
st.error("Please enter a test title.")
elif len(st.session_state['current_questions']) == 0:
st.error("Please add at least one question.")
else:
# Validate that all questions have all fields filled
incomplete = False
for idx, q in enumerate(st.session_state['current_questions'], 1):
if not q['question'] or not all(q['options'][opt] for opt in ['A','B','C','D']):
st.error(f"Question {idx} is incomplete. Please fill in all fields.")
incomplete = True
break
if not incomplete:
# Add the test to the session state
test = {
'title': test_title,
'questions': st.session_state['current_questions'].copy()
}
st.session_state['tests'].append(test)
st.success(f"Test '{test_title}' created successfully!")
# Clear current questions after creation
st.session_state['current_questions'] = []
# Provide download button
html_content = generate_html(test_title, test['questions'])
st.download_button(
label="πŸ“„ Download Test as HTML",
data=html_content,
file_name=f"{test_title.replace(' ', '_')}.html",
mime="text/html"
)
# Optionally, display the test
st.markdown("---")
st.header("πŸ“ Your Test")
st.markdown(html_content, unsafe_allow_html=True)
# -------------------- Take Test Tab -------------------- #
with tabs[1]:
st.header("Take a Multiple-Choice Test")
if len(st.session_state['tests']) == 0:
st.info("No tests available. Please create a test first.")
else:
# Select a test to take
test_titles = [test['title'] for test in st.session_state['tests']]
selected_test_title = st.selectbox("Select a Test to Take", options=test_titles)
# Retrieve the selected test
selected_test = next((test for test in st.session_state['tests'] if test['title'] == selected_test_title), None)
if selected_test:
# Initialize session state for user answers if not present
if 'user_answers' not in st.session_state:
st.session_state['user_answers'] = {}
with st.form("take_test_form"):
for idx, q in enumerate(selected_test['questions'], start=1):
st.markdown(f"**{idx}. {q['question']}**")
# Prepare options with letters and text
option_list = [
f"A. {q['options']['A']}",
f"B. {q['options']['B']}",
f"C. {q['options']['C']}",
f"D. {q['options']['D']}"
]
# Create radio buttons with the full option text
answer = st.radio(
f"Select an answer for Question {idx}",
options=option_list,
key=f"test_{selected_test_title}_q{idx}"
)
# Store the selected answer's letter
st.session_state['user_answers'][idx] = answer.split(".")[0].strip()
st.markdown("---")
# Submit button
submit = st.form_submit_button("Submit Test")
if submit:
# Grade the test
score = 0
total = len(selected_test['questions'])
feedback = []
for idx, q in enumerate(selected_test['questions'], start=1):
user_ans = st.session_state['user_answers'].get(idx, None)
correct_ans = q['correct']
is_correct = user_ans == correct_ans
if is_correct:
score += 1
feedback.append(f"**Question {idx}**: Correct βœ…")
else:
feedback.append(f"**Question {idx}**: Incorrect ❌ (Correct Answer: {correct_ans})")
# Display the result
st.success(f"You scored {score} out of {total}.")
# Display feedback
with st.expander("View Feedback"):
for fb in feedback:
st.markdown(fb)
# Optionally, clear answers for next test
st.session_state['user_answers'] = {}