File size: 5,272 Bytes
73b1793
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d9c2543
 
73b1793
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# -*- coding: utf-8 -*-
"""SONG.ipynb

Automatically generated by Colab.

Original file is located at
    https://colab.research.google.com/drive/1D_uRTl2aO65nt7ABxgODlb57aLqY05HC
"""

import gradio as gr
import numpy as np
import librosa
import os
import requests
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report
import joblib  # to save/load model

# === CONFIGURATION ===
SAAVN_SEARCH_URL = "https://saavn.dev/api/search/songs?query={query}&limit=1"
DATA_DIR = "audio"
  # update this if your folder is different

# Create data directory if it doesn't exist
if not os.path.exists(DATA_DIR):
    os.makedirs(DATA_DIR)
    print(f"Created directory: {DATA_DIR}. Please upload your audio dataset into this folder.")
    # You might want to exit or handle this case where data is missing

# === FEATURE EXTRACTION ===
def extract_features(file_path):
    try:
        audio, sr = librosa.load(file_path, duration=3, offset=0.5)
        mfccs = librosa.feature.mfcc(y=audio, sr=sr, n_mfcc=13)
        return np.mean(mfccs.T, axis=0)
    except Exception as e:
        print("Error loading file:", e)
        return None

# === LOAD DATA AND TRAIN MODEL ===
def train_model(data_dir):
    features = []
    labels = []
    for folder in os.listdir(data_dir):
        emotion = folder.split('_')[-1].lower()
        folder_path = os.path.join(data_dir, folder)
        for filename in os.listdir(folder_path):
            if filename.endswith('.wav'):
                file_path = os.path.join(folder_path, filename)
                mfcc = extract_features(file_path)
                if mfcc is not None:
                    features.append(mfcc)
                    labels.append(emotion)

    # Check if any data was loaded
    if not features:
        print(f"No audio files found in {data_dir}. Please upload your dataset.")
        return None # Or raise an error

    X = np.array(features)
    y = np.array(labels)
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
    model = RandomForestClassifier()
    model.fit(X_train, y_train)

    # Optional: Save model
    joblib.dump(model, "voice_mood_model.pkl")

    # Evaluate (Optional)
    y_pred = model.predict(X_test)
    print("βœ… Model Trained - Accuracy:", accuracy_score(y_test, y_pred))
    print(classification_report(y_test, y_pred))
    return model

# Load existing or train new model
model = None # Initialize model to None
if os.path.exists("voice_mood_model.pkl"):
    try:
        model = joblib.load("voice_mood_model.pkl")
        print("Loaded existing model.")
    except Exception as e:
        print(f"Error loading model: {e}. Retraining model.")
        model = train_model(DATA_DIR)
else:
    model = train_model(DATA_DIR)

# Ensure model is trained before proceeding
if model is None:
    print("Model could not be trained or loaded. Exiting.")
    # You might want to add sys.exit() here if running as a script
else:
    # === PREDICT EMOTION FROM AUDIO ===
    def predict_emotion(file_path):
        mfcc = extract_features(file_path)
        if mfcc is not None:
            # Ensure the model is available before predicting
            if model:
                return model.predict(mfcc.reshape(1, -1))[0]
            else:
                print("Model not loaded or trained.")
                return "Error: Model not available"
        return "Unknown"

    # === GET SONG FROM SAAVN ===
    def get_song_from_mood(mood, language="tamil"):
        query = f"{mood} {language} song"
        url = SAAVN_SEARCH_URL.format(query=query)
        try:
            response = requests.get(url)
            response.raise_for_status() # Raise an exception for bad status codes
            data = response.json()
            if data.get("data") and data["data"]["results"]:
                song = data["data"]["results"][0]
                title = song["name"]
                artist = (
                    song.get("artists", {}).get("primary", [{}])[0].get("name") or
                    song.get("primaryArtists") or song.get("artist") or "Unknown Artist"
                )
                return f"🎢 **{title}** by *{artist}*\nπŸ”— [Listen here]({song['url']})"
        except requests.exceptions.RequestException as e:
            print("Song fetch error:", e)
        except Exception as e:
            print("Song fetch error:", e)
        return "πŸ˜• No song found for this mood."

    # === GRADIO INTERFACE FUNCTION ===
    def detect_and_recommend(audio_path):
        if model: # Check if model is available
            mood = predict_emotion(audio_path)
            song = get_song_from_mood(mood)
            return f"🎭 Detected Mood: **{mood}**\n\n{song}"
        else:
            return "Model not trained or loaded. Cannot detect mood."


    # === LAUNCH GRADIO APP ===
    gr.Interface(
        fn=detect_and_recommend,
        inputs=gr.Audio(type="filepath", label="πŸŽ™ Upload Your Voice"),
        outputs="markdown",
        title="🎀 Voice2Vibes (Offline Version)",
        description="Detects mood from your voice using your dataset and recommends a matching Tamil song 🎢"
    ).launch()