Spaces:
Sleeping
Sleeping
| # app.py | |
| """TriviaVerse Enhanced - Advanced Quiz Application""" | |
| import streamlit as st | |
| import time | |
| from datetime import datetime | |
| import random | |
| # Removed dotenv import and os import as .env file is not persisting | |
| # from dotenv import load_dotenv | |
| # import os | |
| from config.settings import ( | |
| DIFFICULTY_LEVELS, | |
| BADGES, | |
| RANDOM_TOPICS, | |
| ) | |
| from config.themes import THEMES | |
| from config.languages import SUPPORTED_LANGUAGES | |
| from modules.mcq_generator import generate_quiz_set | |
| from modules.flashcard_generator import generate_smart_deck | |
| from modules.fact_game import generate_random_fact | |
| from modules.adaptive_engine import AdaptiveEngine | |
| from utils.ui_components import ( | |
| apply_custom_theme, | |
| display_user_stats, | |
| display_badges, | |
| create_progress_chart, | |
| animated_success, | |
| create_quiz_card, | |
| render_flashcard, | |
| ) | |
| from utils.score_tracker import ScoreTracker | |
| from utils.mobile_responsive import responsive_columns, responsive_css | |
| from utils.user_auth import init_authentication, authenticate_user | |
| from utils.challenge_manager import ChallengeManager | |
| from modules.info_page import display_page_info | |
| from utils.translator import get_translated_texts | |
| # Removed load_dotenv() call as .env file is not persisting | |
| # load_dotenv() | |
| # --- Page Config --- | |
| st.set_page_config( | |
| page_title="TriviaVerse", | |
| page_icon="🎯", | |
| layout="wide", | |
| initial_sidebar_state="expanded", | |
| ) | |
| # --- App State Initialization --- | |
| if "user_id" not in st.session_state: | |
| st.session_state.user_id = st.session_state.get("username", f"user_{int(time.time())}") | |
| if "score_tracker" not in st.session_state: | |
| st.session_state.score_tracker = ScoreTracker(st.session_state.user_id) | |
| if "theme" not in st.session_state: | |
| st.session_state.theme = "default" | |
| if "language" not in st.session_state: | |
| st.session_state.language = "en" | |
| if "topic" not in st.session_state: | |
| st.session_state.topic = "Python programming" | |
| # --- Load UI Text based on Language --- | |
| ui = get_translated_texts(st.session_state.language) | |
| # --- Update Page Title with Translated Text --- | |
| st.title(f"{ui.get('app_name', 'TriviaVerse')} - {ui.get('enhanced_edition', 'Enhanced Edition')}") | |
| # Initialize other session state variables | |
| if "current_streak" not in st.session_state: | |
| st.session_state.current_streak = 0 | |
| if "adaptive_engine" not in st.session_state: | |
| st.session_state.adaptive_engine = AdaptiveEngine(st.session_state.user_id) | |
| if "answer" not in st.session_state: | |
| st.session_state.answer = None | |
| if "mcq_quiz_questions" not in st.session_state: | |
| st.session_state.mcq_quiz_questions = [] | |
| if "current_question_index" not in st.session_state: | |
| st.session_state.current_question_index = 0 | |
| if "quiz_started" not in st.session_state: | |
| st.session_state.quiz_started = False | |
| if "quiz_results" not in st.session_state: | |
| st.session_state.quiz_results = [] | |
| if "flashcard_deck" not in st.session_state: | |
| st.session_state.flashcard_deck = [] | |
| if "current_flashcard_index" not in st.session_state: | |
| st.session_state.current_flashcard_index = 0 | |
| if "challenge_manager" not in st.session_state: | |
| st.session_state.challenge_manager = ChallengeManager() | |
| if "current_challenge_id" not in st.session_state: | |
| st.session_state.current_challenge_id = None | |
| if "challenge_quiz_questions" not in st.session_state: | |
| st.session_state.challenge_quiz_questions = [] | |
| if "challenge_current_question_index" not in st.session_state: | |
| st.session_state.challenge_current_question_index = 0 | |
| if "game_state" not in st.session_state: | |
| st.session_state.game_state = "menu" | |
| if "challenge_created_id" not in st.session_state: | |
| st.session_state.challenge_created_id = None | |
| if "current_page" not in st.session_state: | |
| st.session_state.current_page = "home" | |
| # --- Authentication --- | |
| init_authentication() | |
| if not authenticate_user(): | |
| st.stop() | |
| # --- UI Rendering --- | |
| apply_custom_theme(st.session_state.theme) | |
| st.markdown(responsive_css(), unsafe_allow_html=True) | |
| def render_homepage(): | |
| st.markdown(f""" | |
| <div class="homepage-container" style="text-align: center;"> | |
| <h1 class="homepage-title">{ui.get('app_name', 'TriviaVerse')}</h1> | |
| <p class="homepage-description">{ui.get('app_description', 'A Dynamic Quiz App')}</p> | |
| <br><br> | |
| """, unsafe_allow_html=True) | |
| if st.button(ui.get('start_your_learning_journey', "Start Your Learning Journey"), key="start_journey"): | |
| st.session_state.current_page = "game_modes" | |
| st.rerun() | |
| with st.sidebar: | |
| st.title(f"🎯 {ui.get('app_name', 'TriviaVerse')}") | |
| st.markdown(f"### 🎮 {ui.get('game_settings', 'Game Settings')}") | |
| if st.button(f"🏠 {ui.get('home', 'Home')}", key="sidebar_home"): | |
| st.session_state.current_page = "home" | |
| st.rerun() | |
| st.divider() | |
| lang_choice_key = st.selectbox( | |
| f"🌐 {ui.get('choose_language', 'Choose Language')}", | |
| options=list(SUPPORTED_LANGUAGES.keys()), | |
| index=list(SUPPORTED_LANGUAGES.values()).index(st.session_state.language) | |
| ) | |
| if SUPPORTED_LANGUAGES[lang_choice_key] != st.session_state.language: | |
| st.session_state.language = SUPPORTED_LANGUAGES[lang_choice_key] | |
| st.rerun() | |
| st.info(f"👤 {ui.get('welcome', 'Welcome')}, {st.session_state.get('username', 'Guest')}!") | |
| theme_select = st.selectbox( | |
| f"🎨 {ui.get('choose_theme', 'Choose Theme')}", | |
| list(THEMES.keys()), | |
| index=list(THEMES.keys()).index(st.session_state.theme), | |
| ) | |
| if theme_select != st.session_state.theme: | |
| st.session_state.theme = theme_select | |
| st.rerun() | |
| st.divider() | |
| mode = st.radio( | |
| f"🎲 {ui.get('select_game_mode', 'Select Game Mode')}", | |
| [ui.get(k, k) for k in ["mcq_quiz", "flashcards", "fact_game", "challenge_mode", "page_info"]], | |
| ) | |
| use_adaptive = st.checkbox(f"🤖 {ui.get('use_adaptive_difficulty', 'Use Adaptive Difficulty')}", value=True) | |
| difficulty = st.session_state.adaptive_engine.get_recommended_difficulty() if use_adaptive else st.selectbox( | |
| f"⚡ {ui.get('difficulty_level', 'Difficulty Level')}", | |
| list(DIFFICULTY_LEVELS.keys()), | |
| ) | |
| if use_adaptive: | |
| st.info(f"{ui.get('recommended', 'Recommended')}: {difficulty}") | |
| st.markdown(f"### 📖 {ui.get('choose_topic', 'Choose Topic')}") | |
| def update_topic_text_input(): | |
| st.session_state.topic = st.session_state.topic_text_input | |
| st.text_input(ui.get("enter_topic", "Enter topic"), value=st.session_state.topic, key="topic_text_input", on_change=update_topic_text_input) | |
| def update_random_topic(): | |
| st.session_state.topic = random.choice(RANDOM_TOPICS) | |
| if st.button(f"🎲 {ui.get('random_topic', 'Random')}", on_click=update_random_topic): | |
| pass # The topic is updated by the on_click callback | |
| st.markdown(f"### 🔥 {ui.get('trending_topics', 'Trending Topics')}") | |
| def update_trending_topic(): | |
| if st.session_state.trending_topic_select: | |
| st.session_state.topic = st.session_state.trending_topic_select | |
| st.selectbox(ui.get("quick_select", "Quick select"), [""] + RANDOM_TOPICS, key="trending_topic_select", on_change=update_trending_topic) | |
| if mode in [ui.get("mcq_quiz"), ui.get("challenge_mode")]: | |
| st.markdown(f"### 🔢 {ui.get('number_of_questions', 'Number of Questions')}") | |
| st.session_state.num_questions = st.selectbox(ui.get("select_number_of_questions", "Select number"), [5, 10, 15], index=1) | |
| st.divider() | |
| st.markdown(f"### 📊 {ui.get('your_stats', 'Your Stats')}") | |
| stats = st.session_state.score_tracker.get_stats() | |
| display_user_stats(stats, ui) | |
| if st.button(f"🚪 {ui.get('logout', 'Logout')}", type="secondary", use_container_width=True): | |
| st.session_state.clear() | |
| st.rerun() | |
| if st.session_state.current_page == "home": | |
| render_homepage() | |
| else: | |
| # Header with user dashboard | |
| col1, col2 = st.columns([2, 1]) | |
| with col1: | |
| st.markdown(f"<h1 class='app-title'>🎮 {ui.get('app_name', 'TriviaVerse')} - {ui.get('enhanced_edition', 'Enhanced Edition')}</h1>", unsafe_allow_html=True) | |
| st.markdown(f"*{ui.get('app_description', 'A gamified learning platform powered by Wikimedia')}*") | |
| with col2: | |
| # Display current time and greeting | |
| current_hour = datetime.now().hour | |
| greeting = ( | |
| ui.get("good_morning", "Good morning") | |
| if current_hour < 12 | |
| else ui.get("good_afternoon", "Good afternoon") | |
| if current_hour < 18 | |
| else ui.get("good_evening", "Good evening") | |
| ) | |
| st.markdown(f"### {greeting}, {st.session_state.get('username', 'Learner')}! 👋") | |
| st.caption(f"{datetime.now().strftime('%B %d, %Y - %I:%M %p')}") | |
| # Display user statistics dashboard | |
| stats = st.session_state.score_tracker.get_stats() | |
| display_user_stats(stats, ui) | |
| # Display badges | |
| if stats["badges"]: | |
| st.markdown(f"### 🏅 {ui.get('your_achievements', 'Your Achievements')}") | |
| display_badges(stats["badges"], ui) | |
| # Progress chart | |
| with st.expander(f"📈 {ui.get('view_detailed_progress', 'View Detailed Progress')}", expanded=False): | |
| if stats["quizzes_completed"] > 0: | |
| fig = create_progress_chart(stats, ui) | |
| st.plotly_chart(fig, use_container_width=True) | |
| else: | |
| st.info(ui.get("complete_quizzes_prompt", "Complete some quizzes to see your progress chart!")) | |
| st.divider() | |
| # Main game area | |
| if mode == ui.get("mcq_quiz"): | |
| st.header(ui.get("mcq_quiz")) | |
| # Initialize or reset quiz | |
| if not st.session_state.quiz_started: | |
| if st.button(ui.get("start_new_quiz", "Start New Quiz"), type="primary", use_container_width=True): | |
| with st.spinner(ui.get("generating_quiz_questions", "Generating quiz questions...")): | |
| st.session_state.mcq_quiz_questions = generate_quiz_set( | |
| st.session_state.topic, | |
| difficulty, | |
| st.session_state.num_questions | |
| ) | |
| if st.session_state.mcq_quiz_questions: | |
| st.session_state.current_question_index = 0 | |
| st.session_state.quiz_started = True | |
| st.session_state.answered = False | |
| st.session_state.question_start_time = time.time() | |
| st.session_state.hints_used = 0 | |
| st.session_state.quiz_results = [] # Reset quiz results | |
| st.rerun() | |
| else: | |
| st.error(ui.get("failed_quiz_generation", "Failed to generate quiz questions. Please try a different topic.")) | |
| if st.session_state.quiz_started and st.session_state.mcq_quiz_questions: | |
| # Display current question | |
| current_mcq = st.session_state.mcq_quiz_questions[st.session_state.current_question_index] | |
| question_number = st.session_state.current_question_index + 1 | |
| total_questions = len(st.session_state.mcq_quiz_questions) | |
| st.subheader(f"{ui.get('question', 'Question')} {question_number} {ui.get('of', 'of')} {total_questions}") | |
| col1, col2, col3 = responsive_columns([1, 1, 1], [1, 1, 1]) | |
| with col2: | |
| time_limit = DIFFICULTY_LEVELS[difficulty]["time_limit"] | |
| st.info(f"⏱️ {ui.get('time_limit', 'Time Limit')}: {time_limit}s") | |
| with col3: | |
| hints_allowed = DIFFICULTY_LEVELS[difficulty]["hints_allowed"] | |
| st.info(f"💡 {ui.get('hints', 'Hints')}: {hints_allowed}") | |
| # Timer | |
| elapsed_time = int(time.time() - st.session_state.question_start_time) | |
| remaining_time = max(0, time_limit - elapsed_time) | |
| if remaining_time > 0 and not st.session_state.answered: | |
| st.progress(remaining_time / time_limit) | |
| st.caption(f"⏱️ {ui.get('time_remaining', 'Time remaining')}: {remaining_time}s") | |
| create_quiz_card( | |
| current_mcq["question"], | |
| current_mcq["options"], | |
| key="answer" | |
| ) | |
| if hints_allowed > st.session_state.hints_used: | |
| if st.button(f"💡 {ui.get('get_hint', 'Get Hint')} ({hints_allowed - st.session_state.hints_used} {ui.get('left', 'left')})"): | |
| st.session_state.hints_used += 1 | |
| st.info(f"💡 {ui.get('hint', 'Hint')}: {current_mcq['explanation'][:100]}...") | |
| col1_btn, col2_btn, col3_btn = st.columns([1, 2, 1]) | |
| with col2_btn: | |
| if st.button(ui.get("submit_answer", "Submit Answer"), type="primary", use_container_width=True): | |
| is_correct = st.session_state.answer == current_mcq["correct_answer"] | |
| st.session_state.answered = True | |
| st.session_state.quiz_results.append({ | |
| "question": current_mcq["question"], | |
| "user_answer": st.session_state.answer, | |
| "correct_answer": current_mcq["correct_answer"], | |
| "is_correct": is_correct, | |
| "explanation": current_mcq["explanation"] | |
| }) | |
| st.session_state.adaptive_engine.update_performance(is_correct, difficulty, topic=current_mcq.get("topic")) | |
| if is_correct: | |
| st.session_state.current_streak += 1 | |
| points = st.session_state.score_tracker.add_quiz_result("MCQ Quiz", 1, 1, difficulty) | |
| animated_success(f"{ui.get('correct', 'Correct')}! +{points} {ui.get('points', 'points')}") | |
| st.balloons() | |
| else: | |
| st.session_state.current_streak = 0 | |
| st.error(f"❌ {ui.get('incorrect', 'Incorrect')}. {ui.get('the_answer_was', 'The answer was')}: {current_mcq['correct_answer']}") | |
| st.info(f"📚 {current_mcq['explanation']}") | |
| st.rerun() | |
| elif st.session_state.answered: | |
| if st.session_state.current_question_index < total_questions - 1: | |
| if st.button(ui.get("next_question", "Next Question"), type="secondary", use_container_width=True): | |
| st.session_state.current_question_index += 1 | |
| st.session_state.answered = False | |
| st.session_state.question_start_time = time.time() | |
| st.session_state.hints_used = 0 | |
| st.rerun() | |
| else: | |
| st.success(ui.get("quiz_completed", "Quiz Completed!")) | |
| st.session_state.quiz_started = False | |
| st.session_state.mcq_quiz_questions = [] | |
| st.session_state.current_question_index = 0 | |
| st.markdown(f"### {ui.get('quiz_results_summary', 'Quiz Results Summary')}") | |
| for i, result in enumerate(st.session_state.quiz_results): | |
| st.markdown(f"**{ui.get('question', 'Question')} {i+1}:** {result['question']}") | |
| if result['is_correct']: | |
| st.success(f"✅ {ui.get('your_answer', 'Your Answer')}: {result['user_answer']} ({ui.get('correct', 'Correct')})") | |
| else: | |
| st.error(f"❌ {ui.get('your_answer', 'Your Answer')}: {result['user_answer']} ({ui.get('incorrect', 'Incorrect')})") | |
| st.info(f"{ui.get('correct_answer', 'Correct Answer')}: {result['correct_answer']}") | |
| st.caption(f"{ui.get('explanation', 'Explanation')}: {result['explanation']}") | |
| st.divider() | |
| if st.button(ui.get("start_new_quiz", "Start New Quiz"), type="primary", use_container_width=True): | |
| st.rerun() | |
| else: | |
| st.error(f"⏱️ {ui.get('times_up', 'Time is up!')}") | |
| st.session_state.answered = True | |
| st.session_state.quiz_results.append({ | |
| "question": current_mcq["question"], | |
| "user_answer": ui.get("no_answer_timed_out", "No answer (Time's up)"), | |
| "correct_answer": current_mcq["correct_answer"], | |
| "is_correct": False, | |
| "explanation": current_mcq["explanation"] | |
| }) | |
| st.session_state.score_tracker.add_quiz_result("MCQ Quiz", 0, 1, difficulty) | |
| st.rerun() | |
| elif mode == ui.get("flashcards"): | |
| st.header(ui.get("interactive_flashcards", "Interactive Flashcards")) | |
| if st.button(ui.get("generate_flashcard", "Generate Flashcard"), type="primary"): | |
| with st.spinner(ui.get("creating_flashcard_deck", "Creating flashcard deck...")): | |
| st.session_state.flashcard_deck = generate_smart_deck( | |
| st.session_state.topic, | |
| deck_size=10, | |
| difficulty=difficulty, | |
| adaptive_engine=st.session_state.adaptive_engine | |
| ) | |
| if st.session_state.flashcard_deck: | |
| st.session_state.current_flashcard_index = 0 | |
| st.session_state.card_flipped = False | |
| st.rerun() | |
| else: | |
| st.error(ui.get("failed_flashcard_generation", "Failed to generate flashcards. Please try a different topic.")) | |
| if st.session_state.flashcard_deck: | |
| current_flashcard = st.session_state.flashcard_deck[st.session_state.current_flashcard_index] | |
| st.subheader(f"{ui.get('flashcard', 'Flashcard')} {st.session_state.current_flashcard_index + 1} {ui.get('of', 'of')} {len(st.session_state.flashcard_deck)}") | |
| col1, col2, col3 = st.columns([1, 2, 1]) | |
| with col2: | |
| render_flashcard( | |
| current_flashcard["front"], | |
| current_flashcard["back"], | |
| is_flipped=st.session_state.get("card_flipped", False), | |
| ) | |
| if not st.session_state.get("card_flipped", False): | |
| if st.button(ui.get("flip_card", "Flip Card"), use_container_width=True): | |
| st.session_state.card_flipped = True | |
| st.rerun() | |
| else: | |
| st.write("") | |
| btn_col1, btn_col2 = st.columns(2) | |
| with btn_col1: | |
| if st.button(ui.get("got_it", "Got it!"), use_container_width=True): | |
| st.session_state.adaptive_engine.update_performance( | |
| is_correct=True, | |
| difficulty=current_flashcard.get("difficulty", "Medium"), | |
| item_id=current_flashcard.get("item_id"), | |
| topic=current_flashcard.get("topic") | |
| ) | |
| points = st.session_state.score_tracker.add_quiz_result("Flashcards", 1, 1, current_flashcard.get("difficulty", "Medium")) | |
| animated_success(f"{ui.get('great', 'Great')}! +{points} {ui.get('points', 'points')}") | |
| st.session_state.card_flipped = False | |
| if st.session_state.current_flashcard_index < len(st.session_state.flashcard_deck) - 1: | |
| st.session_state.current_flashcard_index += 1 | |
| else: | |
| st.success(ui.get("flashcard_deck_completed", "Flashcard Deck Completed!")) | |
| st.session_session.flashcard_deck = [] | |
| st.session_state.current_flashcard_index = 0 | |
| st.rerun() | |
| with btn_col2: | |
| if st.button(ui.get("need_practice", "Need Practice"), use_container_width=True): | |
| st.session_state.adaptive_engine.update_performance( | |
| is_correct=False, | |
| difficulty=current_flashcard.get("difficulty", "Medium"), | |
| item_id=current_flashcard.get("item_id"), | |
| topic=current_flashcard.get("topic") | |
| ) | |
| st.session_state.score_tracker.add_quiz_result("Flashcards", 0, 1, current_flashcard.get("difficulty", "Medium")) | |
| st.session_state.card_flipped = False | |
| if st.session_state.current_flashcard_index < len(st.session_state.flashcard_deck) - 1: | |
| st.session_state.current_flashcard_index += 1 | |
| else: | |
| st.info(ui.get("flashcard_deck_completed_practice", "Flashcard Deck Completed. Keep practicing!")) | |
| st.session_state.flashcard_deck = [] | |
| st.session_state.current_flashcard_index = 0 | |
| st.rerun() | |
| else: | |
| st.info(ui.get("no_flashcards_in_deck", "No flashcards in deck. Click 'Generate Flashcard' to create a new one.")) | |
| elif mode == ui.get("fact_game"): | |
| st.header(ui.get("random_fact_game", "Random Fact Game")) | |
| col1, col2 = st.columns([2, 1]) | |
| with col1: | |
| if st.button(ui.get("get_random_fact", "Get Random Fact"), type="primary", use_container_width=True): | |
| if "current_fact" in st.session_state: | |
| del st.session_state["current_fact"] | |
| with st.spinner(ui.get("finding_interesting_fact", "Finding an interesting fact...")): | |
| fact = generate_random_fact() | |
| if fact.get("status"): | |
| st.session_state.current_fact = fact | |
| st.session_state.fact_start_time = time.time() | |
| else: | |
| st.session_state.current_fact = {"status": False} | |
| with col2: | |
| st.info(f"⏱️ {ui.get('quick_read_challenge', 'Quick Read Challenge')}: 15s") | |
| if "current_fact" in st.session_state: | |
| fact = st.session_state.current_fact | |
| if fact.get("status"): | |
| elapsed = int(time.time() - st.session_state.get("fact_start_time", time.time())) | |
| remaining = max(0, 15 - elapsed) | |
| if remaining > 0: | |
| st.progress(remaining / 15) | |
| st.markdown( | |
| f""" | |
| <div class="quiz-container"> | |
| <h3>🌟 {ui.get('did_you_know', 'Did you know?')}</h3> | |
| <p style="font-size: 18px; line-height: 1.8;">{fact["fact"]}</p> | |
| <p style="margin-top: 20px; color: #666;">{ui.get('topic', 'Topic')}: <strong>{fact["topic"]}</strong></p> | |
| </div> | |
| """, | |
| unsafe_allow_html=True, | |
| ) | |
| if st.button(ui.get("interesting_next_fact", "Interesting! Next fact")): | |
| points = st.session_state.score_tracker.add_quiz_result("Fact Game", 1, 1, difficulty) | |
| animated_success(f"{ui.get('knowledge_gained', 'Knowledge gained')}! +{points} {ui.get('points', 'points')}") | |
| del st.session_state["current_fact"] | |
| else: | |
| st.success(ui.get("times_up_next_fact", "Time's up! Ready for the next fact?")) | |
| if st.button(ui.get("next_fact", "Next Fact")): | |
| del st.session_state["current_fact"] | |
| else: | |
| st.error(ui.get("failed_fact_generation", "Failed to generate fact. Please try again.")) | |
| elif mode == ui.get("challenge_mode"): | |
| st.header(ui.get("challenge_mode", "Challenge Mode")) | |
| if not st.session_state.current_challenge_id: | |
| tab1, tab2 = st.tabs([ui.get("create_challenge", "Create Challenge"), ui.get("join_challenge", "Join Challenge")]) | |
| with tab1: | |
| st.subheader(ui.get("create_new_challenge", "Create a New Challenge")) | |
| with st.form("create_challenge_form"): | |
| challenge_topic = st.text_input(ui.get("challenge_topic", "Challenge Topic"), value=st.session_state.topic) | |
| challenge_difficulty = st.selectbox( | |
| ui.get("challenge_difficulty", "Challenge Difficulty"), | |
| list(DIFFICULTY_LEVELS.keys()), | |
| index=list(DIFFICULTY_LEVELS.keys()).index(difficulty), | |
| ) | |
| challenge_num_questions = st.selectbox( | |
| ui.get("number_of_questions", "Number of Questions"), | |
| [5, 10, 15], | |
| index=[5, 10, 15].index(st.session_state.get("num_questions", 5)), | |
| ) | |
| create_challenge_submitted = st.form_submit_button(ui.get("create_challenge", "Create Challenge"), type="primary") | |
| if create_challenge_submitted: | |
| new_challenge_id = st.session_state.challenge_manager.create_challenge( | |
| creator_id=st.session_state.user_id, | |
| topic=challenge_topic, | |
| difficulty=challenge_difficulty, | |
| num_questions=challenge_num_questions | |
| ) | |
| st.session_state.challenge_created_id = new_challenge_id | |
| st.success(f"{ui.get('challenge_created', 'Challenge created! Share this ID')}: **{new_challenge_id}**") | |
| if st.session_state.challenge_created_id: | |
| st.info(f"{ui.get('challenge_id', 'Challenge ID')}: **{st.session_state.challenge_created_id}**") | |
| if st.button(ui.get("start_challenge_play", "Start Challenge Play"), key="start_created_challenge"): | |
| st.session_state.current_challenge_id = st.session_state.challenge_created_id | |
| st.session_state.challenge_quiz_questions = generate_quiz_set( | |
| st.session_state.challenge_manager.get_challenge(st.session_state.current_challenge_id)["topic"], | |
| st.session_state.challenge_manager.get_challenge(st.session_state.current_challenge_id)["difficulty"], | |
| st.session_state.challenge_manager.get_challenge(st.session_state.current_challenge_id)["num_questions"] | |
| ) | |
| st.session_state.challenge_quiz_started = True | |
| st.session_state.challenge_current_question_index = 0 | |
| st.session_state.answered = False | |
| st.session_state.question_start_time = time.time() | |
| st.session_state.hints_used = 0 | |
| st.session_state.quiz_results = [] | |
| st.session_state.challenge_created_id = None | |
| st.rerun() | |
| with tab2: | |
| st.subheader(ui.get("join_existing_challenge", "Join an Existing Challenge")) | |
| with st.form("join_challenge_form"): | |
| join_challenge_id = st.text_input(ui.get("enter_challenge_id", "Enter Challenge ID")) | |
| join_challenge_submitted = st.form_submit_button(ui.get("join_challenge", "Join Challenge"), type="primary") | |
| if join_challenge_submitted: | |
| challenge = st.session_state.challenge_manager.get_challenge(join_challenge_id) | |
| if challenge: | |
| st.success(f"{ui.get('joined_challenge', 'Joined challenge')}: {challenge['topic']} ({challenge['difficulty']})") | |
| st.session_state.current_challenge_id = join_challenge_id | |
| st.session_state.challenge_quiz_questions = generate_quiz_set( | |
| challenge["topic"], | |
| challenge["difficulty"], | |
| challenge["num_questions"] | |
| ) | |
| st.session_state.challenge_quiz_started = True | |
| st.session_state.challenge_current_question_index = 0 | |
| st.session_state.answered = False | |
| st.session_state.question_start_time = time.time() | |
| st.session_state.hints_used = 0 | |
| st.session_state.quiz_results = [] | |
| st.rerun() | |
| else: | |
| st.error(ui.get("challenge_not_found", "Challenge not found. Please check the ID.")) | |
| if st.session_state.current_challenge_id: | |
| current_challenge = st.session_state.challenge_manager.get_challenge(st.session_state.current_challenge_id) | |
| if current_challenge: | |
| st.markdown(f"---") | |
| st.subheader(f"{ui.get('active_challenge', 'Active Challenge')}: {current_challenge['topic']} ({current_challenge['difficulty']})") | |
| st.write(f"{ui.get('created_by', 'Created by')}: {current_challenge['creator_id']}") | |
| st.write(f"{ui.get('questions', 'Questions')}: {current_challenge['num_questions']}") | |
| st.markdown(f"#### {ui.get('participants', 'Participants')}:") | |
| if current_challenge["participants"]: | |
| for participant_id, p_data in current_challenge["participants"].items(): | |
| st.write(f"- {participant_id}: {ui.get('score', 'Score')} {p_data['score']} ({ui.get('completed', 'Completed')}: {p_data.get('completed_at', 'N/A')})") | |
| else: | |
| st.write(ui.get("no_participants_yet", "No participants yet.")) | |
| if st.session_state.challenge_quiz_started and st.session_state.challenge_quiz_questions: | |
| current_mcq = st.session_state.challenge_quiz_questions[st.session_state.challenge_current_question_index] | |
| question_number = st.session_state.challenge_current_question_index + 1 | |
| total_questions = len(st.session_state.challenge_quiz_questions) | |
| st.subheader(f"{ui.get('challenge_question', 'Challenge Question')} {question_number} {ui.get('of', 'of')} {total_questions}") | |
| col1, col2, col3 = responsive_columns([1, 1, 1], [1, 1, 1]) | |
| with col2: | |
| time_limit = DIFFICULTY_LEVELS[current_challenge['difficulty']]["time_limit"] | |
| st.info(f"⏱️ {ui.get('time_limit', 'Time Limit')}: {time_limit}s") | |
| with col3: | |
| hints_allowed = DIFFICULTY_LEVELS[current_challenge['difficulty']]["hints_allowed"] | |
| st.info(f"💡 {ui.get('hints', 'Hints')}: {hints_allowed}") | |
| elapsed_time = int(time.time() - st.session_state.question_start_time) | |
| remaining_time = max(0, time_limit - elapsed_time) | |
| if remaining_time > 0 and not st.session_state.answered: | |
| st.progress(remaining_time / time_limit) | |
| st.caption(f"⏱️ {ui.get('time_remaining', 'Time remaining')}: {remaining_time}s") | |
| create_quiz_card(current_mcq["question"], current_mcq["options"], key="challenge_answer") | |
| if hints_allowed > st.session_state.hints_used: | |
| if st.button(f"💡 {ui.get('get_hint', 'Get Hint')} ({hints_allowed - st.session_state.hints_used} {ui.get('left', 'left')})"): | |
| st.session_state.hints_used += 1 | |
| st.info(f"💡 {ui.get('hint', 'Hint')}: {current_mcq['explanation'][:100]}...") | |
| col1_btn, col2_btn, col3_btn = st.columns([1, 2, 1]) | |
| with col2_btn: | |
| if st.button(ui.get("submit_answer", "Submit Answer"), type="primary", use_container_width=True): | |
| is_correct = st.session_state.challenge_answer == current_mcq["correct_answer"] | |
| st.session_state.answered = True | |
| st.session_state.quiz_results.append({ | |
| "question": current_mcq["question"], | |
| "user_answer": st.session_state.challenge_answer, | |
| "correct_answer": current_mcq["correct_answer"], | |
| "is_correct": is_correct, | |
| "explanation": current_mcq["explanation"] | |
| }) | |
| st.session_state.adaptive_engine.update_performance(is_correct, current_challenge['difficulty'], topic=current_mcq.get("topic")) | |
| if is_correct: | |
| st.session_state.current_streak += 1 | |
| points = st.session_state.score_tracker.add_quiz_result("Challenge Mode", 1, 1, current_challenge['difficulty']) | |
| animated_success(f"{ui.get('correct', 'Correct')}! +{points} {ui.get('points', 'points')}") | |
| st.balloons() | |
| else: | |
| st.session_state.current_streak = 0 | |
| st.error(f"❌ {ui.get('incorrect', 'Incorrect')}. {ui.get('the_answer_was', 'The answer was')}: {current_mcq['correct_answer']}") | |
| st.info(f"📚 {current_mcq['explanation']}") | |
| st.rerun() | |
| elif st.session_state.answered: | |
| if st.session_state.challenge_current_question_index < total_questions - 1: | |
| if st.button(ui.get("next_question", "Next Question"), type="secondary", use_container_width=True): | |
| st.session_state.challenge_current_question_index += 1 | |
| st.session_state.answered = False | |
| st.session_state.question_start_time = time.time() | |
| st.session_state.hints_used = 0 | |
| st.rerun() | |
| else: | |
| st.success(ui.get("challenge_quiz_completed", "Challenge Quiz Completed!")) | |
| final_score = sum(1 for r in st.session_state.quiz_results if r['is_correct']) | |
| st.session_state.challenge_manager.update_challenge_score( | |
| st.session_state.current_challenge_id, | |
| st.session_state.user_id, | |
| final_score, | |
| st.session_state.quiz_results | |
| ) | |
| st.session_state.challenge_quiz_started = False | |
| st.session_state.challenge_quiz_questions = [] | |
| st.session_state.challenge_current_question_index = 0 | |
| st.session_state.current_challenge_id = None | |
| st.rerun() | |
| else: | |
| st.error(f"⏱️ {ui.get('times_up', 'Time is up!')}") | |
| st.session_state.answered = True | |
| st.session_state.quiz_results.append({ | |
| "question": current_mcq["question"], | |
| "user_answer": ui.get("no_answer_timed_out", "No answer (Time's up)"), | |
| "correct_answer": current_mcq["correct_answer"], | |
| "is_correct": False, | |
| "explanation": current_mcq["explanation"] | |
| }) | |
| st.session_state.score_tracker.add_quiz_result("Challenge Mode", 0, 1, difficulty) | |
| st.rerun() | |
| elif mode == ui.get("page_info"): | |
| st.header(ui.get("page_information", "Page Information")) | |
| st.write(ui.get("get_page_info_prompt", "Get detailed information and images for any topic.")) | |
| info_topic = st.text_input(ui.get("enter_topic_for_info", "Enter Topic for Information"), value=st.session_state.topic) | |
| num_images = st.slider(ui.get("number_of_images", "Number of Images"), 0, 5, 1) | |
| if st.button(ui.get("get_information", "Get Information"), type="primary"): | |
| with st.spinner(f"{ui.get('fetching_information_for', 'Fetching information for')} {info_topic}..."): | |
| display_page_info(info_topic, num_images) | |
| st.divider() | |
| st.markdown(f""" | |
| <div style='text-align: center'> | |
| <p>{ui.get('made_with', 'Made with')} ❤️ {ui.get('using_streamlit_and_wikimedia', 'using Streamlit and Wikimedia APIs')}</p> | |
| <p style='opacity: 0.7; font-size: 0.9em;'>{ui.get('app_name', 'TriviaVerse')} v2.0 - {ui.get('enhanced_edition', 'Enhanced Edition')}</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |