def loadSongs(self): if os.path.isfile(self.SONG_DATA_CACHE_FILE): print("song cache file exists. loading song data from:", self.SONG_DATA_CACHE_FILE) with open(self.SONG_DATA_CACHE_FILE, 'rb') as songDataFile: tracks = pickle.load(songDataFile) else: print("no cache file found. loading song data from spotify") categories = ['US'] categories += self.sp.categories(country="US", limit=5)['categories']['items'] categories += ['CA'] #categories += self.sp.categories(country="CA", limit=50)['categories']['items'] categories += ['GB'] #categories += self.sp.categories(country="GB", limit=50)['categories']['items'] categories += ['FR'] #categories += self.sp.categories(country="FR", limit=50)['categories']['items'] categories += ['BR'] #categories += self.sp.categories(country="BR", limit=50)['categories']['items'] categories += ['MX'] #categories += self.sp.categories(country="MX", limit=50)['categories']['items'] print("found {} categories across 1 countries".format( len(categories) - 6)) print("gathering playlists from categories") playlists = [] for i in tqdm(categories): with HiddenPrints(): if type(i) == str: countrycode = i continue #stupid regionalmexican never works if i['id'] == 'regionalmexican': continue try: new_playlists = self.sp.category_playlists( i['id'], country=countrycode, limit=10) except: continue if new_playlists is not None: playlists += new_playlists['playlists']['items'] print("gathered {} playlists across all categories".format( len(playlists))) tracks = [] print("gathering tracks from playlists") for playlist in tqdm(playlists): with HiddenPrints(): track_objects = self.sp.user_playlist_tracks( 'spotify', playlist_id=playlist['id'])['items'] if track_objects is not None: for track in track_objects: if track['track'] is None: continue trackData = track['track'] trackData.pop('album', None) trackData.pop('available_markets', None) trackData.pop('disc_number', None) trackData.pop('external_ids', None) trackData.pop('preview_url', None) trackData.pop('track_number', None) trackData.pop('episode', None) trackData.pop('is_local', None) trackData.pop('duration_ms', None) audioFeatures = self.sp.audio_features( [trackData['id']])[0] if audioFeatures is None: continue trackData['audio_features'] = audioFeatures tracks.append(trackData) print("gathered {} tracks across all playlists".format( len(tracks))) with open(self.SONG_DATA_CACHE_FILE, 'wb') as songDataFile: pickle.dump(tracks, songDataFile) print("saved song data to cache file:", self.SONG_DATA_CACHE_FILE) print("song data successfully loaded, {} total tracks".format( len(tracks))) return tracks
import database_util import unittest from gradescope_utils.autograder_utils.decorators import weight, visibility from HiddenPrints import HiddenPrints with HiddenPrints(): import SQLLab import sqlite3 as sqlite import os class q2(unittest.TestCase): @classmethod def setUpClass(cls): try: os.remove('database.db') except: pass def setUp(self): self.con = sqlite.connect('database.db') self.cur = self.con.cursor() @weight(1) def test_empty(self): """Q2: Function called on an empty database""" SQLLab.populate_table() self.cur.execute("""SELECT * FROM ids""") self.assertListEqual(self.cur.fetchall(), [(1, 'Oski'), (2, 'Is'), (3, 'The'), (4, 'Best')], 'Entries do not equal to expected')
def main(): #evaluate arguments PREFERENCE_DATA_PATH = None RAND_DATA_NUMBER = 0 VERBOSE = False unixOptions = "hr:vp:" gnuOptions = ["help", "random=", "verbose", "preference="] try: arguments, values = getopt.getopt(sys.argv[1:], unixOptions, gnuOptions) except getopt.error as err: # output error, and return with an error code helpmsg = "try 'python3 recommender.py -h' or 'python3 recommender.py --help' for help" print(str(err)) sys.exit(2) for currentArgument, currentValue in arguments: if currentArgument in ("-h", "--help"): print( "usage:\n\tpython3 recommender.py -p | --preference_file file_path.p [-h|--help] [-v|--verbose] [-r|--random n]\n\nOptions:\n\t-p | --preference_file\tPath to preference data file. if one exists, it will be loaded and used to train the neural net. If it does not exist, it will be created to save your preference data.\n\t-h | --help\tDisplay this text\n\t-v | --verbose\tDisplay verbose neural net training information\n\t-r | --random n\tGenerate random training data of size n. If training data file exists this will be ignored. Usually results in recommendations for audiobooks or white noise." ) exit() elif currentArgument in ("-v", "--verbose"): print("enabling verbose mode") VERBOSE = True elif currentArgument in ("-r", "--random"): RAND_DATA_NUMBER = currentValue elif currentArgument in ("-p", "--preference_file"): PREFERENCE_DATA_PATH = currentValue if PREFERENCE_DATA_PATH is None: print( "You must specify a preference data file name.\nUse 'python3 recommender.py -h' for help." ) sys.exit(2) #Initialize DataManager dm = initializeDataManager() #Load/Create preference data if os.path.isfile(PREFERENCE_DATA_PATH): dm.loadPreferencesFromFile(PREFERENCE_DATA_PATH) print("---- {} classified songs loaded.".format(len(dm.y_known))) elif RAND_DATA_NUMBER: print("Generating {} random preferences".format(RAND_DATA_NUMBER)) dm.generateRandomPreferences(RAND_DATA_NUMBER) else: print( "\nNo training data found. Start listening to get personalized recommendations!" ) print( "Here are some random songs from the database. Take a listen, and enter '1' to indicate that you like the song, and '0' to indicate that you don't." ) print("Type 'size' to check how many songs you have classified.") print( "Once you have selected a few songs to start with, type 'train' to train the neural net and start listening to songs it thinks you'll like." ) for id, t in dm.getTrackIterator(): print("\n{} by {}\n-- Listen: {}".format( t['name'], t['artists'][0]['name'], t['external_urls']['spotify'])) i = input(">>> ") if i.strip() == "exit": exit() elif i.strip() == "train": if len(dm.y_known) < 2: print("\nYou must like or dislike at least two songs.") continue print( "\nbuilding the neural net and training with your new preferences" ) break elif i.strip() == "size": print("\nYou have classified {} songs.".format(len( dm.y_known))) elif i.strip() == "1": dm.updateKnownData(id, 1) elif i.strip() == "0": dm.updateKnownData(id, 0) else: print("\ninvalid input, please try again") print("\n\n-------------BUILDING NEURAL NET--------------") print( "----IGNORE KERAS/TENSORFLOW ERRORS THAT DISPLAY ON THE FIRST BUILD----" ) time.sleep(.5) nn = NeuralNet() nn.buildModel() #nn.plotModel() #nn.displayModel() if VERBOSE: print("training neural net") nn.trainModel(dm.x_known, dm.y_known) else: with HiddenPrints(): nn.trainModel(dm.x_known, dm.y_known) print("--------------DONE-------------") #Initialize "radio" mode outOfSongs = False songIndex = 0 recs = getTopSongs(nn, dm) if not recs: outOfSongs = True print( "\n\nYou are now in radio mode!\n------------------\nListen to songs the neural net has picked for you, and tell it if you liked them!" ) print( "Enter '1' to like, '0' to dislike, 'size' to check how many songs you've classified, 'train' to retrain the neural net with your new preferences, and 'exit' to save your preferences to file and quit" ) while not outOfSongs: t = recs[songIndex] print("\n{}% match: {} by {}\n-- Listen: {}".format( t['percent_match'], t['name'], t['artists'][0]['name'], t['external_urls']['spotify'])) i = input(">>> ") if i.strip() == "exit": saveAndQuit(dm, PREFERENCE_DATA_PATH) elif i.strip() == "train": print("\ntraining the neural net on your new preferences") if VERBOSE: nn.trainModel(dm.x_known, dm.y_known) else: with HiddenPrints(): nn.trainModel(dm.x_known, dm.y_known) recs = getTopSongs(nn, dm) songIndex = 0 if not recs: outOfSongs = True continue elif i.strip() == "size": print("\nYou have classified {} songs.".format(len(dm.y_known))) elif i.strip() == "1": dm.updateKnownData(t['id'], 1) songIndex += 1 elif i.strip() == "0": dm.updateKnownData(t['id'], 0) songIndex += 1 else: print("\ninvalid input, please try again") print( "\n\nYou have somehow categorized every song in the local database! (if you created random preferences, maybe the number was too big)\nTo get more songs, add more countries or increase the parameters in SongLoader, then change the name of the SONG_DATA file (or delete it) and restart the program. Your preferences will be saved now." ) saveAndQuit(dm, PREFERENCE_DATA_PATH)