from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel import joblib from sentence_transformers import SentenceTransformer import requests import os from dotenv import load_dotenv load_dotenv() app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*"], # update to your frontend URL after deployment allow_methods=["*"], allow_headers=["*"], ) # loads fine on HF Spaces — no size limit like Render model = joblib.load("emotion_song_model.pkl") encoder = SentenceTransformer("all-MiniLM-L6-v2") LASTFM_API_KEY = os.getenv("LASTFM_API_KEY") class TextInput(BaseModel): text: str mood_to_tags = { "happy": ["happy", "pop"], "sad": ["sad", "melancholy"], "angry": ["metal", "rock"], "anxious": ["chill", "ambient"], "calm": ["ambient", "acoustic"], "romantic": ["love", "romance"], } @app.post("/detect-mood") def detect_mood(input: TextInput): vector = encoder.encode([input.text]) mood = model.predict(vector)[0] return {"mood": mood} import random @app.post("/recommendations") def get_recommendations(input: TextInput): vector = encoder.encode([input.text]) mood = model.predict(vector)[0] tags = mood_to_tags[mood] all_tracks = [] for tag in tags: response = requests.get( "http://ws.audioscrobbler.com/2.0/", params={ "method": "tag.getTopTracks", "tag": tag, "api_key": LASTFM_API_KEY, "format": "json", "limit": 25, } ) data = response.json() if "tracks" in data and "track" in data["tracks"]: all_tracks.extend(data["tracks"]["track"]) # remove duplicates seen = set() unique_tracks = [] for track in all_tracks: key = ( track["name"].lower(), track["artist"]["name"].lower() ) if key not in seen: seen.add(key) unique_tracks.append(track) # randomize playlist random.shuffle(unique_tracks) # return only 10 songs unique_tracks = unique_tracks[:10] songs = [ { "name": track["name"], "artist": track["artist"]["name"], "url": track["url"], } for track in unique_tracks ] return { "mood": mood, "songs": songs }