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
Пример #2
0
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)