| import os |
| import io |
| import tempfile |
| import numpy as np |
| import librosa |
| from fastapi import FastAPI, File, UploadFile |
| from fastapi.responses import JSONResponse |
| import tensorflow as tf |
|
|
| app = FastAPI(title="AI Music Mood Categorizer") |
|
|
| |
| MOODS = ["gym", "travel", "chill", "sleep", "love", "sad", "party", "study"] |
|
|
| |
| |
| |
|
|
| def extract_features(audio_path): |
| """ |
| Extracts audio features using librosa. |
| This takes the 15-second audio chunk sent by the Flutter app. |
| """ |
| |
| |
| y, sr = librosa.load(audio_path, sr=22050) |
| |
| |
| |
| mfcc = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13) |
| mfcc_mean = np.mean(mfcc.T, axis=0) |
| |
| |
| chroma = librosa.feature.chroma_stft(y=y, sr=sr) |
| chroma_mean = np.mean(chroma.T, axis=0) |
| |
| |
| contrast = librosa.feature.spectral_contrast(y=y, sr=sr) |
| contrast_mean = np.mean(contrast.T, axis=0) |
|
|
| |
| tempo, _ = librosa.beat.beat_track(y=y, sr=sr) |
| |
| |
| |
| features = np.hstack([mfcc_mean, chroma_mean, contrast_mean, tempo]) |
| return features, tempo[0] |
|
|
| @app.post("/analyze") |
| async def analyze_audio(file: UploadFile = File(...)): |
| """ |
| Endpoint that receives the 15s audio chunk from Flutter, |
| extracts features, runs the AI model, and returns the mood. |
| """ |
| try: |
| |
| with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_audio: |
| content = await file.read() |
| temp_audio.write(content) |
| temp_audio_path = temp_audio.name |
|
|
| |
| features, bpm = extract_features(temp_audio_path) |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| predicted_mood = "chill" |
| if bpm > 140: |
| predicted_mood = "gym" |
| elif bpm > 120: |
| predicted_mood = "party" |
| elif bpm > 100: |
| predicted_mood = "travel" |
| elif bpm < 70: |
| predicted_mood = "sleep" |
| elif bpm < 90: |
| predicted_mood = "sad" |
| |
|
|
| |
| os.remove(temp_audio_path) |
|
|
| return JSONResponse(content={ |
| "mood": predicted_mood, |
| "bpm": float(bpm), |
| "status": "success" |
| }) |
|
|
| except Exception as e: |
| return JSONResponse( |
| status_code=500, |
| content={"status": "error", "message": str(e)} |
| ) |
|
|
| |
| |
| |
|
|