jdalfonso commited on
Commit
5447dfd
·
unverified ·
2 Parent(s): 959c3f4 41d9375

Merge pull request #2 from jdalfons/develop

Browse files
requirements.txt CHANGED
@@ -15,3 +15,4 @@ scikit-learn
15
  huggingface
16
  huggingface_hub
17
  pyaudio
 
 
15
  huggingface
16
  huggingface_hub
17
  pyaudio
18
+ streamlit_audiorec
src/model/predict.py CHANGED
@@ -13,18 +13,31 @@ model.eval()
13
 
14
  emotion_labels = ["joie", "colère", "neutre"]
15
 
16
- def predict_emotion(audio_path):
17
- waveform, _ = librosa.load(audio_path, sr=16000)
18
- input_values = processor(waveform, return_tensors="pt", sampling_rate=16000).input_values
19
  input_values = input_values.to(device)
20
 
21
  with torch.no_grad():
22
  outputs = model(input_values)
23
-
24
- predicted_label = torch.argmax(outputs, dim=1).item()
25
- return emotion_labels[predicted_label]
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
  # Exemple d'utilisation
28
  audio_test = "data/n1ac.wav"
29
  emotion = predict_emotion(audio_test)
30
- print(f"Émotion détectée : {emotion}")
 
13
 
14
  emotion_labels = ["joie", "colère", "neutre"]
15
 
16
+ def predict_emotion(audio_path, output_probs=False, sampling_rate=16000):
17
+ waveform, _ = librosa.load(audio_path, sr=sampling_rate)
18
+ input_values = processor(waveform, return_tensors="pt", sampling_rate=sampling_rate).input_values
19
  input_values = input_values.to(device)
20
 
21
  with torch.no_grad():
22
  outputs = model(input_values)
23
+
24
+ if output_probs:
25
+ # Appliquer softmax pour obtenir des probabilités
26
+ probabilities = torch.nn.functional.softmax(outputs.logits, dim=-1)
27
+
28
+ # Convertir en numpy array et prendre le premier (et seul) élément
29
+ probabilities = probabilities[0].detach().cpu().numpy()
30
+
31
+ # Créer un dictionnaire associant chaque émotion à sa probabilité
32
+ emotion_probabilities = {emotion: prob for emotion, prob in zip(emotion_labels, probabilities)}
33
+ return emotion_probabilities
34
+ else:
35
+ # Obtenir l'émotion la plus probable (i.e. la prédiction)
36
+ predicted_label = torch.argmax(outputs, dim=1).item()
37
+ return emotion_labels[predicted_label]
38
+
39
 
40
  # Exemple d'utilisation
41
  audio_test = "data/n1ac.wav"
42
  emotion = predict_emotion(audio_test)
43
+ print(f"Émotion détectée : {emotion}")
src/model/transcriber.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from transformers import Wav2Vec2Processor
3
+ from src.model.emotion_classifier import Wav2Vec2EmotionClassifier
4
+ import librosa
5
+
6
+ # device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
7
+ # processor = Wav2Vec2Processor.from_pretrained("facebook/wav2vec2-large-xlsr-53")
8
+ # model = Wav2Vec2EmotionClassifier()
9
+ # model.load_state_dict(torch.load("wav2vec2_emotion.pth"))
10
+ # model.to(device)
11
+
12
+
13
+ def transcribe_audio(audio, sampling_rate=16000):
14
+ # Préparer les données d'entrée pour le modèle
15
+ input_values = processor(audio, sampling_rate=sampling_rate, return_tensors="pt").input_values
16
+
17
+ # Passer les données dans le modèle pour obtenir les logits
18
+ with torch.no_grad():
19
+ logits = model(input_values).logits
20
+
21
+ # Décoder les prédictions en texte
22
+ predicted_ids = torch.argmax(logits, dim=-1)
23
+ transcription = processor.batch_decode(predicted_ids)[0]
24
+ return transcription
src/predictions/feedback.csv ADDED
@@ -0,0 +1 @@
 
 
1
+ filepath,prediction,feedback
views/application.py CHANGED
@@ -1,6 +1,8 @@
1
  import streamlit as st
 
2
  import datetime
3
  import os
 
4
 
5
  DIRECTORY = "audios"
6
  FILE_NAME = "audio.wav"
@@ -17,24 +19,57 @@ def application():
17
 
18
  st.markdown("---")
19
 
20
- tab1, tab2 = st.tabs(["Record Audio", "Register Audio"])
21
 
22
  with tab1:
23
- st.header("Record Audio")
24
- st.write("Here you can record audio.")
25
  audio_file = st.file_uploader("Upload an audio file", type=["wav", "mp3", "ogg"])
26
  if audio_file is not None:
27
 
28
- with open(f"audios/{FILE_NAME}", "wb") as f:
29
  f.write(audio_file.getbuffer())
30
  st.success(f"Saved file: {FILE_NAME}")
31
 
32
  with tab2:
33
- st.header("Register Audio")
34
- st.write("Here you can register audio.")
35
 
 
 
36
 
37
- file = os.path.join(DIRECTORY, FILE_NAME)
38
- if os.path.exists(file):
39
- st.markdown("## File registered:")
40
- audio_data = st.audio(file, format='audio/wav', start_time=0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ from st_audiorec import st_audiorec
3
  import datetime
4
  import os
5
+ from src.model.transcriber import transcribe_audio
6
 
7
  DIRECTORY = "audios"
8
  FILE_NAME = "audio.wav"
 
19
 
20
  st.markdown("---")
21
 
22
+ tab1, tab2, tab3 = st.tabs(["⬆️ Record Audio", "🔈 Realtime Audio", "📝 Transcription"])
23
 
24
  with tab1:
25
+ st.header("⬆️ Upload Audio Record")
26
+ st.write("Here you can upload a pre-recorded audio.")
27
  audio_file = st.file_uploader("Upload an audio file", type=["wav", "mp3", "ogg"])
28
  if audio_file is not None:
29
 
30
+ with open(f"{DIRECTORY}/{FILE_NAME}", "wb") as f:
31
  f.write(audio_file.getbuffer())
32
  st.success(f"Saved file: {FILE_NAME}")
33
 
34
  with tab2:
35
+ st.header("🔈 Realtime Audio Record")
36
+ st.write("Here you can record an audio.")
37
 
38
+ if st.button("Register", key="register-button"):
39
+ st.success("Audio registered successfully.")
40
 
41
+ audio_file = st_audiorec()
42
+
43
+ if audio_file is not None:
44
+ st.audio(audio_file, format='audio/wav')
45
+
46
+ with tab3:
47
+ st.header("📝 Speech2Text Transcription")
48
+ st.write("Here you can get the audio transcript.")
49
+
50
+ save = st.checkbox("Save transcription to .txt", value=False, key="save-transcript")
51
+
52
+ ############################# A décommenté quand ce sera débogué
53
+ if st.button("Transcribe", key="transcribe-button"):
54
+ # # Fonction pour transcrire l'audio
55
+ # transcription = transcribe_audio(st.audio)
56
+
57
+ # # Charger et transcrire l'audio
58
+ # # audio, rate = load_audio(audio_file_path) # (re)chargement de l'audio si nécessaire
59
+ # transcription = transcribe_audio(audio_file, sampling_rate=16000)
60
+
61
+ # # Afficher la transcription
62
+ # st.write("Transcription :", transcription)
63
+
64
+
65
+ st.success("Audio registered successfully.")
66
+ # if save:
67
+ # file_path = "transcript.txt"
68
+
69
+ # # Write the text to the file
70
+ # with open(file_path, "w") as file:
71
+ # file.write(transcription)
72
+
73
+ # st.success(f"Text saved to {file_path}")
74
+
75
+
views/real_time.py CHANGED
@@ -1,5 +1,5 @@
1
  ################################
2
- ### NOT YET TESTED
3
  ###############################
4
 
5
  import streamlit as st
@@ -7,8 +7,10 @@ import pyaudio
7
  import wave
8
  import torch
9
  from transformers import Wav2Vec2ForSequenceClassification, Wav2Vec2Processor
 
10
  import numpy as np
11
  import time
 
12
 
13
  # Charger le modèle Wav2Vec2 pour la classification des émotions
14
  model_name = "superb/wav2vec2-base-superb-er" # Exemple de modèle pour la reconnaissance des émotions
@@ -22,13 +24,13 @@ CHANNELS = 1
22
  RATE = 16000
23
 
24
  # Fonction pour prédire l'émotion à partir d'un segment audio
25
- def predict_emotion(audio_data):
26
- inputs = processor(audio_data, sampling_rate=RATE, return_tensors="pt", padding=True)
27
- with torch.no_grad():
28
- logits = model(**inputs).logits
29
- predicted_id = torch.argmax(logits, dim=-1).item()
30
- emotion = model.config.id2label[predicted_id]
31
- return emotion
32
 
33
  # Interface Streamlit
34
  st.title("Détection des émotions en temps réel")
@@ -56,7 +58,7 @@ if start_button:
56
  # Traitement en temps réel (par tranche de 1 seconde)
57
  if len(frames) >= RATE // CHUNK:
58
  audio_segment = np.frombuffer(b''.join(frames[-(RATE // CHUNK):]), dtype=np.int16)
59
- emotion = predict_emotion(audio_segment)
60
  real_time_emotions.append(emotion)
61
  emotion_placeholder.line_chart(real_time_emotions) # Affichage graphique des émotions
62
 
@@ -78,3 +80,276 @@ if start_button:
78
  final_emotion = predict_emotion(full_audio_data)
79
 
80
  final_emotion_placeholder.write(f"Émotion finale prédite : {final_emotion}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ################################
2
+ ### Real time prediction for real time record
3
  ###############################
4
 
5
  import streamlit as st
 
7
  import wave
8
  import torch
9
  from transformers import Wav2Vec2ForSequenceClassification, Wav2Vec2Processor
10
+ import matplotlib.pyplot as plt
11
  import numpy as np
12
  import time
13
+ from src.model.predict import predict_emotion
14
 
15
  # Charger le modèle Wav2Vec2 pour la classification des émotions
16
  model_name = "superb/wav2vec2-base-superb-er" # Exemple de modèle pour la reconnaissance des émotions
 
24
  RATE = 16000
25
 
26
  # Fonction pour prédire l'émotion à partir d'un segment audio
27
+ # def predict_emotion(audio_data):
28
+ # inputs = processor(audio_data, sampling_rate=RATE, return_tensors="pt", padding=True)
29
+ # with torch.no_grad():
30
+ # logits = model(**inputs).logits
31
+ # predicted_id = torch.argmax(logits, dim=-1).item()
32
+ # emotion = model.config.id2label[predicted_id]
33
+ # return emotion
34
 
35
  # Interface Streamlit
36
  st.title("Détection des émotions en temps réel")
 
58
  # Traitement en temps réel (par tranche de 1 seconde)
59
  if len(frames) >= RATE // CHUNK:
60
  audio_segment = np.frombuffer(b''.join(frames[-(RATE // CHUNK):]), dtype=np.int16)
61
+ emotion = predict_emotion(audio_segment, output_probs=False, sampling_rate=RATE)
62
  real_time_emotions.append(emotion)
63
  emotion_placeholder.line_chart(real_time_emotions) # Affichage graphique des émotions
64
 
 
80
  final_emotion = predict_emotion(full_audio_data)
81
 
82
  final_emotion_placeholder.write(f"Émotion finale prédite : {final_emotion}")
83
+
84
+
85
+ ################################
86
+ ### Real time prediction for uploaded audio file
87
+ ###############################
88
+ # Charger le modèle wav2vec et le processeur
89
+ model = Wav2Vec2ForSequenceClassification.from_pretrained("your_emotion_model_path")
90
+ processor = Wav2Vec2Processor.from_pretrained("your_emotion_model_path")
91
+
92
+ # Définir les émotions
93
+ emotions = ["neutre", "joie", "colère", "tristesse"] # Ajustez selon votre modèle
94
+
95
+ # Fonction pour prédire l'émotion
96
+ # def predict_emotion(audio_chunk):
97
+ # inputs = processor(audio_chunk, sampling_rate=16000, return_tensors="pt", padding=True)
98
+ # with torch.no_grad():
99
+ # logits = model(**inputs).logits
100
+ # scores = torch.softmax(logits, dim=1).squeeze().tolist()
101
+ # return dict(zip(emotions, scores))
102
+
103
+ # Configuration Streamlit
104
+ st.title("Analyse des émotions en temps réel")
105
+ uploaded_file = st.file_uploader("Choisissez un fichier audio", type=["wav", "mp3"])
106
+
107
+ if uploaded_file is not None:
108
+ # Charger et rééchantillonner l'audio
109
+ audio, sr = librosa.load(uploaded_file, sr=16000)
110
+
111
+ # Paramètres de la fenêtre glissante
112
+ window_size = 1 # en secondes
113
+ hop_length = 0.5 # en secondes
114
+
115
+ # Créer un graphique en temps réel
116
+ fig, ax = plt.subplots()
117
+ lines = [ax.plot([], [], label=emotion)[0] for emotion in emotions]
118
+ ax.set_ylim(0, 1)
119
+ ax.set_xlim(0, len(audio) / sr)
120
+ ax.set_xlabel("Temps (s)")
121
+ ax.set_ylabel("Probabilité")
122
+ ax.legend()
123
+
124
+ chart = st.pyplot(fig)
125
+
126
+ # Traitement par fenêtre glissante
127
+ for i in range(0, len(audio), int(hop_length * sr)):
128
+ chunk = audio[i:i + int(window_size * sr)]
129
+ if len(chunk) < int(window_size * sr):
130
+ break
131
+
132
+ emotion_scores = predict_emotion(chunk, output_probs=False, sampling_rate=RATE)
133
+
134
+ # Mettre à jour le graphique
135
+ for emotion, line in zip(emotions, lines):
136
+ xdata = line.get_xdata().tolist()
137
+ ydata = line.get_ydata().tolist()
138
+ xdata.append(i / sr)
139
+ ydata.append(emotion_scores[emotion])
140
+ line.set_data(xdata, ydata)
141
+
142
+ ax.relim()
143
+ ax.autoscale_view()
144
+ chart.pyplot(fig)
145
+
146
+ st.success("Analyse terminée !")
147
+
148
+
149
+
150
+
151
+
152
+
153
+
154
+ ############################################
155
+ ### Progress bar
156
+ ############################################
157
+
158
+ with st.status("Downloading data...", expanded=True) as status:
159
+ st.write("Searching for data...")
160
+ time.sleep(2)
161
+ st.write("Found URL.")
162
+ time.sleep(1)
163
+ st.write("Downloading data...")
164
+ time.sleep(1)
165
+ status.update(
166
+ label="Download complete!", state="complete", expanded=False
167
+ )
168
+
169
+ st.button("Rerun")
170
+
171
+
172
+ ############################################
173
+ ### Time duration estimation
174
+ ############################################
175
+ progress_bar = st.progress(0)
176
+ time_placeholder = st.empty()
177
+
178
+ total_time = 10 # Total estimated time in seconds
179
+ for i in range(total_time):
180
+ # Update progress bar
181
+ progress_bar.progress((i + 1) / total_time)
182
+
183
+ # Update time estimation
184
+ remaining_time = total_time - i - 1
185
+ time_placeholder.text(f"Estimated time remaining: {remaining_time} seconds")
186
+
187
+ # Simulate task progress
188
+ time.sleep(1)
189
+
190
+
191
+
192
+ ############################################
193
+ ### Audio file noise reduction
194
+ ############################################
195
+ from pydub import AudioSegment
196
+ import noisereduce as nr
197
+ from transformers import Wav2Vec2ForCTC, Wav2Vec2Processor
198
+
199
+ # Fonction de réduction de bruit
200
+ def reduce_noise(audio_data, sr):
201
+ reduced_noise = nr.reduce_noise(y=audio_data, sr=sr)
202
+ return reduced_noise
203
+
204
+ # Chargement du modèle wav2vec
205
+ processor = Wav2Vec2Processor.from_pretrained("facebook/wav2vec2-base-960h")
206
+ model = Wav2Vec2ForCTC.from_pretrained("facebook/wav2vec2-base-960h")
207
+
208
+ # Interface Streamlit
209
+ st.title("Application de transcription audio avec réduction de bruit")
210
+
211
+ uploaded_file = st.file_uploader("Choisissez un fichier audio .wav", type="wav")
212
+
213
+ if uploaded_file is not None:
214
+ # Chargement et prétraitement de l'audio
215
+ audio = AudioSegment.from_wav(uploaded_file)
216
+ audio_array = np.array(audio.get_array_of_samples())
217
+
218
+ # Réduction de bruit
219
+ reduced_noise_audio = reduce_noise(audio_array, audio.frame_rate)
220
+
221
+ # Traitement avec wav2vec
222
+ input_values = processor(reduced_noise_audio, sampling_rate=audio.frame_rate, return_tensors="pt").input_values
223
+
224
+ with torch.no_grad():
225
+ logits = model(input_values).logits
226
+
227
+ predicted_ids = torch.argmax(logits, dim=-1)
228
+ transcription = processor.batch_decode(predicted_ids)[0]
229
+
230
+ st.audio(uploaded_file, format="audio/wav")
231
+ st.write("Transcription:")
232
+ st.write(transcription)
233
+
234
+
235
+ ############################################
236
+ ### Choix des émotions
237
+ ############################################
238
+ # options = ['Sadness','Anger', 'Disgust', 'Fear', 'Surprise', 'Joy','Neutral']
239
+ # selected_options = st.multiselect('What emotions do you want to be displayed', options, default=['Joy', 'Anger','Neutral])
240
+
241
+
242
+ ############################################
243
+ ### Transcription Speech2Text
244
+ ############################################
245
+ # # Fonction pour transcrire l'audio
246
+ # def transcribe_audio(audio):
247
+ # # Préparer les données d'entrée pour le modèle
248
+ # input_values = processor(audio, sampling_rate=16000, return_tensors="pt").input_values
249
+
250
+ # # Passer les données dans le modèle pour obtenir les logits
251
+ # with torch.no_grad():
252
+ # logits = model(input_values).logits
253
+
254
+ # # Décoder les prédictions en texte
255
+ # predicted_ids = torch.argmax(logits, dim=-1)
256
+ # transcription = processor.batch_decode(predicted_ids)[0]
257
+ # return transcription
258
+
259
+ # # Charger et transcrire l'audio
260
+ # # audio, rate = load_audio(audio_file_path) # (re)chargement de l'audio si nécessaire
261
+ # transcription = transcribe_audio(audio)
262
+
263
+ # # Afficher la transcription
264
+ # print("Transcription :", transcription)
265
+
266
+
267
+ ############################################
268
+ ### Feedback
269
+ ############################################
270
+ import pandas as pd
271
+ import os
272
+
273
+ # Initialisation du fichier CSV
274
+ csv_file = "predictions/feedback.csv"
275
+
276
+ # Vérifier si le fichier CSV existe, sinon le créer avec des colonnes appropriées
277
+ if not os.path.exists(csv_file):
278
+ df = pd.DataFrame(columns=["filepath", "prediction", "feedback"])
279
+ df.to_csv(csv_file, index=False)
280
+
281
+ # Charger les données existantes du CSV
282
+ df = pd.read_csv(csv_file)
283
+
284
+ # Interface Streamlit
285
+ st.title("Predicted emotion feedback")
286
+
287
+ # Simuler une prédiction pour l'exemple (remplacez par votre modèle réel)
288
+ audio_file_name = "example_audio.wav"
289
+ predicted_emotion = "Joie" # Exemple de prédiction
290
+
291
+ st.write(f"Fichier audio : {audio_file_name}")
292
+ st.write(f"Émotion détectée : {predicted_emotion}")
293
+
294
+ # Formulaire de feedback
295
+ with st.form("feedback_form"):
296
+ st.write("Est-ce la bonne émotion qui a été détectée ? Cochez la réelle émotion.")
297
+ feedback = st.selectbox("Votre réponse :", ['Sadness','Anger', 'Disgust', 'Fear', 'Surprise', 'Joy', 'Neutral'])
298
+ submit_button = st.form_submit_button("Soumettre")
299
+ st.write("En cliquant sur ce bouton, vous acceptez que votre audio soit sauvegardé dans notre base de données.")
300
+
301
+ if submit_button:
302
+ # Ajouter le feedback au DataFrame
303
+ new_entry = {"filepath": audio_file_name, "prediction": predicted_emotion, "feedback": feedback}
304
+ df = df.append(new_entry, ignore_index=True)
305
+
306
+ # Sauvegarder les données mises à jour dans le fichier CSV
307
+ df.to_csv(csv_file, index=False)
308
+
309
+ # Sauvegarder le fichier audio
310
+ with open("predictions/data", "wb") as f:
311
+ f.write(uploaded_file.getbuffer())
312
+
313
+ # Confirmation pour l'utilisateur
314
+ st.success("Merci pour votre retour ! Vos données ont été sauvegardées.")
315
+
316
+ # Afficher les données sauvegardées (optionnel)
317
+ # st.write("Données collectées jusqu'à présent :")
318
+ # st.dataframe(df)
319
+
320
+
321
+
322
+
323
+
324
+
325
+
326
+
327
+
328
+
329
+
330
+
331
+
332
+
333
+
334
+ ############################################
335
+ ### Predict proba (to replace in predict.py)
336
+ ############################################
337
+ import librosa
338
+ def predict_emotion_probabilities(audio_path):
339
+ waveform, _ = librosa.load(audio_path, sr=16000)
340
+ input_values = processor(waveform, return_tensors="pt", sampling_rate=16000).input_values
341
+ input_values = input_values.to(device)
342
+
343
+ with torch.no_grad():
344
+ outputs = model(input_values)
345
+
346
+ # Appliquer softmax pour obtenir des probabilités
347
+ probabilities = torch.nn.functional.softmax(outputs.logits, dim=-1)
348
+
349
+ # Convertir en numpy array et prendre le premier (et seul) élément
350
+ probabilities = probabilities[0].detach().cpu().numpy()
351
+
352
+ # Créer un dictionnaire associant chaque émotion à sa probabilité
353
+ emotion_probabilities = {emotion: prob for emotion, prob in zip(emotion_labels, probabilities)}
354
+
355
+ return emotion_probabilities