Trivia1 / src /app.py
Bharath370's picture
app.py
7a07835 verified
# app.py
"""TriviaVerse Enhanced - Advanced Quiz Application"""
import streamlit as st
import time
from datetime import datetime
from config.settings import (
APP_NAME,
APP_DESCRIPTION,
DIFFICULTY_LEVELS,
BADGES,
RANDOM_TOPICS,
)
from config.themes import THEMES
from modules.mcq_generator import generate_mcq
from modules.flashcard_generator import generate_flashcard
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
# Page configuration
st.set_page_config(
page_title=f"{APP_NAME} - Enhanced Edition",
page_icon="๐ŸŽฏ",
layout="wide",
initial_sidebar_state="expanded",
menu_items={
"Get Help": "https://github.com/yourusername/triviaverse",
"Report a bug": "https://github.com/yourusername/triviaverse/issues",
"About": f"{APP_NAME} - A gamified learning platform powered by Wikimedia",
},
)
# Initialize authentication
init_authentication()
# Check authentication
if not authenticate_user():
st.stop()
# Initialize session state
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 "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)
# Initialize topic in session state
if "topic" not in st.session_state:
st.session_state.topic = "Python programming"
# Apply theme and responsive CSS
apply_custom_theme(st.session_state.theme)
st.markdown(responsive_css(), unsafe_allow_html=True)
# Sidebar with enhanced features
with st.sidebar:
st.title(f"๐ŸŽฏ {APP_NAME}")
st.markdown("### ๐ŸŽฎ Game Settings")
# User info
st.info(f"๐Ÿ‘ค Welcome, {st.session_state.get('username', 'Guest')}!")
# Theme selector
theme_select = st.selectbox(
"๐ŸŽจ 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()
# Game mode selection with icons
mode = st.radio(
"๐ŸŽฒ Select Game Mode",
["๐Ÿงฉ MCQ Quiz", "๐Ÿ“š Flashcards", "๐Ÿ’ก Fact Game"],
help="Choose your preferred learning mode",
)
# Adaptive difficulty
use_adaptive = st.checkbox("๐Ÿค– Use Adaptive Difficulty", value=True)
if use_adaptive:
difficulty = st.session_state.adaptive_engine.get_recommended_difficulty()
st.info(f"Recommended: {difficulty}")
else:
difficulty = st.selectbox(
"โšก Difficulty Level",
list(DIFFICULTY_LEVELS.keys()),
format_func=lambda x: f"{x} - {DIFFICULTY_LEVELS[x]['description']}",
)
# Enhanced topic input
st.markdown("### ๐Ÿ“– Choose Topic")
col1, col2 = st.columns([3, 1])
with col1:
# Use st.session_state.topic for the text input
st.session_state.topic = st.text_input(
"Enter topic", value=st.session_state.topic, label_visibility="collapsed"
)
with col2:
if st.button("๐ŸŽฒ", help="Random topic"):
import random # random is still needed here
st.session_state.topic = random.choice(RANDOM_TOPICS)
st.rerun()
# Popular topics
st.markdown("### ๐Ÿ”ฅ Trending Topics")
trending = [
"Machine Learning",
"Blockchain",
"Sustainability",
"Genetics",
"Cybersecurity",
]
selected_trending = st.selectbox(
"Quick select", [""] + trending, label_visibility="collapsed"
)
if selected_trending:
st.session_state.topic = selected_trending
st.rerun()
st.divider()
# User stats in sidebar
st.markdown("### ๐Ÿ“Š Your Stats")
stats = st.session_state.score_tracker.get_stats()
col1, col2 = st.columns(2)
with col1:
st.metric("Total Score", f"{stats['total_score']:,}")
st.metric("Current Streak", f"๐Ÿ”ฅ {stats['current_streak']}")
with col2:
st.metric("Quizzes", stats["quizzes_completed"])
st.metric("Best Streak", f"โญ {stats['best_streak']}")
# Display badges in sidebar
if stats["badges"]:
st.markdown("### ๐Ÿ† Your Badges")
for badge_id in stats["badges"]:
badge = BADGES.get(badge_id, {})
st.write(f"{badge.get('icon', '๐Ÿ†')} {badge.get('name', badge_id)}")
# Logout button
if st.button("๐Ÿšช Logout", type="secondary", use_container_width=True):
st.session_state.clear() # A more efficient way to clear the session state
st.rerun() # Rerun to go back to the login page
# Main content area
# Header with user dashboard
col1, col2 = st.columns([2, 1])
with col1:
st.title(f"๐ŸŽฎ {APP_NAME} - Enhanced Edition")
st.markdown(f"*{APP_DESCRIPTION}*")
with col2:
# Display current time and greeting
current_hour = datetime.now().hour
greeting = (
"Good morning"
if current_hour < 12
else "Good afternoon"
if current_hour < 18
else "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)
# Display badges
if stats["badges"]:
st.markdown("### ๐Ÿ… Your Achievements")
display_badges(stats["badges"])
# Progress chart
with st.expander("๐Ÿ“ˆ View Detailed Progress", expanded=False):
if stats["quizzes_completed"] > 0:
fig = create_progress_chart(stats)
st.plotly_chart(fig, use_container_width=True)
else:
st.info("Complete some quizzes to see your progress chart!")
st.divider()
# Main game area
if "MCQ" in mode:
st.header("๐Ÿงฉ Multiple Choice Quiz")
# Quiz controls
col1, col2, col3 = responsive_columns([1, 1, 1], [1, 1, 1])
with col1:
if st.button("๐ŸŽฏ Generate Question", type="primary", use_container_width=True):
with st.spinner("๐Ÿค” Generating question..."):
mcq = generate_mcq(st.session_state.topic, difficulty)
if mcq.get("status"):
st.session_state.current_question = mcq
st.session_state.question_start_time = time.time()
st.session_state.hints_used = 0
st.session_state.answered = False
with col2:
time_limit = DIFFICULTY_LEVELS[difficulty]["time_limit"]
st.info(f"โฑ๏ธ Time Limit: {time_limit}s")
with col3:
hints_allowed = DIFFICULTY_LEVELS[difficulty]["hints_allowed"]
st.info(f"๐Ÿ’ก Hints: {hints_allowed}")
# Display question if available
if hasattr(st.session_state, "current_question") and not st.session_state.get(
"answered", True
):
mcq = st.session_state.current_question
# Timer
elapsed_time = int(time.time() - st.session_state.question_start_time)
remaining_time = max(0, time_limit - elapsed_time)
if remaining_time > 0:
progress = remaining_time / time_limit
st.progress(progress)
st.caption(f"โฑ๏ธ Time remaining: {remaining_time}s")
# Quiz card
answer = create_quiz_card(mcq["question"], mcq["options"])
# Hint system
if hints_allowed > st.session_state.hints_used:
if st.button(
f"๐Ÿ’ก Get Hint ({hints_allowed - st.session_state.hints_used} left)"
):
st.session_state.hints_used += 1
st.info(f"๐Ÿ’ก Hint: {mcq['explanation'][:100]}...")
# Submit answer
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
if st.button(
"โœ… Submit Answer", type="primary", use_container_width=True
):
is_correct = answer == mcq["correct_answer"]
st.session_state.answered = True
# Update adaptive engine
st.session_state.adaptive_engine.update_performance(
is_correct, difficulty, topic=mcq.get("topic")
)
# Update streak
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"Correct! +{points} points")
st.balloons()
else:
st.session_state.current_streak = 0
st.error(
f"โŒ Incorrect. The answer was: {mcq['correct_answer']}"
)
st.info(f"๐Ÿ“š {mcq['explanation']}")
else:
st.error("โฑ๏ธ Time's up!")
st.session_state.answered = True
st.session_state.score_tracker.add_quiz_result("MCQ Quiz", 0, 1, difficulty)
elif "Flashcards" in mode:
st.header("๐Ÿ“š Interactive Flashcards")
# Flashcard controls
if st.button("๐Ÿ“‡ Generate Flashcard", type="primary"):
with st.spinner("Creating flashcard..."):
flashcard = generate_flashcard(st.session_state.topic)
if flashcard.get("status"):
st.session_state.current_flashcard = flashcard
st.session_state.card_flipped = False
# Display flashcard
if hasattr(st.session_state, "current_flashcard"):
flashcard = st.session_state.current_flashcard
# Create flashcard UI
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
render_flashcard(
front_content=flashcard["front"],
back_content=flashcard["back"],
is_flipped=st.session_state.get("card_flipped", False),
)
if not st.session_state.get("card_flipped", False):
if st.button("๐Ÿ”„ Flip Card", use_container_width=True):
st.session_state.card_flipped = True
st.rerun()
else:
# Add a small spacer for the buttons
st.write("")
btn_col1, btn_col2 = st.columns(2)
with btn_col1:
if st.button("โœ… Got it!", use_container_width=True):
points = st.session_state.score_tracker.add_quiz_result(
"Flashcards", 1, 1, difficulty
)
animated_success(f"Great! +{points} points")
st.session_state.card_flipped = False
with btn_col2:
if st.button("โŒ Need Practice", use_container_width=True):
st.session_state.score_tracker.add_quiz_result(
"Flashcards", 0, 1, difficulty
)
st.session_state.card_flipped = False
elif "Fact" in mode:
st.header("๐Ÿ’ก Random Fact Game")
# Fact game with timer
col1, col2 = st.columns([2, 1])
with col1:
if st.button("๐ŸŽฒ Get Random Fact", type="primary", use_container_width=True):
with st.spinner("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()
with col2:
st.info("โฑ๏ธ Quick Read Challenge: 15s")
# Display fact
if hasattr(st.session_state, "current_fact"):
fact = st.session_state.current_fact
# Timer for reading
elapsed = int(time.time() - st.session_state.fact_start_time)
remaining = max(0, 15 - elapsed)
if remaining > 0:
st.progress(remaining / 15)
st.markdown(
f"""
<div class="quiz-container">
<h3>๐ŸŒŸ Did you know?</h3>
<p style="font-size: 18px; line-height: 1.8;">{fact["fact"]}</p>
<p style="margin-top: 20px; color: #666;">Topic: <strong>{fact["topic"]}</strong></p>
</div>
""",
unsafe_allow_html=True,
)
if st.button("โœ… Interesting! Next fact"):
points = st.session_state.score_tracker.add_quiz_result(
"Fact Game", 1, 1, difficulty
)
animated_success(f"Knowledge gained! +{points} points")
del st.session_state["current_fact"]
st.rerun()
else:
st.success("โฑ๏ธ Time's up! Ready for the next fact?")
if st.button("Next Fact"):
del st.session_state["current_fact"]
st.rerun()
# Footer
st.divider()
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
st.markdown(
"""
<div style='text-align: center'>
<p>Made with โค๏ธ using Streamlit and Wikimedia APIs</p>
<p style='opacity: 0.7; font-size: 0.9em;'>TriviaVerse v2.0 - Enhanced Edition</p>
</div>
""",
unsafe_allow_html=True,
)