Unique game ID
Browse files- app.py +7 -2
- data_manager.py +35 -9
app.py
CHANGED
|
@@ -326,6 +326,8 @@ def build_street_html(image_url: str) -> str:
|
|
| 326 |
def gr_start_game(difficulty: str, username: str, request: gr.Request):
|
| 327 |
rounds: List[Dict[str, Any]] = []
|
| 328 |
date_str = datetime.now(timezone.utc).date().isoformat()
|
|
|
|
|
|
|
| 329 |
for _ in range(3):
|
| 330 |
loc = pick_random_location(difficulty)
|
| 331 |
round_id = generate_id()
|
|
@@ -341,6 +343,7 @@ def gr_start_game(difficulty: str, username: str, request: gr.Request):
|
|
| 341 |
})
|
| 342 |
|
| 343 |
user_sessions[username] = {
|
|
|
|
| 344 |
'difficulty': difficulty,
|
| 345 |
'rounds': rounds,
|
| 346 |
'total_score': 0.0,
|
|
@@ -881,6 +884,7 @@ with gr.Blocks(css=APP_CSS, title="LLM GeoGuessr") as demo:
|
|
| 881 |
|
| 882 |
# Record this round's data immediately to prevent abuse
|
| 883 |
sess = user_sessions.get(username, {})
|
|
|
|
| 884 |
round_idx = next((i for i, rr in enumerate(sess.get('rounds', [])) if rr['id'] == rid), 0) + 1
|
| 885 |
round_record = {
|
| 886 |
"round_number": round_idx,
|
|
@@ -893,7 +897,7 @@ with gr.Blocks(css=APP_CSS, title="LLM GeoGuessr") as demo:
|
|
| 893 |
"ai_score": float(round(rnd.get('ai_score', 0))) if rnd.get('ai_score') else 0.0,
|
| 894 |
"ai_analysis": rnd.get('ai_analysis', ''),
|
| 895 |
}
|
| 896 |
-
data_manager.update_game_record(username, round_data=round_record)
|
| 897 |
except Exception as e:
|
| 898 |
yield "", txt + f"\n\n[Error] {e}"
|
| 899 |
return
|
|
@@ -966,9 +970,10 @@ with gr.Blocks(css=APP_CSS, title="LLM GeoGuessr") as demo:
|
|
| 966 |
if not sess or idx >= len(sess['rounds']):
|
| 967 |
total_human = sum(float(r.get('human_score', 0.0)) for r in sess.get('rounds', []))
|
| 968 |
total_ai = sum(float(r.get('ai_score', 0.0)) for r in sess.get('rounds', []))
|
|
|
|
| 969 |
|
| 970 |
# Update the final scores (rounds already recorded incrementally)
|
| 971 |
-
data_manager.update_game_record(username, final_score=total_human, final_ai_score=total_ai)
|
| 972 |
|
| 973 |
winner_message = "It's a tie!"
|
| 974 |
if total_human > total_ai:
|
|
|
|
| 326 |
def gr_start_game(difficulty: str, username: str, request: gr.Request):
|
| 327 |
rounds: List[Dict[str, Any]] = []
|
| 328 |
date_str = datetime.now(timezone.utc).date().isoformat()
|
| 329 |
+
game_id = str(uuid.uuid4()) # Generate unique game ID
|
| 330 |
+
|
| 331 |
for _ in range(3):
|
| 332 |
loc = pick_random_location(difficulty)
|
| 333 |
round_id = generate_id()
|
|
|
|
| 343 |
})
|
| 344 |
|
| 345 |
user_sessions[username] = {
|
| 346 |
+
'game_id': game_id,
|
| 347 |
'difficulty': difficulty,
|
| 348 |
'rounds': rounds,
|
| 349 |
'total_score': 0.0,
|
|
|
|
| 884 |
|
| 885 |
# Record this round's data immediately to prevent abuse
|
| 886 |
sess = user_sessions.get(username, {})
|
| 887 |
+
game_id = sess.get('game_id', '')
|
| 888 |
round_idx = next((i for i, rr in enumerate(sess.get('rounds', [])) if rr['id'] == rid), 0) + 1
|
| 889 |
round_record = {
|
| 890 |
"round_number": round_idx,
|
|
|
|
| 897 |
"ai_score": float(round(rnd.get('ai_score', 0))) if rnd.get('ai_score') else 0.0,
|
| 898 |
"ai_analysis": rnd.get('ai_analysis', ''),
|
| 899 |
}
|
| 900 |
+
data_manager.update_game_record(username, game_id, round_data=round_record)
|
| 901 |
except Exception as e:
|
| 902 |
yield "", txt + f"\n\n[Error] {e}"
|
| 903 |
return
|
|
|
|
| 970 |
if not sess or idx >= len(sess['rounds']):
|
| 971 |
total_human = sum(float(r.get('human_score', 0.0)) for r in sess.get('rounds', []))
|
| 972 |
total_ai = sum(float(r.get('ai_score', 0.0)) for r in sess.get('rounds', []))
|
| 973 |
+
game_id = sess.get('game_id', '')
|
| 974 |
|
| 975 |
# Update the final scores (rounds already recorded incrementally)
|
| 976 |
+
data_manager.update_game_record(username, game_id, final_score=total_human, final_ai_score=total_ai)
|
| 977 |
|
| 978 |
winner_message = "It's a tie!"
|
| 979 |
if total_human > total_ai:
|
data_manager.py
CHANGED
|
@@ -42,25 +42,47 @@ def get_todays_games(token: str) -> list:
|
|
| 42 |
|
| 43 |
def has_user_played_today(username: str, todays_games: list) -> bool:
|
| 44 |
"""Checks if a user has completed a game today."""
|
|
|
|
|
|
|
| 45 |
for game in todays_games:
|
| 46 |
if game.get("username") == username and game.get("completed", False):
|
| 47 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
return False
|
| 49 |
|
| 50 |
-
def get_user_game_today(username: str, todays_games: list) -> dict:
|
| 51 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
for game in todays_games:
|
| 53 |
if game.get("username") == username:
|
| 54 |
-
|
|
|
|
|
|
|
|
|
|
| 55 |
return None
|
| 56 |
|
| 57 |
-
def update_game_record(username: str, round_data: dict = None, final_score: float = None, final_ai_score: float = None):
|
| 58 |
"""
|
| 59 |
Updates or creates a game record for a user after each round.
|
| 60 |
This ensures data is recorded incrementally and prevents abuse.
|
| 61 |
|
| 62 |
Args:
|
| 63 |
username: The player's username
|
|
|
|
| 64 |
round_data: Single round details to append to the record
|
| 65 |
final_score: Final total human score (only set when game is complete)
|
| 66 |
final_ai_score: Final total AI score (only set when game is complete)
|
|
@@ -74,8 +96,8 @@ def update_game_record(username: str, round_data: dict = None, final_score: floa
|
|
| 74 |
# Fetch the latest records
|
| 75 |
todays_games = get_todays_games(token=write_token)
|
| 76 |
|
| 77 |
-
# Find existing game record for this user today
|
| 78 |
-
existing_game = get_user_game_today(username, todays_games)
|
| 79 |
|
| 80 |
if existing_game:
|
| 81 |
# Update existing record
|
|
@@ -92,6 +114,7 @@ def update_game_record(username: str, round_data: dict = None, final_score: floa
|
|
| 92 |
# Create new game record
|
| 93 |
game_record = {
|
| 94 |
"username": username,
|
|
|
|
| 95 |
"human_score": 0.0, # Will be updated when game completes
|
| 96 |
"ai_score": 0.0, # Will be updated when game completes
|
| 97 |
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
@@ -122,9 +145,12 @@ def update_game_record(username: str, round_data: dict = None, final_score: floa
|
|
| 122 |
if 'tmp_file_path' in locals() and os.path.exists(tmp_file_path):
|
| 123 |
os.remove(tmp_file_path)
|
| 124 |
|
| 125 |
-
def record_game(username: str, score: float, rounds_data: list = None, ai_score: float = None):
|
| 126 |
"""
|
| 127 |
Legacy function - now just calls update_game_record with final score.
|
| 128 |
Kept for backwards compatibility.
|
| 129 |
"""
|
| 130 |
-
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
def has_user_played_today(username: str, todays_games: list) -> bool:
|
| 44 |
"""Checks if a user has completed a game today."""
|
| 45 |
+
today_date = datetime.now(timezone.utc).date().isoformat()
|
| 46 |
+
|
| 47 |
for game in todays_games:
|
| 48 |
if game.get("username") == username and game.get("completed", False):
|
| 49 |
+
# Additional check: ensure the game's timestamp is from today
|
| 50 |
+
game_timestamp = game.get("timestamp", "")
|
| 51 |
+
if game_timestamp:
|
| 52 |
+
try:
|
| 53 |
+
game_date = datetime.fromisoformat(game_timestamp.replace('Z', '+00:00')).date().isoformat()
|
| 54 |
+
if game_date == today_date:
|
| 55 |
+
return True
|
| 56 |
+
except:
|
| 57 |
+
# If we can't parse the timestamp, assume it's from today (since it's in todays_games)
|
| 58 |
+
return True
|
| 59 |
+
else:
|
| 60 |
+
# If no timestamp, assume it's from today (since it's in todays_games)
|
| 61 |
+
return True
|
| 62 |
return False
|
| 63 |
|
| 64 |
+
def get_user_game_today(username: str, todays_games: list, game_id: str = None) -> dict:
|
| 65 |
+
"""
|
| 66 |
+
Gets the user's game record for today, if it exists.
|
| 67 |
+
If game_id is provided, returns the specific game with that ID.
|
| 68 |
+
Otherwise, returns the first game found for the user.
|
| 69 |
+
"""
|
| 70 |
for game in todays_games:
|
| 71 |
if game.get("username") == username:
|
| 72 |
+
if game_id and game.get("game_id") == game_id:
|
| 73 |
+
return game
|
| 74 |
+
elif not game_id:
|
| 75 |
+
return game
|
| 76 |
return None
|
| 77 |
|
| 78 |
+
def update_game_record(username: str, game_id: str, round_data: dict = None, final_score: float = None, final_ai_score: float = None):
|
| 79 |
"""
|
| 80 |
Updates or creates a game record for a user after each round.
|
| 81 |
This ensures data is recorded incrementally and prevents abuse.
|
| 82 |
|
| 83 |
Args:
|
| 84 |
username: The player's username
|
| 85 |
+
game_id: Unique identifier for this game session
|
| 86 |
round_data: Single round details to append to the record
|
| 87 |
final_score: Final total human score (only set when game is complete)
|
| 88 |
final_ai_score: Final total AI score (only set when game is complete)
|
|
|
|
| 96 |
# Fetch the latest records
|
| 97 |
todays_games = get_todays_games(token=write_token)
|
| 98 |
|
| 99 |
+
# Find existing game record for this user today with this specific game_id
|
| 100 |
+
existing_game = get_user_game_today(username, todays_games, game_id)
|
| 101 |
|
| 102 |
if existing_game:
|
| 103 |
# Update existing record
|
|
|
|
| 114 |
# Create new game record
|
| 115 |
game_record = {
|
| 116 |
"username": username,
|
| 117 |
+
"game_id": game_id,
|
| 118 |
"human_score": 0.0, # Will be updated when game completes
|
| 119 |
"ai_score": 0.0, # Will be updated when game completes
|
| 120 |
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
|
|
| 145 |
if 'tmp_file_path' in locals() and os.path.exists(tmp_file_path):
|
| 146 |
os.remove(tmp_file_path)
|
| 147 |
|
| 148 |
+
def record_game(username: str, score: float, rounds_data: list = None, ai_score: float = None, game_id: str = None):
|
| 149 |
"""
|
| 150 |
Legacy function - now just calls update_game_record with final score.
|
| 151 |
Kept for backwards compatibility.
|
| 152 |
"""
|
| 153 |
+
if not game_id:
|
| 154 |
+
import uuid
|
| 155 |
+
game_id = str(uuid.uuid4())
|
| 156 |
+
update_game_record(username, game_id, final_score=score, final_ai_score=ai_score)
|