File size: 4,714 Bytes
bf356c4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | import warnings
warnings.filterwarnings("ignore")
import pandas as pd
import numpy as np
import pickle
MODEL_PATH = "genre_model.pkl"
SCALER_PATH = "genre_scaler.pkl"
ENCODER_PATH = "genre_encoder.pkl"
NUMERICAL_FEATURES = [
"melody_complexity (vocals)",
"melody_range (vocals)",
"melody_variability (vocals)",
"tempo_bpm_original (mix)",
"danceability custom (mix)",
"loudness_integrated_lufs custom (mix)",
"loudness_range_lu custom (mix)",
"energy_librosa (mix)",
"energy_librosa_std (mix)",
"energy_essentia (mix)",
"energy_essentia_std (mix)",
"energy_combined (mix)",
"spectral_centroid_mean custom (mix)",
"mfcc_mean_1 (mix)",
"mfcc_mean_2 (mix)",
"chroma_mean (mix)",
"spectral_contrast_mean (mix)",
"repetition_score custom (mix)",
"pitch_mean (mix)",
"pitch_std (mix)",
"rms_energy_mean (mix)",
"rms_energy_std (mix)",
"zero_crossing_rate (mix)",
]
def engineer_features(df, feature_cols):
df = df.copy()
df['energy_per_tempo'] = df['energy_combined (mix)'] / (df['tempo_bpm_original (mix)'] + 1)
df['dance_energy_ratio'] = df['danceability custom (mix)'] * df['energy_combined (mix)']
df['loudness_range_ratio'] = df['loudness_range_lu custom (mix)'] / (
abs(df['loudness_integrated_lufs custom (mix)']) + 1)
df['melody_energy'] = df['melody_variability (vocals)'] * df['energy_combined (mix)']
df['spectral_complexity'] = df['spectral_centroid_mean custom (mix)'] * df['spectral_contrast_mean (mix)']
df['mfcc_ratio'] = df['mfcc_mean_1 (mix)'] / (abs(df['mfcc_mean_2 (mix)']) + 1)
df['rhythm_strength'] = df['tempo_bpm_original (mix)'] * df['danceability custom (mix)']
df['pitch_variation'] = df['pitch_std (mix)'] / (df['pitch_mean (mix)'] + 1)
df['rms_energy_ratio'] = df['rms_energy_mean (mix)'] / (df['rms_energy_std (mix)'] + 1)
df['chroma_energy'] = df['chroma_mean (mix)'] * df['energy_combined (mix)']
df['zero_tempo'] = df['zero_crossing_rate (mix)'] * df['tempo_bpm_original (mix)']
df['tempo_category'] = np.where(df['tempo_bpm_original (mix)'] < 100, 0,
np.where(df['tempo_bpm_original (mix)'] < 130, 1, 2))
df['energy_category'] = np.where(df['energy_combined (mix)'] < 0.3, 0,
np.where(df['energy_combined (mix)'] < 0.6, 1, 2))
df['dance_category'] = np.where(df['danceability custom (mix)'] < 0.5, 0,
np.where(df['danceability custom (mix)'] < 0.75, 1, 2))
engineered = ['energy_per_tempo', 'dance_energy_ratio', 'loudness_range_ratio', 'melody_energy',
'spectral_complexity',
'mfcc_ratio', 'rhythm_strength', 'pitch_variation', 'rms_energy_ratio', 'chroma_energy', 'zero_tempo',
'tempo_category', 'energy_category', 'dance_category']
return df, feature_cols + engineered
class GenrePredictor:
def __init__(self):
with open(MODEL_PATH, "rb") as f:
self.model = pickle.load(f)
with open(SCALER_PATH, "rb") as f:
self.scaler = pickle.load(f)
with open(ENCODER_PATH, "rb") as f:
self.genre_encoder, self.all_subgenres, self.all_features = pickle.load(f)
def predict(self, feature_dict):
df = pd.DataFrame([feature_dict])
df, _ = engineer_features(df, NUMERICAL_FEATURES)
for col in self.all_features:
if col not in df.columns:
df[col] = 0
values = df[self.all_features].values[0]
values = np.nan_to_num(values, nan=0, posinf=0, neginf=0)
input_scaled = self.scaler.transform(values.reshape(1, -1))
genre_idx = self.model.predict(input_scaled)[0]
genre = self.genre_encoder.inverse_transform([genre_idx])[0]
genre_probs = self.model.predict_proba(input_scaled)[0]
top_indices = np.argsort(genre_probs)[::-1][:5]
similar = [(self.genre_encoder.classes_[i], genre_probs[i]) for i in top_indices]
related_subs = [s for s in self.all_subgenres if genre.lower() in s.lower()]
if not related_subs:
related_subs = self.all_subgenres[:10]
return {
"genre": genre,
"similar_genres": similar,
"subgenres": related_subs
}
df = pd.read_csv("all_genres_clean.csv",low_memory=False)
df_input = df[NUMERICAL_FEATURES]
model = GenrePredictor()
answer = model.predict(df_input.iloc[105148].to_dict())
print(answer)
print("Original :", df[["genre","sub_genres"]].iloc[105148]) |