Spaces:
Running
Running
Filtrer les speakers vides
Browse files
app.py
CHANGED
@@ -5,36 +5,11 @@ import soundfile as sf
|
|
5 |
from sklearn.preprocessing import StandardScaler
|
6 |
from sklearn.cluster import KMeans
|
7 |
from transformers import pipeline
|
8 |
-
import noisereduce as nr
|
9 |
-
from sklearn.metrics import silhouette_score
|
10 |
|
11 |
print("Chargement du modèle Wav2Vec2...")
|
12 |
stt_pipeline = pipeline("automatic-speech-recognition", model="boumehdi/wav2vec2-large-xlsr-moroccan-darija")
|
13 |
print("Modèle chargé avec succès !")
|
14 |
|
15 |
-
def is_silent(audio, threshold=0.005):
|
16 |
-
"""Vérifie si l'audio est principalement du silence ou du bruit de fond faible."""
|
17 |
-
energy = np.mean(np.abs(audio)) # Mesure de l'énergie du signal
|
18 |
-
print(f"Énergie du signal: {energy}")
|
19 |
-
return energy < threshold
|
20 |
-
|
21 |
-
def find_optimal_clusters(mfccs_scaled):
|
22 |
-
"""Trouve le nombre optimal de locuteurs en utilisant le score silhouette"""
|
23 |
-
best_score = -1
|
24 |
-
best_n_clusters = 1 # Par défaut, on suppose un seul locuteur
|
25 |
-
|
26 |
-
for n_clusters in range(1, 3): # On teste pour 1 ou 2 locuteurs
|
27 |
-
kmeans = KMeans(n_clusters=n_clusters, random_state=42, n_init=10)
|
28 |
-
labels = kmeans.fit_predict(mfccs_scaled)
|
29 |
-
|
30 |
-
if n_clusters > 1:
|
31 |
-
score = silhouette_score(mfccs_scaled, labels) # Score silhouette
|
32 |
-
if score > best_score:
|
33 |
-
best_score = score
|
34 |
-
best_n_clusters = n_clusters
|
35 |
-
|
36 |
-
return best_n_clusters
|
37 |
-
|
38 |
def process_audio(audio_path):
|
39 |
print(f"Fichier reçu : {audio_path}")
|
40 |
|
@@ -43,17 +18,8 @@ def process_audio(audio_path):
|
|
43 |
audio, sr = librosa.load(audio_path, sr=None, duration=30)
|
44 |
print(f"Audio chargé : {len(audio)} échantillons à {sr} Hz")
|
45 |
|
46 |
-
# Vérifier si l'audio est vide (silence)
|
47 |
-
if is_silent(audio):
|
48 |
-
print("Aucun locuteur détecté (audio trop silencieux).")
|
49 |
-
return "Aucun locuteur détecté."
|
50 |
-
|
51 |
-
# Réduction du bruit (SNR)
|
52 |
-
audio_denoised = nr.reduce_noise(y=audio, sr=sr)
|
53 |
-
print("Bruit réduit.")
|
54 |
-
|
55 |
# Extraction des MFCC
|
56 |
-
mfccs = librosa.feature.mfcc(y=
|
57 |
print(f"MFCC extrait, shape: {mfccs.shape}")
|
58 |
|
59 |
# Normalisation
|
@@ -61,23 +27,20 @@ def process_audio(audio_path):
|
|
61 |
mfccs_scaled = scaler.fit_transform(mfccs.T)
|
62 |
print("MFCC normalisé.")
|
63 |
|
64 |
-
#
|
65 |
-
|
66 |
-
print(f"Nombre optimal de locuteurs détecté : {optimal_clusters}")
|
67 |
-
|
68 |
-
# Appliquer KMeans avec le bon nombre de locuteurs
|
69 |
-
kmeans = KMeans(n_clusters=optimal_clusters, random_state=42, n_init=10)
|
70 |
speaker_labels = kmeans.fit_predict(mfccs_scaled)
|
|
|
71 |
|
72 |
# Regrouper les segments audio par speaker
|
73 |
speaker_audio = {speaker: [] for speaker in set(speaker_labels)}
|
74 |
-
segment_duration = len(
|
75 |
|
76 |
for i in range(len(speaker_labels)):
|
77 |
start = i * segment_duration
|
78 |
end = start + segment_duration
|
79 |
speaker_id = speaker_labels[i]
|
80 |
-
speaker_audio[speaker_id].extend(
|
81 |
|
82 |
# Transcrire les segments fusionnés
|
83 |
result = []
|
@@ -89,11 +52,19 @@ def process_audio(audio_path):
|
|
89 |
sf.write(temp_filename, np.array(audio_segment), sr) # Sauvegarder le segment
|
90 |
|
91 |
transcription = stt_pipeline(temp_filename) # Transcrire
|
92 |
-
|
|
|
|
|
|
|
|
|
93 |
|
94 |
print(f"Transcription Speaker {speaker} terminée.")
|
95 |
|
96 |
-
|
|
|
|
|
|
|
|
|
97 |
|
98 |
except Exception as e:
|
99 |
print(f"Erreur : {e}")
|
|
|
5 |
from sklearn.preprocessing import StandardScaler
|
6 |
from sklearn.cluster import KMeans
|
7 |
from transformers import pipeline
|
|
|
|
|
8 |
|
9 |
print("Chargement du modèle Wav2Vec2...")
|
10 |
stt_pipeline = pipeline("automatic-speech-recognition", model="boumehdi/wav2vec2-large-xlsr-moroccan-darija")
|
11 |
print("Modèle chargé avec succès !")
|
12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
def process_audio(audio_path):
|
14 |
print(f"Fichier reçu : {audio_path}")
|
15 |
|
|
|
18 |
audio, sr = librosa.load(audio_path, sr=None, duration=30)
|
19 |
print(f"Audio chargé : {len(audio)} échantillons à {sr} Hz")
|
20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
# Extraction des MFCC
|
22 |
+
mfccs = librosa.feature.mfcc(y=audio, sr=sr, n_mfcc=13)
|
23 |
print(f"MFCC extrait, shape: {mfccs.shape}")
|
24 |
|
25 |
# Normalisation
|
|
|
27 |
mfccs_scaled = scaler.fit_transform(mfccs.T)
|
28 |
print("MFCC normalisé.")
|
29 |
|
30 |
+
# Clustering avec KMeans
|
31 |
+
kmeans = KMeans(n_clusters=2, random_state=42, n_init=10)
|
|
|
|
|
|
|
|
|
32 |
speaker_labels = kmeans.fit_predict(mfccs_scaled)
|
33 |
+
print(f"Clustering terminé, {len(set(speaker_labels))} locuteurs détectés.")
|
34 |
|
35 |
# Regrouper les segments audio par speaker
|
36 |
speaker_audio = {speaker: [] for speaker in set(speaker_labels)}
|
37 |
+
segment_duration = len(audio) // len(speaker_labels)
|
38 |
|
39 |
for i in range(len(speaker_labels)):
|
40 |
start = i * segment_duration
|
41 |
end = start + segment_duration
|
42 |
speaker_id = speaker_labels[i]
|
43 |
+
speaker_audio[speaker_id].extend(audio[start:end])
|
44 |
|
45 |
# Transcrire les segments fusionnés
|
46 |
result = []
|
|
|
52 |
sf.write(temp_filename, np.array(audio_segment), sr) # Sauvegarder le segment
|
53 |
|
54 |
transcription = stt_pipeline(temp_filename) # Transcrire
|
55 |
+
text = transcription["text"].strip()
|
56 |
+
|
57 |
+
# Ajouter seulement si le texte n'est pas vide
|
58 |
+
if text:
|
59 |
+
result.append(f"Speaker {speaker}: {text}")
|
60 |
|
61 |
print(f"Transcription Speaker {speaker} terminée.")
|
62 |
|
63 |
+
# Filtrer les speakers sans texte
|
64 |
+
if not result:
|
65 |
+
return "Aucune parole détectée."
|
66 |
+
|
67 |
+
return "\n".join(result)
|
68 |
|
69 |
except Exception as e:
|
70 |
print(f"Erreur : {e}")
|