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()