Spaces:
Running
Running
Upload 5 files
Browse files- .gitattributes +1 -0
- music_mental_health.csv +3 -0
- sentiment_analysis.py +26 -0
- serve_streamlit.py +53 -0
- song_matching.py +39 -0
- spotify_api.py +33 -0
.gitattributes
CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
music_mental_health.csv filter=lfs diff=lfs merge=lfs -text
|
music_mental_health.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:d0cbdc528fb1e62a93c1cb61f2a416072154f7c74e344cc2143e75d6abfa51d0
|
3 |
+
size 161543173
|
sentiment_analysis.py
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import tensorflow as tf
|
2 |
+
from transformers import RobertaTokenizer, TFRobertaForSequenceClassification
|
3 |
+
|
4 |
+
class SentimentAnalyzer:
|
5 |
+
def __init__(self, model_name='roberta-base', classifier_model='arpanghoshal/EmoRoBERTa'):
|
6 |
+
"""
|
7 |
+
Initializes the sentiment analyzer with the specified models.
|
8 |
+
:param model_name: Name of the tokenizer model
|
9 |
+
:param classifier_model: Name of the sentiment classification model
|
10 |
+
"""
|
11 |
+
self.tokenizer = RobertaTokenizer.from_pretrained(model_name)
|
12 |
+
self.model = TFRobertaForSequenceClassification.from_pretrained(classifier_model)
|
13 |
+
|
14 |
+
def analyze_sentiment(self, user_input):
|
15 |
+
"""
|
16 |
+
Analyzes the sentiment of the given user input.
|
17 |
+
:param user_input: Text input from the user
|
18 |
+
:return: A tuple of sentiment label and sentiment score
|
19 |
+
"""
|
20 |
+
encoded_input = self.tokenizer(user_input, return_tensors="tf", truncation=True, padding=True, max_length=512)
|
21 |
+
outputs = self.model(encoded_input)
|
22 |
+
scores = tf.nn.softmax(outputs.logits, axis=-1).numpy()[0]
|
23 |
+
predicted_class_idx = tf.argmax(outputs.logits, axis=-1).numpy()[0]
|
24 |
+
sentiment_label = self.model.config.id2label[predicted_class_idx]
|
25 |
+
sentiment_score = scores[predicted_class_idx]
|
26 |
+
return sentiment_label, sentiment_score
|
serve_streamlit.py
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pathlib
|
2 |
+
import modal
|
3 |
+
|
4 |
+
# Define container dependencies
|
5 |
+
image = (
|
6 |
+
modal.Image.debian_slim()
|
7 |
+
.apt_install("git")
|
8 |
+
.pip_install("streamlit", "numpy", "pandas", "tensorflow", "transformers", "spotipy", "sentence_transformers")
|
9 |
+
)
|
10 |
+
|
11 |
+
stub = modal.Stub(name="streamlit_app.py", image=image)
|
12 |
+
|
13 |
+
# Define the run_streamlit function
|
14 |
+
@stub.function(
|
15 |
+
mounts=[
|
16 |
+
modal.Mount.from_local_directory(
|
17 |
+
local_path=pathlib.Path(__file__).parent,
|
18 |
+
remote_path=pathlib.Path("/app"),
|
19 |
+
exclude=["*.pyc", "__pycache__"]
|
20 |
+
)
|
21 |
+
],
|
22 |
+
timeout=15 * 60 # Set the session timeout as needed
|
23 |
+
)
|
24 |
+
def run_streamlit(publish_url: bool = False):
|
25 |
+
import streamlit.web.bootstrap
|
26 |
+
|
27 |
+
streamlit_script_remote_path = pathlib.Path("streamlit_app.py")
|
28 |
+
|
29 |
+
# Run the server. This function will not return until the server is shut down.
|
30 |
+
with modal.forward(8501) as tunnel:
|
31 |
+
# Reload Streamlit config with information about Modal tunnel address.
|
32 |
+
if publish_url:
|
33 |
+
stub.q.put(tunnel.url)
|
34 |
+
streamlit.web.bootstrap.run(
|
35 |
+
main_script_path=str(streamlit_script_remote_path),
|
36 |
+
command_line=None,
|
37 |
+
args=["--timeout", str(15 * 60)], # Adjust as needed
|
38 |
+
flag_options={},
|
39 |
+
)
|
40 |
+
|
41 |
+
# Additional function for creating a web endpoint
|
42 |
+
@stub.function()
|
43 |
+
@modal.web_endpoint(method="GET")
|
44 |
+
def share():
|
45 |
+
from fastapi.responses import RedirectResponse
|
46 |
+
|
47 |
+
run_streamlit.spawn(publish_url=True)
|
48 |
+
url = stub.q.get()
|
49 |
+
return RedirectResponse(url, status_code=303)
|
50 |
+
|
51 |
+
# Deploy the app
|
52 |
+
if __name__ == "__main__":
|
53 |
+
stub.deploy()
|
song_matching.py
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
from sentence_transformers import SentenceTransformer, util
|
3 |
+
|
4 |
+
class SongMatcher:
|
5 |
+
def __init__(self, songs_data_file, model_name="sentence-transformers/all-mpnet-base-v2"):
|
6 |
+
"""
|
7 |
+
Initializes the SongMatcher with the songs data file and the SentenceTransformer model.
|
8 |
+
:param songs_data_file: Path to the CSV file containing songs data
|
9 |
+
:param model_name: Name of the SentenceTransformer model
|
10 |
+
"""
|
11 |
+
self.songs_df = pd.read_csv(songs_data_file)
|
12 |
+
self.sim_model = SentenceTransformer(model_name)
|
13 |
+
|
14 |
+
def match_songs_with_sentiment(self, user_sentiment_label, user_sentiment_score, user_input, score_range=0.00625):
|
15 |
+
"""
|
16 |
+
Matches songs from the dataset with the user's sentiment.
|
17 |
+
:param user_sentiment_label: The sentiment label of the user input
|
18 |
+
:param user_sentiment_score: The sentiment score of the user input
|
19 |
+
:param user_input: Text input from the user
|
20 |
+
:param score_range: Range for filtering songs based on sentiment score
|
21 |
+
:return: DataFrame of top 5 matched songs
|
22 |
+
"""
|
23 |
+
# Filter songs with the same sentiment label
|
24 |
+
matched_songs = self.songs_df[self.songs_df['sentiment'] == user_sentiment_label]
|
25 |
+
|
26 |
+
# Calculate the score range
|
27 |
+
score_min = max(0, user_sentiment_score - score_range)
|
28 |
+
score_max = min(1, user_sentiment_score + score_range)
|
29 |
+
|
30 |
+
# Further filter songs whose scores fall within the specified range
|
31 |
+
matched_songs = matched_songs[(matched_songs['score'] >= score_min) & (matched_songs['score'] <= score_max)]
|
32 |
+
|
33 |
+
# Compute similarity between user input and song lyrics
|
34 |
+
input_vector = self.sim_model.encode(user_input)
|
35 |
+
matched_songs['similarity'] = matched_songs['seq'].apply(lambda x: util.pytorch_cos_sim(self.sim_model.encode(x), input_vector))
|
36 |
+
|
37 |
+
# Select the top five songs based on similarity and return
|
38 |
+
top_5 = matched_songs.nlargest(5, 'similarity')
|
39 |
+
return top_5[['song', 'artist', 'seq', 'similarity', 'sentiment', 'score']]
|
spotify_api.py
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import spotipy
|
2 |
+
from spotipy.oauth2 import SpotifyClientCredentials
|
3 |
+
|
4 |
+
class SpotifyClient:
|
5 |
+
def __init__(self, client_id, client_secret):
|
6 |
+
"""
|
7 |
+
Initializes the SpotifyClient with given client credentials.
|
8 |
+
:param client_id: Spotify API Client ID
|
9 |
+
:param client_secret: Spotify API Client Secret
|
10 |
+
"""
|
11 |
+
self.sp = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials(client_id, client_secret))
|
12 |
+
|
13 |
+
def get_track_id(self, song_name):
|
14 |
+
"""
|
15 |
+
Searches for a track by name and returns its Spotify ID.
|
16 |
+
:param song_name: The name of the song to search for
|
17 |
+
:return: Spotify track ID or None if not found
|
18 |
+
"""
|
19 |
+
results = self.sp.search(q=song_name, type='track', limit=1)
|
20 |
+
if results['tracks']['items']:
|
21 |
+
return results['tracks']['items'][0]['id']
|
22 |
+
else:
|
23 |
+
print(f"No results found for {song_name}")
|
24 |
+
return None
|
25 |
+
|
26 |
+
def get_track_preview_url(self, track_id):
|
27 |
+
"""
|
28 |
+
Retrieves the 30-second preview URL for a given track ID.
|
29 |
+
:param track_id: Spotify track ID
|
30 |
+
:return: Preview URL or None if not available
|
31 |
+
"""
|
32 |
+
track_info = self.sp.track(track_id)
|
33 |
+
return track_info.get('preview_url')
|