AISeptember 29, 20253 min read

AI Flashcard Generator using Python and Streamlit

Turn any notes into flashcards with Python, Streamlit, and Mistral AI — automatic Q&A generation, flip animations, and CSV export for Anki.

Galvan

Galvan

Founder & Creator

Introduction

Making flashcards is tedious, which is exactly why it should be automated. Paste your notes, and this app asks Mistral to extract question-answer pairs — definitions, dates, cause-effect pairs — then presents them as flip-style cards with an Anki-compatible CSV export. It is the study-buddy application of the Mistral patterns from the chatbot tutorial, with the state handling of the quiz app.

The engineering lesson is structured output from an LLM: getting a model to return clean, parseable JSON instead of chatty prose — and recovering gracefully when it doesn't.

Features

  • Notes to cards — any pasted text becomes Q&A pairs.
  • Count control — generate 5 to 20 cards per run.
  • Flip-style review — question first, reveal answer on click.
  • Edit before export — fix any card the model fumbled.
  • Anki CSV export — import straight into spaced-repetition apps.
  • Prerequisites

  • Python 3.9+ — from python.org.
  • A free Mistral API key — from console.mistral.ai.
  • Dependencies:
  • code
    pip install streamlit requests pandas

    Step 1: Create the Script

    Save as flashcards.py:

    code
    import streamlit as st
    import requests
    import json
    import pandas as pd
    import re
    
    st.set_page_config(page_title="AI Flashcards", page_icon="🃏")
    st.title("🃏 AI Flashcard Generator")
    
    api_key = st.secrets.get("MISTRAL_API_KEY", "") or st.text_input("Mistral API key", type="password")
    notes = st.text_area("Your notes", height=220, placeholder="Paste lecture notes, a chapter summary, or documentation...")
    count = st.slider("How many cards?", 5, 20, 10)
    
    
    def generate_cards(notes, n, key):
        prompt = (
            f"Create {n} flashcards from these notes. "
            'Respond with ONLY a JSON array like: '
            '[{"q": "question", "a": "answer"}]. No other text.\n\nNotes:\n' + notes
        )
        r = requests.post(
            "https://api.mistral.ai/v1/chat/completions",
            headers={"Authorization": f"Bearer {key}"},
            json={"model": "mistral-small-latest",
                  "messages": [{"role": "user", "content": prompt}],
                  "temperature": 0.3},
            timeout=60,
        )
        raw = r.json()["choices"][0]["message"]["content"]
        match = re.search(r"\[.*\]", raw, re.S)
        return json.loads(match.group()) if match else []
    
    
    if st.button("⚡ Generate flashcards", type="primary", disabled=not (notes.strip() and api_key)):
        try:
            with st.spinner("Writing cards..."):
                st.session_state.cards = generate_cards(notes, count, api_key)
        except (json.JSONDecodeError, KeyError, requests.RequestException):
            st.error("The model returned something unexpected — try again or lower the count.")
    
    for i, card in enumerate(st.session_state.get("cards", [])):
        with st.expander(f"Card {i + 1}: {card['q'][:60]}"):
            q = st.text_input("Question", card["q"], key=f"q{i}")
            a = st.text_area("Answer", card["a"], height=70, key=f"a{i}")
            st.session_state.cards[i] = {"q": q, "a": a}
    
    if st.session_state.get("cards"):
        df = pd.DataFrame(st.session_state.cards)
        csv = df.to_csv(index=False, header=False).encode()
        st.download_button("⬇️ Download for Anki (CSV)", csv, "flashcards.csv", "text/csv")

    Step 2: Run the App

    code
    streamlit run flashcards.py

    Paste a few paragraphs of real notes, generate, and review — edit weak cards inline, then export to Anki.

    How It Works

    The prompt does three jobs at once: states the task, *shows the exact output format* (a JSON array example), and forbids everything else. Models are excellent mimics — showing one example is worth a paragraph of instructions. temperature: 0.3 keeps output factual and consistent; flashcards want reliability, not creativity.

    The extraction regex \[.*\] with DOTALL is the safety net: even when the model wraps its JSON in "Sure! Here are your cards:" the regex finds the array. This extract-don't-trust pattern is essential for every structured-output app — the same grounded thinking as the PDF chat app's context-only instruction.

    The editable expander list closes the human-in-the-loop gap: each card's text inputs write back into st.session_state.cards, so edits flow into the export automatically. The model drafts; you finalize.

    Common Errors & Fixes

  • `KeyError: 'q'` — the model returned JSON with different keys; strengthen the format example or validate entries before display.
  • Regex matched but `json.loads` still fails — trailing commas or single quotes in the model output; strip them or fall back to ast.literal_eval-style repair.
  • Cards repeat or are trivial — raise temperature slightly or add "avoid trivial yes/no questions" to the prompt; quality tracks note quality too.
  • 401 errors — the API key didn't reach the header; check st.secrets configuration.
  • Key Concepts

  • Few-shot format control — one JSON example beats a page of rules.
  • Low temperature — determinism for factual tasks.
  • Extract-don't-trust — regex out the payload, never parse raw chat text.
  • Human-in-the-loop editing — model drafts, user finalizes, export stays truthful.
  • What to Try Next

  • Add difficulty tags — ask the model to rate each card easy/medium/hard.
  • Add cloze deletion mode — fill-in-the-blank cards from definitions.
  • Generate from PDFs or transcripts — combine with the OCR app or Whisper transcriber.
  • Track review sessions with a localStorage-style JSON, like the habit tracker.
  • FAQ

    Are AI-generated flashcards good enough to study from?

    As drafts, yes — expect to edit 10–20%. The expander editors exist precisely because the model occasionally writes vague questions or misses the point you cared about.

    Why JSON instead of plain text Q&A lines?

    JSON is parseable and unambiguous — questions containing colons or newlines break line-based formats. Structured output scales; string splitting doesn't.

    Does the Anki CSV include formatting?

    Plain text only. Anki supports HTML in cards — wrap answers in <b> tags in the generator if you want bold terms after import.