How to implement recursive functions within streamlit scripts?

I want to build a spell bee app on Streamlit.
It will play a word when a button is clicked, wait for the word to be spelled in a text box, and then play another word and repeat the process as long as the answers are correct.
I wanted to have a recursive function that will call itself if the answer is correct, but due to Streamlit’s behaviour of rerunning the entire script when a button is pressed, I am having troubles implementing the functionality.

Here is the python script which works perfectly as a CLI app:

import json
import random
import os
from pprint import PrettyPrinter
from PyDictionary import PyDictionary
from pathlib import Path

from gtts import gTTS
from playsound import playsound

pp = PrettyPrinter(compact=True, sort_dicts=True, width=100)
dictionary = PyDictionary()


def play(word: str, slow: bool = False) -> None:
    """Pronounces `word`

    Args:
        word (str): Word to be pronounced
        slow (bool, optional): Pronounces `word` slowly. Defaults to False.
    """

    t1 = gTTS(word, slow=slow)
    if os.path.exists("audio.mp3"):
        os.remove("audio.mp3")
    t1.save("audio.mp3")
    return playsound("audio.mp3")


# --------- RECURSIVE FUNCTION ---------
def recurse(words: list, score: int = 0) -> None:
    """Recursive scoring function.

    Args:
        words (list): List of words to choose from
        score (int, optional): Intermediate score. Defaults to 0.

    """

    word = random.choice(words)
    words.remove(word)
    play(word)

    answer = (
        input(
            'Enter spelling (type "define" to get the definition, or "repeat" to repeat the pronounciation slowly): '
        )
        .lower()
        .strip()
    )

    while answer in ["define", "repeat"]:

        if answer == "define":
            if meaning := dictionary.meaning(word, disable_errors=True):
                pp.pprint(meaning)
            else:
                print("Definition not available")
        else:
            play(word, slow=True)
        answer = (
            input('Enter spelling (type "repeat" to repeat slowly): ').lower().strip()
        )

    if answer == word:
        score += 1
        print(f"Correct! Score: {score}")
        recurse(words, score)
    else:
        print(f'Wrong answer. The correct answer is "{word}"\nFinal score: {score}')


# ---------- RUN ---------

with open("words.txt", "r") as f:
    words = json.load(f)

recurse(words)

Below is a barebones implementation of the above in Streamlit:

import json
import random
import os
from pprint import PrettyPrinter
from pathlib import Path
import sys

from gtts import gTTS
from playsound import playsound

pp = PrettyPrinter(compact=True, sort_dicts=True, width=100)

import streamlit as st

# --- PLAY WORD ----
def play(word: str, slow: bool = False) -> None:
    """Pronounces `word`

    Args:
        word (str): Word to be pronounced
        slow (bool, optional): Pronounces `word` slowly. Defaults to False.
    """

    t1 = gTTS(word, slow=slow)
    if os.path.exists("audio.mp3"):
        os.remove("audio.mp3")
    t1.save("audio.mp3")
    return playsound("audio.mp3")


# --------- RECURSIVE FUNCTION ---------
def recurse(words: list, score: int = 0) -> None:
    """Recursive scoring function.

    Args:
        words (list): List of words to choose from
        score (int, optional): Intermediate score. Defaults to 0.
    """

    word = random.choice(words)
    words.remove(word)
    play(word)
    st.write(word)
    if answer := st.text_input("Enter spelling: ").lower().strip():
        if answer == word:
            score += 1
            st.success(f"Correct! Score: {score}")
            recurse(words, score)
        else:
            st.error(
                f'Wrong answer. The correct answer is "{word}"\nFinal score: {score}'
            )
            sys.exit()


# ---------- RUN ---------
import contextlib

with open("words.txt", "r") as f:
    words = json.load(f)

with contextlib.suppress(SystemExit):
    if st.button("Hear word"):
        recurse(words)

As soon as text is entered in the text box, the whole app resets.

Can this even be implemented in Streamlit? I tried using session state to save words already displayed to have an idea of the current state, but no luck.

Thanks in advance!