import base64 import json import os import uuid from datetime import datetime from pathlib import Path import pandas as pd import pytz import streamlit as st from datasets import Dataset, load_dataset, Features, Value from huggingface_hub import CommitScheduler # File paths as constants USERS_JSON = 'leaders/users.json' MATCHES_JSON = 'matches.json' OUTCOMES_JSON = 'match_outcomes.json' OUTCOMES = 'outcomes/match_outcomes.json' PLAYERS_JSON = 'players.json' image_path = 'ipl_image.png' PREDICTIONS_FOLDER = Path("predictions") PREDICTIONS_FOLDER.mkdir(parents=True, exist_ok=True) users_file = Path("leaders") / f"users.json" USERS_FOLDER = users_file.parent USERS_FOLDER.mkdir(parents=True, exist_ok=True) outcomes_file = Path("outcomes") / f"match_outcomes.json" OUTCOMES_FOLDER = outcomes_file.parent OUTCOMES_FOLDER.mkdir(parents=True, exist_ok=True) REDISTRIBUTED_JSON = Path("redistributed_matches.json") if not REDISTRIBUTED_JSON.exists(): REDISTRIBUTED_JSON.write_text("[]") # Initialize CommitScheduler scheduler = CommitScheduler( repo_id="DIS_IPL_Preds", repo_type="dataset", folder_path=PREDICTIONS_FOLDER, # Local folder where predictions are saved temporarily path_in_repo="predictions", # Path in dataset repo where predictions will be saved every=720, # Push every 240 minutes (4 hours) ) # Initialize CommitScheduler scheduler = CommitScheduler( repo_id="DIS_IPL_Leads", repo_type="dataset", folder_path=USERS_FOLDER, # Local folder where users are saved temporarily path_in_repo="leaders", # Path in dataset repo where predictions will be saved every=720, # Push every 240 minutes (4 hours) ) # Initialize CommitScheduler scheduler = CommitScheduler( repo_id="DIS_IPL_Outcomes", repo_type="dataset", folder_path=OUTCOMES_FOLDER, # Local folder where users are saved temporarily path_in_repo="outcomes", # Path in dataset repo where predictions will be saved every=720, # Push every 240 minutes (4 hours) ) def load_data(file_path): """ Load data from a JSON or CSV file. Args: file_path (str): The path to the file to load. Returns: pd.DataFrame or dict: The loaded data. """ try: if file_path.endswith('.json'): with open(file_path, 'r') as file: return json.load(file) elif file_path.endswith('.csv'): return pd.read_csv(file_path) except FileNotFoundError: if file_path.endswith('.json'): return {} elif file_path.endswith('.csv'): return pd.DataFrame() def get_base64_of_image(path): with open(path, "rb") as image_file: return base64.b64encode(image_file.read()).decode() # Get today's date in IST to load today's match def get_current_date_ist(): tz_IST = pytz.timezone('Asia/Kolkata') datetime_ist = datetime.now(tz_IST) return datetime_ist.strftime('%Y-%m-%d') # Function to get matches for today def get_today_matches(): today = get_current_date_ist() matches = load_data(MATCHES_JSON) today_matches = [match for match in matches if match['date'] == today] return today_matches # Function to check if prediction submission is allowed def is_submission_allowed(match_id): matches = load_data(MATCHES_JSON) # This loads matches correctly with IST times for match in matches: if match["match_id"] == match_id: # Parse the match start time in IST tz_IST = pytz.timezone('Asia/Kolkata') match_datetime_str = f'{match["date"]} {match["time"]}' # The match time string is like "2024-03-21 7:30 PM" match_datetime = datetime.strptime(match_datetime_str, "%Y-%m-%d %I:%M %p") match_datetime = tz_IST.localize(match_datetime) # Set the timezone to IST # Get the current time in IST current_datetime = datetime.now(tz_IST) if current_datetime > match_datetime: return False else: return True return False # If match_id not found, default to False # Submit prediction function def submit_prediction( user_name, match_id, predicted_winner, predicted_motm, bid_points, max_bid_points ): # Validation for user selection if user_name == "Select a user...": st.warning("Please select a valid user.") return # Check if prediction submission is allowed for the match if not is_submission_allowed(match_id): st.error("Prediction submission time has passed. Predictions can't be submitted after match start.") return if bid_points > max_bid_points or bid_points <= 0: st.error(f"Oops, Invalid bid! 🙈 You must bid at least 100 points and not exceed the 20% limit of your total points. Maximum allowed bid points: {max_bid_points}.") # st.error(f"Oops! 🙈 Looks like you're going overboard with your bid points! Your bid points cannot exceed your total points. Maximum allowed bid points: {max_bid_points} 😱") return prediction_id = uuid.uuid4().hex prediction_time = datetime.now().strftime('%Y-%m-%d') prediction_data = { 'prediction_id': prediction_id, 'user_name': user_name, 'match_id': match_id, 'predicted_winner': predicted_winner, 'predicted_motm': predicted_motm, 'bid_points': bid_points, 'prediction_date': prediction_time # Include the prediction time } # Construct the filename to include match_id for easier retrieval prediction_file_name = f"prediction_{match_id}_{user_name}.json" prediction_file = PREDICTIONS_FOLDER / prediction_file_name # Load existing predictions for the user and match, if any existing_predictions = [] if prediction_file.exists(): with prediction_file.open("r") as file: for line in file: existing_predictions.append(json.loads(line.strip())) # Update existing prediction if it exists for the same user and match prediction_updated = False for existing_prediction in existing_predictions: if existing_prediction['user_name'] == user_name and existing_prediction['match_id'] == match_id: existing_prediction.update(prediction_data) prediction_updated = True break # Save the updated predictions back to the file with scheduler.lock: if not prediction_updated: # Append the new prediction if it doesn't already exist with prediction_file.open("a") as file: file.write(json.dumps(prediction_data)) file.write("\n") else: with prediction_file.open("w") as file: for prediction in existing_predictions: file.write(json.dumps(prediction)) file.write("\n") st.success("Prediction submitted successfully!") def get_user_total_points(user_name): # users_dataset = load_dataset("Jay-Rajput/DIS_IPL_Leads", split="train") # users = users_dataset.to_dict() users = load_users(USERS_JSON) return users.get(user_name, {}).get('points') def calculate_max_bid_points(user_name): total_points = get_user_total_points(user_name) max_bid_points = int(total_points * 0.20) # 20% of total points return max_bid_points def load_users(USERS_JSON): try: with open(USERS_JSON, 'r') as file: return json.load(file) except FileNotFoundError: return {} def user_selection_and_prediction(): users = list(load_data(USERS_JSON)) user_name = st.selectbox("Select User", ["Select a user..."] + users) max_bid_points = None if user_name != "Select a user...": max_bid_points = calculate_max_bid_points(user_name) st.write(f"Maximum bid points you can submit: {max_bid_points}") matches = get_today_matches() if matches: match_choice = st.selectbox("Select Today's Match", matches, format_func=lambda match: f"{match['teams'][0]} vs {match['teams'][1]}") match_id = match_choice['match_id'] teams = match_choice['teams'] predicted_winner = st.selectbox("Predicted Winner", teams) player_list = load_data(PLAYERS_JSON) predicted_motm = "" if predicted_winner in player_list: players = player_list[predicted_winner] predicted_motm = st.selectbox("Predicted Man of the Match", players) bid_points = st.number_input("Bid Points", min_value=0, value=100, format="%d") if st.button("Submit Prediction"): submit_prediction(user_name, match_id, predicted_winner, predicted_motm, bid_points, max_bid_points) else: st.write("No matches are scheduled for today.") def display_predictions(): if st.button("Show Predictions"): all_predictions = [] # Check if the directory exists if not os.path.exists(PREDICTIONS_FOLDER): st.write("No predictions directory found.") return # List all JSON files in the directory for filename in os.listdir(PREDICTIONS_FOLDER): if filename.endswith('.json'): file_path = os.path.join(PREDICTIONS_FOLDER, filename) # Read each JSON file and append its contents to the list with open(file_path, 'r') as file: prediction = json.load(file) all_predictions.append(prediction) # Convert the list of dictionaries to a DataFrame predictions_df = pd.DataFrame(all_predictions) if not predictions_df.empty: predictions_df['prediction_date'] = predictions_df.apply(lambda x: datetime.strptime(x['prediction_date'], '%Y-%m-%d'), axis=1) # Filter for today's predictions today_str = datetime.now().strftime('%Y-%m-%d') todays_predictions = predictions_df[predictions_df['prediction_date'] == today_str] # Remove the 'prediction_id' column if it exists if 'prediction_id' in todays_predictions.columns: todays_predictions = todays_predictions.drop(columns=['prediction_id', 'prediction_date']) st.dataframe(todays_predictions, hide_index=True) else: st.write("No predictions for today's matches yet.") def redistribute_lost_points(match_id) -> dict: # Load already processed matches with open(REDISTRIBUTED_JSON, "r") as f: done_matches = json.load(f) if match_id in done_matches: return {} users = load_users(USERS_JSON) predictions = [] for file in PREDICTIONS_FOLDER.glob(f"prediction_{match_id}_*.json"): with open(file, "r") as f: for line in f: predictions.append(json.loads(line.strip())) outcomes = load_data(OUTCOMES_JSON) outcome = next((m for m in outcomes if m["match_id"] == match_id), None) if not outcome: st.error("Match outcome not found.") return {} correct_winner = outcome["winner"] correct_motm = outcome["man_of_the_match"] user_losses = {} for pred in predictions: user = pred["user_name"] bid = pred["bid_points"] if (pred["predicted_winner"] != correct_winner) or (pred["predicted_motm"] != correct_motm): user_losses[user] = user_losses.get(user, 0) + bid top_5_users = sorted(users.items(), key=lambda x: x[1]["points"], reverse=True)[:5] top_5_usernames = [user for user, _ in top_5_users] lost_points_by_top5 = sum(user_losses.get(user, 0) for user in top_5_usernames) if lost_points_by_top5 == 0: return {} rest_users = [user for user in users if user not in top_5_usernames] total_points_rest_users = sum(users[u]["points"] for u in rest_users if users[u]["points"] > 0) bonus_map = {} for user in rest_users: user_points = users[user]["points"] if user_points <= 0: continue share_ratio = user_points / total_points_rest_users bonus = round(share_ratio * lost_points_by_top5) users[user]["points"] += bonus bonus_map[user] = bonus with open(USERS_JSON, "w") as f: json.dump(users, f, indent=2) # Record this match as done done_matches.append(match_id) with open(REDISTRIBUTED_JSON, "w") as f: json.dump(done_matches, f, indent=2) return bonus_map def display_leaderboard(): if st.button("Show Leaderboard"): try: # # Load the 'leaders' configuration dataset = load_dataset("Jay-Rajput/DIS_IPL_Leads", split='train') # Load outcomes data from HF instead of local file outcome_dataset = load_dataset("Jay-Rajput/DIS_IPL_Outcomes", split='train') latest_match_id = outcome_dataset[-1]["match_id"] if outcome_dataset else None # Redistribute points only once per match bonus_map = {} if latest_match_id: bonus_map = redistribute_lost_points(latest_match_id) users_data = [] if dataset: for user, points_dict in dataset[0].items(): points = points_dict.get("points", 0) last_5_results = " ".join(points_dict.get("last_5_results", ["⚪"] * 5)) # Default: 5 white circles bonus = bonus_map.get(user, 0) users_data.append({ 'User': user, 'Points': points, 'Last 5 Bids': last_5_results, 'Redistribution Bonus': bonus }) else: st.warning("No leaderboard data found.") leaderboard = pd.DataFrame(users_data) # Sort DataFrame by points in descending order leaderboard = leaderboard.sort_values(by='Points', ascending=False) # Add a 'Rank' column starting from 1 leaderboard['Rank'] = range(1, len(leaderboard) + 1) # Select and order the columns for display leaderboard = leaderboard[['Rank', 'User', 'Points', 'Redistribution Bonus', 'Last 5 Bids']] st.dataframe(leaderboard, hide_index=True) except Exception as e: st.write("Failed to load leaderboard data: ", str(e)) # Streamlit UI encoded_image = get_base64_of_image(image_path) custom_css = f""" """ # Apply custom CSS st.markdown(custom_css, unsafe_allow_html=True) # Use the custom class in a div with your title st.markdown('