import gradio as gr import pandas as pd import numpy as np import os import random from sklearn.metrics.pairwise import cosine_similarity # --- SAFE IMPORT BLOCK --- # Prevents crash if advanced ML libraries are missing try: import joblib from sentence_transformers import SentenceTransformer from huggingface_hub import hf_hub_download LIBRARIES_AVAILABLE = True except ImportError: LIBRARIES_AVAILABLE = False print("⚠️ Warning: Advanced ML libraries missing. Running in Simulation Mode.") # ========================================== # 1. LOAD MODELS & DATA (FAIL-SAFE) # ========================================== print("🔄 System Startup...") # Global Variables MODE = "SIMULATION" PREDICTION_MODEL = None EMBEDDINGS = None EMBEDDING_MODEL = None DATASET = None # 1.1 Attempt to load real AI models if LIBRARIES_AVAILABLE: try: print("⏳ Attempting to load AI Models...") # Load Embedder EMBEDDING_MODEL = SentenceTransformer('all-MiniLM-L6-v2') # Check and load local files if os.path.exists("play_embeddings.npy") and os.path.exists("playticker_engine.pkl"): EMBEDDINGS = np.load("play_embeddings.npy") PREDICTION_MODEL = joblib.load("playticker_engine.pkl") MODE = "PRODUCTION (AI-POWERED)" print("✅ SUCCESS: Real AI Models Loaded.") else: print("⚠️ Files not found on disk. Switching to Logic Fallback.") except Exception as e: print(f"❌ Error loading models: {e}") print("⚠️ Switching to Logic Fallback.") # 1.2 Attempt to load dataset (CSV) try: if LIBRARIES_AVAILABLE: # Attempt to download from Repo dataset_path = hf_hub_download( repo_id="meirnm13/playticker-nba-momentum", filename="synthetic_nba_momentum_data.csv", repo_type="dataset" ) DATASET = pd.read_csv(dataset_path) print(f"✅ Loaded Dataset: {len(DATASET)} rows.") else: raise Exception("No libraries") except Exception as e: print(f"⚠️ Could not load CSV ({e}). Generating dummy data.") DATASET = pd.DataFrame({ 'play_description': [ "LeBron James throws down a monster dunk", "Stephen Curry hits a deep three pointer", "Timeout called by the Miami Heat", "Turnover by James Harden", "Giannis blocks the shot" ] * 20, 'player_name': ["LeBron James", "Stephen Curry", "Team", "James Harden", "Giannis Antetokounmpo"] * 20, 'team': ["Lakers", "Warriors", "Heat", "Clippers", "Bucks"] * 20, 'momentum_score': [0.85, 0.92, -0.1, -0.6, 0.75] * 20 }) # ========================================== # 2. LOGIC ENGINES (HYBRID) # ========================================== def heuristic_logic(text): text = str(text).lower() score = 0.0 if any(x in text for x in ["dunk", "3-pointer", "win", "clutch", "lead", "steal", "block"]): score = random.uniform(0.6, 0.95) elif any(x in text for x in ["miss", "turnover", "foul", "lose", "brick", "timeout"]): score = random.uniform(-0.7, -0.3) else: score = random.uniform(-0.2, 0.2) return score def predict_momentum(user_input_text): if not user_input_text: return "", 0.0 momentum_score = 0.0 if MODE.startswith("PRODUCTION") and PREDICTION_MODEL is not None: try: embedding = EMBEDDING_MODEL.encode([user_input_text]) momentum_score = PREDICTION_MODEL.predict(embedding.reshape(1, -1))[0] if isinstance(momentum_score, (str, int, np.integer)): mapping = {0: -0.8, 1: 0.0, 2: 0.8} momentum_score = mapping.get(momentum_score, 0.5) except: momentum_score = heuristic_logic(user_input_text) else: momentum_score = heuristic_logic(user_input_text) # Visualization if momentum_score > 0.4: category, color, icon = "HIGH POSITIVE", "#10b981", "🔥" elif momentum_score > 0.1: category, color, icon = "POSITIVE", "#22c55e", "✅" elif momentum_score < -0.4: category, color, icon = "HIGH NEGATIVE", "#ef4444", "🛑" else: category, color, icon = "NEUTRAL", "#6b7280", "⚖️" html_output = f"""

{icon} {category}

{float(momentum_score):.3f}
System Mode: {MODE}
""" return html_output, float(momentum_score) # ========================================== # 3. RECOMMENDATION PIPELINE # ========================================== def find_similar_plays(user_input_text, top_k=5): # Fixed: Always return a DataFrame, even if empty if not user_input_text: return pd.DataFrame(columns=['Similarity', 'Play', 'Player', 'Score']) results = [] if MODE.startswith("PRODUCTION") and EMBEDDINGS is not None: try: input_embedding = EMBEDDING_MODEL.encode([user_input_text]) similarities = cosine_similarity(input_embedding, EMBEDDINGS)[0] top_indices = similarities.argsort()[-top_k:][::-1] for idx in top_indices: play = DATASET.iloc[idx] results.append({ 'Similarity': f"{similarities[idx]:.2f}", 'Play': str(play['play_description'])[:80] + "...", 'Player': play['player_name'], 'Score': f"{play['momentum_score']:.2f}" }) return pd.DataFrame(results) except: pass # Fallback try: sample = DATASET.sample(top_k) for _, play in sample.iterrows(): results.append({ 'Similarity': "N/A (Sim)", 'Play': str(play['play_description'])[:80] + "...", 'Player': play['player_name'], 'Score': f"{play['momentum_score']:.2f}" }) except: pass return pd.DataFrame(results) # ========================================== # 4. MAIN ANALYZER (UI HANDLER) # ========================================== def analyze_play(user_input): # FIXED: Return valid empty states instead of None to prevent Gradio Crash if not user_input or len(str(user_input).strip()) < 2: return "", 0, pd.DataFrame(columns=['Similarity', 'Play', 'Player', 'Score']) html, score = predict_momentum(user_input) sim_df = find_similar_plays(user_input) return html, score, sim_df # ========================================== # 5. GRADIO INTERFACE # ========================================== custom_css = ".gradio-container {max-width: 1100px !important; margin: auto;}" with gr.Blocks(css=custom_css, theme=gr.themes.Soft(primary_hue="orange")) as demo: gr.HTML(f"""

🏀 PlayTicker Pro

System Status: {MODE}

""") with gr.Row(): with gr.Column(): input_text = gr.Textbox(label="Play Description", placeholder="E.g., LeBron hits a clutch three...", lines=3) btn = gr.Button("Analyze", variant="primary") # FIXED: Added cache_examples=False to prevent startup timeout gr.Examples( examples=[ ["LeBron James hits a clutch three-pointer"], ["Steph Curry turnover leading to a fast break"], ["Giannis blocks the shot"] ], inputs=input_text, cache_examples=False ) with gr.Column(): out_html = gr.HTML(label="Prediction") out_score = gr.Number(visible=False) gr.Markdown("### 🔍 Similar Historical Plays") out_table = gr.Dataframe(headers=['Similarity', 'Play', 'Player', 'Score']) with gr.Accordion("📚 Dataset Explorer", open=False): gr.Dataframe(DATASET.head(50) if DATASET is not None else [], interactive=False) btn.click(analyze_play, input_text, [out_html, out_score, out_table]) if __name__ == "__main__": demo.launch()