Boltz79/Sentiment-Analysis
0
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()