CoolFace
Apppublic

Boltz79/Sentiment-Analysis

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
app.py187 linesDownload Raw Back to root
1# app.py2import gradio as gr3import librosa4import numpy as np5import os6import tempfile7from collections import Counter8from speechbrain.inference.interfaces import foreign_class9import io10import matplotlib.pyplot as plt11import librosa.display12from PIL import Image  # For image conversion13 14# Try to import noisereduce (if not available, noise reduction will be skipped)15try:16    import noisereduce as nr17    NOISEREDUCE_AVAILABLE = True18except ImportError:19    NOISEREDUCE_AVAILABLE = False20 21# Mapping from emotion labels to emojis22emotion_to_emoji = {23    "angry": "๐Ÿ˜ ",24    "happy": "๐Ÿ˜Š",25    "sad": "๐Ÿ˜ข",26    "neutral": "๐Ÿ˜",27    "excited": "๐Ÿ˜„",28    "fear": "๐Ÿ˜จ",29    "disgust": "๐Ÿคข",30    "surprise": "๐Ÿ˜ฒ"31}32 33def add_emoji_to_label(label):34    """Append an emoji corresponding to the emotion label."""35    emoji = emotion_to_emoji.get(label.lower(), "")36    return f"{label.capitalize()} {emoji}"37 38# Load the pre-trained SpeechBrain classifier39classifier = foreign_class(40    source="speechbrain/emotion-recognition-wav2vec2-IEMOCAP",41    pymodule_file="custom_interface.py",42    classname="CustomEncoderWav2vec2Classifier",43    run_opts={"device": "cpu"}  # Change to {"device": "cuda"} if GPU is available44)45 46def preprocess_audio(audio_file, apply_noise_reduction=False):47    """48    Load and preprocess the audio file:49      - Convert to 16kHz mono.50      - Optionally apply noise reduction.51      - Normalize the audio.52    Saves the processed audio to a temporary file and returns its path.53    """54    y, sr = librosa.load(audio_file, sr=16000, mono=True)55    if apply_noise_reduction and NOISEREDUCE_AVAILABLE:56        y = nr.reduce_noise(y=y, sr=sr)57    if np.max(np.abs(y)) > 0:58        y = y / np.max(np.abs(y))59    temp_file = tempfile.NamedTemporaryFile(suffix=".wav", delete=False)60    import soundfile as sf61    sf.write(temp_file.name, y, sr)62    return temp_file.name63 64def ensemble_prediction(audio_file, apply_noise_reduction=False, segment_duration=3.0, overlap=1.0):65    """66    For longer audio files, split into overlapping segments, predict each segment,67    and return the majority-voted emotion label.68    """69    y, sr = librosa.load(audio_file, sr=16000, mono=True)70    total_duration = librosa.get_duration(y=y, sr=sr)71    72    if total_duration <= segment_duration:73        temp_file = preprocess_audio(audio_file, apply_noise_reduction)74        _, _, _, label = classifier.classify_file(temp_file)75        os.remove(temp_file)76        return label[0]77 78    step = segment_duration - overlap79    segments = []80    for start in np.arange(0, total_duration - segment_duration + 0.001, step):81        start_sample = int(start * sr)82        end_sample = int((start + segment_duration) * sr)83        segment_audio = y[start_sample:end_sample]84        temp_seg = tempfile.NamedTemporaryFile(suffix=".wav", delete=False)85        import soundfile as sf86        sf.write(temp_seg.name, segment_audio, sr)87        segments.append(temp_seg.name)88    89    predictions = []90    for seg in segments:91        temp_file = preprocess_audio(seg, apply_noise_reduction)92        _, _, _, label = classifier.classify_file(temp_file)93        predictions.append(label[0])94        os.remove(temp_file)95        os.remove(seg)96    97    vote = Counter(predictions)98    most_common = vote.most_common(1)[0][0]99    return most_common100 101def predict_emotion(audio_file, use_ensemble=False, apply_noise_reduction=False, segment_duration=3.0, overlap=1.0):102    """103    Predict emotion from an audio file and return the emotion with an emoji.104    """105    try:106        if use_ensemble:107            label = ensemble_prediction(audio_file, apply_noise_reduction, segment_duration, overlap)108        else:109            temp_file = preprocess_audio(audio_file, apply_noise_reduction)110            result = classifier.classify_file(temp_file)111            os.remove(temp_file)112            if isinstance(result, tuple) and len(result) > 3:113                label = result[3][0]  # Extract predicted emotion label from the tuple114            else:115                label = str(result)116        return add_emoji_to_label(label.lower())117    except Exception as e:118        return f"Error processing file: {str(e)}"119 120def plot_waveform(audio_file):121    """122    Generate and return a waveform plot image (as a PIL Image) for the given audio file.123    """124    y, sr = librosa.load(audio_file, sr=16000, mono=True)125    plt.figure(figsize=(10, 3))126    librosa.display.waveshow(y, sr=sr)127    plt.title("Waveform")128    buf = io.BytesIO()129    plt.savefig(buf, format="png")130    plt.close()131    buf.seek(0)132    return Image.open(buf)133 134def predict_and_plot(audio_file, use_ensemble, apply_noise_reduction, segment_duration, overlap):135    """136    Run emotion prediction and generate a waveform plot.137    Returns a tuple: (emotion label with emoji, waveform image as a PIL Image).138    """139    emotion = predict_emotion(audio_file, use_ensemble, apply_noise_reduction, segment_duration, overlap)140    waveform = plot_waveform(audio_file)141    return emotion, waveform142 143with gr.Blocks(css=".gradio-container {background-color: #f7f7f7; font-family: Arial;}") as demo:144    gr.Markdown("<h1 style='text-align: center;'>Enhanced Emotion Recognition</h1>")145    gr.Markdown(146        "Upload an audio file, and the model will predict the emotion using a wav2vec2 model fine-tuned on IEMOCAP data. "147        "The prediction is accompanied by an emoji in the output, and you can also view the audio's waveform. "148        "Use the options below to adjust ensemble prediction and noise reduction settings."149    )150    151    with gr.Tabs():152        with gr.TabItem("Emotion Recognition"):153            with gr.Row():154                audio_input = gr.Audio(type="filepath", label="Upload Audio")155            use_ensemble = gr.Checkbox(label="Use Ensemble Prediction (for long audio)", value=False)156            apply_noise_reduction = gr.Checkbox(label="Apply Noise Reduction", value=False)157            with gr.Row():158                segment_duration = gr.Slider(minimum=1.0, maximum=10.0, step=0.5, value=3.0, label="Segment Duration (s)")159                overlap = gr.Slider(minimum=0.0, maximum=5.0, step=0.5, value=1.0, label="Segment Overlap (s)")160            predict_button = gr.Button("Predict Emotion")161            result_text = gr.Textbox(label="Predicted Emotion")162            waveform_image = gr.Image(label="Audio Waveform", type="pil")163            164            predict_button.click(165                predict_and_plot,166                inputs=[audio_input, use_ensemble, apply_noise_reduction, segment_duration, overlap],167                outputs=[result_text, waveform_image]168            )169        170        with gr.TabItem("About"):171            gr.Markdown("""172**Enhanced Emotion Recognition App**173 174- **Model:** SpeechBrain's wav2vec2 model fine-tuned on IEMOCAP for emotion recognition.175- **Features:**176  - Ensemble Prediction for long audio files.177  - Optional Noise Reduction.178  - Visualization of the audio waveform.179  - Emoji representation of the predicted emotion in the output.180 181**Credits:**182- [SpeechBrain](https://speechbrain.github.io)183- [Gradio](https://gradio.app)184            """)185 186if __name__ == "__main__":187    demo.launch()