import base64 import io import json import os import uuid from datetime import datetime from pathlib import Path import pandas as pd import pytz from datasets import load_dataset import streamlit as st from huggingface_hub import CommitScheduler, HfApi # File paths as constants PREDICTIONS_CSV = 'dis_predictions.csv' USERS_JSON = 'leaders/users.json' MATCHES_JSON = 'matches.json' OUTCOMES_JSON = '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) # Initialize CommitScheduler scheduler = CommitScheduler( repo_id="DIS_IPL_Dataset", 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=10, # Push every 240 minutes (4 hours) ) # Initialize CommitScheduler scheduler = CommitScheduler( repo_id="DIS_IPL_Dataset", 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=5, # Push every 240 minutes (4 hours) ) # Initialize CSV and JSON files if they don't exist def initialize_files(): # Initialize predictions CSV try: pd.read_csv(PREDICTIONS_CSV) except FileNotFoundError: df = pd.DataFrame(columns=['user_name', 'match_id', 'predicted_winner', 'predicted_motm', 'bid_points']) df.to_csv(PREDICTIONS_CSV, index=False) 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 def load_predictions(PREDICTIONS_CSV): try: return pd.read_csv(PREDICTIONS_CSV) except FileNotFoundError: return pd.DataFrame() # 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: st.error(f"Your bid points exceed the 20% limit of your total points. Maximum allowed bid points: {max_bid_points}") return prediction_id = uuid.uuid4().hex prediction_date = 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_date # Include the prediction date } # Construct the filename to include match_id for easier retrieval prediction_file_name = f"prediction_{match_id}_{prediction_id}.json" prediction_file = PREDICTIONS_FOLDER / prediction_file_name with scheduler.lock: with prediction_file.open("a") as file: file.write(json.dumps(prediction_data)) file.write("\n") st.success("Prediction submitted successfully!") def get_user_total_points(user_name): users = load_data(USERS_JSON) return users.get(user_name, 0) # Define the new function 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=1, 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 display_leaderboard(): if st.button("Show Leaderboard"): try: users = load_users(USERS_JSON) leaderboard = sorted(users.items(), key=lambda x: x[1], reverse=True) # Generate a list of dictionaries, each representing a row in the leaderboard leaderboard_dicts = [{"Rank": rank+1, "User": user[0], "Points": user[1]} for rank, user in enumerate(leaderboard)] # Convert the list of dictionaries to a DataFrame df_leaderboard = pd.DataFrame(leaderboard_dicts) st.dataframe(df_leaderboard, hide_index=True) except FileNotFoundError: st.write("Leaderboard data not available.") # 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('
DIS IPL Match Predictions
', unsafe_allow_html=True) st.write("🏆 Predict, Compete, and Win 🏏 - Where Every Guess Counts! 🏆") user_guide_content = """ ### 📘 User Guide #### Submitting Predictions - **Match Selection**: Choose the match you want to predict from today's available matches. - **Team and Player Prediction**: Select the team you predict will win and the "Man of the Match". - **Bid Points**: Enter the number of points you wish to bid on your prediction. Remember, the maximum you can bid is capped at 20% of your total points. #### Scoring System - **Winning Team Prediction**: Correct predictions earn you 1000 points, while incorrect predictions deduct 200 points. - **Man of the Match Prediction**: Correctly predicting the "Man of the Match" awards you 200 points. No penalty for incorrect guesses. - **Bonus Points**: An additional 200 points bonus is awarded for getting both the team and "Man of the Match" predictions right. #### Bid Point Constraints - You cannot bid more than 20% of your current total points. - Bid points will be doubled if your prediction is correct, and deducted if incorrect. #### Rules for Submission - Predictions must be submitted before the match starts. - Only one prediction per match is allowed. - Review your prediction carefully before submission, as it cannot be changed once submitted. """ # User Guide as an expander with st.expander("User Guide 📘"): st.markdown(user_guide_content) with st.expander("Submit Prediction 📝"): user_selection_and_prediction() with st.expander("Predictions 🔍"): display_predictions() with st.expander("Leaderboard 🏆"): display_leaderboard() ############################# Admin Panel ################################## ADMIN_PASSPHRASE = "admin123" def fetch_latest_predictions(match_id): dataset = load_dataset("Jay-Rajput/DIS_IPL_Dataset", config_name="predictions") predictions = dataset['train'].filter(lambda example: example['match_id'] == match_id) return predictions def save_match_outcomes(outcomes): with open(OUTCOMES_JSON, 'w') as file: json.dump(outcomes, file, indent=4) def update_leaderboard_and_outcomes(match_id, winning_team, man_of_the_match): # Fetch latest predictions from the dataset repo predictions = fetch_latest_predictions(match_id) outcomes = load_data(OUTCOMES_JSON) # Load existing match outcomes # Load existing match outcomes and user data from the test split dataset = load_dataset("Jay-Rajput/DIS_IPL_Dataset", config_name="leaders") users = {item['user_name']: item for item in dataset['train']} # Directly update or add the match outcome outcome_exists = False for outcome in outcomes: if outcome['match_id'] == match_id: outcome.update({"winning_team": winning_team, "man_of_the_match": man_of_the_match}) outcome_exists = True break if not outcome_exists: outcomes.append({"match_id": match_id, "winning_team": winning_team, "man_of_the_match": man_of_the_match}) # Update user points based on prediction accuracy for prediction in predictions: user_name = prediction['user_name'] # Initialize user points if not present if user_name not in users: users[user_name] = {'user_name': user_name, 'points': 0} # Update points based on prediction accuracy if prediction['predicted_winner'] == winning_team: users[user_name] += 1000 users[user_name] += prediction['bid_points'] if prediction['predicted_motm'] == man_of_the_match: users[user_name] += 400 # Bonus for both correct predictions else: users[user_name] -= 200 + prediction['bid_points'] # Penalty for wrong team prediction save_match_outcomes(outcomes) users.save_to_disk(USERS_JSON) with st.sidebar: expander = st.expander("Admin Panel", expanded=False) admin_pass = expander.text_input("Enter admin passphrase:", type="password", key="admin_pass") if admin_pass == ADMIN_PASSPHRASE: expander.success("Authenticated") all_matches = load_data(MATCHES_JSON) match_outcomes = load_data(OUTCOMES_JSON) submitted_match_ids = [outcome["match_id"] for outcome in match_outcomes] # Filter matches to those that do not have outcomes submitted yet matches_without_outcomes = [match for match in all_matches if match["match_id"] not in submitted_match_ids] # If matches are available, let the admin select one if matches_without_outcomes: match_selection = expander.selectbox("Select Match", matches_without_outcomes, format_func=lambda match: f"{match['teams'][0]} vs {match['teams'][1]}", key="match_selection") selected_match_id = match_selection['match_id'] teams = match_selection['teams'] # Let admin select the winning team winning_team = expander.selectbox("Winning Team", teams, key="winning_team") # Fetch and display players for the selected winning team player_list = load_data(PLAYERS_JSON) if winning_team in player_list: players = player_list[winning_team] man_of_the_match = expander.selectbox("Man of the Match", players, key="man_of_the_match") else: players = [] man_of_the_match = expander.text_input("Man of the Match (Type if not listed)", key="man_of_the_match_fallback") if expander.button("Submit Match Outcome", key="submit_outcome"): update_leaderboard_and_outcomes(selected_match_id, winning_team, man_of_the_match) expander.success("Match outcome submitted and leaderboard updated!") else: expander.write("No matches are available for today.") else: if admin_pass: # Show error only if something was typed expander.error("Not authenticated")