Spaces:
Sleeping
Sleeping
from fastapi import FastAPI, File, UploadFile, Request | |
from fastapi.middleware.cors import CORSMiddleware | |
from fastapi.responses import JSONResponse | |
import os | |
import shutil | |
import librosa | |
import numpy as np | |
from spotipy import Spotify | |
from spotipy.oauth2 import SpotifyClientCredentials | |
app = FastAPI() | |
# CORS for frontend integration | |
app.add_middleware( | |
CORSMiddleware, | |
allow_origins=["*"], # For production, restrict to your frontend URL | |
allow_credentials=True, | |
allow_methods=["*"], | |
allow_headers=["*"], | |
) | |
# Spotify API client initialization from environment variables (set as HF Secrets) | |
client_id = os.getenv('SPOTIPY_CLIENT_ID') | |
client_secret = os.getenv('SPOTIPY_CLIENT_SECRET') | |
if not client_id or not client_secret: | |
raise RuntimeError("Spotify API credentials not found in environment variables") | |
sp = Spotify(client_credentials_manager=SpotifyClientCredentials(client_id=client_id, client_secret=client_secret)) | |
def extract_fingerprint(audio_path: str): | |
"""Extracts a simple MFCC-based fingerprint from the audio file.""" | |
y, sr = librosa.load(audio_path, sr=22050, mono=True) | |
mfcc = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13) | |
fingerprint = np.mean(mfcc, axis=1) | |
return fingerprint.tolist() | |
async def recognize(request: Request, file: UploadFile = File(None)): | |
if request.method == "GET": | |
return JSONResponse( | |
{"message": "Send a POST request with an audio file (field name: 'file') to recognize a song."} | |
) | |
# POST logic: | |
# Use fallback demo.mp3 if no file uploaded | |
if file is None or file.filename == "": | |
audio_path = "demo.mp3" | |
if not os.path.exists(audio_path): | |
return JSONResponse({"error": "No file uploaded and demo.mp3 not found"}, status_code=400) | |
else: | |
audio_path = f"temp_{file.filename}" | |
with open(audio_path, "wb") as buffer: | |
shutil.copyfileobj(file.file, buffer) | |
try: | |
fingerprint = extract_fingerprint(audio_path) | |
except Exception as e: | |
if audio_path.startswith("temp_") and os.path.exists(audio_path): | |
os.remove(audio_path) | |
return JSONResponse({"error": f"Audio processing failed: {str(e)}"}, status_code=500) | |
# For demo: search Spotify for a fixed song | |
try: | |
results = sp.search(q='Shape of You', type='track', limit=1) | |
if results['tracks']['items']: | |
track = results['tracks']['items'][0] | |
response = { | |
'title': track['name'], | |
'artist': track['artists'][0]['name'], | |
'album': track['album']['name'], | |
'cover_url': track['album']['images'][0]['url'], | |
'preview_url': track['preview_url'] | |
} | |
else: | |
response = {'error': 'No match found'} | |
except Exception as e: | |
response = {'error': f'Spotify API error: {str(e)}'} | |
if audio_path.startswith("temp_") and os.path.exists(audio_path): | |
os.remove(audio_path) | |
return JSONResponse(content=response) | |
def root(): | |
return {"message": "TrueTrace FastAPI backend is running!"} | |