Build a Study Quiz Generator with Groq

Turn your study notes into an interactive quiz using Groq's AI API.

Introduction

30 Second Summary

You know that moment when you finish reading your notes and think you understand everything, only to blank out on the actual test? Turning your notes into practice questions is one of the most effective study techniques, but writing good questions takes almost as long as studying itself.

In this project, you will build a web application that uses AI to instantly generate multiple-choice quiz questions from any text you paste in. You'll connect to a real AI model, design prompts that produce structured output, and wrap it all in a browser-based interface.

What You'll Build

A Python web app powered by Groq's ultra-fast AI inference that turns study notes into interactive multiple-choice quizzes.

By the end of this project, you'll have:

  • A Python script that connects to the Groq API and generates structured quiz questions from any text.
  • A Streamlit web interface with a text input area, quiz display, and scoring system.
  • A well-crafted system prompt that reliably produces JSON-formatted quiz output from an LLM.
  • Secret Mission: Add a hint button that uses AI to generate contextual clues when you're stuck on a question.

Are there any prerequisites?

None. This guide walks you through installing Python, setting up VS Code, and creating a free Groq account from scratch. No prior coding experience is required.

Set Up Python and Your Project

Your quiz generator is a Python application that talks to an AI model through an API. Before writing any code, you need Python installed on your machine and a clean project folder to work in.

In this step, you'll install Python, create a virtual environment (an isolated workspace for your project's packages), and set up the files your app needs.

In this step, get ready to:
  • Install Python 3.13 and the VS Code Python extension.
  • Create your project folder and virtual environment.
  • Set up your project files.
Install Python 3.13 and the Python extension

Python is the programming language your quiz generator runs on. You need version 3.13 installed so that all the libraries you'll use are compatible.

  • In VS Code, open a terminal by clicking Terminal in the top menu bar, then New Terminal.
  • Check if Python is already installed by running this command:

macOS

python3 --version

Windows

python --version

✔️ I see Python 3.13.x

Python 3.13 is already installed. Skip ahead to installing the Python extension below.

ⓧ I see an older version

You have an older version of Python that won't work with this project's dependencies. You need to install 3.13 alongside it.

macOS

  • Go to python.org/downloads in your browser.
  • Click the Download Python 3.13 button and run the installer.
  • Follow the prompts and complete the installation.
  • Close and reopen your VS Code terminal, then run python3 --version again to confirm it shows 3.13.
macOS default Python

macOS may ship with an older system Python. The python.org installer places the new version at python3 so it won't conflict with the system copy.

Windows

  • Go to python.org/downloads in your browser.
  • Click the Download Python 3.13 button and run the installer.
  • On the first screen of the installer, check the box that says Add python.exe to PATH. This is critical.
  • Click Install Now and wait for it to finish.
  • Close and reopen your VS Code terminal, then run python --version again to confirm it shows 3.13.

ⓧ Command not found

Python is not installed on your machine. Follow the steps below for your operating system.

macOS

  • Go to python.org/downloads in your browser.
  • Click the Download Python 3.13 button and run the installer.
  • Follow the prompts and complete the installation.
  • Close and reopen your VS Code terminal, then run:
python3 --version

You should see Python 3.13.x in the output.

Windows

  • Go to python.org/downloads in your browser.
  • Click the Download Python 3.13 button and run the installer.
  • On the first screen of the installer, check the box that says Add python.exe to PATH. This is critical.
  • Click Install Now and wait for it to finish.
  • Close and reopen your VS Code terminal, then run:
python --version

You should see Python 3.13.x in the output.

Still not seeing Python 3.13?

On Windows, make sure you checked Add python.exe to PATH during installation. If you missed it, re-run the installer, choose Modify, and enable the PATH option.

On macOS, make sure you're running python3 (not python). The macOS system may not have a python command at all.

Help me get Python 3.13 working in my terminal

Now install the Python extension in VS Code so you get syntax highlighting and code suggestions.

  • Open the Extensions view by pressing Cmd+Shift+X (macOS) or Ctrl+Shift+X (Windows).
  • Type Python in the search box.
  • Find the extension published by Microsoft (it has millions of installs) and click Install.

What does the Python extension do?

The Python extension adds code autocompletion, error highlighting, and debugging support for Python files in VS Code. It also automatically installs Pylance (a language server) for smarter suggestions.

Create your project folder and virtual environment

A virtual environment is an isolated copy of Python just for this project. It keeps your project's packages separate from anything else on your machine.

  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir study-quiz-generator
cd study-quiz-generator
  • Now open this folder in VS Code so it becomes your workspace.
  • Click File in the top menu bar.
  • Click Open Folder.
  • Navigate to your Desktop, select the study-quiz-generator folder, and click Open.

VS Code reloads with your project folder as the workspace. The Explorer sidebar on the left now shows an empty study-quiz-generator folder.

  • Open a new terminal by clicking Terminal in the top menu, then New Terminal. It opens inside your project folder automatically.
  • Create a virtual environment by running this command:

macOS

python3 -m venv venv

Windows

python -m venv venv

What does this command do?

The -m venv flag tells Python to run its built-in virtual environment module. The second venv is the name of the folder it creates to store the environment's files.

  • Activate the virtual environment by running:

macOS

source venv/bin/activate

Windows

venv\Scripts\activate

You should see (venv) appear at the start of your terminal prompt. This confirms the virtual environment is active.

  • Install the packages your project needs by running:
pip install groq streamlit python-dotenv

What are these packages?

The groq package lets your Python code talk to the Groq API. Streamlit turns your Python script into a web app with zero HTML or CSS.

The python-dotenv package loads your API key from a .env file so you don't have to paste secrets directly in your code.

  • Verify the packages installed correctly by running:
pip list

You should see groq, streamlit, and python-dotenv in the list of installed packages.

Packages not installing?

Make sure you see (venv) in your terminal prompt. If you don't, run the activate command again for your operating system.

If you get a permissions error, make sure you're running inside the virtual environment and not trying to install globally.

Help me fix my package installation error

Create your project files

Your project needs three files: a .env file for your API key, an app.py file for your code, and a requirements.txt to record which packages you're using.

  • In the VS Code Explorer sidebar on the left, hover over the STUDY-QUIZ-GENERATOR heading to reveal the icons.
  • Click the New File icon (a page with a plus sign).
  • Type .env and press Enter.
  • Paste the following into the file:
GROQ_API_KEY=your-api-key-here
  • Replace your-api-key-here with your actual Groq API key.
  • Save the file with Cmd+S (macOS) or Ctrl+S (Windows).

Why use a .env file?

A .env file keeps sensitive values like API keys out of your main code. The python-dotenv package reads this file automatically so your code can access the key without it being visible in your script.

  • Click the New File icon again.
  • Type app.py and press Enter. Leave this file empty for now.
  • Save the empty file.
  • Click the New File icon one more time.
  • Type requirements.txt and press Enter.
  • Paste the following into the file:
groq==1.4.0
streamlit==1.58.0
python-dotenv==1.1.0
  • Save the file.

What is requirements.txt?

This file records the exact versions of each package your project uses. Anyone (including future you) can recreate the same environment by running pip install -r requirements.txt.

  • Confirm your files exist by running:
ls

You should see .env, app.py, requirements.txt, and a venv folder in the output.

Don't see all the files?

Make sure you created each file inside the study-quiz-generator folder, not inside the venv folder. The Explorer sidebar should show them at the top level of your project.

If ls doesn't show .env, try ls -a on macOS. Files starting with a dot are hidden by default.

Help me find my missing project files

✔️ Awesome, I've got everything!

Great. Double check you've saved all three files.

ⓧ I'd like to double check the full code

Here's what each file should contain at this point:

GROQ_API_KEY=your-api-key-here

Your app.py should be empty (no content yet).

groq==1.4.0
streamlit==1.58.0
python-dotenv==1.1.0

Your development environment is ready to go. Next up, you'll write Python code that connects to Groq and gets your first AI-generated response.

Connect to Groq and Get Your First AI Response

Your project is set up and your API key is ready. Now it's time to write the code that actually talks to an AI model.

In this step, you'll send your first request to Groq's Llama 3.3 70B model and get a response back in your terminal. Then you'll refine that request into a structured prompt that generates quiz questions in JSON format.

In this step, get ready to:
  • Send your first message to an AI model using the Groq API.
  • Design a prompt that generates structured quiz questions from study notes.
Write your first API call to Groq

Before building the full quiz generator, you need to confirm that your code can reach the Groq API and get a response. You'll write a short script that sends a simple question to the AI and prints the answer.

  • In VS Code, open app.py and add the following setup code that imports your libraries, loads the API key, and creates the Groq client:
import os
from groq import Groq

# Load environment variables from .env file
from dotenv import load_dotenv
load_dotenv()

# Create the Groq client using your API key
client = Groq(api_key=os.environ.get("GROQ_API_KEY"))

What does this code do?

load_dotenv() reads the .env file and loads your GROQ_API_KEY into the environment. This keeps your secret key out of your code.

Groq(api_key=...) creates a client object that handles all communication with the Groq API. Every request you make goes through this client.

  • Below the client line, add this code that sends a simple test message to the Llama 3.3 70B model and prints the response:
# Send a simple test message to confirm the connection works
chat_completion = client.chat.completions.create(
    messages=[
        {
            "role": "user",
            "content": "What is photosynthesis in one sentence?"
        }
    ],
    model="llama-3.3-70b-versatile",
    temperature=0.7,
    max_tokens=2048
)

# Print the AI's response
print(chat_completion.choices[0].message.content)

What does this code do?

client.chat.completions.create() sends a request to Groq's API. The messages list contains your conversation. Each message has a role (who is speaking) and content (what they say).

temperature controls how creative the model is (0 is very predictable, 2 is very random). max_tokens sets the maximum length of the response.

  • Save app.py.
  • Run your script by entering this command in your terminal:
python app.py
  • You should see a one-sentence explanation of photosynthesis printed in your terminal. The exact wording varies each time because the model has creative freedom.

Seeing an authentication error?

If you see an error mentioning an invalid API key or authentication failure, double-check that your .env file contains GROQ_API_KEY= followed by your actual key (no spaces around the = sign). Make sure the key you pasted from the Groq console is complete and not cut off.

If you see a "module not found" error, make sure your virtual environment is activated. You should see (venv) at the start of your terminal prompt.

help me fix my Groq API connection error

Design a structured prompt for quiz generation

Your API connection works. Now you'll transform this simple call into something much more useful. Instead of asking a general question, you'll instruct the model to generate multiple-choice quiz questions in JSON format from study notes.

What is a system prompt?

A system prompt is a special message (with role system) that tells the AI how to behave. The model reads it first and follows those instructions for the entire conversation. You'll use one to force the model to always respond with valid JSON.

  • In app.py, find these import lines at the top:
import os
from groq import Groq
  • Replace the entire contents of app.py with the updated code below. This adds import json and import streamlit as st (which you'll need in the next step), defines sample study notes, builds a detailed prompt, and sends it with a system message:
import os
import json
import streamlit as st
from groq import Groq
from dotenv import load_dotenv

load_dotenv()

# Initialize Groq client
client = Groq(api_key=os.environ.get("GROQ_API_KEY"))

# Sample study notes to test with
notes = "Sample study notes about photosynthesis."
num_questions = 2

# Build a detailed prompt that instructs the model to return JSON
prompt = f"""Based on the following study notes, generate exactly {num_questions} multiple-choice quiz questions.

Return your response as a JSON array where each element has this structure:
{{
    "question": "The question text",
    "options": ["Option A", "Option B", "Option C", "Option D"],
    "correct_answer": "The correct option text exactly as it appears in options"
}}

Only return the JSON array, no other text.

Study notes:
{notes}"""

# Send the request with a system prompt and user prompt
chat_completion = client.chat.completions.create(
    messages=[
        {
            "role": "system",
            "content": "You are a helpful study assistant that creates quiz questions. Always respond with valid JSON only."
        },
        {
            "role": "user",
            "content": prompt
        }
    ],
    model="llama-3.3-70b-versatile",
    temperature=0.7,
    max_tokens=2048
)

print(chat_completion.choices[0].message.content)

What changed in this version?

  • The system message tells the model to always respond with valid JSON. This dramatically improves the reliability of structured output.
  • The prompt variable contains an f-string with the exact JSON structure you want back. Showing the model an example of the output format is called "few-shot prompting."
  • Double curly braces {{ and }} are used in the f-string so Python doesn't treat them as variable placeholders.
  • Save app.py and run it again:
python app.py
  • You should see a JSON array printed in your terminal containing 2 quiz questions about photosynthesis. Each question has a question field, four options, and a correct_answer.

Not seeing valid JSON output?

If the output contains extra text alongside the JSON (like explanations before or after the array), make sure your system message says "Always respond with valid JSON only." exactly as written above. The system prompt is what enforces the format.

If you see a Python error about streamlit, make sure you installed it in your virtual environment in the previous step. Run pip list and confirm streamlit appears.

help me fix my quiz generation prompt output

✔️ Awesome, I've got everything!

Great. Double check you've saved your file before moving on.

ⓧ I'd like to double check the full code

Here is the complete app.py file at this point:

import os
import json
import streamlit as st
from groq import Groq
from dotenv import load_dotenv

load_dotenv()

client = Groq(api_key=os.environ.get("GROQ_API_KEY"))

notes = "Sample study notes about photosynthesis."
num_questions = 2

prompt = f"""Based on the following study notes, generate exactly {num_questions} multiple-choice quiz questions.

Return your response as a JSON array where each element has this structure:
{{
    "question": "The question text",
    "options": ["Option A", "Option B", "Option C", "Option D"],
    "correct_answer": "The correct option text exactly as it appears in options"
}}

Only return the JSON array, no other text.

Study notes:
{notes}"""

chat_completion = client.chat.completions.create(
    messages=[
        {
            "role": "system",
            "content": "You are a helpful study assistant that creates quiz questions. Always respond with valid JSON only."
        },
        {
            "role": "user",
            "content": prompt
        }
    ],
    model="llama-3.3-70b-versatile",
    temperature=0.7,
    max_tokens=2048
)

print(chat_completion.choices[0].message.content)

Your script can now generate structured quiz questions from any text you give it. Next up, you'll wrap this logic in a reusable function with proper error handling.

Build the Quiz Generator Logic

In the last step, you confirmed that your script can talk to Groq and get AI-generated quiz questions back as JSON.

Now you need to turn that flat script into a reusable function. A function lets you call the same quiz-generation logic from anywhere in your app, with different study notes and different question counts each time.

In this step, get ready to:
  • Wrap your API logic into a reusable generate_quiz() function.
  • Add input validation and error handling so the app never crashes.
Create the generate_quiz() function

Your script currently runs top-to-bottom with hardcoded notes. You will replace that flat code with a function that accepts any study notes and returns structured quiz questions.

  • In app.py, select and delete everything below the client = Groq(...) line (the hardcoded notes variable, the prompt string, the API call, and the print statement).
  • Replace it with the following function:
def generate_quiz(notes, num_questions):
    """Generate quiz questions from study notes using Groq."""
    if len(notes.strip()) < 50:
        st.error("Please enter at least 50 characters of study notes.")
        return None

    prompt = f"""Based on the following study notes, generate exactly {num_questions} multiple-choice quiz questions.

Return your response as a JSON array where each element has this structure:
{{
    "question": "The question text",
    "options": ["Option A", "Option B", "Option C", "Option D"],
    "correct_answer": "The correct option text exactly as it appears in options"
}}

Only return the JSON array, no other text.

Study notes:
{notes}"""

    try:
        chat_completion = client.chat.completions.create(
            messages=[
                {
                    "role": "system",
                    "content": "You are a helpful study assistant that creates quiz questions. Always respond with valid JSON only."
                },
                {
                    "role": "user",
                    "content": prompt
                }
            ],
            model="llama-3.3-70b-versatile",
            temperature=0.7,
            max_tokens=2048
        )

        response_text = chat_completion.choices[0].message.content
        questions = json.loads(response_text)
        return questions

    except json.JSONDecodeError:
        st.error("The AI returned an unexpected format. Please try again.")
        return None
    except Exception as e:
        st.error(f"An error occurred: {str(e)}")
        return None

What does this code do?

This function packages your entire quiz generation workflow into a single callable unit.

  • if len(notes.strip()) < 50: checks that the input has enough content for meaningful questions. If it is too short, the function shows an error and returns None.
  • The prompt variable builds the same JSON instruction you used before, but now with dynamic notes and num_questions parameters.
  • json.loads(response_text) converts the AI's text response into a Python list of dictionaries you can loop through.
  • The try/except blocks catch two failure modes: the AI returning invalid JSON (json.JSONDecodeError) and any other unexpected error.

Why temperature 0.7?

The temperature parameter controls how creative or random the AI's output is. A value of 0.7 gives varied, interesting questions without being so random that the output breaks your expected JSON format.

Lower values (closer to 0) make output more predictable. Higher values (up to 2) make it more creative but less reliable.

  • Save app.py.
  • Add a temporary test call at the very bottom of app.py so you can verify the function works. Type: print(generate_quiz("Photosynthesis is the process by which green plants convert sunlight into chemical energy. Chlorophyll absorbs light.", 2)).
  • Run your script by running this command:
python app.py

You should see a list of dictionaries printed in your terminal. Each dictionary has a question key, an options key with four choices, and a correct_answer key.

Seeing an error or empty output?

  • Make sure you deleted all the old code below client = Groq(...) before pasting the function. Leftover lines can cause syntax errors.
  • Check that your test call text is longer than 50 characters. The validation rejects anything shorter.
  • If you see None printed, the function hit one of the error paths. Check your terminal for a Streamlit warning about being run outside a session context and confirm your API key is still valid in .env.

Help me debug my generate_quiz function

Test error handling with edge cases

Your function already includes error handling. Now you will confirm it works by feeding it input that should trigger the validation guard.

  • In app.py, find the temporary test call you added at the bottom.
  • Change the test text to something very short, like "Too short". This triggers the 50-character minimum check.
  • Run the script again:
python app.py

You should see None printed instead of quiz questions. The function returned early because the input was too short.

Why does it print None instead of an error message?

The st.error() calls in your function are designed for Streamlit's browser interface. When you run the script directly with python app.py, those error messages have nowhere to display visually.

Once you connect this function to Streamlit in the next step, those errors will appear as styled red alert boxes in the browser. For now, seeing None confirms the function handled the bad input gracefully without crashing.

  • Delete the temporary test call from the bottom of app.py.
  • Save app.py.

Script crashed instead of returning None?

  • Make sure the if len(notes.strip()) < 50: check is inside the function, before the prompt variable. If it is outside the function, it will not catch short input.
  • Confirm the try: block wraps the entire API call and json.loads() line. If either is outside the try block, exceptions will not be caught.

Help me fix my error handling in generate_quiz

✔️ Awesome, I've got everything!

Great. Make sure you have deleted the temporary test call and saved app.py.

ⓧ I'd like to double check the full code

Here is the complete app.py at this point:

import os
import json
import streamlit as st
from groq import Groq
from dotenv import load_dotenv

load_dotenv()

client = Groq(api_key=os.environ.get("GROQ_API_KEY"))


def generate_quiz(notes, num_questions):
    """Generate quiz questions from study notes using Groq."""
    if len(notes.strip()) < 50:
        st.error("Please enter at least 50 characters of study notes.")
        return None

    prompt = f"""Based on the following study notes, generate exactly {num_questions} multiple-choice quiz questions.

Return your response as a JSON array where each element has this structure:
{{
    "question": "The question text",
    "options": ["Option A", "Option B", "Option C", "Option D"],
    "correct_answer": "The correct option text exactly as it appears in options"
}}

Only return the JSON array, no other text.

Study notes:
{notes}"""

    try:
        chat_completion = client.chat.completions.create(
            messages=[
                {
                    "role": "system",
                    "content": "You are a helpful study assistant that creates quiz questions. Always respond with valid JSON only."
                },
                {
                    "role": "user",
                    "content": prompt
                }
            ],
            model="llama-3.3-70b-versatile",
            temperature=0.7,
            max_tokens=2048
        )

        response_text = chat_completion.choices[0].message.content
        questions = json.loads(response_text)
        return questions

    except json.JSONDecodeError:
        st.error("The AI returned an unexpected format. Please try again.")
        return None
    except Exception as e:
        st.error(f"An error occurred: {str(e)}")
        return None

Your quiz generation logic is solid. Next up, you will build a web interface with Streamlit so users can paste their notes, generate quizzes, and check their answers all in the browser.

Build the Web Interface with Streamlit

Your generate_quiz() function works, but the only way to use it right now is to edit the Python file directly every time you want to change your study notes. That's not much of an app.

Streamlit turns Python scripts into interactive web apps. In this step, you'll build a complete browser-based interface with a text input area, a quiz display, and a scoring system.

In this step, get ready to:
  • Add a text input form with a title, notes area, and question slider.
  • Display generated quiz questions with selectable answer choices.
  • Add scoring logic that checks answers and shows results.
Add the input form and generate button

Every Streamlit app needs a way to collect input from the user. You'll add a title, a description, a text area for pasting study notes, a slider for choosing the number of questions, and a button that triggers quiz generation.

  • In app.py, scroll to the very bottom of the file (after the generate_quiz() function's closing except block).
  • Add the Streamlit input form by pasting this code at the bottom:
# Streamlit App
st.title("Study Quiz Generator")
st.write("Paste your study notes below and get instant quiz questions powered by AI!")

notes = st.text_area(
    "Your study notes:",
    height=200,
    placeholder="Paste your lecture notes, textbook passages, or any study material here..."
)

num_questions = st.slider("Number of questions:", min_value=1, max_value=5, value=3)

What does this code do?

  • st.title() sets the main heading of your web app.
  • st.text_area() creates a large text input box where the learner can paste their notes. The height=200 gives it plenty of room.
  • st.slider() adds a draggable slider so users can choose between 1 and 5 quiz questions. It defaults to 3.
  • Now add the "Generate Quiz" button directly below the slider code:
if st.button("Generate Quiz"):
    if notes.strip():
        with st.spinner("Generating your quiz..."):
            questions = generate_quiz(notes, num_questions)
            if questions:
                st.session_state.questions = questions
                st.session_state.notes = notes
                st.session_state.answers = {}
                st.session_state.hints = {}
    else:
        st.warning("Please enter some study notes first.")

What is session state?

Streamlit reruns your entire script from top to bottom every time a user interacts with the app. Without st.session_state, your quiz questions would disappear the moment someone clicks a radio button.

By saving results to st.session_state, the data persists across those reruns. Think of it as a storage locker that survives each page refresh.

  • Save app.py.
  • Launch the app by running this command in your terminal:
streamlit run app.py
  • Your browser should open automatically to a page showing your app title, the text area, the slider, and the **Generate Quiz** button.

Browser didn't open?

  • Check your terminal output for a URL (usually http://localhost:8501). Copy and paste it into your browser manually.
  • If you see an import error, make sure your virtual environment is still activated. You should see your environment name in parentheses at the start of the terminal line.
  • help me debug why my Streamlit app won't start
Display the quiz questions with answer choices

The form collects input, but you also need to display the generated quiz. You'll add a loop that renders each question with radio buttons so users can select their answers.

  • In app.py, add this code below the st.warning("Please enter some study notes first.") line (outside the if st.button block):
if "questions" in st.session_state and st.session_state.questions:
    st.divider()
    st.subheader("Your Quiz")

    for i, q in enumerate(st.session_state.questions):
        st.write(f"**Question {i + 1}:** {q['question']}")

        answer = st.radio(
            f"Select your answer for Question {i + 1}:",
            q["options"],
            key=f"q_{i}",
            index=None
        )
        if answer:
            st.session_state.answers[i] = answer

        st.write("")

What does this code do?

  • The if "questions" in st.session_state check only displays the quiz section after the user has generated questions.
  • st.radio() creates a group of radio buttons for each question's four options. The key=f"q_{i}" gives each radio group a unique ID so Streamlit can track them independently.
  • When a user selects an answer, it gets stored in st.session_state.answers using the question index as the key.
  • Now add the "Check Answers" button and scoring logic directly below, still inside the if "questions" in st.session_state block. Paste this code after the st.write("") line, at the same indentation level as the for loop:
    if st.button("Check Answers"):
        if len(st.session_state.answers) < len(st.session_state.questions):
            st.warning("Please answer all questions before checking.")
        else:
            score = 0
            for i, q in enumerate(st.session_state.questions):
                if st.session_state.answers.get(i) == q["correct_answer"]:
                    score += 1

            total = len(st.session_state.questions)
            st.divider()

            if score == total:
                st.success(f"Perfect! You got {score}/{total} correct!")
            elif score >= total / 2:
                st.info(f"Good job! You got {score}/{total} correct.")
            else:
                st.warning(f"You got {score}/{total} correct. Keep studying!")

            st.subheader("Answer Key")
            for i, q in enumerate(st.session_state.questions):
                user_answer = st.session_state.answers.get(i, "No answer")
                correct = q["correct_answer"]
                if user_answer == correct:
                    st.write(f"Question {i + 1}: Correct!")
                else:
                    st.write(f"Question {i + 1}: Your answer: {user_answer} | Correct answer: {correct}")

What does the scoring logic do?

The code loops through each question and compares the user's answer in st.session_state.answers against the correct_answer field from the quiz data. It tallies correct answers into a score variable.

Depending on how well the user did, it shows a green success message, a blue info message, or an orange warning. The answer key at the bottom reveals where they went wrong.

  • Save app.py.
  • Switch back to your browser. Streamlit auto-reloads when you save, so the page should update on its own. If it doesn't, click **Always rerun** in the top-right banner.
  • Paste some study notes into the text area (at least 50 characters). Click **Generate Quiz**. Select answers for each question, then click **Check Answers**.
  • You should see a score message (like "You got 3/5 correct.") and an answer key showing which questions you got right or wrong.

Quiz not appearing after clicking Generate?

  • Make sure you pasted at least 50 characters of study notes. Shorter input triggers the validation error you built in the previous step.
  • Check your terminal for any error messages. A common issue is indentation. The if "questions" in st.session_state block should be at the top level (no indentation), not nested inside the button's if block.
  • help me figure out why my Streamlit quiz isn't displaying after I click Generate Quiz

✔️ Awesome, I've got everything!

Great. Double check you've saved your file and that the quiz generation, answer selection, and scoring all work end-to-end.

ⓧ I'd like to double check the full code

Here is the full app.py file as it should look at the end of this step:

import os
import json
import streamlit as st
from groq import Groq
from dotenv import load_dotenv

load_dotenv()

client = Groq(api_key=os.environ.get("GROQ_API_KEY"))


def generate_quiz(notes, num_questions):
    """Generate quiz questions from study notes using Groq."""
    if len(notes.strip()) < 50:
        st.error("Please enter at least 50 characters of study notes.")
        return None

    prompt = f"""Based on the following study notes, generate exactly {num_questions} multiple-choice quiz questions.

Return your response as a JSON array where each element has this structure:
{{
    "question": "The question text",
    "options": ["Option A", "Option B", "Option C", "Option D"],
    "correct_answer": "The correct option text exactly as it appears in options"
}}

Only return the JSON array, no other text.

Study notes:
{notes}"""

    try:
        chat_completion = client.chat.completions.create(
            messages=[
                {
                    "role": "system",
                    "content": "You are a helpful study assistant that creates quiz questions. Always respond with valid JSON only."
                },
                {
                    "role": "user",
                    "content": prompt
                }
            ],
            model="llama-3.3-70b-versatile",
            temperature=0.7,
            max_tokens=2048
        )

        response_text = chat_completion.choices[0].message.content
        questions = json.loads(response_text)
        return questions

    except json.JSONDecodeError:
        st.error("The AI returned an unexpected format. Please try again.")
        return None
    except Exception as e:
        st.error(f"An error occurred: {str(e)}")
        return None


# Streamlit App
st.title("Study Quiz Generator")
st.write("Paste your study notes below and get instant quiz questions powered by AI!")

notes = st.text_area(
    "Your study notes:",
    height=200,
    placeholder="Paste your lecture notes, textbook passages, or any study material here..."
)

num_questions = st.slider("Number of questions:", min_value=1, max_value=5, value=3)

if st.button("Generate Quiz"):
    if notes.strip():
        with st.spinner("Generating your quiz..."):
            questions = generate_quiz(notes, num_questions)
            if questions:
                st.session_state.questions = questions
                st.session_state.notes = notes
                st.session_state.answers = {}
                st.session_state.hints = {}
    else:
        st.warning("Please enter some study notes first.")

if "questions" in st.session_state and st.session_state.questions:
    st.divider()
    st.subheader("Your Quiz")

    for i, q in enumerate(st.session_state.questions):
        st.write(f"**Question {i + 1}:** {q['question']}")

        answer = st.radio(
            f"Select your answer for Question {i + 1}:",
            q["options"],
            key=f"q_{i}",
            index=None
        )
        if answer:
            st.session_state.answers[i] = answer

        st.write("")

    if st.button("Check Answers"):
        if len(st.session_state.answers) < len(st.session_state.questions):
            st.warning("Please answer all questions before checking.")
        else:
            score = 0
            for i, q in enumerate(st.session_state.questions):
                if st.session_state.answers.get(i) == q["correct_answer"]:
                    score += 1

            total = len(st.session_state.questions)
            st.divider()

            if score == total:
                st.success(f"Perfect! You got {score}/{total} correct!")
            elif score >= total / 2:
                st.info(f"Good job! You got {score}/{total} correct.")
            else:
                st.warning(f"You got {score}/{total} correct. Keep studying!")

            st.subheader("Answer Key")
            for i, q in enumerate(st.session_state.questions):
                user_answer = st.session_state.answers.get(i, "No answer")
                correct = q["correct_answer"]
                if user_answer == correct:
                    st.write(f"Question {i + 1}: Correct!")
                else:
                    st.write(f"Question {i + 1}: Your answer: {user_answer} | Correct answer: {correct}")

Your study quiz generator is fully functional. You can paste any notes, generate questions, answer them, and see exactly how you scored. Next up, you'll take it further with a Secret Mission that adds AI-powered hints for when you're stuck.

Secret mission

Add a Hint Feature

Your quiz works great, but what about when you're stuck on a tough question? In this bonus challenge, you'll add a "Get Hint" button that makes a second AI call to Groq, generating a contextual clue that nudges you toward the answer without giving it away.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally with Groq's free tier, so there are no ongoing costs.

Resources you used:

  • Project folder containing app.py, .env, requirements.txt, and your virtual environment.
  • Groq API key stored in your .env file.
  • Groq account (free tier, no credit card attached).
  • Python 3.13 installed on your system.

Keep everything running

No action needed. Choose this if you're still actively building or plan to extend the quiz generator with new features.

  • Your project folder stays on your Desktop ready to use.
  • Your Groq API key remains active. The free tier has no charges, so leaving it does not cost anything.
  • Python 3.13 stays installed and is useful for future Python projects.

Pause - I'll come back to this later

Stop any running processes to free up memory. Your files and accounts stay intact for when you return.

  • If Streamlit is still running in your terminal, press Ctrl+C to stop it.
  • Close the browser tab that was running your quiz app.
  • Your project folder, virtual environment, and Groq API key all remain ready to pick up where you left off.

Delete - I don't want to use this again

Remove all project resources and start fresh. Follow each step below to fully clean up.

  • If Streamlit is still running, press Ctrl+C in the terminal to stop it.
  • Delete your project folder by running these commands in your terminal:

macOS

cd ~/Desktop
rm -rf study-quiz-generator

Windows

cd ~\Desktop
Remove-Item -Recurse -Force study-quiz-generator

This removes app.py, .env, requirements.txt, and your virtual environment in one step.

  • To revoke your Groq API key, log in to the Groq Console at console.groq.com and navigate to the API Keys section in the left sidebar. Find the key you created for this project and delete it.
  • If you want to fully delete your Groq account, contact Groq support through the console by clicking your organization name in the upper-right corner and selecting Chat with us.

What about Python?

Python 3.13 is a general-purpose tool useful for many future projects. Most learners choose to keep it installed. If you do want to remove it, use Add or remove programs on Windows or delete the Python framework from /Library/Frameworks/Python.framework on macOS.

That's a Wrap!

That's a Wrap!

Nice work! You just built a fully functional AI-powered study quiz generator from scratch and deployed it as a web app running in your browser.

You've learned how to:

  • Set up a Python project and connected to the Groq API to send requests to the Llama 3.3 70B model.
  • Designed a system prompt that reliably generates structured quiz questions as JSON from any text input.
  • Built a complete web interface with Streamlit that displays interactive quizzes with radio buttons, scores your answers, and shows an answer key.
  • Secret Mission: Added a contextual hint feature that makes a second AI call to help users who are stuck without revealing the answer.

Ready to quiz yourself?