<jupyter_start><jupyter_text>Automated Recommendations Utilizing User Data<jupyter_code>class Sound_Drip:
    
    def __init__(self, token):
        self.token = token
    
    def instantiate_sp(self,token):
        sp = spotipy.Spotify(auth=token)
        return sp

    def get_user_song_id(self,sp):
        results = sp.current_user_saved_tracks()
        genre = []
        counter = 0 
        for song_number in range(0,19):
            counter += 1 
            song_id = results['items'][song_number]['track']['id']
            artist_id = self.get_artist_id(song_id)
            genre = self.get_genres(artist_id)
            if genre != []:
                break
        return song_id

    def get_acoustical_features(self,song_id,sp):
        acoustical_features = sp.audio_features(song_id)[0]
        return acoustical_features

    def get_popularity(self, song_id):
        popularity =  sp.track(song_id)['popularity']
        return popularity

    def get_artist_id(self, song_id):
        artist = sp.track(song_id)['artists'][0]['id']
        return artist

    def get_genres(self, artist):
        genre = sp.artist(artist)['genres']
        return genre
    
    def create_feature_object(self,popularity, acoustical_features):
        popularity_dict = {'popularity': popularity}
        song_features = acoustical_features
        song_features.update(popularity_dict)
        song_features = {
    "audio_features": {
        key: song_features[key] for key in song_features.keys() & {
            'popularity',
            'acousticness',
            'danceability',
            'energy',
            'instrumentalness',
            'key',
            'liveness',
            'loudness',
            'mode',
            'speechiness',
            'tempo',
            'time_signature',
            'valence'}}}

        df = pd.DataFrame.from_dict(json_normalize(song_features["audio_features"]),orient='columns')   
        df = df.reindex(sorted(df.columns), axis=1)
        return df
    
    def get_results(self,song_features_df):
        scaler = load("./models/scalar3.joblib")
        print('Scaling data...')
        data_scaled = scaler.transform(song_features_df)
        normalizer = Normalizer()
        data_normalized = normalizer.fit_transform(data_scaled)
        print('Loading pickled model...')
        model = load('./models/model5.joblib')
        results = model.kneighbors([data_normalized][0])[1:]
        print('results returned')
        return results[0]
    
    def filter_model(self,model_results,source_genre_list): 
        #loop takes KNN results and filters by source track genres
        print("filter for genres initiated")
        genre_array = pickle.load(open("./data/genres_array_2.pkl","rb"))
        filtered_list = []
        song_list_length = 20
        for output_song_index in model_results[0][1:]:
            output_genre_list = genre_array[output_song_index]
            for output_genre in output_genre_list:
                output_genre = output_genre.strip(" ")
                for source_genre in source_genre_list:
                    source_genre = "'" + source_genre + "'"
                    if source_genre == output_genre:
                        filtered_list.append(output_song_index)
                    else:
                        continue
        if len(set(filtered_list)) > song_list_length:
            print("filter found at least 20 genre matches")
            filtered_list = set(filtered_list)
            filtered_list = list(filtered_list)[0:20]
        else:
            counter = song_list_length - len(set(filtered_list))
            print(len(set(filtered_list)))
            print(counter)
            print(f'need to add {counter} items to final song output')
            for output_song_index in model_results[1:]:
                if output_song_index not in filtered_list:
                    if counter > 0:
                        filtered_list.append(output_song_index)
                        counter -= 1
                    else:
                        break
        print("filtered list with 20 unique song indices returned")
        return filtered_list
    
    def song_id_prediction_output(self,filtered_list): 
        similar_songs = []
        print('song_id_list loading...')
        song_id_array = pickle.load(open('./data/song_id_array3.pkl', 'rb'))
        print('song_id_list loaded')
        for song_row in filtered_list:
            song_id = song_id_array[song_row]
            similar_songs.append({'similarity': [.99], 'values': song_id})
        json_dict = {"songs": similar_songs}
        print("Results returned")
        return json_dict
sd = Sound_Drip(token)
sp = sd.instantiate_sp(token)
song_id = sd.get_user_song_id(sp)
acoustical_features = sd.get_acoustical_features(song_id, sp)
popularity = sd.get_popularity(song_id)
song_features_df = sd.create_feature_object(popularity, acoustical_features)
results = sd.get_results(song_features_df)
source_genre = sd.get_genres(sd.get_artist_id(song_id))
filtered_list = sd.filter_model(results,source_genre)
sd.song_id_prediction_output(filtered_list)<jupyter_output>Scaling data...
Loading pickled model...
results returned
filter for genres initiated
filter found at least 20 genre matches
filtered list with 20 unique song indices returned
song_id_list loading...
song_id_list loaded
Results returned<jupyter_text>Slider Functionality Utilizing Acoustical Features / Popularity<jupyter_code>class Slider(Sound_Drip):

    def __init__(self,slider_features):
        self.slider_features = slider_features
        self.slider_features_df = self.create_slider_feature_df(slider_features)
        self.slider_results_list = self.get_slider_results(self.slider_features_df)[0][0:20]
        self.slider_predictions = self.song_id_prediction_output(self.slider_results_list)

    def create_slider_feature_df(self,slider_features):
            df = pd.DataFrame.from_dict(json_normalize(self.slider_features["audio_features"]),orient='columns')   
            df = df.reindex(sorted(df.columns), axis=1)
            return df
        
    def get_slider_results(self,song_features_df):
        scaler = load("./models/scalar3.joblib")
        print('Scaling data...')
        data_scaled = scaler.transform(song_features_df)
        normalizer = Normalizer()
        data_normalized = normalizer.fit_transform(data_scaled)
        print('Loading pickled model...')
        model = load('./models/slider_model6.joblib')
        results = model.kneighbors([data_normalized][0])[1:]
        print('results returned')
        return results[0]
slider = Slider({'audio_features': {'time_signature': 4,
  'speechiness': 0.0486,
  'acousticness': 0.961,
  'danceability': 0.62,
  'tempo': 104.853,
  'loudness': -23.873,
  'mode': 1,
  'popularity': 31,
  'valence': 0.053,
  'key': 11,
  'liveness': 0.0741,
  'instrumentalness': 0.911,
  'energy': 0.231}})
slider.slider_predictions<jupyter_output><empty_output><jupyter_text>Sandbox - Play Dirty!<jupyter_code># import numpy as np

# old_song_list = load('data/song_id_list2(1).joblib')

# old_song_array = np.array(old_song_list)

# pickle.dump(old_song_array, open('data/old_song_array.pkl', 'wb'))<jupyter_output><empty_output><jupyter_text>Prediction Functions Slated for Production - Canvas 2<jupyter_code>## Updated function - Not in Flask - 

def get_results(song_features_df):
    scaler = load("./data/scalar3.joblib")
#     print('Scaling data...')
    data_scaled = scaler.transform(song_features_df)
#     print(data_scaled)
#     print('Data scaled')
    normalizer = Normalizer()
#     print('Normalizing data...')
    data_normalized = normalizer.fit_transform(data_scaled)
#     print(data_normalized)
#     print('Data normalized')
#     print('Loading pickled model...')
    model = load('./models/model5.joblib')
    results = model.kneighbors([data_normalized][0])[1:]
    print('Prediction executed')
    return results[0]
def filter_model(model_results,source_genre_list): 
    #loop takes KNN results and filters by source track genres
    genre_array = pickle.load(open("./data/genres_array_2.pkl","rb"))
    filtered_list = []
    song_list_length = 20
    for output_song_index in model_results[0][1:]:
        output_genre_list = genre_array[output_song_index]
        for output_genre in output_genre_list:
            output_genre = output_genre.strip(" ")
            for source_genre in source_genre_list:
                source_genre = "'" + source_genre + "'"
                if source_genre == output_genre:
                    filtered_list.append(output_song_index)
                else:
                    continue
    if len(set(filtered_list)) > song_list_length:
        filtered_list = set(filtered_list)
        filtered_list = list(filtered_list)[0:20]
    else:
        counter = song_list_length - len(set(filtered_list))
        print(len(set(filtered_list)))
        print(counter)
        print(f'need to add {counter} items to final song output')
        for output_song_index in model_results[1:]:
            if output_song_index not in filtered_list:
                if counter > 0:
                    filtered_list.append(output_song_index)
                    counter -= 1
                else:
                    break
    return filtered_list    
# results = predictfunc(song_features)
source_genre_list = (get_genres(get_artist_id(song_id)))
# source_genre_list =['techno']
# print(source_genre_list)
filtered_list = filter_model(results,source_genre_list)
def song_id_prediction_output(filtered_list): 
    similar_songs = []
    print('song_id_list loading...')
    song_id_array = pickle.load(open('./data/song_id_array3.pkl', 'rb'))
    print('song_id_list loaded')
    print('beginning for loop...')
    for song_row in filtered_list:
        song_id = song_id_array[song_row]
        similar_songs.append({'similarity': [.99], 'values': song_id})
    json_dict = {"songs": similar_songs}
    print("Results returned")
    return json_dict
song_id_prediction_output(filtered_list)<jupyter_output>song_id_list loading...
song_id_list loaded
beginning for loop...
Results returned<jupyter_text>Older Genre Filtering Code for Reference - Attemping another approach using dataframe<jupyter_code># #loop takes KNN results and filters by source track genres
# # old
# filtered_list = []
# # filtered_lists = []
# source_song_index = knn_results1[0][0]
# source_genre_list = df.loc[source_song_index]["genres_stripped"].split(",")
# # print(source_genre_list)
# for output_song_index in knn_results1[0][1:]:
# #     print(output_song_index)
#     output_genre_list = df.loc[output_song_index]["genres_stripped"].split(",")
# #     print(output_genre_list)
#     for output_genre in output_genre_list:
#         output_genre = output_genre.strip(' ')
# #         print(output_genre)
#         for source_genre in source_genre_list:
#             source_genre = source_genre.strip(' ')
# #             print(source_genre)
#             if source_genre == output_genre:
# #                 print(output_song_index,source_genre,output_genre)
#                 filtered_list.append(output_song_index)
# #             print(filtered_list)
#             else:
# # #             print("source genre does not match output genre!")
#                 continue
# #     filtered_lists.append(filtered_list)
# print(len(set(filtered_list)),"!!!!!")<jupyter_output>807 !!!!!<jupyter_text>For Reference - Working code in KNN Model 3 Notebook -  Ready for Production - Load in Genre Array and Utilize in updated function for genre filtering<jupyter_code>def filter_model(): 
    #loop takes KNN results and filters by source track genres
    filtered_list = []
    song_list_length = 364
    source_song_index = knn_results1[0][0]
    source_genre_list = genre_array[source_song_index]
    for output_song_index in knn_results1[0][1:]:
        output_genre_list = genre_array[output_song_index]
        for output_genre in output_genre_list:
            for source_genre in source_genre_list:
                if source_genre == output_genre:
                    filtered_list.append(output_song_index)
                else:
                    continue
    if len(set(filtered_list)) > song_list_length:
        print("list large enough")
    else:
        counter = song_list_length - len(set(filtered_list))
        print(len(set(filtered_list)))
        print(counter)
        print(f'need to add {counter} items to final song output')
        for output_song_index in knn_results1[0][1:]:
            if output_song_index not in filtered_list:
                if counter > 0:
                    filtered_list.append(output_song_index)
                    counter -= 1
                else:
                    break
            
#     print(len(output_song_index_list),"!!!!!")    
filter_model()<jupyter_output><empty_output><jupyter_text>Test Multiple Rows - Functional!<jupyter_code>def output_len_of_lists(list_of_lists):
    for list_item in list_of_lists:
        print(len(list_item))
#loop takes range of KNN results per defined track range and filter matches by source track genres
filtered_lists = []
for source_song_index in range(0,1000):
    knn_results1 = knn1.kneighbors([data_normalized[source_song_index]])[1]
    knn_result_ouputs = knn_results1[0][1:]
    filtered_list = []
    source_genre_list = genre_array[source_song_index]
    for output_song_index in knn_result_ouputs:
        output_genre_list = genre_array[output_song_index]
        for output_genre in output_genre_list:
            for source_genre in source_genre_list:
                if source_genre == output_genre:
                    filtered_list.append(output_song_index)
                else:
                    continue
    filtered_lists.append(set(filtered_list))
    
output_len_of_lists(filtered_lists)<jupyter_output><empty_output><jupyter_text>From predict.py - Old Production Code<jupyter_code>def instantiate_sp(token):
    sp = spotipy.Spotify(auth=token)
    return sp
instantiate_sp(token)
def get_user_song_id(sp):
    results = sp.current_user_saved_tracks()
    genre = []
    counter = 0 
    for song_number in range(0,19):
        counter += 1 
        song_id = results['items'][song_number]['track']['id']
        artist_id = get_artist_id(song_id)
        genre = get_genres(artist_id)
        if genre != []:
            break
    return song_id
def get_acoustical_features(song_id,sp):
    return sp.audio_features(song_id)[0]
def get_popularity(trackID):
    return sp.track(trackID)['popularity']
def get_artist_id(trackID):
    return sp.track(trackID)['artists'][0]['id']
def get_genres(artistID):
    return sp.artist(artistID)['genres']
song_id = get_user_song_id(instantiate_sp(token))
song_id
get_acoustical_features(song_id,sp)<jupyter_output><empty_output><jupyter_text>Production Flask Predict function<jupyter_code>def get_features(song_id,sp):
    results_dict = sp.audio_features(song_id)[0]
    audio_features = {
        "audio_features": {
            key: results_dict[key] for key in results_dict.keys() & {
                'danceability',
                'energy',
                'key',
                'loudness',
                'mode',
                'speechiness',
                'acousticness',
                'instrumentalness',
                'liveness',
                'valence',
                'tempo',
                'time_signature'}}}

    return audio_features
get_features(song_id,sp)
def predict(content):
    similar_songs = []
    print('Loading dataframe...')
    dataframe = pd.DataFrame.from_dict(
        json_normalize(content['audio_features']),
                                orient='columns')
    print(dataframe)
    print('Dataframe Object Created')
    print('Loading pickled scaler...')
    scalar = load('./models/scalar2.joblib')
    print('Pickled scaler loaded')
    print('Scaling dataframe object...')
    df_array = np.array(dataframe)
    print(df_array)
    dataframe_scaled = scalar.transform(df_array)
    print(dataframe_scaled)
    print('Dataframe scaled')
    print('Loading pickled model...')
    model = load('./models/model2.joblib')
    print('Model loaded')
    results = model.kneighbors([dataframe_scaled][0])[1]
    print('Prediction executed')
    print('song_id_list loading...')
    song_id_list = load('./data/song_id_list2.joblib')
    print('song_id_list loaded')
    
    print('beginning for loop...')
    for song_row in results[0][1:]:
        song_id = song_id_list[song_row]
        similar_songs.append({'similarity': [.99], 'values': song_id})
    json_dict = {"songs": similar_songs}
    return json_dict
predict(get_features(song_id,sp))
song_id<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1047391952309985, 'fraction_numerical': 0.009836065573770493, 'mean_word_length': 2.8815363257751043, 'pattern_counts': {'":': 5, '<': 34, '<?xml version=': 0, '>': 40, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '233424', 'license': 'MIT', 'n_tokens_mistral': 5483, 'n_tokens_neox': 5170, 'n_words': 951, 'path': 'Flask_notebooks/Flask_Notebook.ipynb', 'repo_name': 'BloomTech-Labs/sound-drip-ds-x', 'size': '16775'}