IPA-practice / app.py
MK-316's picture
Update app.py
bf41f69 verified
import pandas as pd
import random
import gradio as gr
import asyncio
# Load the CSV data asynchronously
async def load_data():
url = "IPA.csv"
try:
data = await asyncio.to_thread(pd.read_csv, url, encoding='utf-8')
if 'IPA' not in data.columns:
raise ValueError("The required 'IPA' column is missing in the data.")
return data
except Exception as e:
raise ValueError(f"Error loading data: {e}")
# Initial empty dataframe
df = pd.DataFrame()
# Properties to ask about for each IPA symbol
properties = ['Voicing', 'Place', 'Centrality', 'Oro-nasal', 'Manner']
# Generate a new question
def generate_question(used_ipa_symbols):
if df.empty or 'IPA' not in df.columns:
raise ValueError("IPA data is not loaded properly or missing.")
# Loop until we get a valid IPA symbol that hasn't been used yet
while True:
current_ipa = df.sample(1).iloc[0]
if not pd.isnull(current_ipa['IPA']) and current_ipa['IPA'] not in used_ipa_symbols:
available_properties = [prop for prop in properties if not pd.isnull(current_ipa[prop])]
if available_properties:
break
used_ipa_symbols.append(current_ipa['IPA'])
property_name = random.choice(available_properties)
question = f"IPA Symbol: {current_ipa['IPA']}\nWhat is the {property_name.lower()} of this IPA symbol?"
answer = current_ipa[property_name].lower()
return question, answer, used_ipa_symbols
# Check the answer and update the score and trials
def quiz_function(user_answer, correct_answer, score, trials):
if user_answer.lower() == correct_answer:
score += 1
result = f"Correct! The answer was '{correct_answer}'."
else:
result = f"Wrong! The correct answer was '{correct_answer}'."
trials += 1
return result, score, trials
# Initialize a dictionary to store session-specific data
user_sessions = {}
# Define the Gradio interface
def gradio_interface():
with gr.Blocks(css="""
#start_button, #submit_button, #quit_button {
width: 200px;
height: 50px;
font-size: 16px;
color: black;
background-color: #f0f0f0;
text-align: center;
padding: 0;
display: inline-block;
font-family: Arial, sans-serif;
vertical-align: middle;
line-height: 50px;
}
""") as app:
# Define the components with `elem_id` to apply custom CSS
name_input = gr.Textbox(label="Enter your name", placeholder="Your name")
start_button = gr.Button("Start Quiz", elem_id="start_button")
question_label = gr.Textbox(label="Question", interactive=False)
answer_input = gr.Textbox(label="Your Answer", placeholder="Type your answer here")
submit_button = gr.Button("Submit", elem_id="submit_button")
output_label = gr.Textbox(label="Result", interactive=False)
quit_button = gr.Button("Quit", elem_id="quit_button")
score_state = gr.State(0)
trials_state = gr.State(0)
used_ipa_symbols_state = gr.State([])
current_answer_state = gr.State("")
# Start quiz function with async loading
async def start_quiz(name):
global df
if not name:
yield gr.update(), gr.update(value="Please enter your name to start the quiz."), "", "", gr.update()
if df.empty:
# Display loading message
yield gr.update(), gr.update(value="Loading data... Please wait."), "", "", gr.update()
# Asynchronously load data
try:
df = await load_data()
yield gr.update(), gr.update(value="Data loaded. Starting the quiz."), "", "", gr.update()
except Exception as e:
yield gr.update(), gr.update(value=f"Failed to load data: {e}"), "", "", gr.update()
return # Exit the function if data fails to load
# Initialize user session for the current user
if name not in user_sessions:
user_sessions[name] = {
"score": 0,
"trials": 0,
"used_ipa_symbols": [],
"current_answer": ""
}
session = user_sessions[name]
# Generate first question
question, answer, used_ipa_symbols = generate_question(session["used_ipa_symbols"])
session["current_answer"] = answer
session["used_ipa_symbols"] = used_ipa_symbols
yield gr.update(value=question), "", "", gr.update(value="Submit"), gr.update()
# Submit answer function
def submit_answer(name, user_answer):
if name not in user_sessions:
return gr.update(), gr.update(value="Please start the quiz first."), "", "", gr.update()
session = user_sessions[name]
# Check the answer
result, score, trials = quiz_function(user_answer, session["current_answer"], session["score"], session["trials"])
session["score"] = score
session["trials"] = trials
# Generate next question
question, answer, used_ipa_symbols = generate_question(session["used_ipa_symbols"])
session["current_answer"] = answer
session["used_ipa_symbols"] = used_ipa_symbols
return gr.update(value=question), "", gr.update(value=result), gr.update(value="Submit"), gr.update()
# Quit quiz function
def quit_quiz(name):
if name not in user_sessions:
return gr.update(value="You haven't started the quiz yet."), gr.update()
session = user_sessions.pop(name)
return gr.update(value=f"Quiz ended. Well done, {name}! Your total score: {session['score']}/{session['trials']} points."), gr.update()
# Bind functions to buttons
start_button.click(
fn=start_quiz,
inputs=[name_input],
outputs=[question_label, answer_input, output_label, submit_button, quit_button]
)
submit_button.click(
fn=submit_answer,
inputs=[name_input, answer_input],
outputs=[question_label, answer_input, output_label, submit_button, quit_button]
)
quit_button.click(
fn=quit_quiz,
inputs=[name_input],
outputs=[output_label, quit_button]
)
return app
app = gradio_interface()
app.launch()