Spaces:
Sleeping
Sleeping
| 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'] = {} | |