Diarisation : Identifier Qui Parle
Qu’est-ce que la diarisation
La diarisation (speaker diarization) est la capacité à identifier et séparer les différents locuteurs dans un enregistrement audio. Le modèle attribue automatiquement un identifiant à chaque voix distincte et segmente la transcription en conséquence.
C’est une fonctionnalité essentielle pour les enregistrements multi-locuteurs : réunions, interviews, appels téléphoniques, débats, tables rondes.
Activer la diarisation
Un seul paramètre suffit : diarize=True.
import os
from mistralai import Mistral
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
with open("reunion_equipe.mp3", "rb") as f:
response = client.audio.transcriptions.complete(
model="voxtral-mini-latest",
file={"content": f, "file_name": "reunion_equipe.mp3"},
diarize=True,
timestamp_granularities=["segment"]
)
La diarisation fonctionne de pair avec les timestamps par segment. Chaque segment retourné contient désormais un champ speaker identifiant le locuteur.
Exploiter les résultats
Affichage simple
for seg in response.segments:
temps = f"{seg.start:.1f}s"
print(f"[{temps}] {seg.speaker} : {seg.text}")
Résultat typique :
[0.0s] speaker_0 : Bonjour à tous, on commence la réunion hebdomadaire.
[3.2s] speaker_0 : Julien, tu veux commencer avec le point technique ?
[5.8s] speaker_1 : Oui, alors cette semaine on a finalisé la migration.
[12.4s] speaker_1 : Tout est déployé en production depuis mercredi.
[15.1s] speaker_2 : Super, et côté performances, on a vu une amélioration ?
[18.3s] speaker_1 : Oui, le temps de réponse a baissé de trente pour cent.
Les locuteurs sont identifiés comme speaker_0, speaker_1, speaker_2, etc. Le modèle ne connaît pas les noms — c’est à vous de mapper ces identifiants aux personnes réelles.
Mapper les locuteurs à des noms
# Mapping des identifiants aux noms réels
noms_locuteurs = {
"speaker_0": "Marie (Manager)",
"speaker_1": "Julien (Tech Lead)",
"speaker_2": "Sarah (Product)",
}
for seg in response.segments:
nom = noms_locuteurs.get(seg.speaker, seg.speaker)
minutes = int(seg.start // 60)
secondes = int(seg.start % 60)
print(f"[{minutes:02d}:{secondes:02d}] {nom}")
print(f" {seg.text}\n")
Compter le temps de parole par locuteur
from collections import defaultdict
temps_parole = defaultdict(float)
for seg in response.segments:
duree = seg.end - seg.start
temps_parole[seg.speaker] += duree
print("=== Temps de parole ===")
total = sum(temps_parole.values())
for locuteur, duree in sorted(temps_parole.items()):
nom = noms_locuteurs.get(locuteur, locuteur)
pourcentage = (duree / total) * 100
minutes = int(duree // 60)
secondes = int(duree % 60)
print(f"{nom} : {minutes}m{secondes:02d}s ({pourcentage:.1f}%)")
Résultat :
=== Temps de parole ===
Marie (Manager) : 8m23s (28.4%)
Julien (Tech Lead) : 12m45s (43.2%)
Sarah (Product) : 8m22s (28.4%)
Générer un compte-rendu structuré
La diarisation combinée aux segments permet de générer un compte-rendu exploitable :
def generer_compte_rendu(segments, noms):
"""Génère un compte-rendu Markdown à partir des segments diarisés."""
lignes = ["# Compte-rendu de réunion\n"]
locuteur_actuel = None
for seg in segments:
nom = noms.get(seg.speaker, seg.speaker)
if seg.speaker != locuteur_actuel:
locuteur_actuel = seg.speaker
minutes = int(seg.start // 60)
secondes = int(seg.start % 60)
lignes.append(f"\n**{nom}** ({minutes:02d}:{secondes:02d}) :")
lignes.append(f" {seg.text}")
return "\n".join(lignes)
compte_rendu = generer_compte_rendu(response.segments, noms_locuteurs)
with open("compte_rendu.md", "w", encoding="utf-8") as f:
f.write(compte_rendu)
print("Compte-rendu généré")
Cas d’usage avancé : réunion complète
Voici un script complet pour transcrire et analyser une réunion :
import os
import json
from collections import defaultdict
from mistralai import Mistral
def analyser_reunion(chemin_audio: str, noms: dict = None):
"""Transcrit et analyse une réunion complète."""
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
# Transcrire avec diarisation
with open(chemin_audio, "rb") as f:
response = client.audio.transcriptions.complete(
model="voxtral-mini-latest",
file={"content": f, "file_name": chemin_audio},
diarize=True,
timestamp_granularities=["segment"]
)
noms = noms or {}
# Statistiques
stats = defaultdict(lambda: {"duree": 0.0, "segments": 0, "mots": 0})
for seg in response.segments:
stats[seg.speaker]["duree"] += seg.end - seg.start
stats[seg.speaker]["segments"] += 1
stats[seg.speaker]["mots"] += len(seg.text.split())
# Résultat
resultat = {
"transcription": response.text,
"nb_locuteurs": len(stats),
"duree_totale": max(s.end for s in response.segments),
"statistiques": {
noms.get(loc, loc): {
"duree_secondes": round(data["duree"], 1),
"nb_segments": data["segments"],
"nb_mots": data["mots"]
}
for loc, data in stats.items()
}
}
return resultat
# Utilisation
resultat = analyser_reunion("reunion.mp3", {
"speaker_0": "Marie",
"speaker_1": "Julien",
"speaker_2": "Sarah"
})
print(json.dumps(resultat["statistiques"], indent=2, ensure_ascii=False))
Limites de la diarisation
- Pas de reconnaissance d’identité — Le modèle distingue les voix mais ne sait pas qui est qui. Le mapping est à votre charge.
- Nombre de locuteurs — Le modèle détecte automatiquement le nombre. Pas besoin de le spécifier.
- Voix similaires — Deux voix très proches (par exemple, deux personnes du même sexe et du même âge) peuvent parfois être confondues.
- Pas disponible en temps réel — La diarisation est uniquement supportée en mode offline (Voxtral Mini Transcribe V2), pas avec Voxtral Realtime.
Points clés à retenir
- Activez la diarisation avec
diarize=True— un seul paramètre - Combinez avec
timestamp_granularities=["segment"]pour des résultats structurés - Chaque segment contient un champ
speaker(speaker_0,speaker_1, etc.) - Mappez les identifiants aux noms réels dans votre code
- Exploitez les statistiques : temps de parole, nombre d’interventions, nombre de mots
- La diarisation n’est disponible qu’en mode offline