Spaces:
Running
Running
Update app.py (#59)
Browse files- Update app.py (07cd3a879936e06995c80340c1c20c4c021aaaa3)
app.py
CHANGED
|
@@ -505,6 +505,51 @@ def compute_winners(game_id):
|
|
| 505 |
|
| 506 |
return df.head(3).to_dict(orient="records")
|
| 507 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 508 |
def join_game(game_id, username, avatar):
|
| 509 |
games = unified_get("games") or {}
|
| 510 |
if game_id not in games:
|
|
@@ -685,12 +730,21 @@ def home_page():
|
|
| 685 |
def create_game(topics=None, num_questions=5, auto_close=True, ai_topic=None):
|
| 686 |
"""
|
| 687 |
Creates a game and returns a unique game ID.
|
|
|
|
| 688 |
"""
|
| 689 |
topics = topics or []
|
| 690 |
|
| 691 |
# Generate a unique game ID
|
| 692 |
gid = f"GAME{int(time.time())}{random.randint(100,999)}"
|
| 693 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 694 |
# Save game data in session_state
|
| 695 |
if "games" not in st.session_state:
|
| 696 |
st.session_state["games"] = {}
|
|
@@ -700,69 +754,12 @@ def create_game(topics=None, num_questions=5, auto_close=True, ai_topic=None):
|
|
| 700 |
"auto_close": auto_close,
|
| 701 |
"ai_topic": ai_topic,
|
| 702 |
"players": [],
|
| 703 |
-
"closed": False
|
|
|
|
| 704 |
}
|
| 705 |
|
| 706 |
return gid
|
| 707 |
|
| 708 |
-
# 🔹 Function to render the Create Game page
|
| 709 |
-
def create_game_page():
|
| 710 |
-
st.header("Create Game")
|
| 711 |
-
|
| 712 |
-
# Host input
|
| 713 |
-
host = st.text_input(
|
| 714 |
-
"Host name",
|
| 715 |
-
value=st.session_state.get("username", "")
|
| 716 |
-
)
|
| 717 |
-
|
| 718 |
-
# Normal topics (static)
|
| 719 |
-
topics = st.multiselect(
|
| 720 |
-
"Topics",
|
| 721 |
-
list(questions_db.keys())
|
| 722 |
-
)
|
| 723 |
-
|
| 724 |
-
# AI topic input
|
| 725 |
-
ai_topic = st.text_input(
|
| 726 |
-
"AI Topic (optional)",
|
| 727 |
-
placeholder="Eg: IPL 2024, Python basics, Technology trends"
|
| 728 |
-
)
|
| 729 |
-
|
| 730 |
-
# Number of questions
|
| 731 |
-
num_q = st.selectbox(
|
| 732 |
-
"Number of questions",
|
| 733 |
-
[5, 10, 15, 20],
|
| 734 |
-
index=0
|
| 735 |
-
)
|
| 736 |
-
|
| 737 |
-
# Auto-close option
|
| 738 |
-
auto_close = st.checkbox(
|
| 739 |
-
"Auto-close when someone submits",
|
| 740 |
-
value=True
|
| 741 |
-
)
|
| 742 |
-
|
| 743 |
-
# Create Game button
|
| 744 |
-
if st.button("Create Game"):
|
| 745 |
-
# Input validation
|
| 746 |
-
if not host or (not topics and not ai_topic):
|
| 747 |
-
st.error("Enter host and choose topics or AI topic.")
|
| 748 |
-
return
|
| 749 |
-
|
| 750 |
-
# Call create_game correctly
|
| 751 |
-
gid = create_game(
|
| 752 |
-
topics=topics,
|
| 753 |
-
num_questions=num_q,
|
| 754 |
-
auto_close=auto_close,
|
| 755 |
-
ai_topic=ai_topic
|
| 756 |
-
)
|
| 757 |
-
|
| 758 |
-
# Save session state info
|
| 759 |
-
st.session_state['game_id'] = gid
|
| 760 |
-
st.session_state['username'] = host
|
| 761 |
-
st.session_state['avatar'] = st.session_state.get('avatar', '🎮')
|
| 762 |
-
st.session_state['is_host'] = True
|
| 763 |
-
|
| 764 |
-
st.success(f"Created game: {gid}")
|
| 765 |
-
|
| 766 |
# Join game
|
| 767 |
def join_game_page():
|
| 768 |
st.header("Join Game")
|
|
@@ -790,6 +787,9 @@ def join_game_page():
|
|
| 790 |
st.rerun()
|
| 791 |
|
| 792 |
# Play page
|
|
|
|
|
|
|
|
|
|
| 793 |
def play_page():
|
| 794 |
st.header("Play")
|
| 795 |
gid = st.session_state.get('game_id')
|
|
@@ -815,31 +815,33 @@ def play_page():
|
|
| 815 |
st.error("Game closed.")
|
| 816 |
return
|
| 817 |
|
| 818 |
-
|
|
|
|
| 819 |
if not questions:
|
| 820 |
st.error("No questions loaded.")
|
| 821 |
return
|
| 822 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 823 |
idx = st.session_state.get('current_index', 0)
|
| 824 |
if idx >= len(questions):
|
| 825 |
st.success("All done — submit!")
|
| 826 |
return
|
|
|
|
| 827 |
q = questions[idx]
|
| 828 |
st.subheader(f"Question {idx+1}/{len(questions)}")
|
| 829 |
st.write(q[0])
|
| 830 |
|
| 831 |
-
# Ensure timer always exists
|
| 832 |
-
if 'question_started_at' not in st.session_state or st.session_state['question_started_at'] is None:
|
| 833 |
-
st.session_state['question_started_at'] = time.time()
|
| 834 |
-
|
| 835 |
-
choice = st.radio("Choose an answer:", q[1], key=f"choice_{idx}")
|
| 836 |
-
|
| 837 |
elapsed = int(time.time() - st.session_state['question_started_at'])
|
| 838 |
time_limit = 15
|
| 839 |
st.markdown(f"**Time left:** {max(0, time_limit - elapsed)} seconds")
|
| 840 |
|
|
|
|
|
|
|
| 841 |
col1, col2 = st.columns(2)
|
| 842 |
-
|
| 843 |
with col1:
|
| 844 |
if st.button("Next"):
|
| 845 |
taken = time.time() - st.session_state['question_started_at']
|
|
@@ -854,8 +856,8 @@ def play_page():
|
|
| 854 |
st.session_state['answer_times'] = times
|
| 855 |
st.session_state['current_index'] = idx + 1
|
| 856 |
|
| 857 |
-
#
|
| 858 |
-
|
| 859 |
|
| 860 |
players = unified_get("players") or {}
|
| 861 |
if players.get(gid, {}).get(uname):
|
|
@@ -871,7 +873,7 @@ def play_page():
|
|
| 871 |
answers = st.session_state.get('answers', [""]*len(questions))
|
| 872 |
times = st.session_state.get('answer_times', [None]*len(questions))
|
| 873 |
answers[idx] = choice
|
| 874 |
-
times[idx] = time.time() - st.session_state
|
| 875 |
st.session_state['answers'] = answers
|
| 876 |
st.session_state['answer_times'] = times
|
| 877 |
score, flags = compute_score(questions, answers, times)
|
|
@@ -893,7 +895,7 @@ def play_page():
|
|
| 893 |
players[gid][uname]['submitted'] = True
|
| 894 |
players[gid][uname]['submitted_at'] = now
|
| 895 |
unified_set("players", players)
|
| 896 |
-
if game.get('
|
| 897 |
games[gid]['closed'] = True
|
| 898 |
games[gid]['closed_at'] = now
|
| 899 |
unified_set("games", games)
|
|
@@ -903,20 +905,7 @@ def play_page():
|
|
| 903 |
st.session_state['last_game'] = gid
|
| 904 |
st.session_state['current_index'] = 0
|
| 905 |
st.rerun()
|
| 906 |
-
|
| 907 |
-
st.markdown("---")
|
| 908 |
-
st.subheader("Game Chat")
|
| 909 |
-
msgs = unified_get("messages") or {}
|
| 910 |
-
game_msgs = msgs.get(gid, []) if isinstance(msgs, dict) else msgs
|
| 911 |
-
for m in game_msgs[-100:]:
|
| 912 |
-
st.write(f"**{m.get('user')}** [{m.get('ts')}]: {m.get('text')}")
|
| 913 |
-
new_msg = st.text_input("Send message to game", key=f"chat_{gid}")
|
| 914 |
-
if st.button("Send", key=f"send_{gid}"):
|
| 915 |
-
if new_msg and new_msg.strip():
|
| 916 |
-
unified_push_message(gid, {"user": uname, "text": new_msg.strip(), "ts": now_iso()})
|
| 917 |
-
heartbeat_unified(gid, uname)
|
| 918 |
-
st.rerun()
|
| 919 |
-
|
| 920 |
# Friends page
|
| 921 |
def friends_page():
|
| 922 |
st.header("Friends")
|
|
|
|
| 505 |
|
| 506 |
return df.head(3).to_dict(orient="records")
|
| 507 |
|
| 508 |
+
# ----------------- Create Game Page -----------------
|
| 509 |
+
def create_game_page():
|
| 510 |
+
st.header("Create Game")
|
| 511 |
+
|
| 512 |
+
host = st.text_input(
|
| 513 |
+
"Host name",
|
| 514 |
+
value=st.session_state.get("username", "")
|
| 515 |
+
)
|
| 516 |
+
|
| 517 |
+
# 🔹 Normal topics (static)
|
| 518 |
+
topics = st.multiselect(
|
| 519 |
+
"Topics",
|
| 520 |
+
list(questions_db.keys())
|
| 521 |
+
)
|
| 522 |
+
|
| 523 |
+
# 🔥 NEW: AI topic input
|
| 524 |
+
ai_topic = st.text_input(
|
| 525 |
+
"AI Topic (optional)",
|
| 526 |
+
placeholder="Eg: IPL 2024, Space, Python"
|
| 527 |
+
)
|
| 528 |
+
|
| 529 |
+
num_questions = st.number_input("Number of Questions", min_value=1, max_value=20, value=5)
|
| 530 |
+
auto_close = st.checkbox("Auto-close game after submission?", value=True)
|
| 531 |
+
|
| 532 |
+
if st.button("Create Game"):
|
| 533 |
+
if not host:
|
| 534 |
+
st.warning("Please enter your name.")
|
| 535 |
+
return
|
| 536 |
+
if not topics and not ai_topic:
|
| 537 |
+
st.warning("Please select at least one topic or enter an AI topic.")
|
| 538 |
+
return
|
| 539 |
+
|
| 540 |
+
# Pass AI topic to create_game
|
| 541 |
+
gid = create_game(topics=topics, num_questions=num_questions, auto_close=auto_close, ai_topic=ai_topic)
|
| 542 |
+
|
| 543 |
+
st.success(f"Game created! Game ID: {gid}")
|
| 544 |
+
st.session_state['game_id'] = gid
|
| 545 |
+
st.session_state['username'] = host
|
| 546 |
+
|
| 547 |
+
# Optional: generate AI questions immediately if AI topic is provided
|
| 548 |
+
if ai_topic:
|
| 549 |
+
st.info(f"AI questions will be generated for: {ai_topic}")
|
| 550 |
+
# Here you can call your AI question generator function if you have one
|
| 551 |
+
|
| 552 |
+
|
| 553 |
def join_game(game_id, username, avatar):
|
| 554 |
games = unified_get("games") or {}
|
| 555 |
if game_id not in games:
|
|
|
|
| 730 |
def create_game(topics=None, num_questions=5, auto_close=True, ai_topic=None):
|
| 731 |
"""
|
| 732 |
Creates a game and returns a unique game ID.
|
| 733 |
+
Stores questions to avoid KeyError on join/play.
|
| 734 |
"""
|
| 735 |
topics = topics or []
|
| 736 |
|
| 737 |
# Generate a unique game ID
|
| 738 |
gid = f"GAME{int(time.time())}{random.randint(100,999)}"
|
| 739 |
|
| 740 |
+
# Generate questions from selected topics (random)
|
| 741 |
+
questions = []
|
| 742 |
+
for t in topics:
|
| 743 |
+
qlist = questions_db.get(t, [])
|
| 744 |
+
if qlist:
|
| 745 |
+
questions.extend(random.sample(qlist, min(len(qlist), num_questions)))
|
| 746 |
+
questions = questions[:num_questions]
|
| 747 |
+
|
| 748 |
# Save game data in session_state
|
| 749 |
if "games" not in st.session_state:
|
| 750 |
st.session_state["games"] = {}
|
|
|
|
| 754 |
"auto_close": auto_close,
|
| 755 |
"ai_topic": ai_topic,
|
| 756 |
"players": [],
|
| 757 |
+
"closed": False,
|
| 758 |
+
"questions": questions # important to store questions
|
| 759 |
}
|
| 760 |
|
| 761 |
return gid
|
| 762 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 763 |
# Join game
|
| 764 |
def join_game_page():
|
| 765 |
st.header("Join Game")
|
|
|
|
| 787 |
st.rerun()
|
| 788 |
|
| 789 |
# Play page
|
| 790 |
+
# ----------------- Create Game -----------------
|
| 791 |
+
|
| 792 |
+
# ----------------- Play Page -----------------
|
| 793 |
def play_page():
|
| 794 |
st.header("Play")
|
| 795 |
gid = st.session_state.get('game_id')
|
|
|
|
| 815 |
st.error("Game closed.")
|
| 816 |
return
|
| 817 |
|
| 818 |
+
# Ensure questions exist
|
| 819 |
+
questions = st.session_state.get('game_questions') or game.get('questions', [])
|
| 820 |
if not questions:
|
| 821 |
st.error("No questions loaded.")
|
| 822 |
return
|
| 823 |
|
| 824 |
+
# Ensure timer exists
|
| 825 |
+
if 'question_started_at' not in st.session_state or st.session_state['question_started_at'] is None:
|
| 826 |
+
st.session_state['question_started_at'] = time.time()
|
| 827 |
+
|
| 828 |
idx = st.session_state.get('current_index', 0)
|
| 829 |
if idx >= len(questions):
|
| 830 |
st.success("All done — submit!")
|
| 831 |
return
|
| 832 |
+
|
| 833 |
q = questions[idx]
|
| 834 |
st.subheader(f"Question {idx+1}/{len(questions)}")
|
| 835 |
st.write(q[0])
|
| 836 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 837 |
elapsed = int(time.time() - st.session_state['question_started_at'])
|
| 838 |
time_limit = 15
|
| 839 |
st.markdown(f"**Time left:** {max(0, time_limit - elapsed)} seconds")
|
| 840 |
|
| 841 |
+
choice = st.radio("Choose an answer:", q[1], key=f"choice_{idx}")
|
| 842 |
+
|
| 843 |
col1, col2 = st.columns(2)
|
| 844 |
+
|
| 845 |
with col1:
|
| 846 |
if st.button("Next"):
|
| 847 |
taken = time.time() - st.session_state['question_started_at']
|
|
|
|
| 856 |
st.session_state['answer_times'] = times
|
| 857 |
st.session_state['current_index'] = idx + 1
|
| 858 |
|
| 859 |
+
# Do NOT reset question_started_at to None
|
| 860 |
+
st.session_state['question_started_at'] = time.time() # reset for next question
|
| 861 |
|
| 862 |
players = unified_get("players") or {}
|
| 863 |
if players.get(gid, {}).get(uname):
|
|
|
|
| 873 |
answers = st.session_state.get('answers', [""]*len(questions))
|
| 874 |
times = st.session_state.get('answer_times', [None]*len(questions))
|
| 875 |
answers[idx] = choice
|
| 876 |
+
times[idx] = time.time() - st.session_state.get('question_started_at', time.time())
|
| 877 |
st.session_state['answers'] = answers
|
| 878 |
st.session_state['answer_times'] = times
|
| 879 |
score, flags = compute_score(questions, answers, times)
|
|
|
|
| 895 |
players[gid][uname]['submitted'] = True
|
| 896 |
players[gid][uname]['submitted_at'] = now
|
| 897 |
unified_set("players", players)
|
| 898 |
+
if game.get('auto_close', True):
|
| 899 |
games[gid]['closed'] = True
|
| 900 |
games[gid]['closed_at'] = now
|
| 901 |
unified_set("games", games)
|
|
|
|
| 905 |
st.session_state['last_game'] = gid
|
| 906 |
st.session_state['current_index'] = 0
|
| 907 |
st.rerun()
|
| 908 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 909 |
# Friends page
|
| 910 |
def friends_page():
|
| 911 |
st.header("Friends")
|