|
import json |
|
from urllib import request |
|
from fastapi import FastAPI |
|
from starlette.middleware.sessions import SessionMiddleware |
|
from starlette.responses import HTMLResponse, RedirectResponse |
|
from starlette.requests import Request |
|
import gradio as gr |
|
import uvicorn |
|
from fastapi.responses import HTMLResponse |
|
from fastapi.responses import RedirectResponse |
|
import pandas as pd |
|
|
|
import spotipy |
|
from spotipy import oauth2 |
|
|
|
import heatmap |
|
|
|
import numpy as np |
|
|
|
import matplotlib.pyplot as plt |
|
from matplotlib.patches import Circle, RegularPolygon |
|
from matplotlib.path import Path |
|
from matplotlib.projections.polar import PolarAxes |
|
from matplotlib.projections import register_projection |
|
from matplotlib.spines import Spine |
|
from matplotlib.transforms import Affine2D |
|
import matplotlib |
|
|
|
matplotlib.use('SVG') |
|
|
|
|
|
def get_features2(spotify): |
|
features = [] |
|
for index in range(0, 10): |
|
results = spotify.current_user_saved_tracks(offset=index*50, limit=50) |
|
track_ids = [item['track']['id'] for item in results['items']] |
|
features.extend(spotify.audio_features(track_ids)) |
|
|
|
df = pd.DataFrame(data=features) |
|
names = [ |
|
'danceability', |
|
'energy', |
|
|
|
'speechiness', |
|
'acousticness', |
|
'instrumentalness', |
|
'liveness', |
|
'valence', |
|
] |
|
features_means = df[names].mean() |
|
return names, features_means.values |
|
|
|
|
|
def radar_factory(num_vars, frame='circle'): |
|
""" |
|
Create a radar chart with `num_vars` axes. |
|
|
|
This function creates a RadarAxes projection and registers it. |
|
|
|
Parameters |
|
---------- |
|
num_vars : int |
|
Number of variables for radar chart. |
|
frame : {'circle', 'polygon'} |
|
Shape of frame surrounding axes. |
|
|
|
""" |
|
|
|
theta = np.linspace(0, 2*np.pi, num_vars, endpoint=False) |
|
|
|
class RadarTransform(PolarAxes.PolarTransform): |
|
|
|
def transform_path_non_affine(self, path): |
|
|
|
|
|
|
|
if path._interpolation_steps > 1: |
|
path = path.interpolated(num_vars) |
|
return Path(self.transform(path.vertices), path.codes) |
|
|
|
class RadarAxes(PolarAxes): |
|
|
|
name = 'radar' |
|
PolarTransform = RadarTransform |
|
|
|
def __init__(self, *args, **kwargs): |
|
super().__init__(*args, **kwargs) |
|
|
|
self.set_theta_zero_location('N') |
|
|
|
def fill(self, *args, closed=True, **kwargs): |
|
"""Override fill so that line is closed by default""" |
|
return super().fill(closed=closed, *args, **kwargs) |
|
|
|
def plot(self, *args, **kwargs): |
|
"""Override plot so that line is closed by default""" |
|
lines = super().plot(*args, **kwargs) |
|
for line in lines: |
|
self._close_line(line) |
|
|
|
def _close_line(self, line): |
|
x, y = line.get_data() |
|
|
|
if x[0] != x[-1]: |
|
x = np.append(x, x[0]) |
|
y = np.append(y, y[0]) |
|
line.set_data(x, y) |
|
|
|
def set_varlabels(self, labels): |
|
self.set_thetagrids(np.degrees(theta), labels) |
|
|
|
def _gen_axes_patch(self): |
|
|
|
|
|
if frame == 'circle': |
|
return Circle((0.5, 0.5), 0.5) |
|
elif frame == 'polygon': |
|
return RegularPolygon((0.5, 0.5), num_vars, |
|
radius=.5, edgecolor="k") |
|
else: |
|
raise ValueError("Unknown value for 'frame': %s" % frame) |
|
|
|
def _gen_axes_spines(self): |
|
if frame == 'circle': |
|
return super()._gen_axes_spines() |
|
elif frame == 'polygon': |
|
|
|
spine = Spine(axes=self, |
|
spine_type='circle', |
|
path=Path.unit_regular_polygon(num_vars)) |
|
|
|
|
|
|
|
spine.set_transform(Affine2D().scale(.5).translate(.5, .5) |
|
+ self.transAxes) |
|
return {'polar': spine} |
|
else: |
|
raise ValueError("Unknown value for 'frame': %s" % frame) |
|
|
|
register_projection(RadarAxes) |
|
return theta |
|
|
|
def get_spider_plot(request: gr.Request): |
|
token = request.request.session.get('token') |
|
sp = spotipy.Spotify(token) |
|
names, data = get_features2(sp) |
|
|
|
theta = radar_factory(len(names), frame='polygon') |
|
|
|
fig = plt.figure(figsize=(9, 9)) |
|
ax = fig.add_axes([0, 0, 1, 1], projection='radar') |
|
|
|
|
|
title = 'test' |
|
ax.set_rgrids([0.2, 0.4, 0.6, 0.8]) |
|
ax.set_title(title, weight='bold', size='medium', position=(0.5, 1.1), |
|
horizontalalignment='center', verticalalignment='center') |
|
|
|
ax.plot(theta, data) |
|
ax.fill(theta, data, alpha=0.25, label='_nolegend_') |
|
|
|
ax.set_varlabels(names) |
|
|
|
return fig |
|
|
|
|
|
PORT_NUMBER = 8080 |
|
SPOTIPY_CLIENT_ID = 'c087fa97cebb4f67b6f08ba841ed8378' |
|
SPOTIPY_CLIENT_SECRET = 'ae27d6916d114ac4bb948bb6c58a72d9' |
|
SPOTIPY_REDIRECT_URI = 'https://hf-hackathon-2023-01-spotify.hf.space' |
|
SCOPE = 'user-library-read' |
|
|
|
sp_oauth = oauth2.SpotifyOAuth(SPOTIPY_CLIENT_ID, SPOTIPY_CLIENT_SECRET, SPOTIPY_REDIRECT_URI, scope=SCOPE) |
|
|
|
app = FastAPI() |
|
app.add_middleware(SessionMiddleware, secret_key="w.o.w") |
|
|
|
@app.get('/', response_class=HTMLResponse) |
|
async def homepage(request: Request): |
|
token = request.session.get('token') |
|
if token: |
|
return RedirectResponse("/gradio") |
|
|
|
url = str(request.url) |
|
code = sp_oauth.parse_response_code(url) |
|
if code != url: |
|
token_info = sp_oauth.get_access_token(code) |
|
request.session['token'] = token_info['access_token'] |
|
return RedirectResponse("/gradio") |
|
|
|
auth_url = sp_oauth.get_authorize_url() |
|
return "<a href='" + auth_url + "'>Login to Spotify</a>" |
|
|
|
|
|
|
|
from vega_datasets import data |
|
|
|
iris = data.iris() |
|
|
|
|
|
def scatter_plot_fn(request: gr.Request): |
|
token = request.request.session.get('token') |
|
if token: |
|
sp = spotipy.Spotify(token) |
|
results = sp.current_user() |
|
print(results) |
|
return gr.ScatterPlot( |
|
value=iris, |
|
) |
|
|
|
def heatmap_plot_fn(request: gr.Request): |
|
token = request.request.session.get('token') |
|
if token: |
|
sp = spotipy.Spotify(token) |
|
data = heatmap.build_heatmap(heatmap.fetch_recent_songs(sp)) |
|
fig, _ = heatmap.plot(data) |
|
return fig |
|
|
|
|
|
def get_features(spotify): |
|
features = [] |
|
for index in range(0, 10): |
|
results = spotify.current_user_saved_tracks(offset=index*50, limit=50) |
|
track_ids = [item['track']['id'] for item in results['items']] |
|
features.extend(spotify.audio_features(track_ids)) |
|
|
|
df = pd.DataFrame(data=features) |
|
names = [ |
|
'danceability', |
|
'energy', |
|
'loudness', |
|
'speechiness', |
|
'acousticness', |
|
'instrumentalness', |
|
'liveness', |
|
'valence', |
|
'tempo', |
|
] |
|
features_means = df[names].mean() |
|
|
|
return features_means |
|
|
|
|
|
|
|
def get_started(): |
|
|
|
|
|
return |
|
|
|
with gr.Blocks() as demo: |
|
gr.Markdown(" ## Spotify Analyzer 🥳🎉") |
|
gr.Markdown("This app analyzes how cool your music taste is. We dare you to take this challenge!") |
|
with gr.Row(): |
|
get_started_btn = gr.Button("Get Started") |
|
with gr.Row(): |
|
spider_plot = gr.Plot() |
|
with gr.Row(): |
|
with gr.Column(): |
|
with gr.Row(): |
|
with gr.Column(): |
|
hm_plot = gr.Plot().style(container=True) |
|
with gr.Column(): |
|
plot = gr.ScatterPlot(show_label=False).style(container=True) |
|
with gr.Row(): |
|
with gr.Column(): |
|
plot = gr.ScatterPlot(show_label=False).style(container=True) |
|
with gr.Column(): |
|
plot = gr.ScatterPlot(show_label=False).style(container=True) |
|
with gr.Row(): |
|
gr.Markdown(" ### We have recommendations for you!") |
|
with gr.Row(): |
|
gr.Dataframe( |
|
headers=["Song", "Album", "Artist"], |
|
datatype=["str", "str", "str"], |
|
label="Reccomended Songs", |
|
value=[["something", "something", "something"], ["something", "something", "something"]] |
|
) |
|
|
|
demo.load(fn=heatmap_plot_fn, output=hm_plot) |
|
demo.load(fn=get_spider_plot, outputs=spider_plot) |
|
|
|
|
|
gradio_app = gr.mount_gradio_app(app, demo, "/gradio") |
|
uvicorn.run(app, host="0.0.0.0", port=7860) |
|
|