Introduction
Streamlit is a fantastic framework for creating interactive web applications in Python. In this tutorial, weโll build a fully functional quiz app with real-time feedback, scoring, and an option to restart the quiz. This project demonstrates how to structure a Streamlit app using fragments for modularity and maintainability.
By the end of this article, youโll have a working quiz app with the following features:
- Display multiple-choice questions.
- Provide instant feedback on user responses.
- Track and display the userโs score.
- Allow restarting the quiz.
Why Use Streamlit Fragments?
The @st.fragment
decorator in Streamlit allows developers to modularize their app by encapsulating related components into reusable and independent blocks. This approach simplifies the development process, improves maintainability, and enhances performance by avoiding unnecessary re-runs of unrelated parts of the app.
In this quiz app, we utilize fragments to manage different functionalities such as displaying questions, providing feedback, showing scores, and restarting the quiz.
The Code
Hereโs the complete code for the Streamlit quiz app:
import streamlit as st
# Initialize session state variables
if "questions" not in st.session_state:
st.session_state.questions = [
{"question": "What is the capital of France?", "options": ["Paris", "London", "Berlin"],
"answer": "Paris"},
{"question": "What is the largest ocean in the world?", "options": ["Atlantic", "Pacific", "Indian"],
"answer": "Pacific"},
{"question": "What is the chemical symbol for water?", "options": ["H2O", "O2", "CO2"], "answer": "H2O"},
]
if "current_question" not in st.session_state:
st.session_state.current_question = 0
if "score" not in st.session_state:
st.session_state.score = 0
if "feedback" not in st.session_state:
st.session_state.feedback = None
@st.fragment
def question_fragment():
"""
Fragment to display a question and capture the user's response.
"""
question_data = st.session_state.questions[st.session_state.current_question]
st.subheader(f"Question {st.session_state.current_question + 1}/{len(st.session_state.questions)}")
st.write(question_data['question'])
selected_option = st.radio('Choose an answer: ', question_data['options'])
if st.button('Submit'):
if selected_option == question_data['answer']:
st.session_state.feedback = ('success', 'Correct! ๐')
st.session_state.score += 1
else:
st.session_state.feedback = ("error", f"Wrong! The correct answer was: {question_data['answer']}")
if st.session_state.current_question + 1 < len(st.session_state.questions):
st.session_state.current_question += 1
st.rerun()
else:
st.session_state.current_question = None
st.rerun()
@st.fragment
def feedback_fragment():
"""
Fragment to display feedback messages.
"""
if st.session_state.feedback:
msg_type, msg_content = st.session_state.feedback
if msg_type == "success":
st.success(msg_content)
elif msg_type == "error":
st.error(msg_content)
st.session_state.feedback = None
@st.fragment
def score_fragment():
"""
Fragment to display the userโs current score.
"""
st.metric('Current Score', st.session_state.score)
@st.fragment
def restart_quiz_fragment():
"""
Fragment to restart the quiz.
"""
if st.button('Restart Quiz'):
st.session_state.current_question = 0
st.session_state.score = 0
st.session_state.feedback = None
st.rerun()
# Main application
st.title('Interactive Quiz App')
feedback_fragment()
if st.session_state.current_question is not None:
score_fragment()
question_fragment()
else:
st.subheader('Quiz Finished! ๐')
st.write(f"Your final score is {st.session_state.score}/{len(st.session_state.questions)}.")
restart_quiz_fragment()
Code Breakdown
1. Session State Initialization
Session state variables ensure the persistence of quiz data (questions, current question index, score, and feedback) across user interactions. These variables are initialized only once during the app's lifecycle.
2. Fragments for Modular Design
The app uses Streamlit fragments (@st.fragment
) to encapsulate functionality into reusable components:
-
question_fragment()
: Displays the current question and options, validates the userโs answer, and updates the state. -
feedback_fragment()
: Provides immediate feedback on the userโs answer (correct or incorrect). -
score_fragment()
: Displays the userโs score dynamically. -
restart_quiz_fragment()
: Resets all session state variables, allowing the user to restart the quiz.
3. Real-Time Feedback
After each response, the app displays a success or error message, enhancing the interactivity of the quiz.
4. Dynamic State Updates
The app updates the question index (current_question
) and re-renders the interface after each question using st.rerun()
.
Features
-
Dynamic Question Progression:
- The app automatically moves to the next question after validation.
-
Real-Time Feedback:
- Users receive instant feedback on their answers.
-
Score Tracking:
- The score is displayed in real-time during the quiz.
-
Restart Option:
- Users can restart the quiz at any time.
Step-by-Step Execution
-
Display a Question:
- The
question_fragment
shows a single question at a time with its multiple-choice options. - Upon selecting an answer and clicking "Submit," the app validates the response and updates the state.
- The
-
Provide Feedback:
- The
feedback_fragment
displays whether the answer was correct or incorrect. - Feedback is reset after displaying to avoid repetition.
- The
-
Update the Score:
- Correct answers increment the score, shown dynamically using the
score_fragment
.
- Correct answers increment the score, shown dynamically using the
-
End of Quiz:
- When all questions are answered, the app displays the final score and provides an option to restart.
Potential Improvements
-
Shuffle Questions:
- Add functionality to randomize the order of questions for each quiz session.
import random
random.shuffle(st.session_state.questions)
-
Add a Timer:
- Introduce a countdown timer for each question to increase difficulty.
-
Custom Questions:
- Allow users to input their own questions and answers before starting the quiz.
-
Multiple Quiz Categories:
- Provide options to choose from different quiz topics or categories.
Conclusion
This Streamlit quiz app showcases the power of modular design and interactive elements. With real-time feedback and score tracking, it provides an engaging user experience. You can enhance it further by adding features like question shuffling, timers, or multiple quiz topics.
Let us know in the comments how you plan to use this app or what features youโd like to add! ๐
Happy coding! ๐
Top comments (0)