huathedev commited on
Commit
db7246b
·
1 Parent(s): 2a81672

Upload 2 files

Browse files
pages/01_Recommend_from_Song🎤.py ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import spotipy
2
+ import streamlit as st
3
+ import numpy as np
4
+ from spotipy.oauth2 import SpotifyClientCredentials
5
+ from PIL import Image
6
+ import requests
7
+ import pandas as pd
8
+
9
+ st.set_page_config(
10
+ page_title="Find Songs Similar to Yours🎤", page_icon="🎤", layout="wide"
11
+ )
12
+
13
+ # Spotify API
14
+ SPOTIPY_CLIENT_ID = st.secrets.spot_creds.spot_client_id
15
+ SPOTIPY_CLIENT_SECRET = st.secrets.spot_creds.spot_client_secret
16
+
17
+ sp = spotipy.Spotify(
18
+ auth_manager=SpotifyClientCredentials(
19
+ client_id=SPOTIPY_CLIENT_ID, client_secret=SPOTIPY_CLIENT_SECRET
20
+ )
21
+ )
22
+
23
+ """
24
+ # Analyze Song and Get Recommendations🎤
25
+
26
+ Input a song title and the app will return recommendations as well as the features of the song.
27
+
28
+ Data is obtained using the Python library [Spotipy](https://spotipy.readthedocs.io/en/2.18.0/) that uses [Spotify Web API.](https://developer.spotify.com/documentation/web-api/)
29
+
30
+ """
31
+ song = st.text_input("Enter a song title", value="Somebody Else")
32
+ search = sp.search(q="track:" + song, type="track")
33
+
34
+
35
+ class GetSongInfo:
36
+ def __init__(self, search):
37
+ self.search = search
38
+
39
+ def song_id(self):
40
+ song_id = search["tracks"]["items"][0]["id"] # -gets song id
41
+ return song_id
42
+
43
+ def song_album(self):
44
+ song_album = search["tracks"]["items"][0]["album"][
45
+ "name"
46
+ ] # -gets song album name
47
+ return song_album
48
+
49
+ def song_image(self):
50
+ song_image = search["tracks"]["items"][0]["album"]["images"][0][
51
+ "url"
52
+ ] # -gets song image URL
53
+ return song_image
54
+
55
+ def song_artist_name(self):
56
+ song_artist_name = search["tracks"]["items"][0]["artists"][0][
57
+ "name"
58
+ ] # -gets artist for song
59
+ return song_artist_name
60
+
61
+ def song_name(self):
62
+ song_name = search["tracks"]["items"][0]["name"] # -gets song name
63
+ return song_name
64
+
65
+ def song_preview(self):
66
+ song_preview = search["tracks"]["items"][0]["preview_url"]
67
+ return song_preview
68
+
69
+
70
+ songs = GetSongInfo(song)
71
+
72
+ ###
73
+
74
+
75
+ def url(song):
76
+ url_to_song = "https://open.spotify.com/track/" + songs.song_id()
77
+ st.write(
78
+ f"Link to stream '{songs.song_name()}' by {songs.song_artist_name()} on Spotify: {url_to_song}"
79
+ )
80
+
81
+
82
+ # Set up two-column layout for Streamlit app
83
+ image, stats = st.columns(2)
84
+
85
+ with image:
86
+ try:
87
+ url(song)
88
+ r = requests.get(songs.song_image())
89
+ open("img/" + songs.song_id() + ".jpg", "w+b").write(r.content)
90
+ image_album = Image.open("img/" + songs.song_id() + ".jpg")
91
+ st.image(
92
+ image_album,
93
+ caption=f"{songs.song_artist_name()} - {songs.song_album()}",
94
+ use_column_width="auto",
95
+ )
96
+
97
+ feat = sp.audio_features(tracks=[songs.song_id()])
98
+ features = feat[0]
99
+ p = pd.Series(features).to_frame()
100
+ data_feat = p.loc[
101
+ [
102
+ "acousticness",
103
+ "danceability",
104
+ "energy",
105
+ "liveness",
106
+ "speechiness",
107
+ "valence",
108
+ ]
109
+ ]
110
+ bpm = p.loc[["tempo"]]
111
+ values = bpm.values[0]
112
+ bpms = values.item()
113
+ ticks = np.linspace(0, 1, 11)
114
+
115
+ plot = data_feat.plot.barh(
116
+ xticks=ticks, legend=False, color="limegreen"
117
+ ) # Use Pandas plot
118
+ plot.set_xlabel("Value")
119
+ plot.set_ylabel("Parameters")
120
+ plot.set_title(f"Analysing '{songs.song_name()}' by {songs.song_artist_name()}")
121
+ plot.invert_yaxis()
122
+ st.pyplot(plot.figure)
123
+ st.subheader(f"BPM (Beats Per Minute): {bpms}")
124
+
125
+ st.warning(
126
+ "Note: Audio previews may have very high default volume and will reset after page refresh"
127
+ )
128
+ st.audio(songs.song_preview(), format="audio/wav")
129
+
130
+ except IndexError or NameError:
131
+ st.error(
132
+ "This error is possibly due to the API being unable to find the song. Maybe try to retype it using the song title followed by artist without any hyphens (e.g. In my Blood Shawn Mendes)"
133
+ )
134
+
135
+ # Recommendations
136
+ with stats:
137
+ st.subheader("You might also like")
138
+
139
+ reco = sp.recommendations(
140
+ seed_artists=None, seed_tracks=[songs.song_id()], seed_genres=[], limit=10
141
+ )
142
+
143
+ for i in reco["tracks"]:
144
+ st.write(f"\"{i['name']}\" - {i['artists'][0]['name']}")
145
+ image_reco = requests.get(i["album"]["images"][2]["url"])
146
+ open("img/" + i["id"] + ".jpg", "w+b").write(image_reco.content)
147
+ st.image(Image.open("img/" + i["id"] + ".jpg"))
pages/02_Recommend_from_Genre_Features🎸.py ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+ # Configure Streamlit page
4
+ st.set_page_config(
5
+ page_title="Find the Song that You Like🎸", page_icon="🎸", layout="wide"
6
+ )
7
+
8
+ import pandas as pd
9
+ import plotly.express as px
10
+ import streamlit.components.v1 as components
11
+ from sklearn.neighbors import NearestNeighbors
12
+
13
+
14
+ @st.cache(allow_output_mutation=True)
15
+ def data_import():
16
+ """Function for loading in cleaned data csv file."""
17
+ df = pd.read_csv("data/clean_data.csv")
18
+ df["genres"] = df.genres.apply(
19
+ lambda x: [i[1:-1] for i in str(x)[1:-1].split(", ")]
20
+ )
21
+ df_explode = df.explode("genres")
22
+ return df_explode
23
+
24
+
25
+ genre_names = [
26
+ "Dance Pop",
27
+ "Electronic",
28
+ "Electropop",
29
+ "Hip Hop",
30
+ "Jazz",
31
+ "K-pop",
32
+ "Latin",
33
+ "Pop",
34
+ "Pop Rap",
35
+ "R&B",
36
+ "Rock",
37
+ ]
38
+ audio_params = [
39
+ "acousticness",
40
+ "danceability",
41
+ "energy",
42
+ "instrumentalness",
43
+ "valence",
44
+ "tempo",
45
+ ]
46
+
47
+ df_explode = data_import()
48
+
49
+
50
+ def match_song(genre, yr_start, yr_end, test_feat):
51
+ """Function for finding similar songs with KNN algorithm."""
52
+ genre = genre.lower()
53
+ genre_data = df_explode[
54
+ (df_explode["genres"] == genre)
55
+ & (df_explode["release_year"] >= yr_start)
56
+ & (df_explode["release_year"] <= yr_end)
57
+ ]
58
+ genre_data = genre_data.sort_values(by="popularity", ascending=False)[:500]
59
+
60
+ # Load KNN from SkLearn
61
+ neigh = NearestNeighbors()
62
+ neigh.fit(genre_data[audio_params].to_numpy())
63
+
64
+ n_neighbors = neigh.kneighbors(
65
+ [test_feat], n_neighbors=len(genre_data), return_distance=False
66
+ )[0]
67
+
68
+ uris = genre_data.iloc[n_neighbors]["uri"].tolist()
69
+ audios = genre_data.iloc[n_neighbors][audio_params].to_numpy()
70
+
71
+ return uris, audios
72
+
73
+
74
+ # Setup page order
75
+ def page():
76
+ title = "Find Your Song🎸"
77
+ st.title(title)
78
+
79
+ st.write(
80
+ "Get recommended songs on Spotify based on genre and key audio parameters."
81
+ )
82
+ st.markdown("##")
83
+
84
+ # Streamlit column layout
85
+ with st.container():
86
+ col1, col2, col3, col4 = st.columns((2, 0.5, 0.5, 0.5))
87
+
88
+ with col3:
89
+ st.markdown("***Select genre:***")
90
+ genre = st.radio("", genre_names, index=genre_names.index("Rock"))
91
+
92
+ with col1:
93
+ st.markdown("***Select audio parameters to customize:***")
94
+ yr_start, yr_end = st.slider(
95
+ "Select the year range", 1908, 2022, (1980, 2022)
96
+ )
97
+ acousticness = st.slider("Acousticness", 0.0, 1.0, 0.5)
98
+ danceability = st.slider("Danceability", 0.0, 1.0, 0.5)
99
+ energy = st.slider("Energy", 0.0, 1.0, 0.5)
100
+ instrumentalness = st.slider("Instrumentalness", 0.0, 1.0, 0.5)
101
+ valence = st.slider("Valence", 0.0, 1.0, 0.45)
102
+ tempo = st.slider("Tempo", 0.0, 244.0, 125.01)
103
+
104
+ pr_page_tracks = 6
105
+ test_feat = [acousticness, danceability, energy, instrumentalness, valence, tempo]
106
+ uris, audios = match_song(genre, yr_start, yr_end, test_feat)
107
+
108
+ tracks = []
109
+ for uri in uris:
110
+ track = """<iframe src="https://open.spotify.com/embed/track/{}" width="280" height="400" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe>""".format(
111
+ uri
112
+ )
113
+ tracks.append(track)
114
+
115
+ if "previous_inputs" not in st.session_state:
116
+ st.session_state["previous_inputs"] = [genre, yr_start, yr_end] + test_feat
117
+
118
+ current_inputs = [genre, yr_start, yr_end] + test_feat
119
+ if current_inputs != st.session_state["previous_inputs"]:
120
+ if "start_track_i" in st.session_state:
121
+ st.session_state["start_track_i"] = 0
122
+
123
+ st.session_state["previous_inputs"] = current_inputs
124
+
125
+ if "start_track_i" not in st.session_state:
126
+ st.session_state["start_track_i"] = 0
127
+
128
+ with st.container():
129
+ col1, col2, col3 = st.columns([2, 1, 2])
130
+ if st.button("More Songs"):
131
+ if st.session_state["start_track_i"] < len(tracks):
132
+ st.session_state["start_track_i"] += pr_page_tracks
133
+
134
+ current_tracks = tracks[
135
+ st.session_state["start_track_i"] : st.session_state["start_track_i"]
136
+ + pr_page_tracks
137
+ ]
138
+ current_audios = audios[
139
+ st.session_state["start_track_i"] : st.session_state["start_track_i"]
140
+ + pr_page_tracks
141
+ ]
142
+ if st.session_state["start_track_i"] < len(tracks):
143
+ for i, (track, audio) in enumerate(zip(current_tracks, current_audios)):
144
+ if i % 2 == 0:
145
+ with col1:
146
+ components.html(
147
+ track,
148
+ height=400,
149
+ )
150
+ with st.expander("Display Chart"):
151
+ df = pd.DataFrame(dict(r=audio[:5], theta=audio_params[:5]))
152
+ fig = px.line_polar(
153
+ df, r="r", theta="theta", line_close=True
154
+ )
155
+ fig.update_layout(height=400, width=340)
156
+ st.plotly_chart(fig)
157
+
158
+ else:
159
+ with col3:
160
+ components.html(
161
+ track,
162
+ height=400,
163
+ )
164
+ with st.expander("Display Chart"):
165
+ df = pd.DataFrame(dict(r=audio[:5], theta=audio_params[:5]))
166
+ fig = px.line_polar(
167
+ df, r="r", theta="theta", line_close=True
168
+ )
169
+ fig.update_layout(height=400, width=340)
170
+ st.plotly_chart(fig)
171
+ else:
172
+ st.write("No more songs")
173
+
174
+
175
+ page()