import streamlit as st import pandas as pd import joblib import matplotlib.pyplot as plt import os # -------------------------------------- # 🎨 PAGE CONFIG # -------------------------------------- st.set_page_config(page_title="Spotify Clustering", layout="wide") # -------------------------------------- # 🔧 AUTO PATH (LOCAL + CLOUD FIX) # -------------------------------------- def get_path(filename): base_dir = os.path.dirname(os.path.abspath(__file__)) local_path = os.path.join(base_dir, filename) parent_path = os.path.join(base_dir, "..", filename) if os.path.exists(local_path): return local_path elif os.path.exists(parent_path): return parent_path else: st.error(f"{filename} bulunamadı!") st.stop() DATA_PATH = get_path("spotify_clustered.csv") MODEL_PATH = get_path("kmeans_music_model.pkl") SCALER_PATH = get_path("scaler_music.pkl") # -------------------------------------- # 📂 LOAD DATA (CACHE) # -------------------------------------- @st.cache_data def load_data(): df = pd.read_csv(DATA_PATH) unnecessary_cols = ['Unnamed: 0', 'track_id', 'album_name', 'explicit'] df_display = df.drop(columns=[c for c in unnecessary_cols if c in df.columns]) return df, df_display @st.cache_resource def load_model(): model = joblib.load(MODEL_PATH) scaler = joblib.load(SCALER_PATH) return model, scaler df, df_display = load_data() model, scaler = load_model() # -------------------------------------- # 🧠 SESSION STATE (NO FLICKER) # -------------------------------------- if "prediction" not in st.session_state: st.session_state.prediction = None st.session_state.samples = None # -------------------------------------- # 🏷️ TITLE # -------------------------------------- st.title("🎵 Spotify Music Clustering / Spotify Müzik Kümeleme") st.markdown("---") # -------------------------------------- # 📄 DATA PREVIEW # -------------------------------------- st.subheader("📄 Dataset Preview / Veri Önizleme") st.dataframe(df_display.head(10), use_container_width=True) # -------------------------------------- # 📊 VISUALS # -------------------------------------- col1, col2 = st.columns(2) with col1: st.subheader("📊 Cluster Distribution / Küme Dağılımı") st.bar_chart(df['cluster'].value_counts(), use_container_width=True) with col2: st.subheader("🎯 Feature Analysis / Özellik Analizi") fig, ax = plt.subplots(figsize=(6, 4)) scatter = ax.scatter( df['danceability'], df['energy'], c=df['cluster'], cmap='viridis', alpha=0.6 ) ax.set_xlabel("Danceability / Dans Edilebilirlik") ax.set_ylabel("Energy / Enerji") plt.colorbar(scatter, ax=ax) st.pyplot(fig, clear_figure=True) plt.close(fig) # -------------------------------------- # 🤖 PREDICTION # -------------------------------------- st.divider() st.subheader("🤖 Predict New Song Cluster / Yeni Şarkı Tahmini") c1, c2, c3 = st.columns(3) with c1: pop = st.slider("Popularity / Popülerlik", 0, 100, 50) dur = st.slider("Duration (ms) / Süre", 0, 600000, 200000) dance = st.slider("Danceability / Dans Edilebilirlik", 0.0, 1.0, 0.5) with c2: energy = st.slider("Energy / Enerji", 0.0, 1.0, 0.5) loud = st.slider("Loudness / Ses Yüksekliği", -60.0, 0.0, -10.0) tempo = st.slider("Tempo / Tempo", 0.0, 250.0, 120.0) with c3: speech = st.slider("Speechiness / Konuşma Oranı", 0.0, 1.0, 0.1) if st.button("Predict Cluster / Kümeyi Tahmin Et ✨"): new_data = [[pop, dur, dance, energy, loud, tempo, speech]] try: new_data_scaled = scaler.transform(new_data) res = model.predict(new_data_scaled)[0] st.session_state.prediction = res st.session_state.samples = df[df['cluster'] == res][['track_name', 'artists']].head(5) except Exception as e: st.error(f"Error / Hata: {e}") # SONUÇ (STABLE) if st.session_state.prediction is not None: st.success(f"### Predicted Cluster / Tahmin Edilen Küme: {st.session_state.prediction}") st.write("Similar Songs / Benzer Şarkılar:") st.table(st.session_state.samples) # -------------------------------------- # 🔍 CLUSTER ANALYSIS # -------------------------------------- st.divider() st.subheader("🔍 Cluster Characteristics / Küme Özellikleri") numeric_only = df.select_dtypes(include=['float64', 'int64']) if 'cluster' in df.columns: means = numeric_only.groupby(df['cluster']).mean() st.dataframe(means, use_container_width=True)